Skip to content

feat(sdk): Frontend @gonext/sdk — slug detection, REST shims, Trusted Types#460

Merged
tayebmokni merged 1 commit into
mainfrom
feat/frontend-sdk
May 25, 2026
Merged

feat(sdk): Frontend @gonext/sdk — slug detection, REST shims, Trusted Types#460
tayebmokni merged 1 commit into
mainfrom
feat/frontend-sdk

Conversation

@tayebmokni
Copy link
Copy Markdown
Contributor

Closes #214.

`@gonext/sdk`: the browser-side TS package plugin authors import.

  • `getSlug()` auto-detects from the loading import-map URL
  • `host.{posts,users,media,cache}` REST shims hit `/api/plugins/{slug}/...`
  • `defineBlock()` forwards to BLOCK_REGISTRY
  • `i18n` wrapper
  • Trusted Types compatible
  • tsup build: ESM + CJS + .d.ts

Surface

Export Purpose
`getSlug() / setSlug() / SlugRequiredError` Plugin identity — auto-detect from the loading import-map URL, with fallbacks to page `<script>` tags, a JSON context block, and `window.GN_PLUGIN_SLUG`.
`host.posts.{list,get}` Read `/wp-json/wp/v2/posts`.
`host.users.{list,get,me}` Read `/wp-json/wp/v2/users` (incl. `/users/me`).
`host.media.{list,get}` Read `/wp-json/wp/v2/media`.
`host.cache.invalidate(tags)` POST to `/api/plugins/{slug}/cache/invalidate`.
`HostFetchError` Typed error with `status` + parsed `responseBody`.
`defineBlock(spec)` Forwards to `GN_BLOCK_REGISTRY` (or legacy `BLOCK_REGISTRY`) when present, else captures for later drain.
`i18n.t(key, args)` Translation lookup with `{placeholder}` interpolation.
`i18n.load(locale)` Preload a catalogue.
`setHTML(el, html)` Trusted-Types-safe `innerHTML` via the host's `gn-plugin` policy.

Build pipeline

`tsup` emits ESM (`dist/index.mjs`), CJS (`dist/index.cjs`), and rolled-up types (`dist/index.d.ts`). `sideEffects: false`, zero runtime dependencies — the SRI hash in the host's import map stays stable.

Tests

69 Vitest cases on jsdom, covering:

  • Slug detection across all four strategies (script src, JSON context block, window global, override) + priority + memoization
  • REST shim transport: header defaults (`Accept`, `Content-Type`), `credentials: include`, AbortSignal forwarding, 204 handling, error envelope parsing, camel→snake query mapping
  • Trusted Types compat: installed factory routing, identity fallback, `createPolicy` refusal fallback
  • Block registry: forward to global, fallback to legacy name, local capture + drain + replace, name validation
  • i18n: catalogue cache reuse, in-flight promise sharing, malformed input filtering, missing-key fallback, missing-slug fallback

Files

  • `packages/ts/sdk/src/` — 6 source modules + 5 test files
  • `packages/ts/sdk/tsup.config.ts`, `tsconfig.json`, `vitest.config.ts`, `vitest.setup.ts`
  • `packages/ts/sdk/README.md` — 10-line hello-world plus surface table
  • `packages/ts/sdk/package.json` — proper `exports` map, `sideEffects: false`, MIT/Apache-2.0 license, types pointer

🤖 Generated with Claude Code

Replaces the package.json-only stub with a working browser-side
SDK plugin authors import via the host's import map.

Surface:
- getSlug() / setSlug() / SlugRequiredError — auto-detects the
  plugin slug from the loading import-map URL (or page <script>
  tags, the gn-plugin-context JSON block, or window.__GN_PLUGIN_SLUG__
  as fallbacks).
- host.{posts,users,media,cache} — same-origin REST shims over the
  WP-compat surface (/wp-json/wp/v2/...) and the plugin-scoped
  subtree (/api/plugins/{slug}/...). HostFetchError carries
  status + parsed body so consumers can branch on transport vs.
  server-side failures.
- defineBlock(spec) — forwards to __GN_BLOCK_REGISTRY__ (or the
  legacy BLOCK_REGISTRY) when published by the editor, else
  captures locally for later drain.
- i18n.t(key, args) / i18n.load(locale) — fetches the per-plugin
  catalogue at /api/plugins/{slug}/i18n/{locale}.json, caches by
  (slug, locale), falls back to the key on miss / error.
- setHTML(el, html) — Trusted-Types-safe innerHTML setter that
  routes through the host's gn-plugin policy when one exists.

Build pipeline (tsup):
- dist/index.mjs  (ESM, what the import map loads)
- dist/index.cjs  (CJS, Node test harnesses)
- dist/index.d.ts (rolled-up declarations)
- sideEffects: false; zero runtime dependencies.

