# Noteback — Integration Contracts This document is the **single source of truth** for the cross-module interfaces in Noteback v1. Every implementation phase MUST honor these signatures exactly so the portable runtime works identically in **extension mode** (content script + `chrome.storage.local`) and **embedded mode** (inlined in a saved canvas + in-file JSON state block). Read this together with the design spec: `docs/design.md`. --- ## 0. Hard environment constraints (do not violate) - Chrome **Manifest V3**. **Vanilla JavaScript only** — NO TypeScript, NO npm dependencies, NO bundler, NO build step. The extension loads unpacked exactly as written. - The **pure-logic** runtime modules (`anchor.js`, `state.js`, `markdown.js`) MUST run **both** in a browser **and** under Node's built-in test runner. They use the dual-export ("UMD-lite") pattern in §4. - **DOM** runtime modules (`highlight.js`, `overlay.js`, `boot.js`) are **browser-only**: they attach to the `NotebackRuntime` global only (no `module.exports`). - Content scripts **cannot** use ES module `import`. Runtime files are listed in dependency order in the manifest's `content_scripts[].js` array and share the `NotebackRuntime` global. - The service worker inlines the runtime into an exported canvas by fetching each runtime file's text via `fetch(chrome.runtime.getURL(path))` and concatenating it into a single inline ``; no checkout marker); "Save clean HTML" saves the raw `v.html` snapshot. Both route through `exporter.onSaveHtml(html, name)` and are **downloaded** — opening the file later is a fresh `file://` canvas with its own storage, which is why this re-uses a version-canvas builder without reintroducing the opaque-origin bug. Implementations (all satisfy the `load`/`save` core; covered by the adapter tests under `test/` — `history-state-adapter.test.js`, `chrome-kv-store.test.js`, `draft-history-core.test.js`): | Implementation | File | Backing store | |-----------------------|-------------------------------------------|---------------| | `ChromeStorageAdapter`| `src/adapters/chrome-storage-adapter.js` | `chrome.storage.local`, keyed by `docId` (comments-only) | | `InFileStateAdapter` | `src/adapters/infile-state-adapter.js` | the in-file `` to `<\/script>` so a comment body can't close it). On reopen the embedded boot **synchronously** seeds `localStorage` from that block — **only keys not already present** (never clobber newer local data) — before the history adapter first resolves. The block is excluded from snapshots (`captureCleanDoc`), clean copies (`rebuildCleanHtml`), plain "with comments" saves (`rebuildHtml`), so it never nests/recurses. Footer **Copy ▾** menu → `onCopyHtml`: *Copy html (with feedback)* → `onCopyHtml(state, {clean:false})` (same bytes as `onSaveCanvas`), *Copy html (clean)* → `onCopyHtml(state, {clean:true})` (same bytes as `onSaveClean`). The main "Copy feedback" button still uses `onCopyMarkdown`. In extension mode the with-feedback variant is assembled by the service worker (`NOTEBACK_BUILD_CANVAS`) and returned as a string; the page writes it to the clipboard. PDF cleanliness relies on the runtime's `@media print` rules (overlay `BUTTON_CSS`), which hide every `[data-noteback-ui]` node and strip highlight styling — so a PDF is the clean document without needing a hook. The embedded canvas supplies `onSaveCanvas`, `onSaveClean`, and `onCopyHtml`; the save hooks serialize the live document (clean copy additionally removes the state block, the inlined runtime ` ``` - `type="application/json"` so the browser does NOT execute it. - `id="noteback-state"` is the lookup key for `InFileStateAdapter`. - Content is `JSON.stringify(state)` (whitespace-insensitive; parsers must tolerate both pretty and minified JSON). - There is **exactly one** such element per canvas. **Baked doc-id.** The canvas body wraps the document in `
` (`canvas-template.html`, filled by the exporter's `{{DOC_ID}}` token). That attribute is the stable identity the snapshot-history engine (§8) keys on — it persists across re-exports, so a re-shared/re-wrapped canvas keeps the same version history. `wrap` (`bin/noteback.js`) mints one when absent and preserves it on re-export (`mintDocId` / `readBakedDocId`); see §8 for the precedence. --- ## 6. Guiding HTML comment string A one-line HTML comment placed at the **top of the canvas ``** (immediately before the original document markup) so any AI handed the file knows what it is. This exact string is the contract (the exporter writes it; tests may assert it): ```html ``` --- ## 7. Canvas assembly summary (who builds what) 1. Service worker (extension) reads page HTML + current State. 2. It fetches each runtime file's text (dependency order, §4) via `fetch(chrome.runtime.getURL(path))` and concatenates them into one runtime blob. 3. `exporter.buildCanvasHtml({ docHtml, state, templateHtml, inlinedRuntime })` fills `src/canvas/canvas-template.html` with: - the guiding HTML comment (§6), - the original document markup, - the original document's `` styling (`{{DOC_STYLE}}`): its inline `