MV3 extension that captures the rendered active tab (via the shared snapshot-extractor contract) and imports it into OpenPencil. Logic lives in the new op-chrome-extension-core crate (wasm): endpoint rules, chunked-transfer integrity, /mcp envelope + reply classification, download-name sanitisation, SSO/account session parsing, and hub snapshot-inbox delivery. JS is glue only (chrome.* APIs, fetch, popup DOM, injected page functions). Capture: full page + element pick. Delivery: local ingress (POST /api/import/web-snapshot) with /mcp fallback, JSON download, and — when signed in to OP Hub — the account snapshot inbox. Flat popup UI, 15-locale strings with an in-popup language switcher, store packaging. Why a crate: keeps the security-sensitive logic in tested Rust rather than glue JS, and the SW/popup split keeps dynamic import() out of the service-worker graph (guarded by check-sw-imports).
82 lines
5.6 KiB
Markdown
82 lines
5.6 KiB
Markdown
# Packages
|
|
|
|
The web SDK packages that remain after the TypeScript retirement. This directory is the **npm/Bun workspace root** (`packages/package.json`); the repository root is a **pure Cargo workspace** with no `package.json`.
|
|
|
|
> The `pen-*` packages (pen-types, pen-core, pen-engine, pen-renderer, pen-figma, pen-mcp, pen-ai-skills, pen-sdk, pen-react, pen-acp) and pen-codegen were **retired** along with `apps/*`. Their functionality now lives in the Rust `crates/` (see `crates/CLAUDE.md`). Nothing here depends on them. The `agent-native` Zig runtime was also **removed** — the built-in agent runtime is now the Rust `agent` crate (`vendor/agent`, shared with Zode).
|
|
|
|
## Workspace tooling
|
|
|
|
Run these from `packages/`:
|
|
|
|
- **Lint / format the SDK:** `bun run lint` (oxlint, plus the extension's extractor drift check) / `bun run format` (oxfmt).
|
|
- **Iconify catalog (Rust assets):** `bun run generate-iconify-catalog` — `scripts/generate-iconify-catalog.mjs` reads `@iconify-json/*` and writes `crates/op-editor-ui/assets/iconify-catalog-{core,brands}.json` (the icon catalog embedded in / served by the Rust web target).
|
|
- **Sync SDK versions:** `bun run sync-version` reads the canonical version from root `Cargo.toml` and updates all SDK consumers; verify with `bun run sync-version:check`.
|
|
|
|
## op-web-sdk (`op-web-sdk/`)
|
|
|
|
Read-only OpenPencil `.op` **viewer** SDK for the web, wasm-backed. Wraps the `op-host-web` CanvasKit wasm bundle behind a small JS/TS embedding API (mount / load `.op` / viewport control / zoom-to-fit). Replaces the public role of the retired `pen-react` (viewing only — editing is not a goal of the public SDK).
|
|
|
|
- Zero runtime dependencies; ships its own wasm under `wasm/`.
|
|
- Build: `tsup` (`bun run build` inside the package). Tests: `vitest`.
|
|
|
|
## op-web-sdk-react (`op-web-sdk-react/`)
|
|
|
|
React 19 adapter for `op-web-sdk` (component + hooks wrapper). Depends only on `@zseven-w/op-web-sdk` (+ peer `react` / `react-dom`).
|
|
|
|
## op-web-sdk-vue (`op-web-sdk-vue/`)
|
|
|
|
Vue 3 adapter for `op-web-sdk`. Depends only on `@zseven-w/op-web-sdk` (+ peer `vue`).
|
|
|
|
## op-chrome-extension (`op-chrome-extension/`)
|
|
|
|
Manifest V3 Chrome extension that captures the **rendered** active tab and
|
|
imports it into a running OpenPencil. No dependencies, not a Bun workspace
|
|
member — load it unpacked from `chrome://extensions`.
|
|
|
|
- **The logic is Rust.** `crates/op-chrome-extension-core` (endpoint rules,
|
|
chunked-transfer integrity, `/mcp` envelope + reply classification, download-name
|
|
sanitisation) compiles to wasm; `packages/op-chrome-extension/scripts/build-wasm.sh`
|
|
runs `cargo build --target wasm32-unknown-unknown` + `wasm-bindgen --target web`
|
|
and installs the shim + module into `op-chrome-extension/wasm/`, which is
|
|
**gitignored** like every other wasm-bindgen output in the repo. **Build it
|
|
before "Load unpacked"** — the popup reports an actionable error otherwise.
|
|
Unit-test the logic natively with `cargo test -p op-chrome-extension-core`.
|
|
- The JS that remains is glue: `chrome.*` calls, `fetch`, popup DOM, and the
|
|
functions injected into the captured tab (which must be JS — they run in the
|
|
page's process). The manifest declares `'wasm-unsafe-eval'` in
|
|
`content_security_policy.extension_pages`, which is what MV3 requires to
|
|
instantiate a bundled `.wasm`; no code is fetched from outside the package.
|
|
- The capture engine is `vendor/snapshot-extractor.js`, a **byte-identical copy**
|
|
of `crates/op-html/assets/snapshot-extractor.js` (the contract
|
|
`op_html::import_snapshot` parses). `bun run lint` runs
|
|
`op-chrome-extension/scripts/check-extractor-sync.sh`, which fails on drift;
|
|
`--fix` re-copies the canonical asset. Never edit the copy.
|
|
- Ingress: `POST /api/import/web-snapshot` on the desktop app's live MCP
|
|
endpoint (insert-only, tokenless, the one route there that accepts a
|
|
`chrome-extension://` origin — see
|
|
`crates/op-host-services/src/mcp_live/snapshot_ingest.rs`), falling back to a
|
|
plain `/mcp` `tools/call import_web_snapshot` for the unmanaged
|
|
`--serve-web` daemon. `Download JSON` + `op import:snapshot` is the offline path.
|
|
- **Account (optional).** The popup header can sign in to OP Hub through the
|
|
hub's own BFF: a tab on `GET /api/v1/auth/login?return_to=/account`, then
|
|
`GET /api/v1/session` with `credentials: 'include'`. The extension is a
|
|
public client — no SSO secret, no token, no `cookies` permission; the hub's
|
|
`HttpOnly` session cookie stays in the browser's jar. Regions `cn` /
|
|
`global` map to `https://op.zseven.cn` / `https://op.zseven.tech`, both in
|
|
`host_permissions`, and `account.rs` asserts the manifest agrees.
|
|
- **Account delivery (optional, signed in).** `POST <hub>/api/v1/snapshots`
|
|
with `credentials: 'include'` + `X-CSRF-Token`, i.e. op-hub's per-user
|
|
snapshot inbox. The envelope, the page-title-derived name, the 32 MiB
|
|
ceiling and the reply classification are Rust (`hub.rs` / `hub_reply.rs`);
|
|
`delivery.rs` remains the single rule that decides local vs account, and an
|
|
expired session collapses to local. The service worker's element-pick flow
|
|
runs its own session probe (`account.js` is in the worker's static graph and
|
|
stays dynamic-import-free). Contract history:
|
|
`op-chrome-extension/docs/hub-inbox-api-proposal.md`.
|
|
- **Store packaging.** `bun run package-extension` (or
|
|
`op-chrome-extension/scripts/package-extension.sh`) builds the wasm, runs
|
|
the tests and all four guards, stages only the runtime files, copies `pt` to
|
|
`pt_BR`/`pt_PT` for Chrome's manifest-locale lookup, and writes
|
|
`op-chrome-extension/dist/op-chrome-extension-<version>.zip` (gitignored).
|
|
The listing's privacy policy is `op-chrome-extension/docs/privacy-policy.md`.
|