@astrale-os/adapter-cloudflare 0.5.0-beta.24 → 0.5.0-beta.26
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/build/artifact.js +44 -6
- package/dist/build/codegen/execution.d.ts +3 -1
- package/dist/build/codegen/execution.js +33 -5
- package/dist/build/codegen/wrangler.d.ts +5 -0
- package/dist/build/codegen/wrangler.js +13 -0
- package/dist/build/wrangler-cli.d.ts +2 -2
- package/dist/build/wrangler-cli.js +2 -2
- package/dist/worker/entry.d.ts +6 -2
- package/dist/worker/entry.js +40 -36
- package/package.json +2 -2
package/dist/build/artifact.js
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join, relative, resolve } from 'node:path';
|
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
6
|
import { SIGNING_IDENTITY_BINDING } from '../identity/binding.js';
|
|
7
7
|
import { releaseNamespace, releaseWorkerName } from '../release/index.js';
|
|
8
|
-
import { generateExecutionEntry } from './codegen/execution.js';
|
|
8
|
+
import { generateExecutionEntry, generateExecutionService } from './codegen/execution.js';
|
|
9
9
|
import { generateGatewayEntry } from './codegen/gateway.js';
|
|
10
10
|
import { generateWranglerConfig } from './codegen/wrangler.js';
|
|
11
11
|
import { deploymentAddressing, resolveRouter, workerName } from './configuration.js';
|
|
@@ -13,6 +13,9 @@ import { frontendFiles } from './frontend-v1.js';
|
|
|
13
13
|
import { qualifyWorkerBundle } from './qualification.js';
|
|
14
14
|
import { runWranglerBundle } from './wrangler-cli.js';
|
|
15
15
|
const encoder = new TextEncoder();
|
|
16
|
+
const SERVICE_MODULE = 'service.mjs';
|
|
17
|
+
const RELEASE_ENTRY = 'bundle/index.mjs';
|
|
18
|
+
const RELEASE_SERVICE = `bundle/${SERVICE_MODULE}`;
|
|
16
19
|
/** Prepare one revision Service and its stateless gateway without provider mutation. */
|
|
17
20
|
export async function artifact(params, context) {
|
|
18
21
|
const stateDirectory = join(context.projectDir, '.astrale');
|
|
@@ -26,7 +29,7 @@ export async function artifact(params, context) {
|
|
|
26
29
|
const namespace = releaseNamespace(name);
|
|
27
30
|
const target = releaseWorkerName(revision);
|
|
28
31
|
const configuredIssuer = deploymentAddressing(params);
|
|
29
|
-
const
|
|
32
|
+
const serviceSource = generateExecutionService({
|
|
30
33
|
origin: context.build.schema.compiled.root.origin,
|
|
31
34
|
runtimeSpecifier,
|
|
32
35
|
material: material(context.build),
|
|
@@ -41,8 +44,40 @@ export async function artifact(params, context) {
|
|
|
41
44
|
},
|
|
42
45
|
}),
|
|
43
46
|
});
|
|
47
|
+
const serviceSourcePath = join(directory, 'service.gen.ts');
|
|
48
|
+
await writeFile(serviceSourcePath, serviceSource);
|
|
49
|
+
const serviceConfigPath = join(directory, 'wrangler.service.prepare.jsonc');
|
|
50
|
+
await writeFile(serviceConfigPath, generateWranglerConfig({
|
|
51
|
+
workerName: name,
|
|
52
|
+
main: './service.gen.ts',
|
|
53
|
+
vars: {
|
|
54
|
+
...params.vars,
|
|
55
|
+
...(configuredIssuer === undefined ? {} : { WORKER_URL: configuredIssuer }),
|
|
56
|
+
},
|
|
57
|
+
secretBindings: [SIGNING_IDENTITY_BINDING],
|
|
58
|
+
...(router === undefined
|
|
59
|
+
? {}
|
|
60
|
+
: { router: { binding: router.binding, service: router.service } }),
|
|
61
|
+
...(params.wrangler === undefined ? {} : { wrangler: params.wrangler }),
|
|
62
|
+
selfBinding: false,
|
|
63
|
+
}));
|
|
64
|
+
const serviceOutput = join(directory, 'dist-service');
|
|
65
|
+
await rm(serviceOutput, { recursive: true, force: true });
|
|
66
|
+
const emittedService = await runWranglerBundle({
|
|
67
|
+
projectDir: context.projectDir,
|
|
68
|
+
configPath: serviceConfigPath,
|
|
69
|
+
outDir: serviceOutput,
|
|
70
|
+
});
|
|
71
|
+
await qualifyWorkerBundle({
|
|
72
|
+
metafilePath: emittedService.metafilePath,
|
|
73
|
+
inputRoot: dirname(serviceConfigPath),
|
|
74
|
+
});
|
|
75
|
+
await admitBundle(emittedService.bundlePath);
|
|
76
|
+
const serviceBundle = await readFile(emittedService.bundlePath);
|
|
77
|
+
await mkdir(dirname(join(directory, RELEASE_SERVICE)), { recursive: true });
|
|
78
|
+
await writeFile(join(directory, RELEASE_SERVICE), serviceBundle);
|
|
44
79
|
const sourcePath = join(directory, 'worker.gen.ts');
|
|
45
|
-
await writeFile(sourcePath,
|
|
80
|
+
await writeFile(sourcePath, generateExecutionEntry(`./${RELEASE_SERVICE}`));
|
|
46
81
|
const configPath = join(directory, 'wrangler.prepare.jsonc');
|
|
47
82
|
await writeFile(configPath, generateWranglerConfig({
|
|
48
83
|
workerName: name,
|
|
@@ -52,6 +87,7 @@ export async function artifact(params, context) {
|
|
|
52
87
|
...(configuredIssuer === undefined ? {} : { WORKER_URL: configuredIssuer }),
|
|
53
88
|
},
|
|
54
89
|
secretBindings: [SIGNING_IDENTITY_BINDING],
|
|
90
|
+
modules: { baseDir: '.', globs: [RELEASE_SERVICE] },
|
|
55
91
|
...(router === undefined
|
|
56
92
|
? {}
|
|
57
93
|
: { router: { binding: router.binding, service: router.service } }),
|
|
@@ -100,12 +136,13 @@ export async function artifact(params, context) {
|
|
|
100
136
|
const gatewayBundle = await readFile(gateway.bundlePath);
|
|
101
137
|
const releaseConfig = generateWranglerConfig({
|
|
102
138
|
workerName: target,
|
|
103
|
-
main:
|
|
139
|
+
main: `./${RELEASE_ENTRY}`,
|
|
104
140
|
vars: {
|
|
105
141
|
...params.vars,
|
|
106
142
|
...(configuredIssuer === undefined ? {} : { WORKER_URL: configuredIssuer }),
|
|
107
143
|
},
|
|
108
144
|
secretBindings: [SIGNING_IDENTITY_BINDING],
|
|
145
|
+
modules: { baseDir: '.', globs: [RELEASE_SERVICE] },
|
|
109
146
|
...(context.build.frontend?.source.kind === 'vite'
|
|
110
147
|
? {
|
|
111
148
|
frontend: {
|
|
@@ -131,7 +168,8 @@ export async function artifact(params, context) {
|
|
|
131
168
|
const files = [
|
|
132
169
|
{ path: 'wrangler.release.jsonc', content: encoder.encode(releaseConfig) },
|
|
133
170
|
{ path: 'wrangler.gateway.jsonc', content: encoder.encode(gatewayConfig) },
|
|
134
|
-
{ path:
|
|
171
|
+
{ path: RELEASE_ENTRY, content: new Uint8Array(bundle) },
|
|
172
|
+
{ path: RELEASE_SERVICE, content: new Uint8Array(serviceBundle) },
|
|
135
173
|
{ path: 'gateway/index.mjs', content: new Uint8Array(gatewayBundle) },
|
|
136
174
|
...frontend.map((file) => ({
|
|
137
175
|
path: `frontend/${file.path}`,
|
|
@@ -139,7 +177,7 @@ export async function artifact(params, context) {
|
|
|
139
177
|
})),
|
|
140
178
|
];
|
|
141
179
|
return Object.freeze({
|
|
142
|
-
entrypoint:
|
|
180
|
+
entrypoint: RELEASE_ENTRY,
|
|
143
181
|
files: Object.freeze(files),
|
|
144
182
|
addressing: configuredIssuer === undefined
|
|
145
183
|
? Object.freeze({ kind: 'provider-assigned', claim: name })
|
|
@@ -10,4 +10,6 @@ export interface ExecutionCodegenOptions {
|
|
|
10
10
|
readonly minLabels: number;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
export declare function
|
|
13
|
+
export declare function generateExecutionService(options: ExecutionCodegenOptions): string;
|
|
14
|
+
/** Generate the isolate-startup entry that realizes the heavy Service on first request. */
|
|
15
|
+
export declare function generateExecutionEntry(serviceSpecifier: string): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function generateExecutionService(options) {
|
|
2
2
|
const router = options.router;
|
|
3
3
|
const routerPredicate = router === undefined
|
|
4
4
|
? ''
|
|
@@ -22,18 +22,18 @@ import type { BuildMaterial } from '@astrale-os/sdk/deployment/build'
|
|
|
22
22
|
import type { CloudflareAdapterBindings } from '@astrale-os/adapter-cloudflare/worker'
|
|
23
23
|
|
|
24
24
|
import { cloudflareWorkerEntry } from '@astrale-os/adapter-cloudflare/worker'
|
|
25
|
-
import runtime from ${JSON.stringify(options.runtimeSpecifier)}
|
|
26
25
|
import { decodeSigningIdentity, runtimeBindings } from '@astrale-os/adapter-cloudflare/worker'
|
|
27
26
|
|
|
28
27
|
type WorkerEnv = CloudflareEnv & CloudflareAdapterBindings & {
|
|
29
28
|
readonly ASTRALE_SIGNING_IDENTITY: string
|
|
30
29
|
}
|
|
31
30
|
type RuntimeEnv = Omit<WorkerEnv, 'ASTRALE_SIGNING_IDENTITY'>
|
|
32
|
-
const MATERIAL = ${JSON.stringify(options.material)} as const satisfies BuildMaterial
|
|
33
31
|
${routerPredicate}
|
|
34
32
|
export default cloudflareWorkerEntry<WorkerEnv, RuntimeEnv>()({
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
load: async () => ({
|
|
34
|
+
runtime: (await import(${JSON.stringify(options.runtimeSpecifier)})).default,
|
|
35
|
+
material: ${JSON.stringify(options.material)} as const satisfies BuildMaterial,
|
|
36
|
+
}),
|
|
37
37
|
privateKey: (env) => decodeSigningIdentity(env.ASTRALE_SIGNING_IDENTITY),
|
|
38
38
|
resolveEnvironment: runtimeBindings,
|
|
39
39
|
resolveUrl: (env, requestOrigin) => env.WORKER_URL ?? env.IDENTITY_ISS ?? requestOrigin,
|
|
@@ -42,3 +42,31 @@ export default cloudflareWorkerEntry<WorkerEnv, RuntimeEnv>()({
|
|
|
42
42
|
})
|
|
43
43
|
`;
|
|
44
44
|
}
|
|
45
|
+
/** Generate the isolate-startup entry that realizes the heavy Service on first request. */
|
|
46
|
+
export function generateExecutionEntry(serviceSpecifier) {
|
|
47
|
+
return `// AUTO-GENERATED by @astrale-os/adapter-cloudflare — do not edit.
|
|
48
|
+
import type { CloudflareWorker } from '@astrale-os/adapter-cloudflare/worker'
|
|
49
|
+
|
|
50
|
+
const SERVICE_SPECIFIER = ${JSON.stringify(serviceSpecifier)}
|
|
51
|
+
let servicePromise: Promise<CloudflareWorker<CloudflareEnv>> | undefined
|
|
52
|
+
|
|
53
|
+
export default {
|
|
54
|
+
async fetch(request: Request, environment: CloudflareEnv, context: ExecutionContext) {
|
|
55
|
+
return (await service()).fetch(request, environment, context)
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function service(): Promise<CloudflareWorker<CloudflareEnv>> {
|
|
60
|
+
return (servicePromise ??= import(SERVICE_SPECIFIER).then((loaded: unknown) => {
|
|
61
|
+
if (loaded === null || typeof loaded !== 'object') invalid()
|
|
62
|
+
const worker = Reflect.get(loaded, 'default') as unknown
|
|
63
|
+
if (worker === null || typeof worker !== 'object' || typeof Reflect.get(worker, 'fetch') !== 'function') invalid()
|
|
64
|
+
return worker as CloudflareWorker<CloudflareEnv>
|
|
65
|
+
}))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function invalid(): never {
|
|
69
|
+
throw new TypeError('Cloudflare execution Service module is invalid.')
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
@@ -27,6 +27,11 @@ export interface WranglerCodegenOptions {
|
|
|
27
27
|
vars?: Record<string, string>;
|
|
28
28
|
/** Secret binding names required by generated Worker code. */
|
|
29
29
|
secretBindings?: readonly string[];
|
|
30
|
+
/** JavaScript modules retained outside the startup entry and loaded on demand. */
|
|
31
|
+
modules?: {
|
|
32
|
+
readonly baseDir: string;
|
|
33
|
+
readonly globs: readonly string[];
|
|
34
|
+
};
|
|
30
35
|
/** Add the SELF service binding (autobinding). */
|
|
31
36
|
selfBinding: boolean;
|
|
32
37
|
/** Bind the stable gateway to its private revision namespace. */
|
|
@@ -60,6 +60,17 @@ export function generateWranglerConfig(opts) {
|
|
|
60
60
|
if (opts.secretBindings && opts.secretBindings.length > 0) {
|
|
61
61
|
config.secrets = { required: [...opts.secretBindings] };
|
|
62
62
|
}
|
|
63
|
+
if (opts.modules !== undefined) {
|
|
64
|
+
config.find_additional_modules = true;
|
|
65
|
+
config.base_dir = opts.modules.baseDir;
|
|
66
|
+
config.rules = [
|
|
67
|
+
{
|
|
68
|
+
type: 'ESModule',
|
|
69
|
+
globs: [...opts.modules.globs],
|
|
70
|
+
fallthrough: true,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
}
|
|
63
74
|
if (opts.releases !== undefined) {
|
|
64
75
|
config.dispatch_namespaces = [opts.releases];
|
|
65
76
|
}
|
|
@@ -75,6 +86,8 @@ const ADAPTER_OWNED_KEYS = [
|
|
|
75
86
|
'compatibility_date',
|
|
76
87
|
'version_metadata',
|
|
77
88
|
'secrets',
|
|
89
|
+
'find_additional_modules',
|
|
90
|
+
'base_dir',
|
|
78
91
|
];
|
|
79
92
|
/**
|
|
80
93
|
* Deep-merge the dev's raw wrangler overlay over the generated config, after
|
|
@@ -84,9 +84,9 @@ export interface WranglerDeploymentStatus {
|
|
|
84
84
|
/** Admit Wrangler's current-deployment JSON before it becomes provider evidence. */
|
|
85
85
|
export declare function admitWranglerDeploymentStatus(output: string): WranglerDeploymentStatus;
|
|
86
86
|
/**
|
|
87
|
-
* Build the
|
|
87
|
+
* Build the Worker entry module WITHOUT deploying — `wrangler deploy
|
|
88
88
|
* --dry-run --outdir` (no Cloudflare auth required). Returns the path of the
|
|
89
|
-
* bundled .js module (the managed adapter publishes its bytes).
|
|
89
|
+
* bundled entry .js module (the managed adapter publishes its bytes).
|
|
90
90
|
*/
|
|
91
91
|
export declare function runWranglerBundle(args: {
|
|
92
92
|
projectDir: string;
|
|
@@ -400,9 +400,9 @@ async function stopChild(child) {
|
|
|
400
400
|
});
|
|
401
401
|
}
|
|
402
402
|
/**
|
|
403
|
-
* Build the
|
|
403
|
+
* Build the Worker entry module WITHOUT deploying — `wrangler deploy
|
|
404
404
|
* --dry-run --outdir` (no Cloudflare auth required). Returns the path of the
|
|
405
|
-
* bundled .js module (the managed adapter publishes its bytes).
|
|
405
|
+
* bundled entry .js module (the managed adapter publishes its bytes).
|
|
406
406
|
*/
|
|
407
407
|
export async function runWranglerBundle(args) {
|
|
408
408
|
await runWranglerTypes(args);
|
package/dist/worker/entry.d.ts
CHANGED
|
@@ -17,8 +17,8 @@ export interface CloudflareAdapterBindings {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
export interface CloudflareWorkerConfig<RuntimeValue extends Runtime, Bindings extends CloudflareAdapterBindings, Environment> {
|
|
20
|
-
|
|
21
|
-
readonly
|
|
20
|
+
/** Load the exact Runtime and Build once, after the isolate has accepted a request. */
|
|
21
|
+
readonly load: () => CloudflareWorkerSource<RuntimeValue> | Promise<CloudflareWorkerSource<RuntimeValue>>;
|
|
22
22
|
readonly privateKey: JsonWebKey | ((bindings: Bindings) => JsonWebKey);
|
|
23
23
|
readonly resolveEnvironment?: (bindings: Bindings) => Environment;
|
|
24
24
|
readonly resolveUrl?: (bindings: Bindings, requestOrigin: string) => string;
|
|
@@ -27,6 +27,10 @@ export interface CloudflareWorkerConfig<RuntimeValue extends Runtime, Bindings e
|
|
|
27
27
|
readonly routeSubrequest?: (url: URL, bindings: Bindings) => Fetcher | null | undefined;
|
|
28
28
|
readonly invocationTimeoutMs?: number;
|
|
29
29
|
}
|
|
30
|
+
export interface CloudflareWorkerSource<RuntimeValue extends Runtime> {
|
|
31
|
+
readonly runtime: RuntimeValue;
|
|
32
|
+
readonly material: BuildMaterial;
|
|
33
|
+
}
|
|
30
34
|
export interface CloudflareWorker<Bindings> {
|
|
31
35
|
fetch(request: Request, environment: Bindings, executionContext?: ExecutionContext): Response | Promise<Response>;
|
|
32
36
|
}
|
package/dist/worker/entry.js
CHANGED
|
@@ -11,43 +11,47 @@ export function cloudflareWorkerEntry() {
|
|
|
11
11
|
const realize = () => {
|
|
12
12
|
if (realized !== undefined)
|
|
13
13
|
return realized;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
14
|
+
realized = Promise.resolve()
|
|
15
|
+
.then(config.load)
|
|
16
|
+
.then((source) => {
|
|
17
|
+
const build = restoreBuild(source.material, source.runtime);
|
|
18
|
+
const application = serve({
|
|
19
|
+
runtime: source.runtime,
|
|
20
|
+
load(environment) {
|
|
21
|
+
if (currentIssuer !== environment.issuer) {
|
|
22
|
+
throw new TypeError('Cloudflare Worker request origin differs from its current Release.');
|
|
23
|
+
}
|
|
24
|
+
return assemble(build, addressing(environment.issuer));
|
|
25
|
+
},
|
|
26
|
+
initialize: (environment) => config.resolveEnvironment === undefined
|
|
27
|
+
? environment.bindings
|
|
28
|
+
: config.resolveEnvironment(environment.bindings),
|
|
29
|
+
identity(environment) {
|
|
30
|
+
return createIdentity({
|
|
31
|
+
issuer: issuer.accept(environment.issuer),
|
|
32
|
+
subject: build.schema.compiled.root.origin,
|
|
33
|
+
privateKey: typeof config.privateKey === 'function'
|
|
34
|
+
? config.privateKey(environment.bindings)
|
|
35
|
+
: config.privateKey,
|
|
36
|
+
fetch: routedFetch(application, environment, config),
|
|
37
|
+
...(new URL(environment.issuer).protocol === 'http:'
|
|
38
|
+
? { allowInsecureHttp: true }
|
|
39
|
+
: {}),
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
server: {
|
|
43
|
+
health: { probe: { check: () => true } },
|
|
44
|
+
limits: {
|
|
45
|
+
maximumRequestBytes: 1024 * 1024,
|
|
46
|
+
maximumPublicationBytes: 1024 * 1024,
|
|
47
|
+
maximumBundleBytes: 8 * 1024 * 1024,
|
|
48
|
+
maximumDeliveryBytes: 8 * 1024 * 1024,
|
|
49
|
+
invocationTimeoutMs: config.invocationTimeoutMs ?? 30_000,
|
|
50
|
+
},
|
|
47
51
|
},
|
|
48
|
-
}
|
|
52
|
+
});
|
|
53
|
+
return Object.freeze({ build, application });
|
|
49
54
|
});
|
|
50
|
-
realized = Object.freeze({ build, application });
|
|
51
55
|
return realized;
|
|
52
56
|
};
|
|
53
57
|
return Object.freeze({
|
|
@@ -69,7 +73,7 @@ export function cloudflareWorkerEntry() {
|
|
|
69
73
|
return new Response('Request origin differs from the current Release.', { status: 421 });
|
|
70
74
|
}
|
|
71
75
|
currentIssuer = issuer;
|
|
72
|
-
const { application, build } = realize();
|
|
76
|
+
const { application, build } = await realize();
|
|
73
77
|
const frontend = await frontendAsset(build.frontend, bindings, url, request);
|
|
74
78
|
if (frontend !== undefined)
|
|
75
79
|
return frontend;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/adapter-cloudflare",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.26",
|
|
4
4
|
"description": "Deploy an Astrale application through Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"hono": "^4.6.20",
|
|
46
46
|
"jose": "^6.1.3",
|
|
47
47
|
"wrangler": "4.123.0",
|
|
48
|
-
"@astrale-os/sdk": "^0.5.0-beta.
|
|
48
|
+
"@astrale-os/sdk": "^0.5.0-beta.23"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@astrale-os/ox": ">=0.1.0 <1.0.0",
|