@astrale-os/adapter-cloudflare 0.5.0-beta.13 → 0.5.0-beta.131
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/CHANGELOG.md +1515 -0
- package/README.md +46 -2
- package/dist/adapter.d.ts +14 -0
- package/dist/adapter.js +82 -0
- package/dist/build/artifact.d.ts +7 -0
- package/dist/build/artifact.js +165 -0
- package/dist/build/bundle/admit.d.ts +1 -0
- package/dist/build/bundle/admit.js +9 -0
- package/dist/build/closure.d.ts +2 -0
- package/dist/build/closure.js +22 -0
- package/dist/build/codegen/execution.d.ts +3 -0
- package/dist/build/codegen/execution.js +2 -0
- package/dist/build/codegen/merge.d.ts +0 -1
- package/dist/build/codegen/merge.js +0 -1
- package/dist/build/codegen/wrangler.d.ts +12 -3
- package/dist/build/codegen/wrangler.js +26 -18
- package/dist/build/configuration/addressing.d.ts +2 -0
- package/dist/build/configuration/addressing.js +11 -0
- package/dist/build/configuration/invocation-timeout.d.ts +2 -0
- package/dist/build/configuration/invocation-timeout.js +9 -0
- package/dist/build/configuration/request-limit.d.ts +2 -0
- package/dist/build/configuration/request-limit.js +9 -0
- package/dist/build/configuration/router.d.ts +7 -0
- package/dist/build/configuration/router.js +11 -0
- package/dist/build/configuration/worker-name.d.ts +2 -0
- package/dist/build/configuration/worker-name.js +18 -0
- package/dist/build/configuration.d.ts +5 -0
- package/dist/build/configuration.js +5 -0
- package/dist/build/direct.d.ts +4 -0
- package/dist/build/direct.js +90 -0
- package/dist/build/frontend/files.d.ts +9 -0
- package/dist/build/frontend/files.js +33 -0
- package/dist/build/frontend/readiness.d.ts +10 -0
- package/dist/build/frontend/readiness.js +21 -0
- package/dist/build/frontend/revision.d.ts +5 -0
- package/dist/build/frontend/revision.js +14 -0
- package/dist/build/frontend/vite.d.ts +8 -0
- package/dist/build/frontend/vite.js +32 -0
- package/dist/build/frontend/vite.process.d.ts +7 -0
- package/dist/build/frontend/vite.process.js +65 -0
- package/dist/build/frontend/vite.runner.d.ts +1 -0
- package/dist/build/frontend/vite.runner.js +120 -0
- package/dist/build/index.d.ts +9 -16
- package/dist/build/index.js +8 -16
- package/dist/build/materialize.d.ts +4 -0
- package/dist/build/materialize.js +10 -0
- package/dist/build/metafile.d.ts +5 -0
- package/dist/build/metafile.js +14 -0
- package/dist/build/qualification.d.ts +5 -0
- package/dist/build/qualification.js +7 -0
- package/dist/build/roots.d.ts +2 -0
- package/dist/build/roots.js +34 -0
- package/dist/build/worker/artifact.d.ts +40 -0
- package/dist/build/worker/artifact.js +1 -0
- package/dist/build/worker/artifact.load.d.ts +3 -0
- package/dist/build/worker/artifact.load.js +308 -0
- package/dist/build/worker/artifact.manifest.d.ts +48 -0
- package/dist/build/worker/artifact.manifest.js +87 -0
- package/dist/build/worker/artifact.paths.d.ts +4 -0
- package/dist/build/worker/artifact.paths.js +25 -0
- package/dist/build/worker/codegen/entry.d.ts +2 -0
- package/dist/build/worker/codegen/entry.js +28 -0
- package/dist/build/worker/codegen/service.d.ts +19 -0
- package/dist/build/worker/codegen/service.js +53 -0
- package/dist/build/worker/execution.prepare.d.ts +19 -0
- package/dist/build/worker/execution.prepare.js +115 -0
- package/dist/build/worker/index.d.ts +2 -0
- package/dist/build/worker/index.js +1 -0
- package/dist/build/worker/modules.d.ts +11 -0
- package/dist/build/worker/modules.js +26 -0
- package/dist/build/worker/runtime.d.ts +10 -0
- package/dist/build/worker/runtime.js +35 -0
- package/dist/build/worker/specifier.d.ts +1 -0
- package/dist/build/worker/specifier.js +5 -0
- package/dist/cloudflare.d.ts +1 -45
- package/dist/cloudflare.js +1 -202
- package/dist/deploy/deploy.d.ts +17 -0
- package/dist/deploy/deploy.js +221 -0
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/index.js +1 -0
- package/dist/deploy/output.d.ts +2 -0
- package/dist/deploy/output.js +10 -0
- package/dist/deploy/readiness.d.ts +5 -0
- package/dist/deploy/readiness.js +18 -0
- package/dist/identity/binding.d.ts +2 -0
- package/dist/identity/binding.js +2 -0
- package/dist/identity/index.d.ts +3 -0
- package/dist/identity/index.js +3 -0
- package/dist/identity/material.d.ts +7 -0
- package/dist/identity/material.js +42 -0
- package/dist/identity/secret.d.ts +3 -0
- package/dist/identity/secret.js +7 -0
- package/dist/identity/source.d.ts +26 -0
- package/dist/identity/source.js +127 -0
- package/dist/index.d.ts +10 -9
- package/dist/index.js +10 -9
- package/dist/params.d.ts +40 -36
- package/dist/params.js +0 -1
- package/dist/release/deployment.d.ts +44 -0
- package/dist/release/deployment.js +141 -0
- package/dist/release/index.d.ts +2 -0
- package/dist/release/index.js +2 -0
- package/dist/release/staged-worker-name.d.ts +3 -0
- package/dist/release/staged-worker-name.js +10 -0
- package/dist/worker/entry.d.ts +48 -0
- package/dist/worker/entry.js +157 -0
- package/dist/worker/fetch.d.ts +0 -1
- package/dist/worker/fetch.js +0 -1
- package/dist/worker/frontend.d.ts +4 -0
- package/dist/worker/frontend.js +46 -0
- package/dist/worker/identity.d.ts +7 -0
- package/dist/worker/identity.js +23 -0
- package/dist/worker/index.d.ts +2 -61
- package/dist/worker/index.js +2 -218
- package/dist/wrangler/bundle.d.ts +10 -0
- package/dist/wrangler/bundle.js +28 -0
- package/dist/wrangler/deploy.d.ts +24 -0
- package/dist/wrangler/deploy.js +44 -0
- package/dist/wrangler/index.d.ts +5 -0
- package/dist/wrangler/index.js +5 -0
- package/dist/wrangler/process.d.ts +15 -0
- package/dist/wrangler/process.js +102 -0
- package/dist/wrangler/rollout.d.ts +27 -0
- package/dist/wrangler/rollout.js +75 -0
- package/dist/wrangler/secrets.d.ts +2 -0
- package/dist/wrangler/secrets.js +24 -0
- package/dist/wrangler/status.d.ts +18 -0
- package/dist/wrangler/status.js +75 -0
- package/dist/wrangler/triggers.d.ts +5 -0
- package/dist/wrangler/triggers.js +12 -0
- package/dist/wrangler/type-generation.d.ts +6 -0
- package/dist/wrangler/type-generation.js +19 -0
- package/dist/wrangler/versions.d.ts +13 -0
- package/dist/wrangler/versions.js +38 -0
- package/package.json +34 -19
- package/template/astrale.config.ts +30 -31
- package/dist/build/codegen/identity.d.ts +0 -10
- package/dist/build/codegen/identity.d.ts.map +0 -1
- package/dist/build/codegen/identity.js +0 -32
- package/dist/build/codegen/identity.js.map +0 -1
- package/dist/build/codegen/merge.d.ts.map +0 -1
- package/dist/build/codegen/merge.js.map +0 -1
- package/dist/build/codegen/worker.d.ts +0 -12
- package/dist/build/codegen/worker.d.ts.map +0 -1
- package/dist/build/codegen/worker.js +0 -40
- package/dist/build/codegen/worker.js.map +0 -1
- package/dist/build/codegen/wrangler.d.ts.map +0 -1
- package/dist/build/codegen/wrangler.js.map +0 -1
- package/dist/build/frontend.d.ts +0 -27
- package/dist/build/frontend.d.ts.map +0 -1
- package/dist/build/frontend.js +0 -252
- package/dist/build/frontend.js.map +0 -1
- package/dist/build/index.d.ts.map +0 -1
- package/dist/build/index.js.map +0 -1
- package/dist/build/parse-output.d.ts +0 -27
- package/dist/build/parse-output.d.ts.map +0 -1
- package/dist/build/parse-output.js +0 -58
- package/dist/build/parse-output.js.map +0 -1
- package/dist/build/prepare.d.ts +0 -18
- package/dist/build/prepare.d.ts.map +0 -1
- package/dist/build/prepare.js +0 -138
- package/dist/build/prepare.js.map +0 -1
- package/dist/build/worker.d.ts +0 -15
- package/dist/build/worker.d.ts.map +0 -1
- package/dist/build/worker.js +0 -21
- package/dist/build/worker.js.map +0 -1
- package/dist/build/wrangler-cli.d.ts +0 -88
- package/dist/build/wrangler-cli.d.ts.map +0 -1
- package/dist/build/wrangler-cli.js +0 -283
- package/dist/build/wrangler-cli.js.map +0 -1
- package/dist/cloudflare.d.ts.map +0 -1
- package/dist/cloudflare.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/params.d.ts.map +0 -1
- package/dist/params.js.map +0 -1
- package/dist/worker/fetch.d.ts.map +0 -1
- package/dist/worker/fetch.js.map +0 -1
- package/dist/worker/index.d.ts.map +0 -1
- package/dist/worker/index.js.map +0 -1
- package/src/build/codegen/identity.ts +0 -40
- package/src/build/codegen/merge.ts +0 -92
- package/src/build/codegen/worker.ts +0 -53
- package/src/build/codegen/wrangler.ts +0 -128
- package/src/build/frontend.ts +0 -298
- package/src/build/index.ts +0 -29
- package/src/build/parse-output.ts +0 -60
- package/src/build/prepare.ts +0 -189
- package/src/build/worker.ts +0 -37
- package/src/build/wrangler-cli.ts +0 -372
- package/src/cloudflare.ts +0 -275
- package/src/index.ts +0 -21
- package/src/params.ts +0 -92
- package/src/worker/fetch.ts +0 -46
- package/src/worker/index.ts +0 -332
- package/src/worker/tsconfig.json +0 -10
package/dist/params.d.ts
CHANGED
|
@@ -1,41 +1,52 @@
|
|
|
1
|
+
import type { ExchangeOptions } from '@astrale-os/sdk/execution';
|
|
1
2
|
/**
|
|
2
3
|
* `CloudflareParams` — the provider-typed config for the Cloudflare adapter.
|
|
3
4
|
*
|
|
4
|
-
* One
|
|
5
|
-
*
|
|
6
|
-
* is `Record<string, CloudflareParams>`.
|
|
7
|
-
*
|
|
8
|
-
* Three deployment shapes fall out of which fields are set:
|
|
9
|
-
* • dev (local) — `watch()` runs `wrangler dev`; URL = http://localhost:<port>
|
|
10
|
-
* • dev-remote — `deploy()` with no `route`; URL = https://<name>.<sub>.workers.dev
|
|
11
|
-
* • remote (custom) — `deploy()` with `route`; URL = https://<route>
|
|
5
|
+
* One value configures one Project Environment. Omitting `route` deploys to the
|
|
6
|
+
* provider-assigned stable `*.workers.dev` address.
|
|
12
7
|
*/
|
|
13
8
|
export interface CloudflareParams {
|
|
14
9
|
/**
|
|
15
10
|
* Custom route / hostname for a routed deploy, e.g. `'crm.acme.dev'`. Omit to
|
|
16
|
-
* deploy to `*.workers.dev`.
|
|
17
|
-
* localhost) but still used as the placeholder base domain there.
|
|
11
|
+
* deploy to `*.workers.dev`.
|
|
18
12
|
*/
|
|
19
13
|
readonly route?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Exact public Addressing expected after deployment. Use this for an already
|
|
16
|
+
* known provider-assigned address such as `*.workers.dev`; `route` remains
|
|
17
|
+
* the field that asks Cloudflare to attach a custom hostname. When both are
|
|
18
|
+
* present they must identify the same HTTPS origin.
|
|
19
|
+
*/
|
|
20
|
+
readonly addressing?: string;
|
|
20
21
|
/** Gitignored secrets file (whole contents = secrets), e.g. `'.env.dev'`. */
|
|
21
22
|
readonly secrets?: string;
|
|
22
|
-
/** Local dev port for `wrangler dev`. Default 8787. */
|
|
23
|
-
readonly port?: number;
|
|
24
23
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* and `WORKER_URL` is pinned to this URL so the worker's per-request-Host
|
|
29
|
-
* identity (`iss`) doesn't drift to the proxy's internal hostname.
|
|
30
|
-
* Usually injected by `pnpm dev --host <url>` rather than written here.
|
|
24
|
+
* Private Ed25519 JWK file retained outside source control. Remote deploys
|
|
25
|
+
* require this explicit source so a fresh runner cannot silently rotate an
|
|
26
|
+
* installed Domain identity.
|
|
31
27
|
*/
|
|
32
|
-
readonly
|
|
28
|
+
readonly signingIdentity?: string;
|
|
33
29
|
/** Override the Worker name. Default: derived from the domain origin. */
|
|
34
30
|
readonly workerName?: string;
|
|
35
|
-
/** Run `wrangler dev --remote` (edge isolate) instead of local workerd. */
|
|
36
|
-
readonly remote?: boolean;
|
|
37
31
|
/** Extra plain (non-secret) vars to inject as Worker vars. */
|
|
38
32
|
readonly vars?: Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Maximum encoded invocation request bytes retained by the Worker Server.
|
|
35
|
+
* Defaults to 1 MiB and is capped at 16 MiB. Increase only from measured
|
|
36
|
+
* application traffic; Publication and Bundle delivery have separate limits.
|
|
37
|
+
*/
|
|
38
|
+
readonly maximumRequestBytes?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Maximum wall-clock lifetime of one invocation, including Workflow steps and
|
|
41
|
+
* returned streams. Defaults to 30 seconds. Increase this for intentionally
|
|
42
|
+
* long provider orchestration while retaining a finite application budget.
|
|
43
|
+
*/
|
|
44
|
+
readonly invocationTimeoutMs?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Configure the caller-only Domain token exchange lifetime, or disable exchange.
|
|
47
|
+
* The default maximum is 30 minutes; production and CI environments may select a shorter bound.
|
|
48
|
+
*/
|
|
49
|
+
readonly tokenExchange?: ExchangeOptions | false;
|
|
39
50
|
/**
|
|
40
51
|
* Escape hatch: raw wrangler config deep-merged over the generated base. Use
|
|
41
52
|
* it to declare extra bindings the adapter has no typed field for — KV, R2,
|
|
@@ -56,26 +67,20 @@ export interface CloudflareParams {
|
|
|
56
67
|
*/
|
|
57
68
|
readonly wrangler?: Record<string, unknown>;
|
|
58
69
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* worker can't fetch an instance kernel's JWKS to verify an inbound credential
|
|
63
|
-
* from that instance, and every cross-instance call (install hooks, the GUI's
|
|
64
|
-
* delegated calls, authed views) fails with `2002 Credential verification
|
|
65
|
-
* failed`. Point it at a router Worker that reaches those hosts internally
|
|
66
|
-
* (Astrale: `admin-router`).
|
|
70
|
+
* Optional private routing through a service binding. By default, subrequests use
|
|
71
|
+
* their public URLs; generated Workers enable `global_fetch_strictly_public` so
|
|
72
|
+
* same-zone Worker calls honor public routes too.
|
|
67
73
|
*
|
|
68
74
|
* Wires BOTH halves the SDK needs: the `<binding>` service binding in the
|
|
69
75
|
* generated wrangler config, and a `routeSubrequest` predicate in the worker
|
|
70
76
|
* entry that diverts matching hosts through it.
|
|
71
77
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* router), or an object to override the target / binding name / host match.
|
|
78
|
+
* Opt in only when the selected router owns every hostname matched by the
|
|
79
|
+
* suffix/label predicate. A shared DNS suffix is not proof of router ownership:
|
|
80
|
+
* standalone Domain deployments may share it with managed instances.
|
|
76
81
|
*
|
|
77
|
-
* router: false
|
|
78
|
-
* router: { service: 'my-router' } //
|
|
82
|
+
* router: false // explicit public routing (the default)
|
|
83
|
+
* router: { service: 'my-router' } // opt into a private router
|
|
79
84
|
*/
|
|
80
85
|
readonly router?: false | {
|
|
81
86
|
/** Router Worker the binding targets. Default `'admin-router'`. */
|
|
@@ -88,4 +93,3 @@ export interface CloudflareParams {
|
|
|
88
93
|
readonly minLabels?: number;
|
|
89
94
|
};
|
|
90
95
|
}
|
|
91
|
-
//# sourceMappingURL=params.d.ts.map
|
package/dist/params.js
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
declare const WORKER_DEPLOYMENT_ID: unique symbol;
|
|
2
|
+
/** Provider-local identity for one immutable staged Cloudflare implementation. */
|
|
3
|
+
export type WorkerDeploymentId = `sha256:${string}` & {
|
|
4
|
+
readonly [WORKER_DEPLOYMENT_ID]: true;
|
|
5
|
+
};
|
|
6
|
+
export interface WorkerDeploymentInput {
|
|
7
|
+
readonly release: {
|
|
8
|
+
readonly entrypoint: string;
|
|
9
|
+
readonly modules: readonly {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly kind: 'esm' | 'wasm' | 'text' | 'data';
|
|
12
|
+
readonly content: Uint8Array;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
readonly runtime: {
|
|
16
|
+
readonly compatibilityDate: string;
|
|
17
|
+
readonly compatibilityFlags: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
readonly bindings: {
|
|
20
|
+
readonly vars: Readonly<Record<string, string>>;
|
|
21
|
+
readonly services: readonly {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly service: string;
|
|
24
|
+
}[];
|
|
25
|
+
readonly requiredSecrets: readonly string[];
|
|
26
|
+
};
|
|
27
|
+
readonly assets?: {
|
|
28
|
+
readonly files: readonly {
|
|
29
|
+
readonly path: string;
|
|
30
|
+
readonly content: Uint8Array;
|
|
31
|
+
readonly contentType?: string;
|
|
32
|
+
}[];
|
|
33
|
+
readonly notFound: 'none' | '404-page' | 'single-page-application';
|
|
34
|
+
readonly runWorkerFirst: boolean;
|
|
35
|
+
readonly htmlHandling?: 'none';
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Canonical provider material used only for staging, promotion, rollback, and cleanup. */
|
|
39
|
+
export declare function workerDeploymentMaterial(input: WorkerDeploymentInput): Uint8Array;
|
|
40
|
+
/** Identify one immutable Cloudflare implementation without changing SDK or Publication identity. */
|
|
41
|
+
export declare function workerDeployment(input: WorkerDeploymentInput): WorkerDeploymentId;
|
|
42
|
+
/** Admit a serialized provider deployment identity at a Cloudflare boundary. */
|
|
43
|
+
export declare function acceptWorkerDeployment(input: unknown): WorkerDeploymentId;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
2
|
+
const DEPLOYMENT = /^sha256:[0-9a-f]{64}$/u;
|
|
3
|
+
/** Canonical provider material used only for staging, promotion, rollback, and cleanup. */
|
|
4
|
+
export function workerDeploymentMaterial(input) {
|
|
5
|
+
const release = executable(input.release);
|
|
6
|
+
const compatibilityFlags = uniqueStrings(input.runtime.compatibilityFlags, 'compatibility flag');
|
|
7
|
+
const vars = Object.fromEntries(Object.entries(input.bindings.vars)
|
|
8
|
+
.map(([name, value]) => {
|
|
9
|
+
stable(name, 'Variable binding name');
|
|
10
|
+
if (typeof value !== 'string')
|
|
11
|
+
invalid();
|
|
12
|
+
return [name, value];
|
|
13
|
+
})
|
|
14
|
+
.sort(([left], [right]) => compare(left, right)));
|
|
15
|
+
const services = [...input.bindings.services]
|
|
16
|
+
.map((binding) => ({
|
|
17
|
+
name: stable(binding.name, 'Service binding name'),
|
|
18
|
+
service: stable(binding.service, 'Service binding target'),
|
|
19
|
+
}))
|
|
20
|
+
.sort((left, right) => compare(left.name, right.name));
|
|
21
|
+
unique(services.map((binding) => binding.name), 'Service binding name');
|
|
22
|
+
const requiredSecrets = uniqueStrings(input.bindings.requiredSecrets, 'required secret');
|
|
23
|
+
unique([...Object.keys(vars), ...services.map((binding) => binding.name), ...requiredSecrets], 'Worker binding name');
|
|
24
|
+
const assets = input.assets === undefined ? undefined : canonicalAssets(input.assets);
|
|
25
|
+
return new TextEncoder().encode(`${JSON.stringify({
|
|
26
|
+
format: 'astrale.cloudflare.deployment',
|
|
27
|
+
version: 1,
|
|
28
|
+
release,
|
|
29
|
+
runtime: {
|
|
30
|
+
compatibilityDate: stable(input.runtime.compatibilityDate, 'compatibility date'),
|
|
31
|
+
compatibilityFlags,
|
|
32
|
+
},
|
|
33
|
+
bindings: { vars, services, requiredSecrets },
|
|
34
|
+
...(assets === undefined ? {} : { assets }),
|
|
35
|
+
})}\n`);
|
|
36
|
+
}
|
|
37
|
+
/** Identify one immutable Cloudflare implementation without changing SDK or Publication identity. */
|
|
38
|
+
export function workerDeployment(input) {
|
|
39
|
+
let hexadecimal = '';
|
|
40
|
+
for (const byte of sha256(workerDeploymentMaterial(input))) {
|
|
41
|
+
hexadecimal += byte.toString(16).padStart(2, '0');
|
|
42
|
+
}
|
|
43
|
+
return `sha256:${hexadecimal}`;
|
|
44
|
+
}
|
|
45
|
+
/** Admit a serialized provider deployment identity at a Cloudflare boundary. */
|
|
46
|
+
export function acceptWorkerDeployment(input) {
|
|
47
|
+
if (typeof input !== 'string' || !DEPLOYMENT.test(input)) {
|
|
48
|
+
throw new TypeError('Cloudflare Worker deployment identity is invalid.');
|
|
49
|
+
}
|
|
50
|
+
return input;
|
|
51
|
+
}
|
|
52
|
+
function executable(input) {
|
|
53
|
+
const entrypoint = stablePath(input.entrypoint, 'Worker release entrypoint');
|
|
54
|
+
const modules = input.modules
|
|
55
|
+
.map((module) => ({
|
|
56
|
+
path: stablePath(module.path, 'Worker release module path'),
|
|
57
|
+
kind: module.kind,
|
|
58
|
+
digest: content(module.content),
|
|
59
|
+
}))
|
|
60
|
+
.sort((left, right) => compare(left.path, right.path));
|
|
61
|
+
unique(modules.map((module) => module.path), 'Worker release module path');
|
|
62
|
+
if (!modules.some((module) => module.path === entrypoint && module.kind === 'esm')) {
|
|
63
|
+
throw new TypeError('Worker release entrypoint must be an ES module in its module set.');
|
|
64
|
+
}
|
|
65
|
+
return { entrypoint, modules };
|
|
66
|
+
}
|
|
67
|
+
function canonicalAssets(input) {
|
|
68
|
+
const files = input.files
|
|
69
|
+
.map((file) => ({
|
|
70
|
+
path: stableAssetPath(file.path),
|
|
71
|
+
digest: content(file.content),
|
|
72
|
+
...(file.contentType === undefined
|
|
73
|
+
? {}
|
|
74
|
+
: { contentType: stable(file.contentType, 'Worker asset content type') }),
|
|
75
|
+
}))
|
|
76
|
+
.sort((left, right) => compare(left.path, right.path));
|
|
77
|
+
unique(files.map((file) => file.path), 'Worker asset path');
|
|
78
|
+
if (!['none', '404-page', 'single-page-application'].includes(input.notFound))
|
|
79
|
+
invalid();
|
|
80
|
+
if (input.htmlHandling !== undefined && input.htmlHandling !== 'none')
|
|
81
|
+
invalid();
|
|
82
|
+
return {
|
|
83
|
+
files,
|
|
84
|
+
notFound: input.notFound,
|
|
85
|
+
runWorkerFirst: input.runWorkerFirst,
|
|
86
|
+
htmlHandling: input.htmlHandling ?? 'none',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function uniqueStrings(input, label) {
|
|
90
|
+
const values = input.map((value) => stable(value, label)).sort(compare);
|
|
91
|
+
unique(values, label);
|
|
92
|
+
return values;
|
|
93
|
+
}
|
|
94
|
+
function unique(values, label) {
|
|
95
|
+
if (new Set(values).size !== values.length) {
|
|
96
|
+
throw new TypeError(`${label} must be unique.`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function content(value) {
|
|
100
|
+
if (!(value instanceof Uint8Array))
|
|
101
|
+
invalid();
|
|
102
|
+
let hexadecimal = '';
|
|
103
|
+
for (const byte of sha256(value))
|
|
104
|
+
hexadecimal += byte.toString(16).padStart(2, '0');
|
|
105
|
+
return `sha256:${hexadecimal}`;
|
|
106
|
+
}
|
|
107
|
+
function stablePath(value, label) {
|
|
108
|
+
const admitted = stable(value, label);
|
|
109
|
+
if (admitted.startsWith('/') ||
|
|
110
|
+
admitted.includes('\\') ||
|
|
111
|
+
admitted.split('/').some((part) => part.length === 0 || part === '.' || part === '..')) {
|
|
112
|
+
invalid();
|
|
113
|
+
}
|
|
114
|
+
return admitted;
|
|
115
|
+
}
|
|
116
|
+
function stableAssetPath(value) {
|
|
117
|
+
const admitted = stable(value, 'Worker asset path');
|
|
118
|
+
if (!admitted.startsWith('/') ||
|
|
119
|
+
admitted.includes('\\') ||
|
|
120
|
+
admitted.includes('?') ||
|
|
121
|
+
admitted.includes('#') ||
|
|
122
|
+
admitted
|
|
123
|
+
.slice(1)
|
|
124
|
+
.split('/')
|
|
125
|
+
.some((part) => part.length === 0 || part === '.' || part === '..')) {
|
|
126
|
+
invalid();
|
|
127
|
+
}
|
|
128
|
+
return admitted;
|
|
129
|
+
}
|
|
130
|
+
function stable(value, label) {
|
|
131
|
+
if (typeof value !== 'string' || value.length === 0 || value.trim() !== value) {
|
|
132
|
+
throw new TypeError(`${label} must be stable non-empty text.`);
|
|
133
|
+
}
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
function compare(left, right) {
|
|
137
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
138
|
+
}
|
|
139
|
+
function invalid() {
|
|
140
|
+
throw new TypeError('Cloudflare Worker deployment material is invalid.');
|
|
141
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { acceptWorkerDeployment } from './deployment.js';
|
|
2
|
+
const DEPLOYMENT = /^sha256:([0-9a-f]{64})$/u;
|
|
3
|
+
/** Provider deployment identities select immutable Workers inside the private namespace. */
|
|
4
|
+
export function stagedWorkerName(deployment) {
|
|
5
|
+
const digest = DEPLOYMENT.exec(acceptWorkerDeployment(deployment))?.[1];
|
|
6
|
+
if (digest === undefined)
|
|
7
|
+
throw new TypeError('Cloudflare Worker deployment identity is invalid.');
|
|
8
|
+
const encoded = BigInt(`0x${digest}`).toString(36).padStart(50, '0');
|
|
9
|
+
return `r-${encoded}`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { JsonWebKey } from '@astrale-os/sdk/auth';
|
|
2
|
+
import type { BuildMaterial, GeneratedBuildMaterial } from '@astrale-os/sdk/deployment/build/material';
|
|
3
|
+
import type { ExchangeOptions, ExecutionContext } from '@astrale-os/sdk/execution';
|
|
4
|
+
import type { Runtime } from '@astrale-os/sdk/runtime';
|
|
5
|
+
export interface Fetcher {
|
|
6
|
+
fetch(request: Request): Response | Promise<Response>;
|
|
7
|
+
}
|
|
8
|
+
export interface CloudflareAdapterBindings {
|
|
9
|
+
readonly ASTRALE_SIGNING_IDENTITY?: string;
|
|
10
|
+
readonly ASTRALE_VERSION_METADATA?: {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
};
|
|
13
|
+
readonly WORKER_URL?: string;
|
|
14
|
+
readonly IDENTITY_ISS?: string;
|
|
15
|
+
readonly ASSETS?: Fetcher;
|
|
16
|
+
readonly SELF?: Fetcher;
|
|
17
|
+
readonly DISPATCHER?: {
|
|
18
|
+
get(name: string): Fetcher;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface CloudflareWorkerConfig<RuntimeValue extends Runtime, Bindings extends CloudflareAdapterBindings, Environment, Material = BuildMaterial> {
|
|
22
|
+
/** Generated frontend evidence available without restoring the execution Build. */
|
|
23
|
+
readonly frontend?: BuildMaterial['frontend'];
|
|
24
|
+
/** Generated browser-file identity used only for deployment propagation checks. */
|
|
25
|
+
readonly frontendRevision?: string;
|
|
26
|
+
/** Load the exact Runtime and Build once, after the isolate has accepted a request. */
|
|
27
|
+
readonly load: () => CloudflareWorkerSource<RuntimeValue, Material> | Promise<CloudflareWorkerSource<RuntimeValue, Material>>;
|
|
28
|
+
readonly privateKey: JsonWebKey | ((bindings: Bindings) => JsonWebKey);
|
|
29
|
+
readonly resolveEnvironment?: (bindings: Bindings) => Environment;
|
|
30
|
+
readonly resolveUrl?: (bindings: Bindings, requestOrigin: string) => string;
|
|
31
|
+
readonly providerAssignedWorker?: string;
|
|
32
|
+
readonly selfBinding?: (bindings: Bindings) => Fetcher | null | undefined;
|
|
33
|
+
readonly routeSubrequest?: (url: URL, bindings: Bindings) => Fetcher | null | undefined;
|
|
34
|
+
readonly invocationTimeoutMs?: number;
|
|
35
|
+
readonly maximumRequestBytes?: number;
|
|
36
|
+
readonly tokenExchange?: ExchangeOptions | false;
|
|
37
|
+
}
|
|
38
|
+
export interface CloudflareWorkerSource<RuntimeValue extends Runtime, Material = BuildMaterial> {
|
|
39
|
+
readonly runtime: RuntimeValue;
|
|
40
|
+
readonly material: Material;
|
|
41
|
+
}
|
|
42
|
+
export interface CloudflareWorker<Bindings> {
|
|
43
|
+
fetch(request: Request, environment: Bindings, executionContext?: ExecutionContext): Response | Promise<Response>;
|
|
44
|
+
}
|
|
45
|
+
/** Compose one Service implementation behind its provider-owned stable address. */
|
|
46
|
+
export declare function cloudflareWorkerEntry<Bindings extends CloudflareAdapterBindings, Environment = Bindings>(): <RuntimeValue extends Runtime>(config: CloudflareWorkerConfig<RuntimeValue, Bindings, Environment, BuildMaterial>) => CloudflareWorker<Bindings>;
|
|
47
|
+
/** Compose generated execution code whose exact Build material carries build-owner evidence. */
|
|
48
|
+
export declare function generatedCloudflareWorkerEntry<Bindings extends CloudflareAdapterBindings, Environment = Bindings>(): <RuntimeValue extends Runtime>(config: CloudflareWorkerConfig<RuntimeValue, Bindings, Environment, GeneratedBuildMaterial>) => CloudflareWorker<Bindings>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { issuer } from '@astrale-os/sdk/auth';
|
|
2
|
+
import { restoreBuild, restoreGeneratedBuild } from '@astrale-os/sdk/deployment/build/material';
|
|
3
|
+
import { addressing, assemble } from '@astrale-os/sdk/deployment/release/runtime';
|
|
4
|
+
import { createIdentity, serve } from '@astrale-os/sdk/execution';
|
|
5
|
+
import { dispatchCloudflareRequest, prepareCloudflareRequest } from './fetch.js';
|
|
6
|
+
import { frontendAsset } from './frontend.js';
|
|
7
|
+
/** Compose one Service implementation behind its provider-owned stable address. */
|
|
8
|
+
export function cloudflareWorkerEntry() {
|
|
9
|
+
return createCloudflareWorkerEntry(restoreBuild);
|
|
10
|
+
}
|
|
11
|
+
/** Compose generated execution code whose exact Build material carries build-owner evidence. */
|
|
12
|
+
export function generatedCloudflareWorkerEntry() {
|
|
13
|
+
return createCloudflareWorkerEntry(restoreGeneratedBuild);
|
|
14
|
+
}
|
|
15
|
+
function createCloudflareWorkerEntry(restore) {
|
|
16
|
+
return function (config) {
|
|
17
|
+
let currentIssuer;
|
|
18
|
+
let realized;
|
|
19
|
+
const realize = () => {
|
|
20
|
+
if (realized !== undefined)
|
|
21
|
+
return realized;
|
|
22
|
+
realized = Promise.resolve()
|
|
23
|
+
.then(config.load)
|
|
24
|
+
.then((source) => {
|
|
25
|
+
const build = restore(source.material, source.runtime);
|
|
26
|
+
const application = serve({
|
|
27
|
+
runtime: source.runtime,
|
|
28
|
+
load(environment) {
|
|
29
|
+
if (currentIssuer !== environment.issuer) {
|
|
30
|
+
throw new TypeError('Cloudflare Worker request origin differs from its current Release.');
|
|
31
|
+
}
|
|
32
|
+
return assemble(build, addressing(environment.issuer));
|
|
33
|
+
},
|
|
34
|
+
initialize: (environment) => config.resolveEnvironment === undefined
|
|
35
|
+
? environment.bindings
|
|
36
|
+
: config.resolveEnvironment(environment.bindings),
|
|
37
|
+
identity(environment) {
|
|
38
|
+
return createIdentity({
|
|
39
|
+
issuer: issuer.accept(environment.issuer),
|
|
40
|
+
subject: build.schema.compiled.root.origin,
|
|
41
|
+
privateKey: typeof config.privateKey === 'function'
|
|
42
|
+
? config.privateKey(environment.bindings)
|
|
43
|
+
: config.privateKey,
|
|
44
|
+
fetch: routedFetch(application, environment, config),
|
|
45
|
+
...(new URL(environment.issuer).protocol === 'http:'
|
|
46
|
+
? { allowInsecureHttp: true }
|
|
47
|
+
: {}),
|
|
48
|
+
...(config.tokenExchange === undefined
|
|
49
|
+
? {}
|
|
50
|
+
: { tokenExchange: config.tokenExchange }),
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
server: {
|
|
54
|
+
health: { probe: { check: () => true } },
|
|
55
|
+
limits: {
|
|
56
|
+
maximumRequestBytes: config.maximumRequestBytes ?? 1024 * 1024,
|
|
57
|
+
maximumPublicationBytes: 1024 * 1024,
|
|
58
|
+
maximumBundleBytes: 8 * 1024 * 1024,
|
|
59
|
+
maximumDeliveryBytes: 8 * 1024 * 1024,
|
|
60
|
+
invocationTimeoutMs: config.invocationTimeoutMs ?? 30_000,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
return Object.freeze({ build, application });
|
|
65
|
+
});
|
|
66
|
+
return realized;
|
|
67
|
+
};
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
async fetch(request, bindings, context) {
|
|
70
|
+
const url = new URL(request.url);
|
|
71
|
+
const issuer = canonicalServingUrl(bindings.WORKER_URL ??
|
|
72
|
+
bindings.IDENTITY_ISS ??
|
|
73
|
+
config.resolveUrl?.(bindings, requestOrigin(url, request)) ??
|
|
74
|
+
requestOrigin(url, request));
|
|
75
|
+
if (config.providerAssignedWorker !== undefined &&
|
|
76
|
+
bindings.WORKER_URL === undefined &&
|
|
77
|
+
bindings.IDENTITY_ISS === undefined &&
|
|
78
|
+
!matchesWorkersDevClaim(issuer, config.providerAssignedWorker)) {
|
|
79
|
+
return new Response('Request origin differs from provider-assigned Addressing.', {
|
|
80
|
+
status: 421,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (currentIssuer !== undefined && currentIssuer !== issuer) {
|
|
84
|
+
return new Response('Request origin differs from the current Release.', { status: 421 });
|
|
85
|
+
}
|
|
86
|
+
currentIssuer = issuer;
|
|
87
|
+
if (config.frontend !== undefined) {
|
|
88
|
+
const frontend = await frontendAsset(config.frontend, bindings.ASSETS, url, request, config.frontendRevision);
|
|
89
|
+
if (frontend !== undefined)
|
|
90
|
+
return withProviderVersion(frontend, bindings);
|
|
91
|
+
}
|
|
92
|
+
const { application, build } = await realize();
|
|
93
|
+
if (config.frontend === undefined) {
|
|
94
|
+
const frontend = await frontendAsset(build.frontend, bindings.ASSETS, url, request, config.frontendRevision);
|
|
95
|
+
if (frontend !== undefined)
|
|
96
|
+
return withProviderVersion(frontend, bindings);
|
|
97
|
+
}
|
|
98
|
+
const response = await application.fetch(request, Object.freeze({ bindings, issuer }), context);
|
|
99
|
+
return withProviderVersion(response, bindings);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function withProviderVersion(response, bindings) {
|
|
105
|
+
if (bindings.ASTRALE_VERSION_METADATA === undefined)
|
|
106
|
+
return response;
|
|
107
|
+
const versioned = new Response(response.body, response);
|
|
108
|
+
versioned.headers.set('X-Astrale-Worker-Version', bindings.ASTRALE_VERSION_METADATA.id);
|
|
109
|
+
return versioned;
|
|
110
|
+
}
|
|
111
|
+
function routedFetch(application, environment, config) {
|
|
112
|
+
return async (input, init) => {
|
|
113
|
+
const { request, rejectRedirect } = prepareCloudflareRequest(input, init);
|
|
114
|
+
const destination = new URL(request.url);
|
|
115
|
+
if (destination.origin === environment.issuer) {
|
|
116
|
+
const self = config.selfBinding?.(environment.bindings);
|
|
117
|
+
return dispatchCloudflareRequest(request, rejectRedirect, (selected) => self === null || self === undefined
|
|
118
|
+
? application.fetch(selected, environment)
|
|
119
|
+
: self.fetch(selected));
|
|
120
|
+
}
|
|
121
|
+
const route = config.routeSubrequest?.(destination, environment.bindings);
|
|
122
|
+
return dispatchCloudflareRequest(request, rejectRedirect, (selected) => route === null || route === undefined ? fetch(selected) : route.fetch(selected));
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function requestOrigin(url, request) {
|
|
126
|
+
if (url.protocol !== 'http:')
|
|
127
|
+
return url.origin;
|
|
128
|
+
const forwarded = request.headers.get('x-forwarded-proto')?.split(',')[0]?.trim().toLowerCase();
|
|
129
|
+
return forwarded === 'https' ? `https://${url.host}` : url.origin;
|
|
130
|
+
}
|
|
131
|
+
function canonicalServingUrl(input) {
|
|
132
|
+
let url;
|
|
133
|
+
try {
|
|
134
|
+
url = new URL(input);
|
|
135
|
+
}
|
|
136
|
+
catch (cause) {
|
|
137
|
+
throw new TypeError('Cloudflare Worker serving URL is invalid.', { cause });
|
|
138
|
+
}
|
|
139
|
+
if ((url.protocol !== 'https:' && url.protocol !== 'http:') ||
|
|
140
|
+
url.username !== '' ||
|
|
141
|
+
url.password !== '' ||
|
|
142
|
+
url.pathname !== '/' ||
|
|
143
|
+
url.search !== '' ||
|
|
144
|
+
url.hash !== '') {
|
|
145
|
+
throw new TypeError('Cloudflare Worker serving URL must be one HTTP(S) origin.');
|
|
146
|
+
}
|
|
147
|
+
return url.origin;
|
|
148
|
+
}
|
|
149
|
+
function matchesWorkersDevClaim(issuer, expectedWorker) {
|
|
150
|
+
const url = new URL(issuer);
|
|
151
|
+
const labels = url.hostname.split('.');
|
|
152
|
+
return (url.protocol === 'https:' &&
|
|
153
|
+
labels.length >= 4 &&
|
|
154
|
+
labels[0] === expectedWorker &&
|
|
155
|
+
labels.at(-2) === 'workers' &&
|
|
156
|
+
labels.at(-1) === 'dev');
|
|
157
|
+
}
|
package/dist/worker/fetch.d.ts
CHANGED
|
@@ -9,4 +9,3 @@ export declare function prepareCloudflareRequest(input: Parameters<typeof fetch>
|
|
|
9
9
|
export declare function dispatchCloudflareRequest(request: Request, rejectRedirect: boolean, dispatch: RequestDispatcher): Promise<Response>;
|
|
10
10
|
/** Restore the requested URL omitted by Cloudflare service-binding Responses. */
|
|
11
11
|
export declare function adaptCloudflareResponse(request: Request, response: Response): Response;
|
|
12
|
-
//# sourceMappingURL=fetch.d.ts.map
|
package/dist/worker/fetch.js
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BuildMaterial } from '@astrale-os/sdk/deployment/build/material';
|
|
2
|
+
import type { Fetcher } from './entry.js';
|
|
3
|
+
/** Serve public frontend files without realizing the Application's execution Runtime. */
|
|
4
|
+
export declare function frontendAsset(frontend: BuildMaterial['frontend'], assets: Fetcher | undefined, url: URL, request: Request, revision?: string): Promise<Response | undefined>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Serve public frontend files without realizing the Application's execution Runtime. */
|
|
2
|
+
export async function frontendAsset(frontend, assets, url, request, revision) {
|
|
3
|
+
if (frontend === undefined || frontend.source.kind === 'external')
|
|
4
|
+
return undefined;
|
|
5
|
+
if (reserved(url.pathname) || (request.method !== 'GET' && request.method !== 'HEAD')) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const assetPath = url.pathname.startsWith('/assets/');
|
|
9
|
+
const route = assetPath
|
|
10
|
+
? undefined
|
|
11
|
+
: frontend.routes
|
|
12
|
+
.filter((candidate) => candidate.path === url.pathname ||
|
|
13
|
+
(frontend.source.kind === 'vite' &&
|
|
14
|
+
frontend.source.spa &&
|
|
15
|
+
(candidate.path === '/' || url.pathname.startsWith(`${candidate.path}/`))))
|
|
16
|
+
.sort((left, right) => right.path.length - left.path.length)[0];
|
|
17
|
+
if (assets === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
if (route === undefined) {
|
|
20
|
+
const response = await assets.fetch(request);
|
|
21
|
+
return assetPath || response.status !== 404 ? publicAsset(response, revision) : undefined;
|
|
22
|
+
}
|
|
23
|
+
if (route.path !== url.pathname) {
|
|
24
|
+
const response = await assets.fetch(request);
|
|
25
|
+
if (response.status !== 404)
|
|
26
|
+
return publicAsset(response, revision);
|
|
27
|
+
}
|
|
28
|
+
return publicAsset(await assets.fetch(new Request(new URL(`/${route.document}${url.search}`, url.origin), request)), revision);
|
|
29
|
+
}
|
|
30
|
+
function publicAsset(response, revision) {
|
|
31
|
+
// Plain Views have an opaque sandbox origin. Their modules, CSS and fonts still need
|
|
32
|
+
// public reads; this neither enables credentials nor changes execution endpoint CORS.
|
|
33
|
+
const readable = new Response(response.body, response);
|
|
34
|
+
if (!readable.headers.has('Access-Control-Allow-Origin'))
|
|
35
|
+
readable.headers.set('Access-Control-Allow-Origin', '*');
|
|
36
|
+
if (revision !== undefined)
|
|
37
|
+
readable.headers.set('X-Astrale-Frontend', revision);
|
|
38
|
+
// Documents select hashed assets. Do not retain stale documents or transient asset misses.
|
|
39
|
+
if (!response.ok || response.headers.get('Content-Type')?.split(';')[0] === 'text/html') {
|
|
40
|
+
readable.headers.set('Cache-Control', 'no-store');
|
|
41
|
+
}
|
|
42
|
+
return readable;
|
|
43
|
+
}
|
|
44
|
+
function reserved(path) {
|
|
45
|
+
return ['/releases', '/install', '/health', '/meta', '/.well-known'].some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
|
|
46
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { JsonWebKey } from '@astrale-os/sdk/auth';
|
|
2
|
+
/** Decode the secret representation at the Worker binding boundary. */
|
|
3
|
+
export declare function decodeSigningIdentity(input: string): JsonWebKey;
|
|
4
|
+
/** Remove adapter-owned signing material before Runtime initialization. */
|
|
5
|
+
export declare function runtimeBindings<Bindings extends {
|
|
6
|
+
readonly ASTRALE_SIGNING_IDENTITY: string;
|
|
7
|
+
}>(bindings: Bindings): Omit<Bindings, 'ASTRALE_SIGNING_IDENTITY'>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Decode the secret representation at the Worker binding boundary. */
|
|
2
|
+
export function decodeSigningIdentity(input) {
|
|
3
|
+
if (typeof input !== 'string' || input.length === 0)
|
|
4
|
+
invalid();
|
|
5
|
+
let decoded;
|
|
6
|
+
try {
|
|
7
|
+
decoded = JSON.parse(input);
|
|
8
|
+
}
|
|
9
|
+
catch (cause) {
|
|
10
|
+
throw new TypeError('Cloudflare signing identity secret is invalid JSON.', { cause });
|
|
11
|
+
}
|
|
12
|
+
if (decoded === null || typeof decoded !== 'object' || Array.isArray(decoded))
|
|
13
|
+
invalid();
|
|
14
|
+
return decoded;
|
|
15
|
+
}
|
|
16
|
+
/** Remove adapter-owned signing material before Runtime initialization. */
|
|
17
|
+
export function runtimeBindings(bindings) {
|
|
18
|
+
const { ASTRALE_SIGNING_IDENTITY: _identity, ...runtime } = bindings;
|
|
19
|
+
return runtime;
|
|
20
|
+
}
|
|
21
|
+
function invalid() {
|
|
22
|
+
throw new TypeError('Cloudflare signing identity secret is invalid.');
|
|
23
|
+
}
|