Tests (Vitest, jsdom): 69 cases covering slug detection across
all four strategies, REST shim transport (headers, abort, errors,
204 handling, query camel→snake mapping), Trusted Types compat
(installed factory, identity fallback, createPolicy refusal),
block registry forwarding + capture, and i18n catalogue caching
with malformed-input filtering.

Refs #214.

Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
@tayebmokni tayebmokni enabled auto-merge (squash) May 25, 2026 20:11
@github-actions
Copy link
Copy Markdown

Heads up — this PR touches strings that often signal a security disclosure (vulnerab, CVE-, exploit, bypass, or auth bypass).

If this PR fixes or describes a real vulnerability that has not yet been publicly disclosed, please stop and use the private path:

  1. Open a private security advisory, or
  2. Email security@gonext.io with subject [SECURITY] GoNext - <summary>.

See /SECURITY.md for the full disclosure flow and /docs/16-bug-bounty.md for bounty terms.

If this is a false positive (test fixture, doc update, release notes, etc.) please ignore this comment — the check is advisory only and does not block the PR.

Matched files:

  • packages/ts/sdk/src/host.ts

@tayebmokni tayebmokni merged commit b24a364 into main May 25, 2026
12 of 16 checks passed
@tayebmokni tayebmokni deleted the feat/frontend-sdk branch May 25, 2026 20:13
tayebmokni pushed a commit that referenced this pull request May 25, 2026
Closes #242.

packages/ts/sdk-plugin: TypeScript SDK for GoNext plugin authors via
Javy (JavaScript → WASM).

- pluginInit + registerAction / registerFilter
- Typed wrappers over every gn_* host ABI through globalThis
- JSON envelope codec
- Manifest builder mirroring the Go side
- bin/gonext-sdk-build.js wraps esbuild + javy compile
- cli/gonext/templates/typescript + 'gonext plugin init --template=typescript'
- examples/plugins/sdk-ts-hello working example
- 54 Vitest tests (codec + manifest + dispatch)

This PR was rebased onto main after #460/#461/#462 landed; the
runInit dispatch now switches on template name and embeds both
templates/go and templates/typescript via the single templatesFS.

Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
tayebmokni pushed a commit that referenced this pull request May 25, 2026
Closes #239.

packages/rust/gonext-sdk + packages/rust/gonext-sdk-macros:
Cargo crates for Rust plugin authors.

- plugin_init! proc-macro generates gn_alloc/gn_free/_start/gn_handle_hook exports
- Safe typed wrappers over every gn_* host ABI (env, env_net, gonext_data, env_platform)
- JSON envelope codec via serde_json
- Manifest builder mirroring the Go side
- cli/gonext/cmd/plugin/templates/rust + 'gonext plugin init --template=rust'
- examples/plugins/sdk-rust-hello: working example (action + filter + kv.set + audit.emit)

Rebased onto main after #460/#461/#462 landed; init.go now switches
on template name. TestRunInitUnknownTemplate updated to use a
clearly-not-real template name so it stays robust as new templates
land.

Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
tayebmokni pushed a commit that referenced this pull request May 25, 2026
Closes #242.

packages/ts/sdk-plugin: TypeScript SDK for GoNext plugin authors via
Javy (JavaScript → WASM).

- pluginInit + registerAction / registerFilter
- Typed wrappers over every gn_* host ABI through globalThis
- JSON envelope codec
- Manifest builder mirroring the Go side
- bin/gonext-sdk-build.js wraps esbuild + javy compile
- cli/gonext/templates/typescript + 'gonext plugin init --template=typescript'
- examples/plugins/sdk-ts-hello working example
- 54 Vitest tests (codec + manifest + dispatch)

This PR was rebased onto main after #460/#461/#462 landed; the
runInit dispatch now switches on template name and embeds both
templates/go and templates/typescript via the single templatesFS.

Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
tayebmokni pushed a commit that referenced this pull request May 26, 2026
Closes #242.

packages/ts/sdk-plugin: TypeScript SDK for GoNext plugin authors via
Javy (JavaScript → WASM).

- pluginInit + registerAction / registerFilter
- Typed wrappers over every gn_* host ABI through globalThis
- JSON envelope codec
- Manifest builder mirroring the Go side
- bin/gonext-sdk-build.js wraps esbuild + javy compile
- cli/gonext/templates/typescript + 'gonext plugin init --template=typescript'
- examples/plugins/sdk-ts-hello working example
- 54 Vitest tests (codec + manifest + dispatch)

This PR was rebased onto main after #460/#461/#462 landed; the
runInit dispatch now switches on template name and embeds both
templates/go and templates/typescript via the single templatesFS.

Signed-off-by: Tayeb Mokni <tayeb.mokni@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Frontend SDK: @host/sdk module surface + slug auto-detection + Trusted Types

2 participants