@spacefast/common 0.0.26 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/connect-targets.d.ts +6 -146
- package/dist/agents/connect-targets.js +63 -295
- package/dist/agents/private-key-oauth.d.ts +31 -1
- package/dist/agents/private-key-oauth.js +124 -33
- package/dist/agents/registry/core.d.ts +292 -0
- package/dist/agents/registry/core.js +1388 -0
- package/dist/agents/registry/deeplink-probes.d.ts +23 -0
- package/dist/agents/registry/deeplink-probes.js +18 -0
- package/dist/agents/registry/node.d.ts +56 -0
- package/dist/agents/registry/node.js +339 -0
- package/dist/brand-assets-build.js +1 -2
- package/dist/brand-assets.js +4 -7
- package/dist/brand.d.ts +17 -0
- package/dist/brand.js +24 -4
- package/dist/config/domains.d.ts +55 -28
- package/dist/config/domains.js +85 -41
- package/dist/config/index.js +1 -2
- package/dist/contracts/abuse.js +9 -24
- package/dist/contracts/access-profiles.d.ts +86 -0
- package/dist/contracts/access-profiles.js +89 -0
- package/dist/contracts/access.d.ts +21 -27
- package/dist/contracts/access.js +33 -64
- package/dist/contracts/activity.d.ts +18 -1
- package/dist/contracts/activity.js +70 -26
- package/dist/contracts/analytics.js +8 -10
- package/dist/contracts/api-keys.d.ts +77 -52
- package/dist/contracts/api-keys.js +44 -24
- package/dist/contracts/application-journal.d.ts +216 -0
- package/dist/contracts/application-journal.js +167 -0
- package/dist/contracts/auth.d.ts +90 -17
- package/dist/contracts/auth.js +86 -17
- package/dist/contracts/beta.d.ts +9 -4
- package/dist/contracts/beta.js +20 -16
- package/dist/contracts/billing.js +7 -11
- package/dist/contracts/bootstrap.d.ts +791 -0
- package/dist/contracts/bootstrap.js +51 -0
- package/dist/contracts/builds.d.ts +192 -7
- package/dist/contracts/builds.js +84 -21
- package/dist/contracts/channels.d.ts +43 -0
- package/dist/contracts/channels.js +25 -9
- package/dist/contracts/cli.d.ts +7 -0
- package/dist/contracts/cli.js +6 -0
- package/dist/contracts/collab-public.d.ts +1 -1
- package/dist/contracts/collab-public.js +5 -8
- package/dist/contracts/comments.d.ts +45 -35
- package/dist/contracts/comments.js +107 -77
- package/dist/contracts/commerce.d.ts +165 -0
- package/dist/contracts/commerce.js +146 -0
- package/dist/contracts/common.d.ts +3 -3
- package/dist/contracts/common.js +18 -29
- package/dist/contracts/content-contract-verification.d.ts +521 -0
- package/dist/contracts/content-contract-verification.js +320 -0
- package/dist/contracts/content-platform-fixture.d.ts +1278 -0
- package/dist/contracts/content-platform-fixture.js +44 -0
- package/dist/contracts/content-program.d.ts +994 -0
- package/dist/contracts/content-program.js +658 -0
- package/dist/contracts/content-sync.d.ts +290 -0
- package/dist/contracts/content-sync.js +167 -0
- package/dist/contracts/content.d.ts +432 -0
- package/dist/contracts/content.js +303 -0
- package/dist/contracts/continuation.d.ts +17 -1
- package/dist/contracts/continuation.js +23 -23
- package/dist/contracts/countries.js +3 -4
- package/dist/contracts/crons.d.ts +17 -0
- package/dist/contracts/crons.js +33 -15
- package/dist/contracts/dashboard-prefs.d.ts +56 -0
- package/dist/contracts/dashboard-prefs.js +51 -0
- package/dist/contracts/device-auth.d.ts +234 -37
- package/dist/contracts/device-auth.js +267 -53
- package/dist/contracts/docs.d.ts +6 -10
- package/dist/contracts/docs.js +5 -13
- package/dist/contracts/domains.d.ts +499 -102
- package/dist/contracts/domains.js +169 -58
- package/dist/contracts/email-preferences.d.ts +3 -3
- package/dist/contracts/email-preferences.js +6 -7
- package/dist/contracts/enums.d.ts +26 -26
- package/dist/contracts/enums.js +61 -54
- package/dist/contracts/error-code-meta.d.ts +273 -7
- package/dist/contracts/error-code-meta.js +81 -5
- package/dist/contracts/error-codes.d.ts +5 -5
- package/dist/contracts/error-codes.js +79 -16
- package/dist/contracts/events.d.ts +100 -20
- package/dist/contracts/events.js +107 -20
- package/dist/contracts/execution.d.ts +47 -66
- package/dist/contracts/execution.js +51 -64
- package/dist/contracts/feature-lifecycle.d.ts +70 -14
- package/dist/contracts/feature-lifecycle.js +86 -15
- package/dist/contracts/features.d.ts +100 -37
- package/dist/contracts/features.js +21 -27
- package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
- package/dist/contracts/frame-session.d.ts +192 -0
- package/dist/contracts/frame-session.js +164 -0
- package/dist/contracts/functions.d.ts +218 -211
- package/dist/contracts/functions.js +273 -260
- package/dist/contracts/grant-copy.d.ts +43 -0
- package/dist/contracts/grant-copy.js +44 -0
- package/dist/contracts/grants.d.ts +64 -56
- package/dist/contracts/grants.js +124 -23
- package/dist/contracts/ids.d.ts +4 -1
- package/dist/contracts/ids.js +4 -1
- package/dist/contracts/internal.d.ts +5 -4
- package/dist/contracts/internal.js +12 -3
- package/dist/contracts/mcp.d.ts +17 -0
- package/dist/contracts/mcp.js +23 -0
- package/dist/contracts/me.d.ts +6 -1
- package/dist/contracts/me.js +12 -6
- package/dist/contracts/notifications.d.ts +27 -29
- package/dist/contracts/notifications.js +9 -4
- package/dist/contracts/oauth-resources.d.ts +121 -10
- package/dist/contracts/oauth-resources.js +130 -11
- package/dist/contracts/oauth-scope-actions.d.ts +90 -0
- package/dist/contracts/oauth-scope-actions.js +126 -0
- package/dist/contracts/operations.d.ts +27 -4
- package/dist/contracts/operations.js +11 -5
- package/dist/contracts/pages.d.ts +29 -5
- package/dist/contracts/pages.js +22 -5
- package/dist/contracts/partner-notifications.d.ts +3 -0
- package/dist/contracts/partner-notifications.js +65 -0
- package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
- package/dist/contracts/{platform.js → partner.js} +27 -40
- package/dist/contracts/plan-policy.d.ts +1 -1
- package/dist/contracts/principal-assertion.d.ts +43 -0
- package/dist/contracts/principal-assertion.js +67 -0
- package/dist/contracts/principals.d.ts +73 -0
- package/dist/contracts/principals.js +59 -0
- package/dist/contracts/privacy.d.ts +11 -0
- package/dist/contracts/privacy.js +17 -0
- package/dist/contracts/problem-document.js +3 -4
- package/dist/contracts/publish-archive.d.ts +116 -18
- package/dist/contracts/publish-archive.js +6 -3
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +3 -3
- package/dist/contracts/realtime.d.ts +52 -0
- package/dist/contracts/realtime.js +54 -0
- package/dist/contracts/repository-connections.d.ts +1 -1
- package/dist/contracts/repository-connections.js +6 -2
- package/dist/contracts/resources.d.ts +105 -14
- package/dist/contracts/resources.js +145 -21
- package/dist/contracts/route-inventory.d.ts +358 -0
- package/dist/contracts/route-inventory.js +141 -0
- package/dist/contracts/runtime-api.d.ts +112 -35
- package/dist/contracts/runtime-api.js +86 -66
- package/dist/contracts/runtime-app.d.ts +11 -21
- package/dist/contracts/runtime-app.js +39 -24
- package/dist/contracts/runtime-components.d.ts +143 -0
- package/dist/contracts/runtime-components.js +199 -0
- package/dist/contracts/runtime-db.d.ts +45 -19
- package/dist/contracts/runtime-db.js +85 -20
- package/dist/contracts/runtime-purge.js +3 -5
- package/dist/contracts/runtime-services.d.ts +43 -75
- package/dist/contracts/runtime-services.js +29 -49
- package/dist/contracts/runtime-storage.d.ts +14 -14
- package/dist/contracts/runtime-storage.js +28 -13
- package/dist/contracts/sf-config-v1.d.ts +14 -18
- package/dist/contracts/slugs.js +13 -4
- package/dist/contracts/space-config.d.ts +235 -28
- package/dist/contracts/space-config.js +246 -91
- package/dist/contracts/spaces.d.ts +360 -255
- package/dist/contracts/spaces.js +190 -122
- package/dist/contracts/superadmin-activity.d.ts +3 -43
- package/dist/contracts/superadmin-activity.js +6 -30
- package/dist/contracts/superadmin-emails.d.ts +1 -0
- package/dist/contracts/superadmin-emails.js +17 -1
- package/dist/contracts/superadmin-runtime.d.ts +199 -0
- package/dist/contracts/superadmin-runtime.js +141 -0
- package/dist/contracts/superadmin-search.d.ts +22 -2
- package/dist/contracts/superadmin-search.js +14 -6
- package/dist/contracts/superadmin-spaces.d.ts +435 -186
- package/dist/contracts/superadmin-spaces.js +131 -25
- package/dist/contracts/superadmin-teams.d.ts +3 -0
- package/dist/contracts/superadmin-teams.js +1 -2
- package/dist/contracts/superadmin-tenants.d.ts +627 -6
- package/dist/contracts/superadmin-tenants.js +32 -7
- package/dist/contracts/superadmin.d.ts +98 -16
- package/dist/contracts/superadmin.js +63 -10
- package/dist/contracts/tags.d.ts +85 -58
- package/dist/contracts/tags.js +44 -34
- package/dist/contracts/teams.d.ts +72 -9
- package/dist/contracts/teams.js +84 -25
- package/dist/contracts/tenants.d.ts +135 -0
- package/dist/contracts/tenants.js +120 -0
- package/dist/contracts/test-triggers.d.ts +70 -0
- package/dist/contracts/test-triggers.js +116 -0
- package/dist/contracts/theme-json.js +3 -8
- package/dist/contracts/transfers.d.ts +1 -0
- package/dist/contracts/transfers.js +1 -0
- package/dist/contracts/usage.d.ts +209 -0
- package/dist/contracts/usage.js +124 -12
- package/dist/contracts/variables.d.ts +2 -2
- package/dist/contracts/variables.js +9 -13
- package/dist/contracts/webhooks.d.ts +13 -5
- package/dist/contracts/webhooks.js +3 -1
- package/dist/contracts/zero.d.ts +57 -64
- package/dist/contracts/zero.js +68 -66
- package/dist/dashboard-paths/index.d.ts +24 -21
- package/dist/dashboard-paths/index.js +35 -47
- package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
- package/dist/dashboard-paths/route-reservations.generated.js +36 -0
- package/dist/docs/agent-arrival.d.ts +92 -0
- package/dist/docs/agent-arrival.js +227 -0
- package/dist/docs/agent-output-policy.d.ts +6 -0
- package/dist/docs/agent-output-policy.js +22 -0
- package/dist/docs/agent-prose.d.ts +11 -17
- package/dist/docs/agent-prose.js +62 -37
- package/dist/docs/agent-setup.d.ts +72 -41
- package/dist/docs/agent-setup.js +336 -436
- package/dist/docs/catalog.d.ts +147 -89
- package/dist/docs/catalog.js +157 -42
- package/dist/docs/error-docs.d.ts +2102 -1
- package/dist/docs/error-docs.js +285 -16
- package/dist/docs/index-build.d.ts +0 -1
- package/dist/docs/index-build.js +2 -3
- package/dist/docs/page-context-prompt.d.ts +77 -0
- package/dist/docs/page-context-prompt.js +131 -0
- package/dist/docs/reference-urls.d.ts +46 -0
- package/dist/docs/reference-urls.js +79 -0
- package/dist/docs/search.d.ts +6 -8
- package/dist/docs/search.js +10 -13
- package/dist/docs/skill-distribution.d.ts +4 -1
- package/dist/docs/skill-distribution.js +10 -5
- package/dist/docs/skills.d.ts +117 -117
- package/dist/docs/skills.js +120 -72
- package/dist/docs/start-prompts.d.ts +45 -0
- package/dist/docs/start-prompts.js +62 -0
- package/dist/domain-exploration.js +9 -13
- package/dist/og-template.d.ts +56 -0
- package/dist/og-template.js +56 -0
- package/dist/slug-policy/index.js +5 -11
- package/dist/utils/browser-credential.d.ts +13 -6
- package/dist/utils/browser-credential.js +14 -7
- package/dist/utils/build-settings.d.ts +16 -0
- package/dist/utils/build-settings.js +63 -17
- package/dist/utils/canonical-json.d.ts +3 -5
- package/dist/utils/canonical-json.js +3 -5
- package/dist/utils/cast-transport.d.ts +5 -17
- package/dist/utils/cast-transport.js +6 -19
- package/dist/utils/claim-token.js +1 -2
- package/dist/utils/comment-avatars.js +4 -6
- package/dist/utils/concurrency.js +2 -3
- package/dist/utils/content-type.d.ts +7 -6
- package/dist/utils/content-type.js +73 -51
- package/dist/utils/credential-policy.d.ts +50 -6
- package/dist/utils/credential-policy.js +123 -57
- package/dist/utils/egress-policy.fixtures.json +1 -1
- package/dist/utils/generate-space-name.d.ts +3 -8
- package/dist/utils/generate-space-name.js +3 -8
- package/dist/utils/grants.d.ts +0 -1
- package/dist/utils/grants.js +4 -7
- package/dist/utils/gravatar.d.ts +2 -4
- package/dist/utils/gravatar.js +6 -12
- package/dist/utils/id-hints.js +14 -23
- package/dist/utils/idempotency.d.ts +3 -3
- package/dist/utils/idempotency.js +6 -7
- package/dist/utils/local-space-state.d.ts +15 -15
- package/dist/utils/local-space-state.js +34 -23
- package/dist/utils/oauth-signed-query.d.ts +3 -5
- package/dist/utils/oauth-signed-query.js +6 -9
- package/dist/utils/one-shot-replay.d.ts +3 -5
- package/dist/utils/one-shot-replay.js +3 -5
- package/dist/utils/page-colors.d.ts +4 -10
- package/dist/utils/page-colors.js +11 -35
- package/dist/utils/page-fonts.js +6 -11
- package/dist/utils/page-preview.d.ts +0 -1
- package/dist/utils/page-preview.js +0 -1
- package/dist/utils/pages.d.ts +22 -11
- package/dist/utils/pages.js +70 -30
- package/dist/utils/privacy-regions.d.ts +19 -0
- package/dist/utils/privacy-regions.js +91 -0
- package/dist/utils/publish-form-data.d.ts +4 -5
- package/dist/utils/publish-form-data.js +2 -3
- package/dist/utils/publish-policy.d.ts +10 -23
- package/dist/utils/publish-policy.js +63 -116
- package/dist/utils/query-client.d.ts +2 -0
- package/dist/utils/query-client.js +10 -1
- package/dist/utils/runtime-paths.d.ts +4 -4
- package/dist/utils/runtime-paths.js +6 -8
- package/dist/utils/runtime-upload.d.ts +4 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/secure-local-file.d.ts +3 -3
- package/dist/utils/secure-local-file.js +18 -24
- package/dist/utils/space-config.d.ts +11 -14
- package/dist/utils/space-config.js +10 -16
- package/dist/utils/static-runtime-policy.d.ts +5 -8
- package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
- package/dist/utils/static-runtime-policy.generated.js +70 -0
- package/dist/utils/static-runtime-policy.js +17 -84
- package/dist/utils/storage-policy.js +1 -2
- package/dist/utils/upload-session.js +8 -14
- package/dist/utils/version-path.js +11 -19
- package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
- package/dist/utils/wpcom-auth-redirects.js +1 -4
- package/dist/vocabulary.d.ts +7 -7
- package/dist/vocabulary.js +30 -16
- package/package.json +14 -2
- package/dist/agents/client-registry.d.ts +0 -22
- package/dist/agents/client-registry.js +0 -41
- package/dist/docs/agent-handoff-document.d.ts +0 -15
- package/dist/docs/agent-handoff-document.js +0 -180
- package/dist/docs/agent-solutions.d.ts +0 -110
- package/dist/docs/agent-solutions.js +0 -183
- package/dist/utils/query-keys.d.ts +0 -84
- package/dist/utils/query-keys.js +0 -108
|
@@ -3,46 +3,33 @@ import { appRoutePathSchema, executionBase64Schema, executionCapabilitiesSchema,
|
|
|
3
3
|
/**
|
|
4
4
|
* Spacefast Functions: tenant workers run as Cloudflare Dynamic Workers.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* negotiable and that together rule out the obvious architecture:
|
|
6
|
+
* Two constraints shape the product:
|
|
8
7
|
*
|
|
9
|
-
* 1.
|
|
10
|
-
*
|
|
8
|
+
* 1. Cloudflare is reached from wp.cloud, never from the control plane. The
|
|
9
|
+
* control plane records intent; the space's own origin makes every
|
|
11
10
|
* Cloudflare call.
|
|
12
|
-
* 2.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `/_next/static/*` and friends never leave our origin.
|
|
11
|
+
* 2. Every asset is served by wp.cloud. A worker receives only the requests
|
|
12
|
+
* that could not be answered from bytes on disk, so `/_next/static/*` and
|
|
13
|
+
* friends never leave our origin.
|
|
16
14
|
*
|
|
17
|
-
* Dynamic Workers
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* script lifecycle
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* cache, not a record.
|
|
24
|
-
*
|
|
25
|
-
* That also keeps the exit cheap. The contract below is "here is a module
|
|
26
|
-
* graph, here is its configuration, run it", which is workerd's own shape; the
|
|
27
|
-
* managed runtime is an implementation of it rather than the thing we built
|
|
28
|
-
* against.
|
|
29
|
-
*
|
|
30
|
-
* What the worker gets in exchange is the thing we could not build: a real V8
|
|
31
|
-
* isolate that runs npm packages and framework output — OpenNext Next.js among
|
|
32
|
-
* them — without us having to sandbox any of it.
|
|
15
|
+
* Dynamic Workers holds both at once. There is no upload: a version's bundle
|
|
16
|
+
* stays in its own content store on wp.cloud and the host worker pulls it
|
|
17
|
+
* through the Worker Loader binding, so no artefact of ours lives on Cloudflare
|
|
18
|
+
* and there is no script lifecycle to manage. What the worker buys is a real V8
|
|
19
|
+
* isolate running npm packages and framework output, OpenNext Next.js among
|
|
20
|
+
* them, without us sandboxing any of it.
|
|
33
21
|
*
|
|
34
22
|
* The cost is that the worker is a continent away from the space's MySQL.
|
|
35
23
|
* `ctx.db` therefore travels back over an HTTPS relay to the same PHP broker
|
|
36
24
|
* the local tier speaks to over a pipe, which is slower and batched rather
|
|
37
25
|
* than transactional. That is why capsules are a different product rather
|
|
38
|
-
* than a placement option
|
|
26
|
+
* than a placement option. See `endpointIsPortable` in `./execution.js`.
|
|
39
27
|
*/
|
|
40
28
|
/**
|
|
41
|
-
* The tag a compiled worker artifact carries
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* version declares: a publish can carry this beside a capsule.
|
|
29
|
+
* The tag a compiled worker artifact carries, so the PHP origin can tell what
|
|
30
|
+
* it is dispatching. `functions-dispatch.php` refuses any other tag. It is a
|
|
31
|
+
* property of the artifact, not a kind a space or a version declares: a publish
|
|
32
|
+
* can carry this beside a capsule.
|
|
46
33
|
*/
|
|
47
34
|
export const FUNCTIONS_RUNTIME_KIND = "functions";
|
|
48
35
|
export const FUNCTIONS_SOURCE_METADATA_KEY = "spacefastFunctions";
|
|
@@ -52,7 +39,7 @@ export const FUNCTIONS_RUNTIME_ROUTE_PATHS = {
|
|
|
52
39
|
/** Where a dispatched worker calls back for brokered capabilities. */
|
|
53
40
|
relay: `${FUNCTIONS_PLATFORM_ROUTE_PREFIX}/relay`,
|
|
54
41
|
/**
|
|
55
|
-
* Where the execution host asks the space origin to drop cached responses
|
|
42
|
+
* Where the execution host asks the space origin to drop cached responses:
|
|
56
43
|
* an OpenNext `revalidatePath` must reach the CDN in front of wp.cloud, and
|
|
57
44
|
* only the origin can speak for its own cache. Authenticated with the
|
|
58
45
|
* version-scoped purge credential in the `sf-purge-token` request header.
|
|
@@ -61,89 +48,161 @@ export const FUNCTIONS_RUNTIME_ROUTE_PATHS = {
|
|
|
61
48
|
};
|
|
62
49
|
/**
|
|
63
50
|
* The header the execution host presents at the origin purge route. Outside the
|
|
64
|
-
* `sf-fx-` namespace
|
|
65
|
-
*
|
|
66
|
-
* purge call is the host speaking for itself, like a relay call.
|
|
51
|
+
* `sf-fx-` namespace because that prefix names dispatch instructions the origin
|
|
52
|
+
* SENDS, and is stripped from anything inbound before tenant code.
|
|
67
53
|
*/
|
|
68
54
|
export const FUNCTIONS_PURGE_TOKEN_HEADER = "sf-purge-token";
|
|
55
|
+
/**
|
|
56
|
+
* The credential a space origin presents to the execution host on every
|
|
57
|
+
* dispatch (`sf-fx-dispatch-token`), and the audience that identifies it.
|
|
58
|
+
*
|
|
59
|
+
* It is a PER-SITE token, not a fleet secret. The control plane mints one
|
|
60
|
+
* Ed25519 JWT per wp.cloud box, bound to that box's `runtime_instance_id`, and
|
|
61
|
+
* writes it into that box's persistent data. The host verifies the signature
|
|
62
|
+
* against the control plane's public key and takes the site identity from the
|
|
63
|
+
* verified claim rather than from anything the caller asserts.
|
|
64
|
+
*
|
|
65
|
+
* Tenant PHP runs on the same box and can read the box's own configuration, so
|
|
66
|
+
* assume the tenant can read this credential. A per-site token read once still
|
|
67
|
+
* speaks only for its own site: the host refuses any bundle whose signed token
|
|
68
|
+
* names a different `runtime_instance_id`. Signing is EdDSA rather than HMAC so
|
|
69
|
+
* that no signing material sits on the edge, where a host compromise would mint
|
|
70
|
+
* dispatch credentials for the whole fleet.
|
|
71
|
+
*/
|
|
72
|
+
export const FUNCTIONS_DISPATCH_TOKEN_AUD = "spacefast-functions-dispatch";
|
|
73
|
+
/**
|
|
74
|
+
* Pinned by every verifier rather than read from the token's own header.
|
|
75
|
+
* Accepting the presented `alg` is how `alg: none` forgeries work.
|
|
76
|
+
*/
|
|
77
|
+
export const FUNCTIONS_TOKEN_ALG = "EdDSA";
|
|
78
|
+
/**
|
|
79
|
+
* Ten years, like the bundle and relay credentials: the token is not re-mintable
|
|
80
|
+
* on any request path. It reaches a box only through a wp.cloud persistent-data
|
|
81
|
+
* sync at provisioning and on maintenance sweeps, so a shorter clock would take
|
|
82
|
+
* a quiet box offline rather than protect it. Scope is the boundary, and
|
|
83
|
+
* rotating the platform signing key invalidates every token at once.
|
|
84
|
+
*/
|
|
85
|
+
export const FUNCTIONS_DISPATCH_TOKEN_TTL_SECONDS = 10 * 365 * 24 * 60 * 60;
|
|
86
|
+
/**
|
|
87
|
+
* What the execution host requires of a dispatch credential before it believes
|
|
88
|
+
* anything else in the request. One signing key mints every platform token, so
|
|
89
|
+
* the pinned audience is what keeps them from meaning one authority.
|
|
90
|
+
*/
|
|
91
|
+
export const functionsDispatchTokenClaimsSchema = z.object({
|
|
92
|
+
aud: z.literal(FUNCTIONS_DISPATCH_TOKEN_AUD),
|
|
93
|
+
runtime_instance_id: z.string().min(1),
|
|
94
|
+
exp: z.number(),
|
|
95
|
+
nbf: z.number().optional(),
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* The claims carried by the token inside a signed bundle or seed URL. The
|
|
99
|
+
* audience stays open because both artifacts share this shape and are separated
|
|
100
|
+
* by their own audience check at the point of use: a bundle grant must never
|
|
101
|
+
* authorise a seed read.
|
|
102
|
+
*/
|
|
103
|
+
export const functionsArtifactTokenClaimsSchema = z.object({
|
|
104
|
+
aud: z.string().min(1),
|
|
105
|
+
runtime_instance_id: z.string().min(1),
|
|
106
|
+
space_id: z.string().min(1),
|
|
107
|
+
version_id: z.string().min(1),
|
|
108
|
+
sha256: z.string().min(1),
|
|
109
|
+
exp: z.number(),
|
|
110
|
+
nbf: z.number().optional(),
|
|
111
|
+
});
|
|
112
|
+
const functionsTokenHeaderSchema = z.object({ alg: z.literal(FUNCTIONS_TOKEN_ALG) });
|
|
113
|
+
/**
|
|
114
|
+
* Undecodable text and a failed schema return the same null on purpose: a reader
|
|
115
|
+
* that told them apart would tell a forger which half was wrong.
|
|
116
|
+
*/
|
|
117
|
+
function parsedTokenJson(json, schema) {
|
|
118
|
+
try {
|
|
119
|
+
const parsed = schema.safeParse(JSON.parse(json));
|
|
120
|
+
return parsed.success ? parsed.data : null;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Whether a compact JWT's protected header declares the one algorithm this
|
|
128
|
+
* platform signs with. Pinned rather than trusted: a verifier that takes the
|
|
129
|
+
* token's own word for `alg` accepts `alg: none`.
|
|
130
|
+
*/
|
|
131
|
+
export function functionsTokenHeaderIsSigned(headerJson) {
|
|
132
|
+
return parsedTokenJson(headerJson, functionsTokenHeaderSchema) !== null;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Claim readers for an already signature-verified payload. They live beside the
|
|
136
|
+
* mint-side constants so the control plane's audiences and the host's required
|
|
137
|
+
* claims stay one definition rather than two that agree today.
|
|
138
|
+
*/
|
|
139
|
+
export function parseFunctionsDispatchTokenClaims(claimsJson) {
|
|
140
|
+
return parsedTokenJson(claimsJson, functionsDispatchTokenClaimsSchema);
|
|
141
|
+
}
|
|
142
|
+
export function parseFunctionsArtifactTokenClaims(claimsJson) {
|
|
143
|
+
return parsedTokenJson(claimsJson, functionsArtifactTokenClaimsSchema);
|
|
144
|
+
}
|
|
69
145
|
/**
|
|
70
146
|
* Where invocation counts are reported, on the CONTROL PLANE rather than the
|
|
71
|
-
* space origin.
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* and stay on their own origin; usage is a number the platform bills from and
|
|
75
|
-
* goes straight to us. Sharing one channel would make either destination a
|
|
76
|
-
* plausible place to look for the other's data, and would put log volume on the
|
|
77
|
-
* path that has to stay cheap.
|
|
147
|
+
* space origin. Logs are the tenant's content and stay on their own origin;
|
|
148
|
+
* usage is a number the platform bills from. One shared channel would put log
|
|
149
|
+
* volume on the path that has to stay cheap.
|
|
78
150
|
*/
|
|
79
151
|
export const FUNCTIONS_USAGE_INTAKE_PATH = "/v1/runtime/functions/usage";
|
|
80
152
|
/** Public, signed read path. Distinct from storage so the token is never a filename. */
|
|
81
153
|
export const FUNCTIONS_BUNDLE_ROUTE_PREFIX = `${FUNCTIONS_PLATFORM_ROUTE_PREFIX}/b`;
|
|
82
154
|
export const FUNCTIONS_RUNTIME_STORAGE_ROOT = "__spacefast/functions";
|
|
83
155
|
/**
|
|
84
|
-
* Where a version's compiled bundle lives
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* -
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* The dispatch configuration — host, capabilities, relay credential — is not
|
|
99
|
-
* here and is not content at all. The engine writes it beside the version's
|
|
100
|
-
* file tree rather than inside it, exactly as it does for Zero, so a publish
|
|
101
|
-
* cannot reach it: no carve-out, no upload path, nothing to guard. A publish
|
|
102
|
-
* able to write that file would be a publish able to grant itself authority it
|
|
103
|
-
* was never given.
|
|
156
|
+
* Where a version's compiled bundle lives, under the same `__spacefast/` prefix
|
|
157
|
+
* as every other platform-owned path. Two consequences, both wanted:
|
|
158
|
+
*
|
|
159
|
+
* - Not servable as static content. The runtime treats the whole prefix as
|
|
160
|
+
* control paths, so a tenant's compiled source is not readable at a guessable
|
|
161
|
+
* URL, and the digest that would make it guessable appears in build output.
|
|
162
|
+
* - Written by the ordinary publish path. The upload policy carves out exactly
|
|
163
|
+
* this subtree (`publish-policy.ts`), so the bundle rides the normal manifest
|
|
164
|
+
* and upload passes.
|
|
165
|
+
*
|
|
166
|
+
* The dispatch configuration is not here and is not content at all. The engine
|
|
167
|
+
* writes it beside the version's file tree, as it does for Zero, so a publish
|
|
168
|
+
* cannot reach it and cannot grant itself authority it was never given.
|
|
104
169
|
*/
|
|
105
170
|
export const FUNCTIONS_RUNTIME_BUNDLE_ROOT = `${FUNCTIONS_RUNTIME_STORAGE_ROOT}/bundles`;
|
|
106
171
|
/**
|
|
107
|
-
* Where a version's Next-cache seed document lives
|
|
108
|
-
* and fetch-cache entries that warm the execution host's cache object so the
|
|
109
|
-
* first visitor gets the page the build rendered
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
172
|
+
* Where a version's Next-cache seed document lives: the build-time prerender
|
|
173
|
+
* and fetch-cache entries that warm the execution host's cache object, so the
|
|
174
|
+
* first visitor gets the page the build rendered. A sibling of `bundles/` with
|
|
175
|
+
* the same properties, publishable through the ordinary upload path with its
|
|
176
|
+
* own carve-out in publish-policy, never servable as static content, read back
|
|
177
|
+
* only through the signed artifact route.
|
|
113
178
|
*/
|
|
114
179
|
export const FUNCTIONS_RUNTIME_SEED_ROOT = `${FUNCTIONS_RUNTIME_STORAGE_ROOT}/seeds`;
|
|
115
180
|
export const FUNCTIONS_BUNDLE_FORMAT = "spacefast.functions.bundle.v1";
|
|
116
181
|
export const FUNCTIONS_SEED_FORMAT = "spacefast.functions.seed.v1";
|
|
117
182
|
/**
|
|
118
|
-
* Ceiling on a bundle's decoded size
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
* memory before instantiating anything. Set below the runtime's own script
|
|
123
|
-
* limit so an oversized build fails in our tooling, where we can say which
|
|
183
|
+
* Ceiling on a bundle's decoded size, and so on how much the host holds in
|
|
184
|
+
* memory before instantiating: the whole module graph arrives in one response,
|
|
185
|
+
* so a cold isolate costs a single round trip. Set below the runtime's own
|
|
186
|
+
* script limit, so an oversized build fails in our tooling, which can say which
|
|
124
187
|
* modules are large, rather than at dispatch, where the tenant sees a 502.
|
|
125
188
|
*/
|
|
126
189
|
export const FUNCTIONS_BUNDLE_MAX_BYTES = 8 * 1024 * 1024;
|
|
127
190
|
/**
|
|
128
|
-
* Ceilings on the cache seed document. Per-entry mirrors the cache object's
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* were left out — an omitted entry is not an error, it just renders live on
|
|
133
|
-
* first request like any cache miss.
|
|
191
|
+
* Ceilings on the cache seed document. Per-entry mirrors the cache object's own
|
|
192
|
+
* row limit; the total bounds what the host pulls and ingests on a cold cache.
|
|
193
|
+
* Both are enforced in the CLI, where an overflow can say WHICH pages were left
|
|
194
|
+
* out. An omitted entry renders live on first request like any cache miss.
|
|
134
195
|
*/
|
|
135
196
|
export const FUNCTIONS_SEED_ENTRY_MAX_BYTES = 2 * 1024 * 1024 - 8192;
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// isolate, and the host enforces this bound again while streaming the response.
|
|
197
|
+
// Far below Cloudflare's 128 MiB SHARED-isolate ceiling: the Durable Object
|
|
198
|
+
// buffers the JSON and holds the parsed graph beside it, and several objects can
|
|
199
|
+
// occupy one isolate. The host enforces this bound again while streaming.
|
|
140
200
|
export const FUNCTIONS_SEED_MAX_BYTES = 8 * 1024 * 1024;
|
|
141
201
|
/**
|
|
142
|
-
* One warm-cache entry:
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* and the cache client to disagree about serialization.
|
|
202
|
+
* One warm-cache entry: what the runtime's incremental-cache client would have
|
|
203
|
+
* written for `key` had it rendered the page itself. `valueJson` stays the JSON
|
|
204
|
+
* string it already is on disk (OpenNext's `.cache` / fetch-cache files), so the
|
|
205
|
+
* seed writer and the cache client cannot disagree about serialization.
|
|
147
206
|
*/
|
|
148
207
|
export const functionsSeedEntrySchema = z
|
|
149
208
|
.object({
|
|
@@ -165,25 +224,20 @@ const functionsRoutePathSchema = appRoutePathSchema({
|
|
|
165
224
|
subject: "Function routes",
|
|
166
225
|
});
|
|
167
226
|
/**
|
|
168
|
-
* How many entries the origin's dispatch table accepts.
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* assembling the artifact — discovering the ceiling as a validation error at
|
|
172
|
-
* finalize would mean a build that classified fine fails at the last step — so
|
|
173
|
-
* the ceiling has to be a value both sides can read, not a literal each side
|
|
174
|
-
* spells for itself.
|
|
227
|
+
* How many entries the origin's dispatch table accepts. Exported because the CLI
|
|
228
|
+
* classifier compacts its route claims BEFORE assembling the artifact: meeting
|
|
229
|
+
* the ceiling as a finalize error would fail a build that classified fine.
|
|
175
230
|
*/
|
|
176
231
|
export const FUNCTIONS_MAX_ROUTES = 256;
|
|
177
232
|
/**
|
|
178
|
-
* A worker's dynamic route table. Anything not matched here is answered from
|
|
179
|
-
*
|
|
180
|
-
* is both the cheaper path and the one that keeps assets ours.
|
|
233
|
+
* A worker's dynamic route table. Anything not matched here is answered from the
|
|
234
|
+
* version's static content by wp.cloud and never reaches Cloudflare.
|
|
181
235
|
*
|
|
182
236
|
* A `subtree` entry covers its own path AND everything below it: the engine
|
|
183
237
|
* expands one into both `path` and `path/:splat`
|
|
184
|
-
* (`_stattic_runtime_functions_routes_artifact`, runtime/engine/admin/management.php)
|
|
185
|
-
*
|
|
186
|
-
*
|
|
238
|
+
* (`_stattic_runtime_functions_routes_artifact`, runtime/engine/admin/management.php).
|
|
239
|
+
* So `wholeSiteRoutes()` is a single `/` subtree entry, and an exact entry beside
|
|
240
|
+
* a subtree entry at the same path is dead weight.
|
|
187
241
|
*/
|
|
188
242
|
export const functionsRouteSchema = z
|
|
189
243
|
.object({
|
|
@@ -210,12 +264,9 @@ export const functionsBundleModuleSchema = z.union([
|
|
|
210
264
|
z.object({ data: executionBase64Schema }).strict(),
|
|
211
265
|
]);
|
|
212
266
|
/**
|
|
213
|
-
* The document served at a bundle URL and parsed by the host.
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* of it living here: the CLI's bundler and the host's loader are separate
|
|
217
|
-
* deployments that must agree, and the only thing keeping them honest is a
|
|
218
|
-
* shared definition of the bytes in between.
|
|
267
|
+
* The document served at a bundle URL and parsed by the host. The CLI's bundler
|
|
268
|
+
* and the host's loader are separate deployments, and this shared definition is
|
|
269
|
+
* the only thing keeping them agreed on the bytes in between.
|
|
219
270
|
*/
|
|
220
271
|
export const functionsBundleManifestSchema = z
|
|
221
272
|
.object({
|
|
@@ -230,10 +281,9 @@ export const functionsBundleManifestSchema = z
|
|
|
230
281
|
});
|
|
231
282
|
/**
|
|
232
283
|
* Where the worker's compiled bytes live in the version's own content store.
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
* forbids.
|
|
284
|
+
* Not inline in the finalize payload like Zero's bundles: framework output runs
|
|
285
|
+
* to megabytes, and inlining it would push the whole thing through the control
|
|
286
|
+
* plane, which the direct-from-wp.cloud rule forbids.
|
|
237
287
|
*/
|
|
238
288
|
export const functionsBundleRefSchema = z
|
|
239
289
|
.object({
|
|
@@ -249,9 +299,9 @@ export const functionsBundleRefSchema = z
|
|
|
249
299
|
})
|
|
250
300
|
.strict();
|
|
251
301
|
/**
|
|
252
|
-
* Where a version's cache seed document sits in its content store
|
|
253
|
-
*
|
|
254
|
-
*
|
|
302
|
+
* Where a version's cache seed document sits in its content store, the bundle
|
|
303
|
+
* ref's sibling with the seed's own root and ceiling. `entries` is carried so
|
|
304
|
+
* status surfaces can say what the seed holds without fetching it.
|
|
255
305
|
*/
|
|
256
306
|
export const functionsSeedRefSchema = z
|
|
257
307
|
.object({
|
|
@@ -268,39 +318,34 @@ export const functionsSeedRefSchema = z
|
|
|
268
318
|
})
|
|
269
319
|
.strict();
|
|
270
320
|
/**
|
|
271
|
-
* The path a bundle is served from.
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
* lacks the bytes, but it is derivable by anyone who *has* them, and it shows up
|
|
284
|
-
* in build output and `sf runtime status`. The token adds the dimension the
|
|
285
|
-
* digest cannot: holding the code does not entitle you to fetch it from us, and
|
|
286
|
-
* rotating the site secret invalidates every URL at once.
|
|
321
|
+
* The path a bundle is served from. Content-addressed, so the response is
|
|
322
|
+
* immutable and cacheable at our edge forever: a cold isolate anywhere costs one
|
|
323
|
+
* CDN hit rather than a round trip to the space's origin.
|
|
324
|
+
*
|
|
325
|
+
* The token rides in the path rather than the query string for the same reason.
|
|
326
|
+
* A query parameter is subject to cache-key normalisation, and a token stripped
|
|
327
|
+
* from the key would let one space's cached bundle answer another space's URL.
|
|
328
|
+
*
|
|
329
|
+
* Both halves are load-bearing. The digest is derivable by anyone holding the
|
|
330
|
+
* bytes and shows up in build output and `sf runtime status`. The token adds
|
|
331
|
+
* what the digest cannot: holding the code does not entitle you to fetch it from
|
|
332
|
+
* us, and rotating the site secret invalidates every URL at once.
|
|
287
333
|
*/
|
|
288
334
|
export function functionsBundlePath(input) {
|
|
289
335
|
return `${FUNCTIONS_BUNDLE_ROUTE_PREFIX}/${bundleDigest(input.sha256)}/${input.token}/bundle.json`;
|
|
290
336
|
}
|
|
291
337
|
/**
|
|
292
|
-
* The seed document's read path
|
|
293
|
-
* filename and its own token audience. One signed artifact route on the
|
|
294
|
-
*
|
|
295
|
-
* audience says what the caller was authorised to read.
|
|
338
|
+
* The seed document's read path: the bundle route with a different terminal
|
|
339
|
+
* filename and its own token audience. One signed artifact route on the origin
|
|
340
|
+
* serves both.
|
|
296
341
|
*/
|
|
297
342
|
export function functionsSeedPath(input) {
|
|
298
343
|
return `${FUNCTIONS_BUNDLE_ROUTE_PREFIX}/${bundleDigest(input.sha256)}/${input.token}/seed.json`;
|
|
299
344
|
}
|
|
300
345
|
/**
|
|
301
|
-
* Where the bundle
|
|
302
|
-
*
|
|
303
|
-
*
|
|
346
|
+
* Where the bundle sits in the published version, the same path minus the token
|
|
347
|
+
* segment. The token authorises the read; it does not name the file, so rotating
|
|
348
|
+
* the signing key changes every URL without moving a byte.
|
|
304
349
|
*/
|
|
305
350
|
export function functionsBundleStoragePath(input) {
|
|
306
351
|
return `${FUNCTIONS_RUNTIME_BUNDLE_ROOT}/${bundleDigest(input.sha256)}/bundle.json`;
|
|
@@ -311,17 +356,16 @@ export function functionsSeedStoragePath(input) {
|
|
|
311
356
|
}
|
|
312
357
|
/**
|
|
313
358
|
* The digest is carried in contracts as `sha256:<hex>` but appears in paths as
|
|
314
|
-
* bare hex: a colon
|
|
315
|
-
*
|
|
359
|
+
* bare hex: a colon in a path segment invites normalisation differences between
|
|
360
|
+
* the edge, the origin, and fetch.
|
|
316
361
|
*/
|
|
317
362
|
function bundleDigest(sha256) {
|
|
318
363
|
return sha256.startsWith("sha256:") ? sha256.slice(7) : sha256;
|
|
319
364
|
}
|
|
320
365
|
/**
|
|
321
|
-
* Cloudflare pins runtime behaviour to a date rather than a version number, so
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
* version restores the compatibility date it was built against.
|
|
366
|
+
* Cloudflare pins runtime behaviour to a date rather than a version number, so a
|
|
367
|
+
* worker built today keeps today's semantics forever. Recorded on the version,
|
|
368
|
+
* so promoting an old version restores the date it was built against.
|
|
325
369
|
*/
|
|
326
370
|
const functionsCompatibilityDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
327
371
|
export const functionsWorkerArtifactSchema = z
|
|
@@ -330,23 +374,22 @@ export const functionsWorkerArtifactSchema = z
|
|
|
330
374
|
appName: z.string().min(1).max(128),
|
|
331
375
|
/**
|
|
332
376
|
* What the author wrote, for display: `handler.ts`, `.open-next/worker.js`.
|
|
333
|
-
*
|
|
377
|
+
* The file no longer exists after bundling.
|
|
334
378
|
*/
|
|
335
379
|
entry: z.string().min(1).max(1024),
|
|
336
380
|
/**
|
|
337
|
-
* The entry module's name *inside the bundle manifest
|
|
338
|
-
* instantiates. Carried here rather than read from the manifest
|
|
339
|
-
* origin dispatches without
|
|
340
|
-
* CDN straight to the isolate
|
|
381
|
+
* The entry module's name *inside the bundle manifest*, which is what the
|
|
382
|
+
* loader instantiates. Carried here rather than read from the manifest
|
|
383
|
+
* because the origin dispatches without opening the bundle: the bytes go
|
|
384
|
+
* from our CDN straight to the isolate.
|
|
341
385
|
*/
|
|
342
386
|
mainModule: z.string().min(1).max(1024),
|
|
343
387
|
bundle: functionsBundleRefSchema,
|
|
344
388
|
/**
|
|
345
|
-
* The build-time cache seed, or null when the build produced nothing
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
* finalize.
|
|
389
|
+
* The build-time cache seed, or null when the build produced nothing worth
|
|
390
|
+
* warming. A ref, not content: the document rides the version's own file
|
|
391
|
+
* tree like the bundle, and the host pulls it through a signed URL minted
|
|
392
|
+
* at finalize.
|
|
350
393
|
*/
|
|
351
394
|
seed: functionsSeedRefSchema.nullable().default(null),
|
|
352
395
|
compatibilityDate: functionsCompatibilityDateSchema,
|
|
@@ -354,25 +397,24 @@ export const functionsWorkerArtifactSchema = z
|
|
|
354
397
|
routes: z.array(functionsRouteSchema).max(FUNCTIONS_MAX_ROUTES).default([]),
|
|
355
398
|
/**
|
|
356
399
|
* Cookie names whose presence must skip the origin's static fast path on
|
|
357
|
-
* claimed routes
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
* draft session without a build-wide draft-usage proof.
|
|
400
|
+
* claimed routes, the framework's draft/preview session markers. Data from
|
|
401
|
+
* the classifier, not names the engine knows: the origin checks the Cookie
|
|
402
|
+
* header against this list and dispatches instead of serving the extracted
|
|
403
|
+
* file, which lets a fully-static page honor a draft session.
|
|
362
404
|
*/
|
|
363
405
|
bypassCookies: z.array(z.string().min(1).max(128)).max(8).default([]),
|
|
364
406
|
/**
|
|
365
|
-
* Aggregate of what the worker's handlers reach,
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
407
|
+
* Aggregate of what the worker's handlers reach, deciding which brokered
|
|
408
|
+
* capabilities the relay honours for this version. A worker that never
|
|
409
|
+
* declares `db` gets a relay that refuses `db.read` outright, so an injected
|
|
410
|
+
* dependency cannot widen authority at runtime.
|
|
369
411
|
*/
|
|
370
412
|
capabilities: executionCapabilitiesSchema,
|
|
371
413
|
/**
|
|
372
|
-
* Platform-owned runtime services this build needs
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
414
|
+
* Platform-owned runtime services this build needs, separate from author
|
|
415
|
+
* capabilities: an OpenNext build needs durable cache storage even when the
|
|
416
|
+
* application declares no database or fetch access, and that storage must
|
|
417
|
+
* never become a general tenant credential.
|
|
376
418
|
*/
|
|
377
419
|
platform: z
|
|
378
420
|
.object({
|
|
@@ -384,12 +426,10 @@ export const functionsWorkerArtifactSchema = z
|
|
|
384
426
|
.strict();
|
|
385
427
|
/**
|
|
386
428
|
* The authority a dispatched worker may exercise, in the vocabulary the host
|
|
387
|
-
* speaks on the wire.
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* *grants*, resolved by the control plane at finalize so the origin forwards a
|
|
392
|
-
* decision rather than making one. Anything absent fails closed at the relay.
|
|
429
|
+
* speaks on the wire. Narrower than `executionCapabilitiesSchema`, which records
|
|
430
|
+
* what a build *declared* it uses; this is what the origin *grants*, resolved by
|
|
431
|
+
* the control plane at finalize so the origin forwards a decision rather than
|
|
432
|
+
* making one. Anything absent fails closed at the relay.
|
|
393
433
|
*/
|
|
394
434
|
export const FUNCTIONS_DISPATCH_CAPABILITIES = [
|
|
395
435
|
"storage.read",
|
|
@@ -407,29 +447,22 @@ export const functionsDispatchCapabilitySchema = z.enum(FUNCTIONS_DISPATCH_CAPAB
|
|
|
407
447
|
/**
|
|
408
448
|
* Resolves a build's declared capabilities into the grant a dispatch carries.
|
|
409
449
|
*
|
|
410
|
-
* Three declared capabilities have no dispatch counterpart
|
|
411
|
-
* reason:
|
|
450
|
+
* Three declared capabilities have no dispatch counterpart:
|
|
412
451
|
*
|
|
413
452
|
* - `env` is not a runtime call at all. Values are resolved at finalize and
|
|
414
453
|
* travel in the config, so a worker reading `env` reaches nothing.
|
|
415
|
-
* - `auth` and `realtime` bind a handler to the local tier
|
|
416
|
-
*
|
|
417
|
-
* never arrives here.
|
|
418
|
-
*
|
|
419
|
-
* `db` widens to both read and write because a declaration says a handler
|
|
420
|
-
* touches the database, not how. Narrowing it would take per-statement analysis
|
|
421
|
-
* we do not do, and guessing "read-only" from a declaration would be a grant
|
|
422
|
-
* the author never asked for and cannot see.
|
|
454
|
+
* - `auth` and `realtime` bind a handler to the local tier, so code declaring
|
|
455
|
+
* them deploys as a capsule and never arrives here. See `endpointIsPortable`.
|
|
423
456
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
457
|
+
* `db` widens to both read and write, and each platform-service grant covers its
|
|
458
|
+
* service's whole operation set, because a declaration says a handler touches
|
|
459
|
+
* the database or checks for spam, not how. Narrowing would take per-statement
|
|
460
|
+
* analysis we do not do.
|
|
428
461
|
*/
|
|
429
462
|
export function functionsDispatchCapabilities(capabilities, platform = {}) {
|
|
430
|
-
// Storage is
|
|
431
|
-
//
|
|
432
|
-
//
|
|
463
|
+
// Storage is a base binding every app receives, like the Zero client's
|
|
464
|
+
// `storage`, not a source-declared capability that disappears when a new
|
|
465
|
+
// version omits an import.
|
|
433
466
|
const granted = new Set(["storage.read", "storage.write"]);
|
|
434
467
|
if (capabilities.db) {
|
|
435
468
|
granted.add("db.read");
|
|
@@ -454,8 +487,7 @@ export function functionsDispatchCapabilities(capabilities, platform = {}) {
|
|
|
454
487
|
granted.add("next.cache");
|
|
455
488
|
}
|
|
456
489
|
// Filtered from the canonical list so the order is stable: the grant is part
|
|
457
|
-
// of the host's isolate identity, and
|
|
458
|
-
// for no reason.
|
|
490
|
+
// of the host's isolate identity, and reordering would retire warm isolates.
|
|
459
491
|
return FUNCTIONS_DISPATCH_CAPABILITIES.filter((capability) => granted.has(capability));
|
|
460
492
|
}
|
|
461
493
|
/** Logs and the host-local Next cache do not transit the origin relay. */
|
|
@@ -463,12 +495,11 @@ export function functionsGrantNeedsRelay(granted) {
|
|
|
463
495
|
return granted.some((capability) => capability !== "log" && capability !== "next.cache");
|
|
464
496
|
}
|
|
465
497
|
/**
|
|
466
|
-
* What the space origin needs
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
* over HTTPS and holds no Cloudflare API credential at all.
|
|
498
|
+
* What the space origin needs to dispatch to the host on its own. The shared
|
|
499
|
+
* secret is a wp.cloud site secret, never part of a version's content and never
|
|
500
|
+
* reachable by tenant code, so it is not modelled here. There is no account id
|
|
501
|
+
* and no namespace: the origin talks to one host worker over HTTPS and holds no
|
|
502
|
+
* Cloudflare API credential.
|
|
472
503
|
*/
|
|
473
504
|
export const functionsHostConfigSchema = z
|
|
474
505
|
.object({
|
|
@@ -479,7 +510,7 @@ export const functionsHostConfigSchema = z
|
|
|
479
510
|
* finalize.
|
|
480
511
|
*
|
|
481
512
|
* It is here rather than on the artifact because the artifact records what
|
|
482
|
-
* was built
|
|
513
|
+
* was built, meaning a path and a digest, both stable. This records how to
|
|
483
514
|
* reach it, which depends on a signing key and a hostname the build knew
|
|
484
515
|
* nothing about. Rotating the key changes every URL without changing a
|
|
485
516
|
* single artifact.
|
|
@@ -487,9 +518,9 @@ export const functionsHostConfigSchema = z
|
|
|
487
518
|
bundleUrl: z.string().url(),
|
|
488
519
|
/**
|
|
489
520
|
* Where the host pulls the version's cache seed, minted beside the bundle
|
|
490
|
-
* URL
|
|
491
|
-
*
|
|
492
|
-
*
|
|
521
|
+
* URL and null exactly when the artifact carries no seed. It feeds the cache
|
|
522
|
+
* object's cold-start path, never request serving: an unreachable seed is a
|
|
523
|
+
* cold cache, not an error.
|
|
493
524
|
*/
|
|
494
525
|
seedUrl: z.string().url().nullable().default(null),
|
|
495
526
|
})
|
|
@@ -497,21 +528,18 @@ export const functionsHostConfigSchema = z
|
|
|
497
528
|
/**
|
|
498
529
|
* The callback a dispatched worker uses for `ctx.db`, `ctx.fetch` and logging.
|
|
499
530
|
*
|
|
500
|
-
* Each relay call re-enters the space's PHP-FPM pool,
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
* against the PHP broker, batching twenty writes into one call is 8.3x faster
|
|
506
|
-
* than twenty separate ones.
|
|
531
|
+
* Each relay call re-enters the space's PHP-FPM pool, the deadlock hazard this
|
|
532
|
+
* product's admission control bounds: a proxied request occupies a worker for
|
|
533
|
+
* its whole life while its relay calls demand more. Batching is the other half.
|
|
534
|
+
* Against the PHP broker, twenty writes in one call is 8.3x faster than twenty
|
|
535
|
+
* separate ones.
|
|
507
536
|
*/
|
|
508
537
|
export const functionsRelayConfigSchema = z
|
|
509
538
|
.object({
|
|
510
539
|
url: z.string().url(),
|
|
511
540
|
/**
|
|
512
|
-
* Bearer credential minted per version.
|
|
513
|
-
* isolate
|
|
514
|
-
* precisely so that a revoked credential cannot outlive its revocation.
|
|
541
|
+
* Bearer credential minted per version. The host folds it into the warm
|
|
542
|
+
* isolate's identity, so rotating it retires the isolate holding it.
|
|
515
543
|
*/
|
|
516
544
|
token: z.string().min(1),
|
|
517
545
|
maxBatchStatements: z.number().int().min(1).max(256),
|
|
@@ -519,21 +547,18 @@ export const functionsRelayConfigSchema = z
|
|
|
519
547
|
})
|
|
520
548
|
.strict();
|
|
521
549
|
/**
|
|
522
|
-
* Where the execution host reports how much this version ran.
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
* the control plane must never fail a request over it. Counting is reporting
|
|
527
|
-
* only — nothing here throttles, and no limit is enforced anywhere from it.
|
|
550
|
+
* Where the execution host reports how much this version ran. Absent means
|
|
551
|
+
* uncounted, not refused: a space whose configuration predates usage reporting
|
|
552
|
+
* must keep serving, and a tier that cannot reach the control plane must never
|
|
553
|
+
* fail a request over it. Nothing here throttles.
|
|
528
554
|
*/
|
|
529
555
|
export const functionsUsageConfigSchema = z
|
|
530
556
|
.object({
|
|
531
557
|
url: z.string().url(),
|
|
532
558
|
/**
|
|
533
559
|
* Minted and verified by the control plane alone; the space only forwards
|
|
534
|
-
* it. Version-scoped
|
|
535
|
-
*
|
|
536
|
-
* outlive its rotation inside a warm isolate.
|
|
560
|
+
* it. Version-scoped and folded into the isolate identity like the relay
|
|
561
|
+
* credential, so a rotated credential cannot outlive its rotation.
|
|
537
562
|
*/
|
|
538
563
|
token: z.string().min(1),
|
|
539
564
|
})
|
|
@@ -542,13 +567,11 @@ export const functionsUsageConfigSchema = z
|
|
|
542
567
|
* The credential the execution host presents at the origin's purge route.
|
|
543
568
|
*
|
|
544
569
|
* Only the token lives here: the purge route is on whichever hostname the
|
|
545
|
-
* visitor
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
* rendered. Version-scoped and folded into the host's isolate identity like its
|
|
551
|
-
* siblings, so a republish revokes it.
|
|
570
|
+
* visitor hit, so the origin composes the URL from the request host at dispatch
|
|
571
|
+
* time rather than freezing one hostname at finalize. A third credential rather
|
|
572
|
+
* than a reuse of the relay's, because a worker whose relay is unusable must
|
|
573
|
+
* still be able to invalidate what it rendered. Version-scoped, so a republish
|
|
574
|
+
* revokes it.
|
|
552
575
|
*/
|
|
553
576
|
export const functionsPurgeConfigSchema = z
|
|
554
577
|
.object({
|
|
@@ -556,15 +579,14 @@ export const functionsPurgeConfigSchema = z
|
|
|
556
579
|
})
|
|
557
580
|
.strict();
|
|
558
581
|
/**
|
|
559
|
-
* What a build declares about its worker
|
|
582
|
+
* What a build declares about its worker, everything the CLI can know from the
|
|
560
583
|
* author's project alone.
|
|
561
584
|
*
|
|
562
|
-
* Unlike Zero, this is *not* the
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
* field in which to assert authority it was not given.
|
|
585
|
+
* Unlike Zero, this is *not* the document the runtime receives. A build cannot
|
|
586
|
+
* name the host it is dispatched to, mint the credential its relay calls carry,
|
|
587
|
+
* or decide what authority it is granted. Keeping all three out of this schema
|
|
588
|
+
* leaves a version's own metadata no field in which to assert authority it was
|
|
589
|
+
* not given.
|
|
568
590
|
*/
|
|
569
591
|
export const functionsSourceFinalizeSchema = z
|
|
570
592
|
.object({
|
|
@@ -583,10 +605,9 @@ export const functionsSourceFinalizeSchema = z
|
|
|
583
605
|
* The document the control plane sends to the runtime, which the engine stores
|
|
584
606
|
* beside the version's files and the origin reads on every dispatch.
|
|
585
607
|
*
|
|
586
|
-
* It is the build's declaration plus
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
* variables.
|
|
608
|
+
* It is the build's declaration plus what only the platform can supply: where to
|
|
609
|
+
* dispatch, what the worker may do, the credentials for doing and reporting it,
|
|
610
|
+
* and the resolved variable values.
|
|
590
611
|
*/
|
|
591
612
|
export const functionsRuntimeConfigSchema = functionsSourceFinalizeSchema
|
|
592
613
|
.extend({
|
|
@@ -597,7 +618,7 @@ export const functionsRuntimeConfigSchema = functionsSourceFinalizeSchema
|
|
|
597
618
|
purge: functionsPurgeConfigSchema.nullable().default(null),
|
|
598
619
|
/**
|
|
599
620
|
* Resolved at finalize, so a worker reading configuration never calls back
|
|
600
|
-
* to us for it
|
|
621
|
+
* to us for it, and so rotating a variable is a republish with an audit
|
|
601
622
|
* trail rather than a live mutation of what running code sees.
|
|
602
623
|
*/
|
|
603
624
|
variableValues: z.record(z.string(), z.string()).default({}),
|
|
@@ -614,11 +635,9 @@ export const functionsDeployMetadataSchema = z
|
|
|
614
635
|
})
|
|
615
636
|
.strict();
|
|
616
637
|
/**
|
|
617
|
-
* Builds the declaration a publish attaches to its version
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* version agree on the shape by construction rather than by copying an object
|
|
621
|
-
* literal around — the same reason `createZeroRuntimeFinalizePayload` exists.
|
|
638
|
+
* Builds the declaration a publish attaches to its version, so the CLI's publish
|
|
639
|
+
* step and every test needing a Functions version agree on the shape by
|
|
640
|
+
* construction. Mirrors `createZeroRuntimeFinalizePayload`.
|
|
622
641
|
*/
|
|
623
642
|
export function createFunctionsSourceFinalize(input) {
|
|
624
643
|
return functionsSourceFinalizeSchema.parse({
|
|
@@ -645,12 +664,9 @@ export function createFunctionsSourceFinalize(input) {
|
|
|
645
664
|
}
|
|
646
665
|
/**
|
|
647
666
|
* What a version's worker is currently doing, as an observer of the space can
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* content store or it is not, and dispatch is decided by which version is
|
|
652
|
-
* serving — so these three cover the whole space of answers, and each one is
|
|
653
|
-
* checkable rather than inferred from a job we ran earlier.
|
|
667
|
+
* determine. There is no upload state: a bundle is either in the version's
|
|
668
|
+
* content store or it is not, and dispatch follows whichever version is serving,
|
|
669
|
+
* so each of these three is checkable rather than inferred from an earlier job.
|
|
654
670
|
*/
|
|
655
671
|
export const functionsExecutionStateSchema = z.enum([
|
|
656
672
|
/** No bundle at the version's bundle path. */
|
|
@@ -663,17 +679,14 @@ export const functionsExecutionStateSchema = z.enum([
|
|
|
663
679
|
/**
|
|
664
680
|
* What a live worker is, as the `worker` member of a space's runtime status.
|
|
665
681
|
*
|
|
666
|
-
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
* version.
|
|
682
|
+
* No kind tag: the member it rides in already says which product answered, and
|
|
683
|
+
* the same tree can carry a capsule beside it. No `versionId`: the status
|
|
684
|
+
* response already names the live version. No `database` field:
|
|
685
|
+
* `capabilities.db` is the fact the whole `/db` family branches on, and stating
|
|
686
|
+
* it twice invites the two to disagree.
|
|
672
687
|
*
|
|
673
|
-
* Everything but `executionState`
|
|
674
|
-
*
|
|
675
|
-
* `database` field: `capabilities.db` is the fact the whole `/db` family
|
|
676
|
-
* branches on, and stating it twice invites the two to disagree.
|
|
688
|
+
* Everything but `executionState` comes from the version's finalize metadata, so
|
|
689
|
+
* this answers whether or not the origin is reachable.
|
|
677
690
|
*/
|
|
678
691
|
export const functionsAppSchema = z
|
|
679
692
|
.object({
|