@astrale-os/adapter-cloudflare 0.5.0-beta.164 → 0.5.0-beta.166
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/README.md +64 -5
- package/dist/adapter.d.ts +5 -4
- package/dist/adapter.js +2 -0
- package/dist/build/artifact.js +134 -149
- package/dist/build/bundle/admit.d.ts +2 -0
- package/dist/build/bundle/admit.js +37 -0
- package/dist/build/bundle/compiled-wasm-loader.d.ts +8 -0
- package/dist/build/bundle/compiled-wasm-loader.js +21 -0
- package/dist/build/bundler.d.ts +21 -0
- package/dist/build/bundler.js +96 -0
- package/dist/build/codegen/wrangler.d.ts +4 -3
- package/dist/build/codegen/wrangler.js +35 -1
- package/dist/build/configuration/invocation-timeout.js +2 -2
- package/dist/build/configuration/legacy/direct.d.ts +15 -0
- package/dist/build/configuration/legacy/direct.js +19 -0
- package/dist/build/configuration/request-limit.js +1 -1
- package/dist/build/configuration/settings.d.ts +15 -0
- package/dist/build/configuration/settings.js +71 -0
- package/dist/build/configuration.d.ts +1 -0
- package/dist/build/configuration.js +1 -0
- package/dist/build/frontend/readiness.d.ts +2 -2
- package/dist/build/index.d.ts +3 -1
- package/dist/build/index.js +3 -1
- package/dist/build/worker/codegen/entry.d.ts +0 -1
- package/dist/build/worker/codegen/entry.js +0 -3
- package/dist/build/worker/codegen/service.d.ts +4 -11
- package/dist/build/worker/codegen/service.js +23 -28
- package/dist/build/worker/execution.prepare.d.ts +11 -11
- package/dist/build/worker/execution.prepare.js +69 -74
- package/dist/build/worker/modules.d.ts +8 -2
- package/dist/build/worker/modules.js +8 -2
- package/dist/build/worker/specifier.d.ts +2 -0
- package/dist/build/worker/specifier.js +5 -0
- package/dist/build/worker/upload.d.ts +18 -0
- package/dist/build/worker/upload.js +40 -0
- package/dist/deploy/deploy.d.ts +2 -2
- package/dist/deploy/deploy.js +18 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/params.d.ts +19 -3
- package/dist/release/build.d.ts +35 -0
- package/dist/release/build.js +44 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/worker/durable.d.ts +11 -0
- package/dist/worker/durable.js +24 -0
- package/dist/worker/entry.d.ts +12 -7
- package/dist/worker/entry.js +79 -56
- package/dist/worker/front.d.ts +23 -1
- package/dist/worker/front.js +3 -14
- package/dist/worker/frontend.d.ts +1 -1
- package/dist/worker/frontend.js +2 -2
- package/dist/worker/index.d.ts +3 -0
- package/dist/worker/index.js +3 -0
- package/dist/worker/legacy/direct.d.ts +37 -0
- package/dist/worker/legacy/direct.js +58 -0
- package/dist/worker/restate.d.ts +6 -0
- package/dist/worker/restate.js +6 -0
- package/dist/worker/settings.d.ts +48 -0
- package/dist/worker/settings.js +161 -0
- package/dist/wrangler/bundle.js +0 -1
- package/package.json +9 -4
- package/template/astrale.config.ts +2 -2
package/dist/worker/front.d.ts
CHANGED
|
@@ -2,13 +2,36 @@ import type { BuildMaterial } from '@astrale-os/sdk/deployment/build/material';
|
|
|
2
2
|
export interface Fetcher {
|
|
3
3
|
fetch(request: Request): Response | Promise<Response>;
|
|
4
4
|
}
|
|
5
|
+
/** Bindings the adapter owns; a deployment's host binds them beside the author's own. */
|
|
5
6
|
export interface CloudflareAdapterBindings {
|
|
6
7
|
readonly ASTRALE_SIGNING_IDENTITY?: string;
|
|
7
8
|
readonly ASTRALE_VERSION_METADATA?: {
|
|
8
9
|
readonly id: string;
|
|
9
10
|
};
|
|
11
|
+
/** Serving origin of this deployment. */
|
|
10
12
|
readonly WORKER_URL?: string;
|
|
13
|
+
/** Build digest an immutable-deployment host recomputed from the uploaded bytes. */
|
|
14
|
+
readonly ASTRALE_BUILD_DIGEST?: string;
|
|
15
|
+
/** Execution settings of this deployment, as canonical JSON (see `deploymentSettings`). */
|
|
16
|
+
readonly ASTRALE_SETTINGS?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Stable issuer of a direct deployment served behind another origin; it is also the serving
|
|
19
|
+
* origin when no `WORKER_URL` is bound.
|
|
20
|
+
*
|
|
21
|
+
* @deprecated Legacy direct mode only. Replacement: an immutable deployment's `WORKER_URL`,
|
|
22
|
+
* which is its issuer (namespace mode). Deleted with direct mode, once the Shell, Services,
|
|
23
|
+
* Issues, domains and ui configurations deploy in namespace mode and no installation pins a
|
|
24
|
+
* direct Worker.
|
|
25
|
+
*/
|
|
11
26
|
readonly IDENTITY_ISS?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Worker name whose workers.dev address a provider-assigned direct deployment must serve.
|
|
29
|
+
*
|
|
30
|
+
* @deprecated Legacy direct mode only. Replacement: an immutable deployment's `WORKER_URL`,
|
|
31
|
+
* bound by its host. Deleted with direct mode, once the Shell, Services, Issues, domains and ui
|
|
32
|
+
* configurations deploy in namespace mode and no installation pins a direct Worker.
|
|
33
|
+
*/
|
|
34
|
+
readonly ASTRALE_PROVIDER_ASSIGNED_WORKER?: string;
|
|
12
35
|
readonly ASSETS?: Fetcher;
|
|
13
36
|
readonly SELF?: Fetcher;
|
|
14
37
|
}
|
|
@@ -20,7 +43,6 @@ export interface CloudflareFrontDoorConfig<Bindings extends CloudflareAdapterBin
|
|
|
20
43
|
/** Served frontend paths the bundler content-addressed; absent means none may be retained. */
|
|
21
44
|
readonly frontendAddressed?: readonly string[];
|
|
22
45
|
readonly resolveUrl?: (bindings: Bindings, requestOrigin: string) => string;
|
|
23
|
-
readonly providerAssignedWorker?: string;
|
|
24
46
|
}
|
|
25
47
|
export type CloudflareFrontDoorAdmission =
|
|
26
48
|
/** The request is not for this isolate's serving origin. */
|
package/dist/worker/front.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { frontendAsset } from './frontend.js';
|
|
2
|
+
import { directServingOrigin, refusesDirectOrigin } from './legacy/direct.js';
|
|
2
3
|
/** Admit requests to one serving origin and answer public frontend files, per isolate. */
|
|
3
4
|
export function cloudflareFrontDoor(config) {
|
|
4
5
|
let currentPublicUrl;
|
|
@@ -6,13 +7,10 @@ export function cloudflareFrontDoor(config) {
|
|
|
6
7
|
async admit(request, bindings) {
|
|
7
8
|
const url = new URL(request.url);
|
|
8
9
|
const publicUrl = canonicalServingUrl(bindings.WORKER_URL ??
|
|
9
|
-
bindings
|
|
10
|
+
directServingOrigin(bindings) ??
|
|
10
11
|
config.resolveUrl?.(bindings, requestOrigin(url, request)) ??
|
|
11
12
|
requestOrigin(url, request));
|
|
12
|
-
if (
|
|
13
|
-
bindings.WORKER_URL === undefined &&
|
|
14
|
-
bindings.IDENTITY_ISS === undefined &&
|
|
15
|
-
!matchesWorkersDevClaim(publicUrl, config.providerAssignedWorker)) {
|
|
13
|
+
if (refusesDirectOrigin(bindings, publicUrl)) {
|
|
16
14
|
return refused('Request origin differs from provider-assigned Addressing.');
|
|
17
15
|
}
|
|
18
16
|
if (currentPublicUrl !== undefined && currentPublicUrl !== publicUrl) {
|
|
@@ -64,12 +62,3 @@ function canonicalServingUrl(input) {
|
|
|
64
62
|
}
|
|
65
63
|
return url.origin;
|
|
66
64
|
}
|
|
67
|
-
function matchesWorkersDevClaim(issuer, expectedWorker) {
|
|
68
|
-
const url = new URL(issuer);
|
|
69
|
-
const labels = url.hostname.split('.');
|
|
70
|
-
return (url.protocol === 'https:' &&
|
|
71
|
-
labels.length >= 4 &&
|
|
72
|
-
labels[0] === expectedWorker &&
|
|
73
|
-
labels.at(-2) === 'workers' &&
|
|
74
|
-
labels.at(-1) === 'dev');
|
|
75
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { BuildMaterial } from '@astrale-os/sdk/deployment/build/material';
|
|
2
2
|
import type { Fetcher } from './front.js';
|
|
3
|
-
/** Serve public frontend files without realizing the
|
|
3
|
+
/** Serve public frontend files without realizing the Domain's execution Runtime. */
|
|
4
4
|
export declare function frontendAsset(frontend: BuildMaterial['frontend'], assets: Fetcher | undefined, url: URL, request: Request, revision?: string, addressed?: readonly string[]): Promise<Response | undefined>;
|
package/dist/worker/frontend.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Serve public frontend files without realizing the
|
|
1
|
+
/** Serve public frontend files without realizing the Domain's execution Runtime. */
|
|
2
2
|
export async function frontendAsset(frontend, assets, url, request, revision, addressed) {
|
|
3
3
|
if (frontend === undefined || frontend.source.kind === 'external')
|
|
4
4
|
return undefined;
|
|
@@ -79,5 +79,5 @@ function publicAsset(response, revision, addressed) {
|
|
|
79
79
|
return readable;
|
|
80
80
|
}
|
|
81
81
|
function reserved(path) {
|
|
82
|
-
return ['/releases', '/install', '/health', '/meta', '/.well-known'].some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
|
|
82
|
+
return ['/releases', '/install', '/health', '/meta', '/.well-known', '/invoke'].some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
|
|
83
83
|
}
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export * from './entry.js';
|
|
2
2
|
export { decodeSigningIdentity, runtimeBindings } from './identity.js';
|
|
3
|
+
export { decodeWorkerSettings, deploymentSettings, encodeWorkerSettings, SETTINGS_BINDING, type CloudflareWorkerSettings, type WorkerSettings, } from './settings.js';
|
|
4
|
+
export { withDirectIssuer } from './legacy/direct.js';
|
|
5
|
+
export { RESTATE_IDENTITY_KEYS_BINDING, restateServing, type DurableBindings } from './durable.js';
|
package/dist/worker/index.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export * from './entry.js';
|
|
2
2
|
export { decodeSigningIdentity, runtimeBindings } from './identity.js';
|
|
3
|
+
export { decodeWorkerSettings, deploymentSettings, encodeWorkerSettings, SETTINGS_BINDING, } from './settings.js';
|
|
4
|
+
export { withDirectIssuer } from './legacy/direct.js';
|
|
5
|
+
export { RESTATE_IDENTITY_KEYS_BINDING, restateServing } from './durable.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CloudflareAdapterBindings } from '../front.js';
|
|
2
|
+
import type { CloudflareWorkerSettings } from '../settings.js';
|
|
3
|
+
/**
|
|
4
|
+
* Legacy direct mode: one stable Worker on a custom route or its provider-assigned workers.dev
|
|
5
|
+
* address. Its deployment binds `IDENTITY_ISS` (a stable issuer served behind another origin) or
|
|
6
|
+
* `ASTRALE_PROVIDER_ASSIGNED_WORKER` (the workers.dev name its origin must claim).
|
|
7
|
+
*
|
|
8
|
+
* Replacement: an immutable deployment, whose host binds `WORKER_URL` to the deployment URL, which
|
|
9
|
+
* is also its issuer (Cloudflare namespace mode).
|
|
10
|
+
*
|
|
11
|
+
* Deletion: with direct mode, once the Shell, Services, Issues, domains and ui configurations
|
|
12
|
+
* deploy in namespace mode and no installation pins a direct Worker.
|
|
13
|
+
*
|
|
14
|
+
* Like the startup front door, this module reaches no runtime SDK module.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Sign as the stable issuer a direct deployment bound, on top of its bound execution settings.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Legacy direct mode only. Replacement: the immutable deployment's `WORKER_URL`, which
|
|
20
|
+
* is its issuer. Deleted with direct mode (see the module header).
|
|
21
|
+
*/
|
|
22
|
+
export declare function withDirectIssuer<Bindings extends CloudflareAdapterBindings>(settings: (bindings: Bindings) => CloudflareWorkerSettings<Bindings>): (bindings: Bindings) => CloudflareWorkerSettings<Bindings>;
|
|
23
|
+
/**
|
|
24
|
+
* The stable issuer, when a deployment bound one without its serving origin.
|
|
25
|
+
*
|
|
26
|
+
* @deprecated Legacy direct mode only. Replacement: `WORKER_URL`. Deleted with direct mode (see
|
|
27
|
+
* the module header).
|
|
28
|
+
*/
|
|
29
|
+
export declare function directServingOrigin(bindings: CloudflareAdapterBindings): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Whether a provider-assigned direct deployment refuses this serving origin: it serves only the
|
|
32
|
+
* workers.dev address of the Worker name it was bound.
|
|
33
|
+
*
|
|
34
|
+
* @deprecated Legacy direct mode only. Replacement: `WORKER_URL`, bound by the host to the
|
|
35
|
+
* deployment URL. Deleted with direct mode (see the module header).
|
|
36
|
+
*/
|
|
37
|
+
export declare function refusesDirectOrigin(bindings: CloudflareAdapterBindings, publicUrl: string): boolean;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy direct mode: one stable Worker on a custom route or its provider-assigned workers.dev
|
|
3
|
+
* address. Its deployment binds `IDENTITY_ISS` (a stable issuer served behind another origin) or
|
|
4
|
+
* `ASTRALE_PROVIDER_ASSIGNED_WORKER` (the workers.dev name its origin must claim).
|
|
5
|
+
*
|
|
6
|
+
* Replacement: an immutable deployment, whose host binds `WORKER_URL` to the deployment URL, which
|
|
7
|
+
* is also its issuer (Cloudflare namespace mode).
|
|
8
|
+
*
|
|
9
|
+
* Deletion: with direct mode, once the Shell, Services, Issues, domains and ui configurations
|
|
10
|
+
* deploy in namespace mode and no installation pins a direct Worker.
|
|
11
|
+
*
|
|
12
|
+
* Like the startup front door, this module reaches no runtime SDK module.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Sign as the stable issuer a direct deployment bound, on top of its bound execution settings.
|
|
16
|
+
*
|
|
17
|
+
* @deprecated Legacy direct mode only. Replacement: the immutable deployment's `WORKER_URL`, which
|
|
18
|
+
* is its issuer. Deleted with direct mode (see the module header).
|
|
19
|
+
*/
|
|
20
|
+
export function withDirectIssuer(settings) {
|
|
21
|
+
return (bindings) => {
|
|
22
|
+
const bound = settings(bindings);
|
|
23
|
+
return bindings.IDENTITY_ISS === undefined
|
|
24
|
+
? bound
|
|
25
|
+
: Object.freeze({ ...bound, identityIssuer: bindings.IDENTITY_ISS });
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The stable issuer, when a deployment bound one without its serving origin.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated Legacy direct mode only. Replacement: `WORKER_URL`. Deleted with direct mode (see
|
|
32
|
+
* the module header).
|
|
33
|
+
*/
|
|
34
|
+
export function directServingOrigin(bindings) {
|
|
35
|
+
return bindings.IDENTITY_ISS;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Whether a provider-assigned direct deployment refuses this serving origin: it serves only the
|
|
39
|
+
* workers.dev address of the Worker name it was bound.
|
|
40
|
+
*
|
|
41
|
+
* @deprecated Legacy direct mode only. Replacement: `WORKER_URL`, bound by the host to the
|
|
42
|
+
* deployment URL. Deleted with direct mode (see the module header).
|
|
43
|
+
*/
|
|
44
|
+
export function refusesDirectOrigin(bindings, publicUrl) {
|
|
45
|
+
return (bindings.ASTRALE_PROVIDER_ASSIGNED_WORKER !== undefined &&
|
|
46
|
+
bindings.WORKER_URL === undefined &&
|
|
47
|
+
bindings.IDENTITY_ISS === undefined &&
|
|
48
|
+
!matchesWorkersDevClaim(publicUrl, bindings.ASTRALE_PROVIDER_ASSIGNED_WORKER));
|
|
49
|
+
}
|
|
50
|
+
function matchesWorkersDevClaim(issuer, expectedWorker) {
|
|
51
|
+
const url = new URL(issuer);
|
|
52
|
+
const labels = url.hostname.split('.');
|
|
53
|
+
return (url.protocol === 'https:' &&
|
|
54
|
+
labels.length >= 4 &&
|
|
55
|
+
labels[0] === expectedWorker &&
|
|
56
|
+
labels.at(-2) === 'workers' &&
|
|
57
|
+
labels.at(-1) === 'dev');
|
|
58
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workflow engine's Workers build. Generated code imports it only for a Domain that declares
|
|
3
|
+
* durable callables and retains it as a separate module, imported on the first engine request.
|
|
4
|
+
* Ordinary requests never evaluate this module or instantiate its WebAssembly core.
|
|
5
|
+
*/
|
|
6
|
+
export * from '@restatedev/restate-sdk-cloudflare-workers/fetch';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The workflow engine's Workers build. Generated code imports it only for a Domain that declares
|
|
3
|
+
* durable callables and retains it as a separate module, imported on the first engine request.
|
|
4
|
+
* Ordinary requests never evaluate this module or instantiate its WebAssembly core.
|
|
5
|
+
*/
|
|
6
|
+
export * from '@restatedev/restate-sdk-cloudflare-workers/fetch';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ExchangeOptions } from '@astrale-os/sdk/execution';
|
|
2
|
+
import type { DurableWorkerOptions } from '../params.js';
|
|
3
|
+
import type { CloudflareAdapterBindings, Fetcher } from './front.js';
|
|
4
|
+
/** Plain binding that carries one deployment's execution settings as canonical JSON. */
|
|
5
|
+
export declare const SETTINGS_BINDING = "ASTRALE_SETTINGS";
|
|
6
|
+
export declare const DEFAULT_MAXIMUM_REQUEST_BYTES: number;
|
|
7
|
+
export declare const MAXIMUM_REQUEST_BYTES: number;
|
|
8
|
+
export declare const DEFAULT_INVOCATION_TIMEOUT_MS = 30000;
|
|
9
|
+
export declare const MAXIMUM_INVOCATION_TIMEOUT_MS = 2147483647;
|
|
10
|
+
/** The execution settings one deployment binds as `ASTRALE_SETTINGS`, defaults resolved. */
|
|
11
|
+
export interface WorkerSettings {
|
|
12
|
+
/** Durable policy bound by this deployment; semantic bounds are admitted lazily by SDK serving. */
|
|
13
|
+
readonly durableOptions?: DurableWorkerOptions;
|
|
14
|
+
readonly maximumRequestBytes: number;
|
|
15
|
+
readonly invocationTimeoutMs: number;
|
|
16
|
+
readonly tokenExchange: false | {
|
|
17
|
+
readonly maximumLifetimeSeconds: number;
|
|
18
|
+
};
|
|
19
|
+
readonly router: false | {
|
|
20
|
+
/**
|
|
21
|
+
* Service binding that reaches the instance router. Hosts that deploy immutable Workers
|
|
22
|
+
* bind `ROUTER`; legacy direct mode binds its configured `router.binding`.
|
|
23
|
+
*/
|
|
24
|
+
readonly binding: string;
|
|
25
|
+
readonly hostSuffix: string;
|
|
26
|
+
readonly minLabels: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** What one isolate executes under, given by a hand-composed Worker or read from its bindings. */
|
|
30
|
+
export interface CloudflareWorkerSettings<Bindings> {
|
|
31
|
+
readonly durableOptions?: DurableWorkerOptions;
|
|
32
|
+
readonly identityIssuer?: string;
|
|
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
|
+
/**
|
|
39
|
+
* Read the execution settings a deployment bound as `ASTRALE_SETTINGS`. The serving origin, and
|
|
40
|
+
* so the issuer, is the deployment's `WORKER_URL`, which the front door reads.
|
|
41
|
+
*/
|
|
42
|
+
export declare function deploymentSettings<Bindings extends CloudflareAdapterBindings>(bindings: Bindings): CloudflareWorkerSettings<Bindings>;
|
|
43
|
+
/** Encode settings as the canonical JSON (RFC 8785) text bound as `ASTRALE_SETTINGS`. */
|
|
44
|
+
export declare function encodeWorkerSettings(settings: WorkerSettings): string;
|
|
45
|
+
/** Admit the `ASTRALE_SETTINGS` text one deployment bound; absent or malformed fails closed. */
|
|
46
|
+
export declare function decodeWorkerSettings(input: unknown): WorkerSettings;
|
|
47
|
+
/** Capture the plain binding shape; SDK serving owns retention/retry/deadline semantics. */
|
|
48
|
+
export declare function captureDurableOptions(input: unknown): DurableWorkerOptions;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// A generated Worker carries no environment value in its bytes: the host that deploys it binds
|
|
2
|
+
// the execution settings of that deployment, so one build serves every environment unchanged.
|
|
3
|
+
/** Plain binding that carries one deployment's execution settings as canonical JSON. */
|
|
4
|
+
export const SETTINGS_BINDING = 'ASTRALE_SETTINGS';
|
|
5
|
+
export const DEFAULT_MAXIMUM_REQUEST_BYTES = 1024 * 1024;
|
|
6
|
+
export const MAXIMUM_REQUEST_BYTES = 16 * 1024 * 1024;
|
|
7
|
+
export const DEFAULT_INVOCATION_TIMEOUT_MS = 30_000;
|
|
8
|
+
export const MAXIMUM_INVOCATION_TIMEOUT_MS = 2_147_483_647;
|
|
9
|
+
const BINDING_NAME = /^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/u;
|
|
10
|
+
/**
|
|
11
|
+
* Read the execution settings a deployment bound as `ASTRALE_SETTINGS`. The serving origin, and
|
|
12
|
+
* so the issuer, is the deployment's `WORKER_URL`, which the front door reads.
|
|
13
|
+
*/
|
|
14
|
+
export function deploymentSettings(bindings) {
|
|
15
|
+
const settings = decodeWorkerSettings(bindings.ASTRALE_SETTINGS);
|
|
16
|
+
return Object.freeze({
|
|
17
|
+
...(settings.durableOptions === undefined ? {} : { durableOptions: settings.durableOptions }),
|
|
18
|
+
maximumRequestBytes: settings.maximumRequestBytes,
|
|
19
|
+
invocationTimeoutMs: settings.invocationTimeoutMs,
|
|
20
|
+
tokenExchange: settings.tokenExchange === false
|
|
21
|
+
? false
|
|
22
|
+
: Object.freeze({ maximumTtlSeconds: settings.tokenExchange.maximumLifetimeSeconds }),
|
|
23
|
+
...(settings.router === false
|
|
24
|
+
? {}
|
|
25
|
+
: { routeSubrequest: instanceRoute(settings.router) }),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Encode settings as the canonical JSON (RFC 8785) text bound as `ASTRALE_SETTINGS`. */
|
|
29
|
+
export function encodeWorkerSettings(settings) {
|
|
30
|
+
const admitted = acceptWorkerSettings(settings);
|
|
31
|
+
return JSON.stringify({
|
|
32
|
+
...(admitted.durableOptions === undefined ? {} : { durableOptions: admitted.durableOptions }),
|
|
33
|
+
invocationTimeoutMs: admitted.invocationTimeoutMs,
|
|
34
|
+
maximumRequestBytes: admitted.maximumRequestBytes,
|
|
35
|
+
router: admitted.router === false
|
|
36
|
+
? false
|
|
37
|
+
: {
|
|
38
|
+
binding: admitted.router.binding,
|
|
39
|
+
hostSuffix: admitted.router.hostSuffix,
|
|
40
|
+
minLabels: admitted.router.minLabels,
|
|
41
|
+
},
|
|
42
|
+
tokenExchange: admitted.tokenExchange === false
|
|
43
|
+
? false
|
|
44
|
+
: { maximumLifetimeSeconds: admitted.tokenExchange.maximumLifetimeSeconds },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Admit the `ASTRALE_SETTINGS` text one deployment bound; absent or malformed fails closed. */
|
|
48
|
+
export function decodeWorkerSettings(input) {
|
|
49
|
+
if (input === undefined) {
|
|
50
|
+
throw new TypeError(`Cloudflare Worker requires the ${SETTINGS_BINDING} binding.`);
|
|
51
|
+
}
|
|
52
|
+
if (typeof input !== 'string')
|
|
53
|
+
invalid();
|
|
54
|
+
let value;
|
|
55
|
+
try {
|
|
56
|
+
value = JSON.parse(input);
|
|
57
|
+
}
|
|
58
|
+
catch (cause) {
|
|
59
|
+
throw new TypeError(`Cloudflare Worker ${SETTINGS_BINDING} binding is invalid JSON.`, {
|
|
60
|
+
cause,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return acceptWorkerSettings(value);
|
|
64
|
+
}
|
|
65
|
+
function acceptWorkerSettings(input) {
|
|
66
|
+
const value = exact(input, ['invocationTimeoutMs', 'maximumRequestBytes', 'router', 'tokenExchange'], ['durableOptions']);
|
|
67
|
+
const durableOptions = value.durableOptions;
|
|
68
|
+
const maximumRequestBytes = integer(value.maximumRequestBytes, 1, MAXIMUM_REQUEST_BYTES);
|
|
69
|
+
const invocationTimeoutMs = integer(value.invocationTimeoutMs, 1, MAXIMUM_INVOCATION_TIMEOUT_MS);
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
...(durableOptions === undefined
|
|
72
|
+
? {}
|
|
73
|
+
: { durableOptions: captureDurableOptions(durableOptions) }),
|
|
74
|
+
maximumRequestBytes,
|
|
75
|
+
invocationTimeoutMs,
|
|
76
|
+
tokenExchange: value.tokenExchange === false ? false : tokenExchange(value.tokenExchange),
|
|
77
|
+
router: value.router === false ? false : router(value.router),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function tokenExchange(input) {
|
|
81
|
+
const value = exact(input, ['maximumLifetimeSeconds']);
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
maximumLifetimeSeconds: integer(value.maximumLifetimeSeconds, 1, Number.MAX_SAFE_INTEGER),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function router(input) {
|
|
87
|
+
const value = exact(input, ['binding', 'hostSuffix', 'minLabels']);
|
|
88
|
+
if (typeof value.binding !== 'string' || !BINDING_NAME.test(value.binding))
|
|
89
|
+
invalid();
|
|
90
|
+
if (typeof value.hostSuffix !== 'string')
|
|
91
|
+
invalid();
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
binding: value.binding,
|
|
94
|
+
hostSuffix: value.hostSuffix,
|
|
95
|
+
minLabels: integer(value.minLabels, 0, Number.MAX_SAFE_INTEGER),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/** Send instance hosts under the router suffix through its binding; everything else is public. */
|
|
99
|
+
function instanceRoute(router) {
|
|
100
|
+
return (url, bindings) => {
|
|
101
|
+
// Services own their public ingress, including retirement and private-route isolation.
|
|
102
|
+
if (url.hostname.split('.')[1] === 'svc')
|
|
103
|
+
return null;
|
|
104
|
+
const fetcher = Reflect.get(bindings, router.binding);
|
|
105
|
+
if (fetcher &&
|
|
106
|
+
url.hostname.endsWith(router.hostSuffix) &&
|
|
107
|
+
url.hostname.split('.').length >= router.minLabels) {
|
|
108
|
+
return fetcher;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function exact(input, keys, optional = []) {
|
|
114
|
+
if (input === null ||
|
|
115
|
+
typeof input !== 'object' ||
|
|
116
|
+
Array.isArray(input) ||
|
|
117
|
+
Reflect.ownKeys(input).some((key) => typeof key !== 'string' || (!keys.includes(key) && !optional.includes(key))) ||
|
|
118
|
+
keys.some((key) => !Object.hasOwn(input, key))) {
|
|
119
|
+
invalid();
|
|
120
|
+
}
|
|
121
|
+
return input;
|
|
122
|
+
}
|
|
123
|
+
/** Capture the plain binding shape; SDK serving owns retention/retry/deadline semantics. */
|
|
124
|
+
export function captureDurableOptions(input) {
|
|
125
|
+
const value = exact(input, [], ['retentionMs', 'retry', 'stepTimeoutMs']);
|
|
126
|
+
const retentionMs = optionalNumber(value.retentionMs);
|
|
127
|
+
const retry = value.retry;
|
|
128
|
+
const stepTimeoutMs = optionalNumber(value.stepTimeoutMs);
|
|
129
|
+
return Object.freeze({
|
|
130
|
+
...(retentionMs === undefined ? {} : { retentionMs }),
|
|
131
|
+
...(retry === undefined ? {} : { retry: captureRetry(retry) }),
|
|
132
|
+
...(stepTimeoutMs === undefined ? {} : { stepTimeoutMs }),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function captureRetry(input) {
|
|
136
|
+
const value = exact(input, [], ['initialIntervalMs', 'maxAttempts', 'maxIntervalMs']);
|
|
137
|
+
const initialIntervalMs = optionalNumber(value.initialIntervalMs);
|
|
138
|
+
const maxAttempts = optionalNumber(value.maxAttempts);
|
|
139
|
+
const maxIntervalMs = optionalNumber(value.maxIntervalMs);
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
...(initialIntervalMs === undefined ? {} : { initialIntervalMs }),
|
|
142
|
+
...(maxAttempts === undefined ? {} : { maxAttempts }),
|
|
143
|
+
...(maxIntervalMs === undefined ? {} : { maxIntervalMs }),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function optionalNumber(input) {
|
|
147
|
+
if (input === undefined)
|
|
148
|
+
return undefined;
|
|
149
|
+
if (typeof input !== 'number' || !Number.isFinite(input))
|
|
150
|
+
invalid();
|
|
151
|
+
return input;
|
|
152
|
+
}
|
|
153
|
+
function integer(input, minimum, maximum) {
|
|
154
|
+
if (!Number.isSafeInteger(input) || input < minimum || input > maximum) {
|
|
155
|
+
invalid();
|
|
156
|
+
}
|
|
157
|
+
return input;
|
|
158
|
+
}
|
|
159
|
+
function invalid() {
|
|
160
|
+
throw new TypeError(`Cloudflare Worker ${SETTINGS_BINDING} binding is invalid.`);
|
|
161
|
+
}
|
package/dist/wrangler/bundle.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/adapter-cloudflare",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
4
|
-
"description": "Deploy an Astrale
|
|
3
|
+
"version": "0.5.0-beta.166",
|
|
4
|
+
"description": "Deploy an Astrale Domain through Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
7
7
|
"astrale",
|
|
@@ -51,14 +51,19 @@
|
|
|
51
51
|
"types": "./dist/release/index.d.ts",
|
|
52
52
|
"import": "./dist/release/index.js"
|
|
53
53
|
},
|
|
54
|
-
"./package.json": "./package.json"
|
|
54
|
+
"./package.json": "./package.json",
|
|
55
|
+
"./worker/restate": {
|
|
56
|
+
"types": "./dist/worker/restate.d.ts",
|
|
57
|
+
"import": "./dist/worker/restate.js"
|
|
58
|
+
}
|
|
55
59
|
},
|
|
56
60
|
"publishConfig": {
|
|
57
61
|
"registry": "https://registry.npmjs.org/"
|
|
58
62
|
},
|
|
59
63
|
"dependencies": {
|
|
60
|
-
"@astrale-os/sdk": "0.6.0-beta.
|
|
64
|
+
"@astrale-os/sdk": "0.6.0-beta.11",
|
|
61
65
|
"@noble/hashes": "2.3.0",
|
|
66
|
+
"@restatedev/restate-sdk-cloudflare-workers": "1.17.0",
|
|
62
67
|
"hono": "^4.6.20",
|
|
63
68
|
"jose": "^6.1.3",
|
|
64
69
|
"wrangler": "4.123.0"
|
|
@@ -9,10 +9,10 @@ import { cloudflare } from '@astrale-os/adapter-cloudflare'
|
|
|
9
9
|
import { defineProject } from '@astrale-os/sdk/project'
|
|
10
10
|
import { dataset, tests } from '@astrale-os/sdk/testing'
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { domain } from './domain.js'
|
|
13
13
|
|
|
14
14
|
export default defineProject({
|
|
15
|
-
|
|
15
|
+
domain,
|
|
16
16
|
|
|
17
17
|
environments: {
|
|
18
18
|
development: {
|