feat(plugins-registry): serve GET /bundles.json + /bundles-schema.json - #95
Merged
Merged
Conversation
Adds the CF worker route ADR-P6-03 specifies (P6-E4-W3-S3-T8): proxies plugins-pro/bundles.json (and bundles-schema.json) via the GitHub Contents API, mirroring fetchProRegistry's existing fetch+decode+KV-cache pattern rather than reimplementing it. Cached in PLUGINS_KV under its own bundles-json-v1 / bundles-schema-v1 keys, distinct from registry:* so a refresh of one never busts the other. bundles.json is schema-validated against the 6 canonical bundle slugs before serving — 502 on upstream fetch failure or schema failure, never a malformed 200. Implemented in both index.js (the file wrangler.toml actually deploys, main = "src/index.js") and the parallel index.ts/registry.ts module, kept functionally in sync. POST /api/sync now also busts the two new KV keys. Both new routes are listed in the 404 fallback's endpoint list. The plugins-pro -> bundles repo rename (ADR-P6-01 / P6-E4-W3-S3-T6) has NOT landed yet, so this fetches from nself-org/plugins-pro (current repo name), not nself-org/bundles. The two URL constants (BUNDLES_JSON_API_URL / BUNDLES_SCHEMA_API_URL in both index.js and registry.ts) are the only things that need to change once the rename lands. Counts: /plugins already returns free/pro/total counts computed live from fetched registry lengths (handlePluginList) — verified this requires zero code change, so no separate counts endpoint was added. Tests: 12 new cases in bundles.test.mjs (validateBundlesJson structural checks + handleBundlesJson KV-hit/fetch-fail/schema-fail/happy-path via a mocked global fetch, no real network call), reusing the existing `node --test src/*.test.mjs` runner. All 21 tests pass (9 pre-existing + 12 new). tsc --noEmit clean. wrangler deploy --dry-run --env production builds clean (36.97 KiB / 8.80 KiB gzip). Sanity-checked validateBundlesJson() against the real, current plugins-pro/bundles.json on disk: passes with 0 errors. Not deployed — production wrangler deploy is owner-gated.
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
P6-E4-W3-S3-T8. Adds the two missing CF worker routes ADR-P6-03 specifies:
GET /bundles.json— bundle-to-plugin membership mapGET /bundles-schema.json— the schema it validates againstBoth fetch from GitHub via the same authenticated Contents API pattern
fetchProRegistryalready uses (reused, not reimplemented — seefetchGitHubContentsJsoninindex.js/ the mirrored helpers inregistry.ts), cached inPLUGINS_KVunder their own keys(
bundles-json-v1,bundles-schema-v1) distinct from the existingregistry:*keys, andPOST /api/syncnow busts those two keys as well.bundles.jsonis structurally validated against the 6 canonical bundleslugs (
task, chat, claw, family, sentry, clawde) before being served —a fetch failure or a schema failure both return
502, never a malformed200.Implemented in both
index.js(the filewrangler.tomlactually deploys —main = "src/index.js") and the parallelindex.ts/registry.tsmodule that this repo also typechecks in CI, kept functionally in sync.
Repo-rename note (important)
The
plugins-pro→bundlesrename (ADR-P6-01 / P6-E4-W3-S3-T6) has notlanded.
nself-org/bundlesdoes not exist yet. This PR therefore fetchesfrom
nself-org/plugins-pro(current, live repo name) — notbundles—so it works today. Once the rename lands, update the two URL constants:
BUNDLES_JSON_API_URL/BUNDLES_SCHEMA_API_URLin.workers/plugins-registry/src/index.js.workers/plugins-registry/src/registry.tsNothing else in this route needs to change — the route handlers, KV keys,
validator, cache headers, and tests are all repo-name-agnostic.
Counts endpoint
The ticket's guide step for "counts" says
GET /pluginsalready returnslive
free/pro/totalcounts computed from the fetched registryarray lengths (
handlePluginList) — confirmed by reading the source, thisrequires zero code change. No separate
/counts.jsonworker route wasadded; I could not find any consumer (CLI, ping_api, web) that expects the
worker itself to serve counts — the CLI's
nself plugin countreads avendored
plugins/counts.jsonartifact directly from thepluginsrepo,unrelated to this worker.
Test plan
pnpm run typecheck(tsc --noEmit) — clean, 0 errorspnpm run test(node --test src/*.test.mjs) — 21/21 pass (9pre-existing + 12 new in
bundles.test.mjs, coveringvalidateBundlesJsonstructural checks andhandleBundlesJson'sKV-hit / fetch-failure / schema-failure / happy-path branches via a
mocked
globalThis.fetch, no real network call)wrangler dev --local—/health200,/bundles.jsongracefully502s with noGH_ACCESS_TOKENset (never a malformed 200), the404 fallback's endpoint list includes both new routes
wrangler deploy --dry-run --env production— clean build (36.97KiB / 8.80 KiB gzip), all production bindings resolve
plugins-pro/bundles.jsonoffdisk through
validateBundlesJson()— passes with 0 errorscurl https://plugins.nself.org/bundles.json— not done,deploy is owner-gated (see below)
Not deployed.
wrangler deploywas intentionally not run.