feat(examples/plugins/seo): worked SEO plugin proving the runtime end-to-end — closes #269#403
Merged
Merged
Conversation
…-to-end — closes #269 ## Summary - `examples/plugins/seo/` — a TinyGo-built plugin that ships `manifest.json` (apiVersion gonext.io/v1), four exported ABI symbols (`gn_alloc`, `gn_free`, `gn_handle_hook`, `gn_handle_job`), and a build script. Subscribes to `the_content` (filter, injects schema.org JSON-LD), `wp_head` (action, emits `<title>` + meta + OpenGraph + Twitter card), and `save_post` (action, computes SEO score). Owns one background job (`seo.recompute-scores`). - `domain.go` — pure Go helpers (`BuildTitle`, `BuildDescription`, `BuildHeadHTML`, `BuildJSONLD`, `ComputeSEOScore`) split out so the test suite exercises the same code the WASM blob links — no TinyGo required to run `go test`. - `dummy_host_test.go` — Go-side fake host bus that mirrors the wazero dispatcher path, proving the wire format the plugin speaks matches what `packages/go/plugins/abi/hooks/marshal.go` produces. Canonical copy at `packages/go/plugins/internal/_seo_dummy.go`. - `seo_test.go` — manifest validates against `packages/go/plugins/manifest/schema.json`; unit tests for all domain functions; HTML escaping; JSON-LD parses + carries Article required fields; pinned-score table; end-to-end filter run. - `docs/04-seo-plugin-tutorial.md` — a 30-minute "build this plugin from scratch" walkthrough. - `go.work` — adds `./examples/plugins/seo` so the example builds alongside the workspace; the example has its own `go.mod` so TinyGo doesn't drag in the host's Postgres/Redis/Asynq deps. The plugin uses every plumbed capability (`posts.read`, `posts.write`, `hooks.subscribe`, `jobs.enqueue`) so the install dialog has a real-world cap list to render. ## Test plan - [x] `cd /tmp/gn-i11 && go test -race -count=1 ./examples/plugins/seo/...` — 14/14 pass - [x] `cd packages/go && go test -race -count=1 ./plugins/lifecycle/... ./plugins/abi/hooks/...` — pass - [x] `cd packages/go && go test -race -count=1 ./plugins/manifest/...` — pass - [x] `cd examples/plugins/seo && bash build.sh` — exits with helpful "tinygo not on PATH" message when toolchain missing; documented in README - [ ] Manual: install TinyGo, run `./build.sh`, pack into `seo.gnplugin` via the documented zip recipe, install + activate via the lifecycle Manager (deferred — requires admin UI from #350) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: Mohamed Tayeb Mokni <tayeb.mokni@gmail.com>
bc77989 to
00f3c05
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
examples/plugins/seo/— a TinyGo-built plugin that shipsmanifest.json(apiVersiongonext.io/v1), four exported ABI symbols (gn_alloc,gn_free,gn_handle_hook,gn_handle_job), and a build script. Subscribes tothe_content(filter, injects schema.org JSON-LD),wp_head(action, emits<title>+<meta>+ OpenGraph + Twitter card), andsave_post(action, computes SEO score). Owns one background job (seo.recompute-scores).domain.go— pure Go helpers (BuildTitle,BuildDescription,BuildHeadHTML,BuildJSONLD,ComputeSEOScore) split out so the test suite exercises the same code the WASM blob links — no TinyGo required to rungo test.dummy_host_test.go— Go-side fake host bus that mirrors the wazero dispatcher path, proving the wire format the plugin speaks matches whatpackages/go/plugins/abi/hooks/marshal.goproduces. Canonical copy atpackages/go/plugins/internal/_seo_dummy.go(leading underscore so Go skips it for builds; doc-only).seo_test.go— manifest validates againstpackages/go/plugins/manifest/schema.json; unit tests for all domain functions; HTML escaping; JSON-LD parses + carries Article required fields; pinned-score table; end-to-end filter run.docs/04-seo-plugin-tutorial.md— a 30-minute "build this plugin from scratch" walkthrough that mirrors the implementation file by file.go.work— adds./examples/plugins/seoso the example builds alongside the workspace; the example has its owngo.modso TinyGo doesn't drag in the host's Postgres/Redis/Asynq deps.Capability rationale (the plugin uses every plumbed capability so the install dialog has a real-world cap list to render):
posts.readposts.write_seo_scorepost meta (via host call).hooks.subscribejobs.enqueueseo.recompute-scores.Test plan
go test -race -count=1 ./examples/plugins/seo/...— 14 tests pass (manifest schema, unit tests, JSON-LD validity, score table, end-to-end filter)cd packages/go && go test -race -count=1 ./plugins/lifecycle/... ./plugins/abi/hooks/...— pass (runtime regression check per the brief)cd packages/go && go test -race -count=1 ./plugins/manifest/...— passbash examples/plugins/seo/build.sh— exits with a helpful "tinygo not on PATH" message when toolchain missing; README documents the install URL./build.sh, pack intoseo.gnpluginviazip -j seo.gnplugin manifest.json seo.wasm, install + activate via the lifecycle Manager (deferred — requires the admin install dialog from feat(plugins/runtime): wazero-backed WASM runtime foundation (#6) #350)🤖 Generated with Claude Code