feat(PRO-401): edge contract 2 on Fastly Compute - #12
Merged
Merged
Conversation
Design in monocle-fastly-port-plan.md (workspace); tracked by PRO-401. The web half is PRO-432 on web feat/pro-432. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Edge-core owns the request pipeline, the /__mcl/* endpoints, decisions, credentials and injection; this package supplies what only the platform can. config.ts reads the deployment the dashboard published to the Config Store (the chunked DeploymentConfig, the chunked route index, exclusions, the origin settings) and the Secret Store lazily. platform.ts is the Platform for Compute: the client address, the origin leg with host override, client-address headers, the chaining signature and cloned cache rules, HTMLRewritingStream for the injected tag, and the POP cache for the breaker and the crawler snapshot, refreshed in waitUntil through static crawler_<host> backends. Plain HTTP goes to HTTPS; a host the config does not name is forwarded unassessed. js-compute has no AES-GCM and no AbortSignal, so cookies use edge-core's HMAC sealer and the Policy deadline is the backend's. It runs JavaScript interpreted inside Wasm, so enforcement is published as lookups: 5,000 entries cost milliseconds instead of the half second compiling them did. The previous plugin (MCLVALID cookie, captcha_page.html, own cookie, policy and path modules, PROTECTED_PATHS) is gone. Tests run the handler in Node against doubles for the fastly:* modules; the typecheck covers edge-core's sources against js-compute's types; CI loads the edge-core deploy key and moves to Node 22. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
alistairsmith-tech
marked this pull request as ready for review
September 21, 2026 08:30
…al packages The lockfile predating this branch never recorded @emnapi/core and @emnapi/runtime, which Linux installs need; npm ci refused it in CI. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The release tag on main, replacing the pre-release. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The repin's `npm install` ran with node_modules present on macOS, which drops the platform-optional packages (`@emnapi/*`, esbuild's binaries) from the lockfile again; a local `npm ci` cannot notice, since macOS never needs them, but the Linux runner refuses the lockfile as out of sync. Regenerated from scratch, as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
The Fastly plugin is now the Compute adapter for edge-core (plan step 2, D9 in
monocle-fastly-port-plan.md; tracked by PRO-401, web half PRO-432). Edge-core owns the request pipeline, the/__mcl/*endpoints, decisions, credentials and injection; this package supplies what only the platform can. The previous plugin (MCLVALIDcookie,captcha_page.html, own cookie/policy/path modules,PROTECTED_PATHSscoping) is gone.The adapter
config.ts: the deployment from the Config Store —v,id,cv,xand the chunkedcfg.<i>DeploymentConfig— validated with edge-core'scompileConfig; the origin settings (ORIGIN_HOST,CACHE_RULES,CHAIN_SECRET,CLIENT_IP_HEADER) read best-effort; secrets read lazily, the Policy key only for/__mcl/*.platform.ts:Platformfor Compute. The client address isevent.client.address. A host the config does not name is forwarded unassessed (the domain is attached to this service either way); plain HTTP is sent to HTTPS, since the cookies are Secure.origin.ts: the origin leg — host override, the client address stamped intoX-Forwarded-For,Fastly-Client-IPand the customer'sCLIENT_IP_HEADER(PRO-326 folded in; overwritten, never appended), the time-limited chaining signature, cloned cache rules as aCacheOverride,originbackend.html.ts:HTMLRewritingStream— every meta CSP through edge-core's augmentation, the tag appended tobody, or to the document when there is none.breaker.tsandcrawlers.ts: the breaker state and the crawler snapshot in the POP cache (SimpleCache), the scope Policy reachability has. Nothing schedules on Compute, so the request that finds the snapshot missing refreshes it inwaitUntil, once per POP per lease, through staticcrawler_<host>backends.backends.ts: the named backend everyfetch()needs, injected into edge-core's Policy client and feed fetcher.What js-compute does not have
Found by
npm run typecheck, which checks edge-core's sources against js-compute's types: no AES-GCM (cookies use edge-core's HMAC sealer), noAbortSignal(the Policy deadline is the backend's first-byte timeout), noredirect/signalrequest options, a lenientTextDecoder. edge-core 0.7.1 (spurintel/monocle-edge-core#17) carries the shims, the exclusions and the store-backed breaker this needs.Verification
fastly:*modules (test/doubles): unreadable and torn config, challenge and state, mint through the Policy backend then an injected cleared page, refusals and blocks, exclusions, unnamed hosts, HTTP→HTTPS, the origin leg (host, client-address headers, chaining signature, cache rules, 502), lazy crawler refresh without stampede, the breaker surviving between requests, secret reads only on the endpoints.example.comorigin:/__mcl/state200, cold enforced navigation 503 with the interstitial, cookieless action 403 with the challenge header, assessed navigation served with the resident tag injected before</body>by the realHTMLRewritingStream, excluded path proxied, resident script servedprivate, no-store.Pinned to
v0.7.1-rc.1; repin tov0.7.1once edge-core #17 merges. Releasev2.0.0when the web side (PRO-432) can write the new store layout.🤖 Generated with Claude Code