WIP: feat(api,host): platform CDN provider — deploy.cdn "platform" (plan 029) - #133
Draft
elliotBraem wants to merge 6 commits into
Draft
elliotBraem wants to merge 6 commits into
elliotBraem wants to merge 6 commits into
Conversation
Plan 023. The graft protocol's mount vocabulary becomes a compile-time
contract instead of a stringly convention:
- mount-registry.ts: MOUNT_REGISTRY now satisfies Record<string, MountEntry>
so MountId derives from its canonical keys; MOUNTS exports the union
value; MOUNT_ALIASES is typed Record<string, MountId> (moved here from
types.ts, which re-exports both for surface stability)
- define.ts: defineUiPlugin({ name, mounts, tree }) validates the tree at
construction — every root child declaring a _mount must resolve to a
declared canonical mount, else it throws with the child id and a
closest-mount hint; associations ride a module-scoped WeakMap
- compose.ts: defined modules graft via declared mounts (no
re-derivation); raw trees keep the deriveMountId fallback, now the
declaredSegment derivation with a MountId return type
- digest-version.ts: MOUNT_REGISTRY_VERSION -> 2026-09-19.1 (graft input
semantics changed; all compose digests invalidate)
- README row records the agreed deviation (validation covers _-roots
only) and the plan-024 note (_template has no ui tree yet)
Verification: everything-dev 489 tests green (compose suite 20 incl. 9
new), host 175 green; no new typecheck or lint findings vs baseline.
…n 029)
Platform CDN provider so bos publish --deploy needs no Zephyr/Cloudflare
account: bundles upload to the platform storage via the CLI session and
are served publicly from /bundles/* with immutable cache headers.
- api: bundle_objects table + BundleStorage Effect service (R2 drop-in
seam), oRPC contract routes POST /storage/bundles (auth'd, ceilings,
path allowlist, traversal guard, server-side SRI) and
GET /bundles/{account}/{gateway}/{workspace}/{+path} (public, File
output)
- host: route-scoped bodyLimit for uploads, second prefix-symmetric
OpenAPIHandler mount at /bundles/* (+ proxy mode), generic
ResponseHeadersHandlerPlugin
- cli: deploy.cdn config (default zephyr), --cdn flag, platform
uploader (dist/ artifacts -> platform storage), session requirement,
bos login refusal without one
- docs: ADR 0007 (file transport as oRPC contract concern), plan 033
(derived OpenAPI mounts follow-up), AGENTS.md deploy.cdn, changeset
Live dev-stack E2E (bos publish --deploy --cdn platform + bos mf check)
left for the operator.
…orageTag (code-review follow-ups) - storage routes follow the template convention: .effect() generators with yield* StorageTag (StorageTag now exposed from initialize's returned layer); inline auth via Effect.fail(errors.UNAUTHORIZED/FORBIDDEN) with the every-plugin/errors data shapes - AGENTS.md 'Adding API Endpoints': new-route handler convention enforced (.effect + yield* Tag; Context.get reserved for streaming; shared auth middlewares' .use() typing gap documented) - ADR 0007: handler-convention bullet + recorded seam deviation (platform provider skips workspace scripts.deploy; parent uploads dist/ via applyDeployResults)
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.
Implements plan 029:
deploy.cdn: "platform"—bos publish --deployuploads MF bundles to the platform storage via the CLI session (same trust model as the gasless relay); the host serves them publicly from/bundles/*with immutable cache headers. No Zephyr/Cloudflare account needed.What's here
bundle_objectstable + migration;BundleStorageEffect service (api/src/services/storage.ts— R2 drop-in seam); oRPC contract routes:POST /storage/bundles— authed (session/API-key, relay trust family), path allowlist + traversal guard, 64 MB total ceiling (BOS_MAX_BUNDLE_UPLOAD_BYTES), SRI computed server-side over stored bytesGET /bundles/{account}/{gateway}/{workspace}/{+path}— public,Fileoutput, immutable cache headersbodyLimitfor uploads, second prefix-symmetricOpenAPIHandlermount at/bundles/*(+ proxy mode), genericResponseHeadersHandlerPlugindeploy.cdnconfig (defaultzephyr),--cdnflag, platform uploader (dist/ artifacts → platform storage),bos loginrefusal without a session, account-match checkdeploy.cdn+ enforced.effect()/yield* Taghandler convention), changesetReview status (Standards / Spec) — all findings closed
bundles/<account>/<gateway>/<workspace>/<path>— spec-verified.effect()+yield* StorageTag(template convention); inline auth viaEffect.fail(errors.UNAUTHORIZED/FORBIDDEN)with the shared error data shapes.effect+yield* Tagrequired for new routes;Context.getreserved for streaming;requireAuthOrApiKey.use()typing gap documented) + ADR 0007withPluginDeployseam deviation recorded in ADR 0007 (platform skipsscripts.deploy; parent uploads dist viaapplyDeployResults)cdnUploadHandledparam removed (review finding)bos publish --deploy --cdn platform→ verify a full page render + plugin RPC through the served artifacts →bos mf checkgreenKnown limitations (documented, deliberate)
Storage)🚢 Do not merge until the operator E2E is verified.