@astrale-os/adapter-cloudflare 0.5.0-beta.4 → 0.5.0-beta.41
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 +11 -0
- package/dist/adapter.d.ts +17 -0
- package/dist/adapter.js +178 -0
- package/dist/build/artifact.d.ts +7 -0
- package/dist/build/artifact.js +151 -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/gateway.d.ts +1 -0
- package/dist/build/codegen/gateway.js +1 -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 +18 -1
- package/dist/build/codegen/wrangler.js +36 -17
- package/dist/build/configuration/addressing.d.ts +2 -0
- package/dist/build/configuration/addressing.js +11 -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 +4 -0
- package/dist/build/configuration.js +4 -0
- package/dist/build/direct.d.ts +4 -0
- package/dist/build/direct.js +91 -0
- package/dist/build/frontend/routes.d.ts +2 -0
- package/dist/build/frontend/routes.js +11 -0
- package/dist/build/frontend-v1.d.ts +16 -0
- package/dist/build/frontend-v1.js +133 -0
- package/dist/build/gateway/prepare.d.ts +8 -0
- package/dist/build/gateway/prepare.js +33 -0
- package/dist/build/gateway/source.d.ts +1 -0
- package/dist/build/gateway/source.js +7 -0
- package/dist/build/index.d.ts +10 -16
- package/dist/build/index.js +9 -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/parse-output.d.ts +0 -1
- package/dist/build/parse-output.js +0 -1
- 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 +39 -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 +277 -0
- package/dist/build/worker/artifact.manifest.d.ts +47 -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 +15 -0
- package/dist/build/worker/codegen/service.js +46 -0
- package/dist/build/worker/execution.prepare.d.ts +18 -0
- package/dist/build/worker/execution.prepare.js +108 -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/build/wrangler/bundle.d.ts +10 -0
- package/dist/build/wrangler/bundle.js +29 -0
- package/dist/build/wrangler/deploy.d.ts +23 -0
- package/dist/build/wrangler/deploy.js +35 -0
- package/dist/build/wrangler/development.d.ts +15 -0
- package/dist/build/wrangler/development.js +135 -0
- package/dist/build/wrangler/namespace.d.ts +10 -0
- package/dist/build/wrangler/namespace.js +26 -0
- package/dist/build/wrangler/process.d.ts +17 -0
- package/dist/build/wrangler/process.js +115 -0
- package/dist/build/wrangler/release.d.ts +11 -0
- package/dist/build/wrangler/release.js +27 -0
- package/dist/build/wrangler/secrets.d.ts +6 -0
- package/dist/build/wrangler/secrets.js +58 -0
- package/dist/build/wrangler/status.d.ts +14 -0
- package/dist/build/wrangler/status.js +56 -0
- package/dist/build/wrangler/type-generation.d.ts +6 -0
- package/dist/build/wrangler/type-generation.js +19 -0
- package/dist/build/wrangler-cli.d.ts +8 -86
- package/dist/build/wrangler-cli.js +8 -275
- package/dist/cloudflare.d.ts +1 -34
- package/dist/cloudflare.js +1 -205
- package/dist/deploy/deploy.d.ts +17 -0
- package/dist/deploy/deploy.js +234 -0
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/index.js +1 -0
- package/dist/identity/binding.d.ts +2 -0
- package/dist/identity/binding.js +2 -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 +98 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +3 -4
- package/dist/params.d.ts +24 -5
- package/dist/params.js +0 -1
- package/dist/release/index.d.ts +2 -0
- package/dist/release/index.js +2 -0
- package/dist/release/namespace.d.ts +2 -0
- package/dist/release/namespace.js +6 -0
- package/dist/release/target.d.ts +2 -0
- package/dist/release/target.js +9 -0
- package/dist/worker/entry.d.ts +39 -0
- package/dist/worker/entry.js +162 -0
- package/dist/worker/fetch.d.ts +11 -0
- package/dist/worker/fetch.js +31 -0
- package/dist/worker/gateway.d.ts +15 -0
- package/dist/worker/gateway.js +26 -0
- package/dist/worker/identity.d.ts +7 -0
- package/dist/worker/identity.js +23 -0
- package/dist/worker/index.d.ts +3 -59
- package/dist/worker/index.js +3 -209
- package/package.json +21 -18
- package/template/astrale.config.ts +19 -11
- 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 -26
- package/dist/build/frontend.d.ts.map +0 -1
- package/dist/build/frontend.js +0 -263
- 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.map +0 -1
- 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 -117
- 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.map +0 -1
- 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/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 -127
- package/src/build/frontend.ts +0 -324
- package/src/build/index.ts +0 -29
- package/src/build/parse-output.ts +0 -60
- package/src/build/prepare.ts +0 -161
- package/src/build/worker.ts +0 -37
- package/src/build/wrangler-cli.ts +0 -362
- package/src/cloudflare.ts +0 -251
- package/src/index.ts +0 -21
- package/src/params.ts +0 -92
- package/src/worker/index.ts +0 -314
- package/src/worker/tsconfig.json +0 -10
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# `@astrale-os/adapter-cloudflare`
|
|
2
|
+
|
|
3
|
+
Cloudflare Worker deployment adapter for Astrale Domains.
|
|
4
|
+
|
|
5
|
+
During the SDK beta program, install the beta package set explicitly:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @astrale-os/sdk@beta @astrale-os/adapter-cloudflare@beta
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Bare installs return to stable releases when the package set is promoted and npm `latest` advances.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Release } from '@astrale-os/sdk/deployment/release';
|
|
2
|
+
import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
|
|
3
|
+
import type { CloudflareParams } from './params.js';
|
|
4
|
+
import { artifact } from './build/artifact.js';
|
|
5
|
+
import { startFrontend } from './build/frontend-v1.js';
|
|
6
|
+
import { runWranglerDev } from './build/wrangler-cli.js';
|
|
7
|
+
import { type CloudflareDeployDependencies } from './deploy/index.js';
|
|
8
|
+
import { signingIdentity } from './identity/source.js';
|
|
9
|
+
export interface CloudflareDependencies extends CloudflareDeployDependencies {
|
|
10
|
+
readonly artifact: typeof artifact;
|
|
11
|
+
readonly runWranglerDev: typeof runWranglerDev;
|
|
12
|
+
readonly startFrontend: typeof startFrontend;
|
|
13
|
+
readonly signingIdentity: typeof signingIdentity;
|
|
14
|
+
}
|
|
15
|
+
export declare function cloudflare(environments: Readonly<Record<string, CloudflareParams>>): import("@astrale-os/sdk/deployment/adapter").Adapter<CloudflareParams>;
|
|
16
|
+
export declare function cloudflareWithDependencies(environments: Readonly<Record<string, CloudflareParams>>, dependencies: CloudflareDependencies): import("@astrale-os/sdk/deployment/adapter").Adapter<CloudflareParams>;
|
|
17
|
+
export declare function waitForReadiness(verify: typeof verifyReadiness, release: Release, signal?: AbortSignal): Promise<void>;
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { defineAdapter } from '@astrale-os/sdk/deployment/adapter';
|
|
2
|
+
import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
|
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { artifact, materialize } from './build/artifact.js';
|
|
7
|
+
import { generateWranglerConfig } from './build/codegen/wrangler.js';
|
|
8
|
+
import { resolveRouter, workerName } from './build/configuration.js';
|
|
9
|
+
import { startFrontend } from './build/frontend-v1.js';
|
|
10
|
+
import { loadWorkerArtifact } from './build/worker/index.js';
|
|
11
|
+
import { workerModules } from './build/worker/modules.js';
|
|
12
|
+
import { ensureWranglerDispatchNamespace, runWranglerDeploymentStatus, runWranglerDeploy, runWranglerDev, runWranglerReleaseDeploy, } from './build/wrangler-cli.js';
|
|
13
|
+
import { deployCloudflare } from './deploy/index.js';
|
|
14
|
+
import { signingIdentitySecrets } from './identity/secret.js';
|
|
15
|
+
import { signingIdentity } from './identity/source.js';
|
|
16
|
+
const packageVersion = createRequire(import.meta.url)('../package.json')
|
|
17
|
+
.version;
|
|
18
|
+
export function cloudflare(environments) {
|
|
19
|
+
return cloudflareWithDependencies(environments, {
|
|
20
|
+
artifact,
|
|
21
|
+
materialize,
|
|
22
|
+
ensureWranglerDispatchNamespace,
|
|
23
|
+
runWranglerDeploy,
|
|
24
|
+
runWranglerReleaseDeploy,
|
|
25
|
+
runWranglerDeploymentStatus,
|
|
26
|
+
runWranglerDev,
|
|
27
|
+
startFrontend,
|
|
28
|
+
signingIdentity,
|
|
29
|
+
waitForReadiness: (release, signal) => waitForReadiness(verifyReadiness, release, signal),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function cloudflareWithDependencies(environments, dependencies) {
|
|
33
|
+
return defineAdapter({
|
|
34
|
+
name: 'cloudflare',
|
|
35
|
+
version: packageVersion,
|
|
36
|
+
environments,
|
|
37
|
+
prepare: dependencies.artifact,
|
|
38
|
+
async watch(parameters, context) {
|
|
39
|
+
const workerArtifact = loadWorkerArtifact(context.artifact);
|
|
40
|
+
const identity = await dependencies.signingIdentity({
|
|
41
|
+
projectDir: context.projectDir,
|
|
42
|
+
source: parameters.signingIdentity,
|
|
43
|
+
origin: context.artifact.build.schema.compiled.root.origin,
|
|
44
|
+
mode: 'local',
|
|
45
|
+
});
|
|
46
|
+
const secrets = signingIdentitySecrets(context.secrets, identity);
|
|
47
|
+
const directory = join(context.projectDir, '.astrale', 'runtime');
|
|
48
|
+
await dependencies.materialize(directory, context.artifact.files);
|
|
49
|
+
const frontend = await dependencies.startFrontend({
|
|
50
|
+
frontend: context.artifact.build.frontend,
|
|
51
|
+
projectDir: context.projectDir,
|
|
52
|
+
});
|
|
53
|
+
const name = workerName(parameters, context.artifact.build.schema.compiled.root.origin);
|
|
54
|
+
// A local workerd cannot reach the default deployed router Worker through a service
|
|
55
|
+
// binding. Keep it for remote isolates and explicit multi-Worker development; ordinary
|
|
56
|
+
// local execution falls back to the admitted fetch path when ROUTER is absent.
|
|
57
|
+
const router = parameters.remote === true || parameters.router !== undefined
|
|
58
|
+
? resolveRouter(parameters.router)
|
|
59
|
+
: undefined;
|
|
60
|
+
const configPath = join(directory, 'wrangler.watch.jsonc');
|
|
61
|
+
await writeFile(configPath, generateWranglerConfig({
|
|
62
|
+
workerName: name,
|
|
63
|
+
main: `./${workerArtifact.release.entrypoint}`,
|
|
64
|
+
modules: workerModules(workerArtifact.release),
|
|
65
|
+
vars: {
|
|
66
|
+
...parameters.vars,
|
|
67
|
+
...(parameters.host === undefined ? {} : { WORKER_URL: parameters.host }),
|
|
68
|
+
...(frontend === undefined ? {} : { FRONTEND_DEV_URL: frontend.url }),
|
|
69
|
+
},
|
|
70
|
+
secretBindings: Object.keys(secrets).sort(),
|
|
71
|
+
...(context.artifact.build.frontend?.source.kind === 'vite'
|
|
72
|
+
? {
|
|
73
|
+
frontend: {
|
|
74
|
+
directory: './frontend',
|
|
75
|
+
routes: frontendRoutes(context.artifact),
|
|
76
|
+
dev: true,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
: {}),
|
|
80
|
+
...(router === undefined
|
|
81
|
+
? {}
|
|
82
|
+
: { router: { binding: router.binding, service: router.service } }),
|
|
83
|
+
...(parameters.wrangler === undefined ? {} : { wrangler: parameters.wrangler }),
|
|
84
|
+
selfBinding: true,
|
|
85
|
+
}));
|
|
86
|
+
let worker;
|
|
87
|
+
try {
|
|
88
|
+
worker = await dependencies.runWranglerDev({
|
|
89
|
+
projectDir: context.projectDir,
|
|
90
|
+
configPath,
|
|
91
|
+
port: parameters.port ?? 8787,
|
|
92
|
+
remote: parameters.remote ?? false,
|
|
93
|
+
secrets,
|
|
94
|
+
autoPickPort: parameters.port === undefined,
|
|
95
|
+
...(parameters.host === undefined ? {} : { ip: '0.0.0.0' }),
|
|
96
|
+
onReload: context.onReload,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (cause) {
|
|
100
|
+
await frontend?.stop().catch(() => undefined);
|
|
101
|
+
throw cause;
|
|
102
|
+
}
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
url: parameters.host ?? worker.url,
|
|
105
|
+
localUrl: worker.url,
|
|
106
|
+
async stop() {
|
|
107
|
+
const results = await Promise.allSettled([
|
|
108
|
+
worker.stop(),
|
|
109
|
+
frontend?.stop() ?? Promise.resolve(),
|
|
110
|
+
]);
|
|
111
|
+
const failures = results.filter((result) => result.status === 'rejected');
|
|
112
|
+
if (failures.length === 1)
|
|
113
|
+
throw failures[0].reason;
|
|
114
|
+
if (failures.length > 1) {
|
|
115
|
+
throw new AggregateError(failures.map((failure) => failure.reason), 'Cloudflare development cleanup failed.');
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
deploy: (parameters, context) => deployCloudflare(parameters, context, dependencies),
|
|
121
|
+
secretsFile: (parameters) => parameters.secrets,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function frontendRoutes(artifact) {
|
|
125
|
+
const frontend = artifact.build.frontend;
|
|
126
|
+
if (frontend === undefined || frontend.source.kind !== 'vite')
|
|
127
|
+
return [];
|
|
128
|
+
return Object.freeze(frontend.routes
|
|
129
|
+
.flatMap((route) => frontend.source.kind === 'vite' && frontend.source.spa && route.path !== '/'
|
|
130
|
+
? [route.path, `${route.path}/*`]
|
|
131
|
+
: route.path === '/'
|
|
132
|
+
? ['/*']
|
|
133
|
+
: [route.path])
|
|
134
|
+
.sort());
|
|
135
|
+
}
|
|
136
|
+
export async function waitForReadiness(verify, release, signal) {
|
|
137
|
+
const deadline = Date.now() + 90_000;
|
|
138
|
+
let last;
|
|
139
|
+
while (Date.now() < deadline) {
|
|
140
|
+
throwIfAborted(signal);
|
|
141
|
+
try {
|
|
142
|
+
await verify(release, {
|
|
143
|
+
signal: signal === undefined
|
|
144
|
+
? AbortSignal.timeout(5_000)
|
|
145
|
+
: AbortSignal.any([signal, AbortSignal.timeout(5_000)]),
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
catch (cause) {
|
|
150
|
+
throwIfAborted(signal);
|
|
151
|
+
last = cause;
|
|
152
|
+
await pause(signal);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
throw last instanceof Error ? last : new Error('Cloudflare Release did not become ready.');
|
|
156
|
+
}
|
|
157
|
+
function pause(signal) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
const timer = setTimeout(done, 1_000);
|
|
160
|
+
const abort = () => done(abortError(signal));
|
|
161
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
162
|
+
function done(cause) {
|
|
163
|
+
clearTimeout(timer);
|
|
164
|
+
signal?.removeEventListener('abort', abort);
|
|
165
|
+
if (cause === undefined)
|
|
166
|
+
resolve();
|
|
167
|
+
else
|
|
168
|
+
reject(cause);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function throwIfAborted(signal) {
|
|
173
|
+
if (signal?.aborted)
|
|
174
|
+
throw abortError(signal);
|
|
175
|
+
}
|
|
176
|
+
function abortError(signal) {
|
|
177
|
+
return signal?.reason instanceof Error ? signal.reason : new Error('Deployment interrupted.');
|
|
178
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ArtifactSource, PrepareContext } from '@astrale-os/sdk/deployment/adapter';
|
|
2
|
+
import type { CloudflareParams } from '../params.js';
|
|
3
|
+
export { materialize } from './materialize.js';
|
|
4
|
+
/** Prepare one revision Service and its stateless gateway without provider mutation. */
|
|
5
|
+
export declare function artifact(params: CloudflareParams, context: PrepareContext): Promise<ArtifactSource>;
|
|
6
|
+
/** Prepare the complete portable Cloudflare Worker without direct Wrangler placement files. */
|
|
7
|
+
export declare function prepareWorkerArtifact(params: CloudflareParams, context: PrepareContext): Promise<ArtifactSource>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { addressing } from '@astrale-os/sdk/deployment/release';
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { SIGNING_IDENTITY_BINDING } from '../identity/binding.js';
|
|
5
|
+
import { releaseNamespace, releaseWorkerName } from '../release/index.js';
|
|
6
|
+
import { generateWranglerConfig } from './codegen/wrangler.js';
|
|
7
|
+
import { deploymentAddressing, resolveRouter, workerName } from './configuration.js';
|
|
8
|
+
import { frontendFiles } from './frontend-v1.js';
|
|
9
|
+
import { frontendRoutes } from './frontend/routes.js';
|
|
10
|
+
import { prepareGateway } from './gateway/prepare.js';
|
|
11
|
+
import { encodeWorkerArtifactManifest, inferMediaType, workerContentDigest, WORKER_MANIFEST_PATH, } from './worker/artifact.manifest.js';
|
|
12
|
+
import { prepareExecution, RELEASE_ENTRY, RELEASE_SERVICE, runtimeVars, } from './worker/execution.prepare.js';
|
|
13
|
+
import { admitWorkerRuntimeConfiguration } from './worker/runtime.js';
|
|
14
|
+
export { materialize } from './materialize.js';
|
|
15
|
+
const encoder = new TextEncoder();
|
|
16
|
+
/** Prepare one revision Service and its stateless gateway without provider mutation. */
|
|
17
|
+
export async function artifact(params, context) {
|
|
18
|
+
return prepare(params, context, true);
|
|
19
|
+
}
|
|
20
|
+
/** Prepare the complete portable Cloudflare Worker without direct Wrangler placement files. */
|
|
21
|
+
export async function prepareWorkerArtifact(params, context) {
|
|
22
|
+
return prepare(params, context, false);
|
|
23
|
+
}
|
|
24
|
+
async function prepare(params, context, direct) {
|
|
25
|
+
const stateDirectory = join(context.projectDir, '.astrale');
|
|
26
|
+
const directory = join(stateDirectory, 'runtime');
|
|
27
|
+
await mkdir(directory, { recursive: true });
|
|
28
|
+
const router = resolveRouter(params.router);
|
|
29
|
+
const name = workerName(params, context.build.schema.compiled.root.origin);
|
|
30
|
+
const revision = context.build.schema.compiled.root.revision;
|
|
31
|
+
const namespace = releaseNamespace(name);
|
|
32
|
+
const target = releaseWorkerName(revision);
|
|
33
|
+
const configuredIssuer = deploymentAddressing(params);
|
|
34
|
+
const execution = await prepareExecution({
|
|
35
|
+
params,
|
|
36
|
+
context,
|
|
37
|
+
directory,
|
|
38
|
+
name,
|
|
39
|
+
direct,
|
|
40
|
+
configuredIssuer,
|
|
41
|
+
router,
|
|
42
|
+
});
|
|
43
|
+
const frontend = await frontendFiles({
|
|
44
|
+
frontend: context.build.frontend,
|
|
45
|
+
projectDir: context.projectDir,
|
|
46
|
+
});
|
|
47
|
+
const gatewayBundle = await prepareGateway({
|
|
48
|
+
projectDir: context.projectDir,
|
|
49
|
+
directory,
|
|
50
|
+
name,
|
|
51
|
+
...(params.route === undefined ? {} : { route: params.route }),
|
|
52
|
+
namespace,
|
|
53
|
+
revision,
|
|
54
|
+
});
|
|
55
|
+
const releaseConfig = generateWranglerConfig({
|
|
56
|
+
workerName: target,
|
|
57
|
+
main: `./${RELEASE_ENTRY}`,
|
|
58
|
+
vars: runtimeVars(params, configuredIssuer),
|
|
59
|
+
secretBindings: [SIGNING_IDENTITY_BINDING],
|
|
60
|
+
modules: { baseDir: './bundle', rules: [{ type: 'ESModule', globs: ['service.mjs'] }] },
|
|
61
|
+
...(context.build.frontend?.source.kind === 'vite'
|
|
62
|
+
? {
|
|
63
|
+
frontend: {
|
|
64
|
+
directory: './frontend',
|
|
65
|
+
routes: frontendRoutes(context.build.frontend),
|
|
66
|
+
dev: false,
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
: {}),
|
|
70
|
+
...(router === undefined
|
|
71
|
+
? {}
|
|
72
|
+
: { router: { binding: router.binding, service: router.service } }),
|
|
73
|
+
...(params.wrangler === undefined ? {} : { wrangler: params.wrangler }),
|
|
74
|
+
selfBinding: false,
|
|
75
|
+
});
|
|
76
|
+
const gatewayConfig = generateWranglerConfig({
|
|
77
|
+
workerName: name,
|
|
78
|
+
main: './gateway/index.mjs',
|
|
79
|
+
...(params.route === undefined ? {} : { route: params.route }),
|
|
80
|
+
releases: { binding: 'RELEASES', namespace },
|
|
81
|
+
selfBinding: false,
|
|
82
|
+
});
|
|
83
|
+
const runtime = admitWorkerRuntimeConfiguration(releaseConfig);
|
|
84
|
+
const manifest = encodeWorkerArtifactManifest({
|
|
85
|
+
origin: context.build.schema.compiled.root.origin,
|
|
86
|
+
revision,
|
|
87
|
+
release: {
|
|
88
|
+
entrypoint: RELEASE_ENTRY,
|
|
89
|
+
modules: [
|
|
90
|
+
{ path: RELEASE_ENTRY, kind: 'esm', digest: workerContentDigest(execution.entry) },
|
|
91
|
+
{ path: RELEASE_SERVICE, kind: 'esm', digest: workerContentDigest(execution.service) },
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
gateway: {
|
|
95
|
+
entrypoint: 'gateway/index.mjs',
|
|
96
|
+
modules: [
|
|
97
|
+
{ path: 'gateway/index.mjs', kind: 'esm', digest: workerContentDigest(gatewayBundle) },
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
runtime: {
|
|
101
|
+
compatibilityDate: runtime.compatibilityDate,
|
|
102
|
+
compatibilityFlags: runtime.compatibilityFlags,
|
|
103
|
+
},
|
|
104
|
+
bindings: {
|
|
105
|
+
vars: runtime.vars,
|
|
106
|
+
services: runtime.services,
|
|
107
|
+
requiredSecrets: [SIGNING_IDENTITY_BINDING],
|
|
108
|
+
},
|
|
109
|
+
...(frontend.length === 0
|
|
110
|
+
? {}
|
|
111
|
+
: {
|
|
112
|
+
assets: {
|
|
113
|
+
files: frontend.map((file) => {
|
|
114
|
+
const contentType = file.mediaType ?? inferMediaType(file.path);
|
|
115
|
+
return {
|
|
116
|
+
path: `/${file.path}`,
|
|
117
|
+
artifactPath: `frontend/${file.path}`,
|
|
118
|
+
digest: workerContentDigest(file.bytes()),
|
|
119
|
+
...(contentType === undefined ? {} : { contentType }),
|
|
120
|
+
};
|
|
121
|
+
}),
|
|
122
|
+
notFound: 'none',
|
|
123
|
+
runWorkerFirst: true,
|
|
124
|
+
htmlHandling: 'none',
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
const files = [
|
|
129
|
+
{ path: RELEASE_ENTRY, content: execution.entry },
|
|
130
|
+
{ path: RELEASE_SERVICE, content: execution.service },
|
|
131
|
+
{ path: 'gateway/index.mjs', content: gatewayBundle },
|
|
132
|
+
{ path: WORKER_MANIFEST_PATH, content: manifest },
|
|
133
|
+
...frontend.map((file) => ({
|
|
134
|
+
path: `frontend/${file.path}`,
|
|
135
|
+
content: file.bytes(),
|
|
136
|
+
})),
|
|
137
|
+
...(direct
|
|
138
|
+
? [
|
|
139
|
+
{ path: 'wrangler.release.jsonc', content: encoder.encode(releaseConfig) },
|
|
140
|
+
{ path: 'wrangler.gateway.jsonc', content: encoder.encode(gatewayConfig) },
|
|
141
|
+
]
|
|
142
|
+
: []),
|
|
143
|
+
];
|
|
144
|
+
return Object.freeze({
|
|
145
|
+
entrypoint: RELEASE_ENTRY,
|
|
146
|
+
files: Object.freeze(files),
|
|
147
|
+
addressing: configuredIssuer === undefined
|
|
148
|
+
? Object.freeze({ kind: 'provider-assigned', claim: name })
|
|
149
|
+
: Object.freeze({ kind: 'configured', addressing: addressing(configuredIssuer) }),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function admitWorkerBundle(path: string): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { pathToFileURL } from 'node:url';
|
|
2
|
+
export async function admitWorkerBundle(path) {
|
|
3
|
+
const loaded = (await import(`${pathToFileURL(path).href}?admit=${Date.now()}`));
|
|
4
|
+
if (loaded.default === null ||
|
|
5
|
+
typeof loaded.default !== 'object' ||
|
|
6
|
+
typeof Reflect.get(loaded.default, 'fetch') !== 'function') {
|
|
7
|
+
throw new TypeError('Generated Worker bundle does not export a Fetch handler.');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readWranglerMetafile } from './metafile.js';
|
|
2
|
+
const FORBIDDEN_RUNTIME_INPUTS = [
|
|
3
|
+
'/v1/builder/',
|
|
4
|
+
'/v1/compiled/compiler/',
|
|
5
|
+
'/node_modules/ajv/',
|
|
6
|
+
'/node_modules/re2js/',
|
|
7
|
+
'/kernel-core/domain/',
|
|
8
|
+
'/core/domain/',
|
|
9
|
+
'/kernel-core/schema/index.',
|
|
10
|
+
'/core/schema/index.',
|
|
11
|
+
];
|
|
12
|
+
/** Prove emitted Worker reachability excludes authoring, compilation, and broad Core Schema owners. */
|
|
13
|
+
export async function assertRuntimeClosure(metafilePath) {
|
|
14
|
+
const metafile = await readWranglerMetafile(metafilePath);
|
|
15
|
+
const forbidden = Object.keys(metafile.inputs).filter((input) => {
|
|
16
|
+
const normalized = `/${input.replaceAll('\\', '/')}`.replace(/(\/node_modules\/@astrale-os\/kernel-[^/]+)\/dist\//gu, '$1/');
|
|
17
|
+
return FORBIDDEN_RUNTIME_INPUTS.some((fragment) => normalized.includes(fragment));
|
|
18
|
+
});
|
|
19
|
+
if (forbidden.length > 0) {
|
|
20
|
+
throw new Error(`Cloudflare Worker reaches build-side modules: ${forbidden.sort().join(', ')}.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { generateGatewayEntry } from '../gateway/source.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { generateGatewayEntry } from '../gateway/source.js';
|
|
@@ -13,17 +13,35 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export interface WranglerCodegenOptions {
|
|
15
15
|
workerName: string;
|
|
16
|
+
/** Provider-ready entrypoint relative to the generated config. */
|
|
17
|
+
main?: string;
|
|
16
18
|
/** Full custom hostname for a routed deploy (e.g. 'crm.acme.dev'). */
|
|
17
19
|
route?: string;
|
|
18
20
|
/** Exact materialized local frontend; absence means no ASSETS binding. */
|
|
19
21
|
frontend?: {
|
|
20
22
|
readonly directory: string;
|
|
21
23
|
readonly routes: readonly string[];
|
|
24
|
+
readonly dev: boolean;
|
|
22
25
|
};
|
|
23
26
|
/** Plain (non-secret) vars to bake in. */
|
|
24
27
|
vars?: Record<string, string>;
|
|
28
|
+
/** Secret binding names required by generated Worker code. */
|
|
29
|
+
secretBindings?: readonly string[];
|
|
30
|
+
/** Modules retained outside the startup entry and loaded on demand. */
|
|
31
|
+
modules?: {
|
|
32
|
+
readonly baseDir: string;
|
|
33
|
+
readonly rules: readonly {
|
|
34
|
+
readonly type: 'ESModule' | 'CompiledWasm' | 'Text' | 'Data';
|
|
35
|
+
readonly globs: readonly string[];
|
|
36
|
+
}[];
|
|
37
|
+
};
|
|
25
38
|
/** Add the SELF service binding (autobinding). */
|
|
26
39
|
selfBinding: boolean;
|
|
40
|
+
/** Bind the stable gateway to its private revision namespace. */
|
|
41
|
+
releases?: {
|
|
42
|
+
readonly binding: string;
|
|
43
|
+
readonly namespace: string;
|
|
44
|
+
};
|
|
27
45
|
/**
|
|
28
46
|
* Add a service binding to a router Worker for instance-host subrequest
|
|
29
47
|
* routing (see `CloudflareParams.router`). Pairs with the worker
|
|
@@ -43,4 +61,3 @@ export interface WranglerCodegenOptions {
|
|
|
43
61
|
wrangler?: Record<string, unknown>;
|
|
44
62
|
}
|
|
45
63
|
export declare function generateWranglerConfig(opts: WranglerCodegenOptions): string;
|
|
46
|
-
//# sourceMappingURL=wrangler.d.ts.map
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
* (extra bindings: KV, R2, D1, queues, …) — see `mergeUserConfig`.
|
|
13
13
|
*/
|
|
14
14
|
import { deepMergeConfig } from './merge.js';
|
|
15
|
-
//
|
|
15
|
+
// Keep the generated date on the runtime baseline qualified with Wrangler 4.123.0.
|
|
16
16
|
const COMPATIBILITY_DATE = '2026-08-11';
|
|
17
17
|
export function generateWranglerConfig(opts) {
|
|
18
18
|
const config = {
|
|
19
19
|
name: opts.workerName,
|
|
20
|
-
main: './worker.gen.ts',
|
|
20
|
+
main: opts.main ?? './worker.gen.ts',
|
|
21
21
|
compatibility_date: COMPATIBILITY_DATE,
|
|
22
22
|
compatibility_flags: ['nodejs_compat'],
|
|
23
|
-
workers_dev:
|
|
23
|
+
workers_dev: opts.route === undefined,
|
|
24
24
|
version_metadata: { binding: 'ASTRALE_VERSION_METADATA' },
|
|
25
25
|
observability: { enabled: true },
|
|
26
26
|
};
|
|
@@ -31,19 +31,20 @@ export function generateWranglerConfig(opts) {
|
|
|
31
31
|
config.assets = {
|
|
32
32
|
directory: opts.frontend.directory,
|
|
33
33
|
binding: 'ASSETS',
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
html_handling: 'none',
|
|
35
|
+
run_worker_first: opts.frontend.dev
|
|
36
|
+
? true
|
|
37
|
+
: [
|
|
38
|
+
'/releases',
|
|
39
|
+
'/releases/*',
|
|
40
|
+
'/install',
|
|
41
|
+
'/install/*',
|
|
42
|
+
'/health',
|
|
43
|
+
'/health/*',
|
|
44
|
+
'/.well-known',
|
|
45
|
+
'/.well-known/*',
|
|
46
|
+
...opts.frontend.routes,
|
|
47
|
+
],
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
const services = [];
|
|
@@ -57,6 +58,21 @@ export function generateWranglerConfig(opts) {
|
|
|
57
58
|
if (opts.vars && Object.keys(opts.vars).length > 0) {
|
|
58
59
|
config.vars = opts.vars;
|
|
59
60
|
}
|
|
61
|
+
if (opts.secretBindings && opts.secretBindings.length > 0) {
|
|
62
|
+
config.secrets = { required: [...opts.secretBindings] };
|
|
63
|
+
}
|
|
64
|
+
if (opts.modules !== undefined) {
|
|
65
|
+
config.find_additional_modules = true;
|
|
66
|
+
config.base_dir = opts.modules.baseDir;
|
|
67
|
+
config.rules = opts.modules.rules.map((rule) => ({
|
|
68
|
+
type: rule.type,
|
|
69
|
+
globs: [...rule.globs],
|
|
70
|
+
fallthrough: true,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
if (opts.releases !== undefined) {
|
|
74
|
+
config.dispatch_namespaces = [opts.releases];
|
|
75
|
+
}
|
|
60
76
|
const merged = opts.wrangler ? mergeUserConfig(config, opts.wrangler) : config;
|
|
61
77
|
return JSON.stringify(merged, null, 2) + '\n';
|
|
62
78
|
}
|
|
@@ -67,7 +83,11 @@ const ADAPTER_OWNED_KEYS = [
|
|
|
67
83
|
'assets',
|
|
68
84
|
'routes',
|
|
69
85
|
'compatibility_date',
|
|
86
|
+
'workers_dev',
|
|
70
87
|
'version_metadata',
|
|
88
|
+
'secrets',
|
|
89
|
+
'find_additional_modules',
|
|
90
|
+
'base_dir',
|
|
71
91
|
];
|
|
72
92
|
/**
|
|
73
93
|
* Deep-merge the dev's raw wrangler overlay over the generated config, after
|
|
@@ -83,4 +103,3 @@ function mergeUserConfig(base, user) {
|
|
|
83
103
|
}
|
|
84
104
|
return deepMergeConfig(base, user);
|
|
85
105
|
}
|
|
86
|
-
//# sourceMappingURL=wrangler.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { addressing } from '@astrale-os/sdk/deployment/release';
|
|
2
|
+
export function deploymentAddressing(parameters) {
|
|
3
|
+
const routed = parameters.route === undefined ? undefined : addressing(`https://${parameters.route}`).issuer;
|
|
4
|
+
if (parameters.addressing === undefined)
|
|
5
|
+
return routed;
|
|
6
|
+
const configured = addressing(parameters.addressing).issuer;
|
|
7
|
+
if (routed !== undefined && configured !== routed) {
|
|
8
|
+
throw new TypeError('Cloudflare route and addressing identify different origins.');
|
|
9
|
+
}
|
|
10
|
+
return configured;
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const MAXIMUM_REQUEST_BYTES = 16 * 1024 * 1024;
|
|
2
|
+
export function workerRequestLimit(value) {
|
|
3
|
+
if (value === undefined)
|
|
4
|
+
return undefined;
|
|
5
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > MAXIMUM_REQUEST_BYTES) {
|
|
6
|
+
throw new TypeError('Cloudflare maximumRequestBytes must be a positive integer at most 16 MiB.');
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CloudflareParams } from '../../params.js';
|
|
2
|
+
export declare function resolveRouter(input: CloudflareParams['router']): {
|
|
3
|
+
readonly binding: string;
|
|
4
|
+
readonly service: string;
|
|
5
|
+
readonly hostSuffix: string;
|
|
6
|
+
readonly minLabels: number;
|
|
7
|
+
} | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function resolveRouter(input) {
|
|
2
|
+
if (input === false)
|
|
3
|
+
return undefined;
|
|
4
|
+
const value = input ?? {};
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
binding: value.binding ?? 'ROUTER',
|
|
7
|
+
service: value.service ?? 'admin-router',
|
|
8
|
+
hostSuffix: value.hostSuffix ?? '.astrale.ai',
|
|
9
|
+
minLabels: value.minLabels ?? 4,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
const WORKER_NAME = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u;
|
|
3
|
+
export function workerName(parameters, origin) {
|
|
4
|
+
if (parameters.workerName !== undefined) {
|
|
5
|
+
if (!WORKER_NAME.test(parameters.workerName) || parameters.workerName.length > 63) {
|
|
6
|
+
throw new TypeError('Cloudflare workerName is invalid.');
|
|
7
|
+
}
|
|
8
|
+
return parameters.workerName;
|
|
9
|
+
}
|
|
10
|
+
const readable = origin
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/gu, '-')
|
|
13
|
+
.slice(0, 12)
|
|
14
|
+
.replace(/^-+|-+$/gu, '') || 'domain';
|
|
15
|
+
const hexadecimal = createHash('sha256').update(origin).digest('hex');
|
|
16
|
+
const identity = BigInt(`0x${hexadecimal}`).toString(36).padStart(50, '0');
|
|
17
|
+
return `${readable}-${identity}`;
|
|
18
|
+
}
|