@astrale-os/adapter-cloudflare 0.5.0-beta.19 → 0.5.0-beta.20

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.
Files changed (111) hide show
  1. package/README.md +2 -2
  2. package/dist/adapter.d.ts +7 -10
  3. package/dist/adapter.js +17 -200
  4. package/dist/build/artifact.d.ts +1 -2
  5. package/dist/build/artifact.js +48 -14
  6. package/dist/build/closure.d.ts +0 -1
  7. package/dist/build/closure.js +0 -1
  8. package/dist/build/codegen/execution.d.ts +0 -1
  9. package/dist/build/codegen/execution.js +8 -5
  10. package/dist/build/codegen/gateway.d.ts +1 -0
  11. package/dist/build/codegen/gateway.js +7 -0
  12. package/dist/build/codegen/merge.d.ts +0 -1
  13. package/dist/build/codegen/merge.js +0 -1
  14. package/dist/build/codegen/wrangler.d.ts +7 -1
  15. package/dist/build/codegen/wrangler.js +7 -1
  16. package/dist/build/configuration.d.ts +1 -1
  17. package/dist/build/configuration.js +19 -5
  18. package/dist/build/frontend-v1.d.ts +0 -1
  19. package/dist/build/frontend-v1.js +0 -1
  20. package/dist/build/index.d.ts +3 -2
  21. package/dist/build/index.js +3 -2
  22. package/dist/build/metafile.d.ts +0 -1
  23. package/dist/build/metafile.js +0 -1
  24. package/dist/build/parse-output.d.ts +0 -1
  25. package/dist/build/parse-output.js +0 -1
  26. package/dist/build/qualification.d.ts +0 -1
  27. package/dist/build/qualification.js +0 -1
  28. package/dist/build/roots.d.ts +0 -1
  29. package/dist/build/roots.js +0 -1
  30. package/dist/build/wrangler-cli.d.ts +23 -33
  31. package/dist/build/wrangler-cli.js +188 -117
  32. package/dist/cloudflare.d.ts +1 -2
  33. package/dist/cloudflare.js +1 -2
  34. package/dist/deploy/deploy.d.ts +17 -0
  35. package/dist/deploy/deploy.js +207 -0
  36. package/dist/deploy/index.d.ts +1 -0
  37. package/dist/deploy/index.js +1 -0
  38. package/dist/identity/binding.d.ts +2 -0
  39. package/dist/identity/binding.js +2 -0
  40. package/dist/identity/material.d.ts +7 -0
  41. package/dist/identity/material.js +42 -0
  42. package/dist/identity/secret.d.ts +3 -0
  43. package/dist/identity/secret.js +7 -0
  44. package/dist/identity/source.d.ts +26 -0
  45. package/dist/identity/source.js +98 -0
  46. package/dist/index.d.ts +3 -4
  47. package/dist/index.js +3 -4
  48. package/dist/params.d.ts +14 -1
  49. package/dist/params.js +0 -1
  50. package/dist/release/index.d.ts +2 -0
  51. package/dist/release/index.js +2 -0
  52. package/dist/release/namespace.d.ts +2 -0
  53. package/dist/release/namespace.js +6 -0
  54. package/dist/release/target.d.ts +2 -0
  55. package/dist/release/target.js +9 -0
  56. package/dist/worker/entry.d.ts +2 -2
  57. package/dist/worker/entry.js +1 -2
  58. package/dist/worker/fetch.d.ts +0 -1
  59. package/dist/worker/fetch.js +0 -1
  60. package/dist/worker/gateway.d.ts +15 -0
  61. package/dist/worker/gateway.js +26 -0
  62. package/dist/worker/identity.d.ts +7 -0
  63. package/dist/worker/identity.js +23 -0
  64. package/dist/worker/index.d.ts +2 -1
  65. package/dist/worker/index.js +2 -1
  66. package/package.json +6 -9
  67. package/template/astrale.config.ts +7 -1
  68. package/dist/adapter.d.ts.map +0 -1
  69. package/dist/adapter.js.map +0 -1
  70. package/dist/build/artifact.d.ts.map +0 -1
  71. package/dist/build/artifact.js.map +0 -1
  72. package/dist/build/closure.d.ts.map +0 -1
  73. package/dist/build/closure.js.map +0 -1
  74. package/dist/build/codegen/execution.d.ts.map +0 -1
  75. package/dist/build/codegen/execution.js.map +0 -1
  76. package/dist/build/codegen/identity.d.ts +0 -10
  77. package/dist/build/codegen/identity.d.ts.map +0 -1
  78. package/dist/build/codegen/identity.js +0 -32
  79. package/dist/build/codegen/identity.js.map +0 -1
  80. package/dist/build/codegen/merge.d.ts.map +0 -1
  81. package/dist/build/codegen/merge.js.map +0 -1
  82. package/dist/build/codegen/wrangler.d.ts.map +0 -1
  83. package/dist/build/codegen/wrangler.js.map +0 -1
  84. package/dist/build/configuration.d.ts.map +0 -1
  85. package/dist/build/configuration.js.map +0 -1
  86. package/dist/build/frontend-v1.d.ts.map +0 -1
  87. package/dist/build/frontend-v1.js.map +0 -1
  88. package/dist/build/index.d.ts.map +0 -1
  89. package/dist/build/index.js.map +0 -1
  90. package/dist/build/metafile.d.ts.map +0 -1
  91. package/dist/build/metafile.js.map +0 -1
  92. package/dist/build/parse-output.d.ts.map +0 -1
  93. package/dist/build/parse-output.js.map +0 -1
  94. package/dist/build/qualification.d.ts.map +0 -1
  95. package/dist/build/qualification.js.map +0 -1
  96. package/dist/build/roots.d.ts.map +0 -1
  97. package/dist/build/roots.js.map +0 -1
  98. package/dist/build/wrangler-cli.d.ts.map +0 -1
  99. package/dist/build/wrangler-cli.js.map +0 -1
  100. package/dist/cloudflare.d.ts.map +0 -1
  101. package/dist/cloudflare.js.map +0 -1
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/index.js.map +0 -1
  104. package/dist/params.d.ts.map +0 -1
  105. package/dist/params.js.map +0 -1
  106. package/dist/worker/entry.d.ts.map +0 -1
  107. package/dist/worker/entry.js.map +0 -1
  108. package/dist/worker/fetch.d.ts.map +0 -1
  109. package/dist/worker/fetch.js.map +0 -1
  110. package/dist/worker/index.d.ts.map +0 -1
  111. package/dist/worker/index.js.map +0 -1
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  Cloudflare Worker deployment adapter for Astrale Domains.
4
4
 
5
- During the SDK beta program, install the beta cohort explicitly:
5
+ During the SDK beta program, install the beta package set explicitly:
6
6
 
7
7
  ```bash
8
8
  npm install @astrale-os/sdk@beta @astrale-os/adapter-cloudflare@beta
9
9
  ```
10
10
 
11
- Bare installs return to stable releases when the cohort is promoted and npm `latest` advances.
11
+ Bare installs return to stable releases when the package set is promoted and npm `latest` advances.
package/dist/adapter.d.ts CHANGED
@@ -1,20 +1,17 @@
1
- import { type Release } from '@astrale-os/sdk/deployment/release';
1
+ import type { Release } from '@astrale-os/sdk/deployment/release';
2
2
  import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
3
3
  import type { CloudflareParams } from './params.js';
4
- import { artifact, materialize } from './build/artifact.js';
4
+ import { artifact } from './build/artifact.js';
5
5
  import { startFrontend } from './build/frontend-v1.js';
6
- import { bulkPutSecrets, runWranglerDeploymentStatus, runWranglerDeploy, runWranglerDev } from './build/wrangler-cli.js';
7
- export interface CloudflareDependencies {
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 {
8
10
  readonly artifact: typeof artifact;
9
- readonly materialize: typeof materialize;
10
- readonly runWranglerDeploy: typeof runWranglerDeploy;
11
- readonly runWranglerDeploymentStatus: typeof runWranglerDeploymentStatus;
12
11
  readonly runWranglerDev: typeof runWranglerDev;
13
- readonly bulkPutSecrets: typeof bulkPutSecrets;
14
12
  readonly startFrontend: typeof startFrontend;
15
- readonly waitForReadiness: (release: Release) => Promise<void>;
13
+ readonly signingIdentity: typeof signingIdentity;
16
14
  }
17
15
  export declare function cloudflare(environments: Readonly<Record<string, CloudflareParams>>): import("@astrale-os/sdk/deployment/adapter").Adapter<CloudflareParams>;
18
16
  export declare function cloudflareWithDependencies(environments: Readonly<Record<string, CloudflareParams>>, dependencies: CloudflareDependencies): import("@astrale-os/sdk/deployment/adapter").Adapter<CloudflareParams>;
19
17
  export declare function waitForReadiness(verify: typeof verifyReadiness, release: Release): Promise<void>;
20
- //# sourceMappingURL=adapter.d.ts.map
package/dist/adapter.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { defineAdapter } from '@astrale-os/sdk/deployment/adapter';
2
- import { addressing, assemble, } from '@astrale-os/sdk/deployment/release';
3
2
  import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
4
3
  import { writeFile } from 'node:fs/promises';
5
4
  import { createRequire } from 'node:module';
@@ -8,19 +7,23 @@ import { artifact, materialize } from './build/artifact.js';
8
7
  import { generateWranglerConfig } from './build/codegen/wrangler.js';
9
8
  import { resolveRouter, workerName } from './build/configuration.js';
10
9
  import { startFrontend } from './build/frontend-v1.js';
11
- import { bulkPutSecrets, runWranglerDeploymentStatus, runWranglerDeploy, runWranglerDev, WranglerDeployError, } from './build/wrangler-cli.js';
12
- const NONE = Object.freeze({ kind: 'none' });
10
+ import { ensureWranglerDispatchNamespace, runWranglerDeploymentStatus, runWranglerDeploy, runWranglerDev, runWranglerReleaseDeploy, } from './build/wrangler-cli.js';
11
+ import { deployCloudflare } from './deploy/index.js';
12
+ import { signingIdentitySecrets } from './identity/secret.js';
13
+ import { signingIdentity } from './identity/source.js';
13
14
  const packageVersion = createRequire(import.meta.url)('../package.json')
14
15
  .version;
15
16
  export function cloudflare(environments) {
16
17
  return cloudflareWithDependencies(environments, {
17
18
  artifact,
18
19
  materialize,
20
+ ensureWranglerDispatchNamespace,
19
21
  runWranglerDeploy,
22
+ runWranglerReleaseDeploy,
20
23
  runWranglerDeploymentStatus,
21
24
  runWranglerDev,
22
- bulkPutSecrets,
23
25
  startFrontend,
26
+ signingIdentity,
24
27
  waitForReadiness: (release) => waitForReadiness(verifyReadiness, release),
25
28
  });
26
29
  }
@@ -31,6 +34,13 @@ export function cloudflareWithDependencies(environments, dependencies) {
31
34
  environments,
32
35
  prepare: dependencies.artifact,
33
36
  async watch(parameters, context) {
37
+ const identity = await dependencies.signingIdentity({
38
+ projectDir: context.projectDir,
39
+ source: parameters.signingIdentity,
40
+ origin: context.artifact.build.schema.compiled.root.origin,
41
+ mode: 'local',
42
+ });
43
+ const secrets = signingIdentitySecrets(context.secrets, identity);
34
44
  const directory = join(context.projectDir, '.astrale', 'runtime');
35
45
  await dependencies.materialize(directory, context.artifact.files);
36
46
  const frontend = await dependencies.startFrontend({
@@ -44,10 +54,10 @@ export function cloudflareWithDependencies(environments, dependencies) {
44
54
  workerName: name,
45
55
  vars: {
46
56
  ...parameters.vars,
47
- ...context.secrets,
48
57
  ...(parameters.host === undefined ? {} : { WORKER_URL: parameters.host }),
49
58
  ...(frontend === undefined ? {} : { FRONTEND_DEV_URL: frontend.url }),
50
59
  },
60
+ secretBindings: Object.keys(secrets).sort(),
51
61
  ...(context.artifact.build.frontend?.source.kind === 'vite'
52
62
  ? {
53
63
  frontend: {
@@ -70,6 +80,7 @@ export function cloudflareWithDependencies(environments, dependencies) {
70
80
  configPath,
71
81
  port: parameters.port ?? 8787,
72
82
  remote: parameters.remote ?? false,
83
+ secrets,
73
84
  autoPickPort: parameters.port === undefined,
74
85
  ...(parameters.host === undefined ? {} : { ip: '0.0.0.0' }),
75
86
  onReload: context.onReload,
@@ -96,185 +107,10 @@ export function cloudflareWithDependencies(environments, dependencies) {
96
107
  },
97
108
  });
98
109
  },
99
- async deploy(parameters, context) {
100
- const directory = join(context.projectDir, '.astrale', 'deploy');
101
- await dependencies.materialize(directory, context.artifact.files);
102
- const name = workerName(parameters, context.artifact.build.schema.compiled.root.origin);
103
- const configPath = join(directory, 'wrangler.jsonc');
104
- const fallbackConfigPath = join(directory, 'wrangler.no-self.jsonc');
105
- let deployed;
106
- try {
107
- deployed = await dependencies.runWranglerDeploy({
108
- projectDir: context.projectDir,
109
- configPath,
110
- fallbackConfigPath,
111
- workerName: name,
112
- ...(parameters.route === undefined ? {} : { route: parameters.route }),
113
- });
114
- }
115
- catch (cause) {
116
- const provider = cause instanceof WranglerDeployError && cause.applied !== undefined
117
- ? partialProvider(cause, context.artifact)
118
- : { kind: 'unknown' };
119
- return failed('provider', progress({ provider }), cause);
120
- }
121
- const submitted = Object.freeze({
122
- provider: 'cloudflare',
123
- deployment: deployed.deploymentVersion,
124
- artifact: context.artifact.digest,
125
- });
126
- let selected;
127
- try {
128
- selected = observeAddressing(context.artifact, deployed.url, name);
129
- }
130
- catch (cause) {
131
- return failed('addressing', progress({ provider: { kind: 'partial', evidence: submitted } }), cause);
132
- }
133
- let observed;
134
- try {
135
- observed = await dependencies.runWranglerDeploymentStatus({
136
- projectDir: context.projectDir,
137
- configPath,
138
- workerName: name,
139
- });
140
- requireCurrentDeployment(observed, deployed.deploymentVersion);
141
- }
142
- catch (cause) {
143
- return failed('readiness', progress({
144
- provider: {
145
- kind: 'partial',
146
- evidence: { ...submitted, issuer: selected.issuer },
147
- },
148
- }), cause);
149
- }
150
- let provider = Object.freeze({
151
- kind: 'applied',
152
- evidence: Object.freeze({
153
- provider: 'cloudflare',
154
- deployment: observed.deployment,
155
- artifact: context.artifact.digest,
156
- issuer: selected.issuer,
157
- }),
158
- });
159
- if (Object.keys(context.secrets).length > 0) {
160
- try {
161
- await dependencies.bulkPutSecrets({
162
- projectDir: context.projectDir,
163
- configPath,
164
- secrets: { ...context.secrets },
165
- });
166
- }
167
- catch (cause) {
168
- return failed('configuration', progress({ provider, configuration: { kind: 'unknown' } }), cause);
169
- }
170
- try {
171
- observed = await dependencies.runWranglerDeploymentStatus({
172
- projectDir: context.projectDir,
173
- configPath,
174
- workerName: name,
175
- });
176
- requireCurrentDeployment(observed);
177
- provider = Object.freeze({
178
- kind: 'applied',
179
- evidence: Object.freeze({
180
- provider: 'cloudflare',
181
- deployment: observed.deployment,
182
- artifact: context.artifact.digest,
183
- issuer: selected.issuer,
184
- }),
185
- });
186
- }
187
- catch (cause) {
188
- return failed('readiness', progress({
189
- provider,
190
- configuration: {
191
- kind: 'applied',
192
- evidence: { names: Object.keys(context.secrets).sort() },
193
- },
194
- }), cause);
195
- }
196
- }
197
- const configuration = Object.keys(context.secrets).length === 0
198
- ? NONE
199
- : Object.freeze({
200
- kind: 'applied',
201
- evidence: Object.freeze({ names: Object.keys(context.secrets).sort() }),
202
- });
203
- let release;
204
- try {
205
- release = assemble(context.artifact.build, selected);
206
- }
207
- catch (cause) {
208
- return failed('release', progress({ provider, configuration }), cause);
209
- }
210
- try {
211
- await dependencies.waitForReadiness(release);
212
- }
213
- catch (cause) {
214
- return failed('readiness', progress({ provider, configuration }), cause, release);
215
- }
216
- return Object.freeze({
217
- status: 'ready',
218
- phase: 'complete',
219
- progress: Object.freeze({ ...progress({ configuration }), provider }),
220
- release,
221
- });
222
- },
110
+ deploy: (parameters, context) => deployCloudflare(parameters, context, dependencies),
223
111
  secretsFile: (parameters) => parameters.secrets,
224
112
  });
225
113
  }
226
- function partialProvider(cause, artifact) {
227
- const applied = cause.applied;
228
- if (applied?.deploymentVersion === undefined)
229
- return Object.freeze({ kind: 'partial' });
230
- let issuer;
231
- if (applied.url !== undefined) {
232
- try {
233
- issuer = addressing(applied.url).issuer;
234
- }
235
- catch {
236
- // The provider effect is known even when its printed URL is not admissible Addressing.
237
- }
238
- }
239
- return Object.freeze({
240
- kind: 'partial',
241
- evidence: Object.freeze({
242
- provider: 'cloudflare',
243
- deployment: applied.deploymentVersion,
244
- artifact: artifact.digest,
245
- ...(issuer === undefined ? {} : { issuer }),
246
- }),
247
- });
248
- }
249
- function requireCurrentDeployment(observed, expectedVersion) {
250
- if (observed.versions.length !== 1 ||
251
- observed.versions[0].percentage !== 100 ||
252
- (expectedVersion !== undefined && observed.versions[0].version !== expectedVersion)) {
253
- throw new TypeError('Cloudflare current deployment is not one exact Worker version at 100%.');
254
- }
255
- }
256
- function observeAddressing(artifact, deployedUrl, expectedWorker) {
257
- const observed = addressing(deployedUrl);
258
- if (artifact.addressing.kind === 'configured') {
259
- if (observed.issuer !== artifact.addressing.addressing.issuer) {
260
- throw new TypeError('Cloudflare deployed URL differs from configured Addressing.');
261
- }
262
- return observed;
263
- }
264
- if (artifact.addressing.claim !== expectedWorker) {
265
- throw new TypeError('PreparedArtifact worker claim differs from the deployment target.');
266
- }
267
- const url = new URL(observed.issuer);
268
- const labels = url.hostname.split('.');
269
- if (url.protocol !== 'https:' ||
270
- labels.length < 4 ||
271
- labels[0] !== artifact.addressing.claim ||
272
- labels.at(-2) !== 'workers' ||
273
- labels.at(-1) !== 'dev') {
274
- throw new TypeError('Cloudflare workers.dev URL does not satisfy its prepared worker claim.');
275
- }
276
- return observed;
277
- }
278
114
  function frontendRoutes(artifact) {
279
115
  const frontend = artifact.build.frontend;
280
116
  if (frontend === undefined || frontend.source.kind !== 'vite')
@@ -287,24 +123,6 @@ function frontendRoutes(artifact) {
287
123
  : [route.path])
288
124
  .sort());
289
125
  }
290
- function progress(input) {
291
- return Object.freeze({
292
- prerequisite: input.prerequisite ?? NONE,
293
- provider: input.provider ?? NONE,
294
- configuration: input.configuration ?? NONE,
295
- installation: input.installation ?? NONE,
296
- });
297
- }
298
- function failed(phase, progressValue, cause, release) {
299
- const error = cause instanceof Error ? cause : new Error(String(cause));
300
- return Object.freeze({
301
- status: 'failed',
302
- phase,
303
- progress: progressValue,
304
- error,
305
- ...(release === undefined ? {} : { release }),
306
- });
307
- }
308
126
  export async function waitForReadiness(verify, release) {
309
127
  const deadline = Date.now() + 90_000;
310
128
  let last;
@@ -320,4 +138,3 @@ export async function waitForReadiness(verify, release) {
320
138
  }
321
139
  throw last instanceof Error ? last : new Error('Cloudflare Release did not become ready.');
322
140
  }
323
- //# sourceMappingURL=adapter.js.map
@@ -1,9 +1,8 @@
1
1
  import type { ArtifactSource, PrepareContext } from '@astrale-os/sdk/deployment/adapter';
2
2
  import type { CloudflareParams } from '../params.js';
3
- /** Prepare one self-contained Worker bundle without provider mutation. */
3
+ /** Prepare one revision Service and its stateless gateway without provider mutation. */
4
4
  export declare function artifact(params: CloudflareParams, context: PrepareContext): Promise<ArtifactSource>;
5
5
  export declare function materialize(root: string, files: readonly {
6
6
  readonly path: string;
7
7
  bytes(): Uint8Array;
8
8
  }[]): Promise<void>;
9
- //# sourceMappingURL=artifact.d.ts.map
@@ -1,28 +1,31 @@
1
1
  import { material } from '@astrale-os/sdk/deployment/build';
2
2
  import { addressing } from '@astrale-os/sdk/deployment/release';
3
- import { copyFile, readFile, writeFile, mkdir, rm } from 'node:fs/promises';
3
+ import { readFile, writeFile, mkdir, rm } from 'node:fs/promises';
4
4
  import { dirname, join, relative, resolve } from 'node:path';
5
5
  import { pathToFileURL } from 'node:url';
6
+ import { SIGNING_IDENTITY_BINDING } from '../identity/binding.js';
7
+ import { releaseNamespace, releaseWorkerName } from '../release/index.js';
6
8
  import { generateExecutionEntry } from './codegen/execution.js';
7
- import { ensureIdentity } from './codegen/identity.js';
9
+ import { generateGatewayEntry } from './codegen/gateway.js';
8
10
  import { generateWranglerConfig } from './codegen/wrangler.js';
9
- import { resolveRouter, workerName } from './configuration.js';
11
+ import { deploymentAddressing, resolveRouter, workerName } from './configuration.js';
10
12
  import { frontendFiles } from './frontend-v1.js';
11
13
  import { qualifyWorkerBundle } from './qualification.js';
12
14
  import { runWranglerBundle } from './wrangler-cli.js';
13
15
  const encoder = new TextEncoder();
14
- /** Prepare one self-contained Worker bundle without provider mutation. */
16
+ /** Prepare one revision Service and its stateless gateway without provider mutation. */
15
17
  export async function artifact(params, context) {
16
18
  const stateDirectory = join(context.projectDir, '.astrale');
17
19
  const directory = join(stateDirectory, 'runtime');
18
20
  await mkdir(directory, { recursive: true });
19
- await ensureIdentity(stateDirectory, context.build.schema.compiled.root.origin);
20
- await copyFile(join(stateDirectory, 'identity.ts'), join(directory, 'identity.ts'));
21
21
  const runtimePath = resolve(context.projectDir, context.runtime.reference.path);
22
22
  const runtimeSpecifier = moduleSpecifier(relative(directory, runtimePath));
23
23
  const router = resolveRouter(params.router);
24
24
  const name = workerName(params, context.build.schema.compiled.root.origin);
25
- const configuredIssuer = params.route === undefined ? params.host : `https://${params.route}`;
25
+ const revision = context.build.schema.compiled.root.revision;
26
+ const namespace = releaseNamespace(name);
27
+ const target = releaseWorkerName(revision);
28
+ const configuredIssuer = deploymentAddressing(params);
26
29
  const source = generateExecutionEntry({
27
30
  origin: context.build.schema.compiled.root.origin,
28
31
  runtimeSpecifier,
@@ -48,11 +51,12 @@ export async function artifact(params, context) {
48
51
  ...params.vars,
49
52
  ...(configuredIssuer === undefined ? {} : { WORKER_URL: configuredIssuer }),
50
53
  },
54
+ secretBindings: [SIGNING_IDENTITY_BINDING],
51
55
  ...(router === undefined
52
56
  ? {}
53
57
  : { router: { binding: router.binding, service: router.service } }),
54
58
  ...(params.wrangler === undefined ? {} : { wrangler: params.wrangler }),
55
- selfBinding: true,
59
+ selfBinding: false,
56
60
  }));
57
61
  const output = join(directory, 'dist-prepare');
58
62
  await rm(output, { recursive: true, force: true });
@@ -71,14 +75,37 @@ export async function artifact(params, context) {
71
75
  });
72
76
  await admitBundle(emitted.bundlePath);
73
77
  const bundle = await readFile(emitted.bundlePath);
74
- const deploymentConfig = (selfBinding) => generateWranglerConfig({
78
+ const gatewaySource = join(directory, 'gateway.gen.ts');
79
+ await writeFile(gatewaySource, generateGatewayEntry(revision));
80
+ const gatewayPrepareConfig = join(directory, 'wrangler.gateway.prepare.jsonc');
81
+ await writeFile(gatewayPrepareConfig, generateWranglerConfig({
75
82
  workerName: name,
76
- main: './bundle/index.mjs',
83
+ main: './gateway.gen.ts',
77
84
  ...(params.route === undefined ? {} : { route: params.route }),
85
+ releases: { binding: 'RELEASES', namespace },
86
+ selfBinding: false,
87
+ }));
88
+ const gatewayOutput = join(directory, 'dist-gateway');
89
+ await rm(gatewayOutput, { recursive: true, force: true });
90
+ const gateway = await runWranglerBundle({
91
+ projectDir: context.projectDir,
92
+ configPath: gatewayPrepareConfig,
93
+ outDir: gatewayOutput,
94
+ });
95
+ await qualifyWorkerBundle({
96
+ metafilePath: gateway.metafilePath,
97
+ inputRoot: dirname(gatewayPrepareConfig),
98
+ });
99
+ await admitBundle(gateway.bundlePath);
100
+ const gatewayBundle = await readFile(gateway.bundlePath);
101
+ const releaseConfig = generateWranglerConfig({
102
+ workerName: target,
103
+ main: './bundle/index.mjs',
78
104
  vars: {
79
105
  ...params.vars,
80
106
  ...(configuredIssuer === undefined ? {} : { WORKER_URL: configuredIssuer }),
81
107
  },
108
+ secretBindings: [SIGNING_IDENTITY_BINDING],
82
109
  ...(context.build.frontend?.source.kind === 'vite'
83
110
  ? {
84
111
  frontend: {
@@ -92,12 +119,20 @@ export async function artifact(params, context) {
92
119
  ? {}
93
120
  : { router: { binding: router.binding, service: router.service } }),
94
121
  ...(params.wrangler === undefined ? {} : { wrangler: params.wrangler }),
95
- selfBinding,
122
+ selfBinding: false,
123
+ });
124
+ const gatewayConfig = generateWranglerConfig({
125
+ workerName: name,
126
+ main: './gateway/index.mjs',
127
+ ...(params.route === undefined ? {} : { route: params.route }),
128
+ releases: { binding: 'RELEASES', namespace },
129
+ selfBinding: false,
96
130
  });
97
131
  const files = [
98
- { path: 'wrangler.jsonc', content: encoder.encode(deploymentConfig(true)) },
99
- { path: 'wrangler.no-self.jsonc', content: encoder.encode(deploymentConfig(false)) },
132
+ { path: 'wrangler.release.jsonc', content: encoder.encode(releaseConfig) },
133
+ { path: 'wrangler.gateway.jsonc', content: encoder.encode(gatewayConfig) },
100
134
  { path: 'bundle/index.mjs', content: new Uint8Array(bundle) },
135
+ { path: 'gateway/index.mjs', content: new Uint8Array(gatewayBundle) },
101
136
  ...frontend.map((file) => ({
102
137
  path: `frontend/${file.path}`,
103
138
  content: file.bytes(),
@@ -142,4 +177,3 @@ function moduleSpecifier(input) {
142
177
  const normalized = input.split('\\').join('/');
143
178
  return normalized.startsWith('.') ? normalized : `./${normalized}`;
144
179
  }
145
- //# sourceMappingURL=artifact.js.map
@@ -1,3 +1,2 @@
1
1
  /** Prove emitted Worker reachability excludes authoring, compilation, and broad Core Schema owners. */
2
2
  export declare function assertRuntimeClosure(metafilePath: string): Promise<void>;
3
- //# sourceMappingURL=closure.d.ts.map
@@ -20,4 +20,3 @@ export async function assertRuntimeClosure(metafilePath) {
20
20
  throw new Error(`Cloudflare Worker reaches build-side modules: ${forbidden.sort().join(', ')}.`);
21
21
  }
22
22
  }
23
- //# sourceMappingURL=closure.js.map
@@ -11,4 +11,3 @@ export interface ExecutionCodegenOptions {
11
11
  };
12
12
  }
13
13
  export declare function generateExecutionEntry(options: ExecutionCodegenOptions): string;
14
- //# sourceMappingURL=execution.d.ts.map
@@ -23,19 +23,22 @@ import type { CloudflareAdapterBindings } from '@astrale-os/adapter-cloudflare/w
23
23
 
24
24
  import { cloudflareWorkerEntry } from '@astrale-os/adapter-cloudflare/worker'
25
25
  import runtime from ${JSON.stringify(options.runtimeSpecifier)}
26
- import { PRIVATE_JWK } from './identity.js'
26
+ import { decodeSigningIdentity, runtimeBindings } from '@astrale-os/adapter-cloudflare/worker'
27
27
 
28
- type WorkerEnv = CloudflareEnv & CloudflareAdapterBindings
28
+ type WorkerEnv = CloudflareEnv & CloudflareAdapterBindings & {
29
+ readonly ASTRALE_SIGNING_IDENTITY: string
30
+ }
31
+ type RuntimeEnv = Omit<WorkerEnv, 'ASTRALE_SIGNING_IDENTITY'>
29
32
  const MATERIAL = ${JSON.stringify(options.material)} as const satisfies BuildMaterial
30
33
  ${routerPredicate}
31
- export default cloudflareWorkerEntry<WorkerEnv>()({
34
+ export default cloudflareWorkerEntry<WorkerEnv, RuntimeEnv>()({
32
35
  runtime,
33
36
  material: MATERIAL,
34
- privateKey: PRIVATE_JWK,
37
+ privateKey: (env) => decodeSigningIdentity(env.ASTRALE_SIGNING_IDENTITY),
38
+ resolveEnvironment: runtimeBindings,
35
39
  resolveUrl: (env, requestOrigin) => env.WORKER_URL ?? env.IDENTITY_ISS ?? requestOrigin,
36
40
  ${options.providerAssignedWorker === undefined ? '' : `providerAssignedWorker: ${JSON.stringify(options.providerAssignedWorker)},`}
37
41
  selfBinding: (env) => env.SELF,${routeSubrequest}
38
42
  })
39
43
  `;
40
44
  }
41
- //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ export declare function generateGatewayEntry(revision: string): string;
@@ -0,0 +1,7 @@
1
+ export function generateGatewayEntry(revision) {
2
+ return `// AUTO-GENERATED by @astrale-os/adapter-cloudflare — do not edit.
3
+ import { cloudflareGatewayEntry } from '@astrale-os/adapter-cloudflare/worker'
4
+
5
+ export default cloudflareGatewayEntry({ current: ${JSON.stringify(revision)} })
6
+ `;
7
+ }
@@ -17,4 +17,3 @@
17
17
  * the caller (`generateWranglerConfig`), not here — this stays a generic merge.
18
18
  */
19
19
  export declare function deepMergeConfig(base: Record<string, unknown>, overlay: Record<string, unknown>): Record<string, unknown>;
20
- //# sourceMappingURL=merge.d.ts.map
@@ -88,4 +88,3 @@ function isPlainObject(v) {
88
88
  function isPrimitive(v) {
89
89
  return v === null || (typeof v !== 'object' && typeof v !== 'function');
90
90
  }
91
- //# sourceMappingURL=merge.js.map
@@ -25,8 +25,15 @@ export interface WranglerCodegenOptions {
25
25
  };
26
26
  /** Plain (non-secret) vars to bake in. */
27
27
  vars?: Record<string, string>;
28
+ /** Secret binding names required by generated Worker code. */
29
+ secretBindings?: readonly string[];
28
30
  /** Add the SELF service binding (autobinding). */
29
31
  selfBinding: boolean;
32
+ /** Bind the stable gateway to its private revision namespace. */
33
+ releases?: {
34
+ readonly binding: string;
35
+ readonly namespace: string;
36
+ };
30
37
  /**
31
38
  * Add a service binding to a router Worker for instance-host subrequest
32
39
  * routing (see `CloudflareParams.router`). Pairs with the worker
@@ -46,4 +53,3 @@ export interface WranglerCodegenOptions {
46
53
  wrangler?: Record<string, unknown>;
47
54
  }
48
55
  export declare function generateWranglerConfig(opts: WranglerCodegenOptions): string;
49
- //# sourceMappingURL=wrangler.d.ts.map
@@ -57,6 +57,12 @@ export function generateWranglerConfig(opts) {
57
57
  if (opts.vars && Object.keys(opts.vars).length > 0) {
58
58
  config.vars = opts.vars;
59
59
  }
60
+ if (opts.secretBindings && opts.secretBindings.length > 0) {
61
+ config.secrets = { required: [...opts.secretBindings] };
62
+ }
63
+ if (opts.releases !== undefined) {
64
+ config.dispatch_namespaces = [opts.releases];
65
+ }
60
66
  const merged = opts.wrangler ? mergeUserConfig(config, opts.wrangler) : config;
61
67
  return JSON.stringify(merged, null, 2) + '\n';
62
68
  }
@@ -68,6 +74,7 @@ const ADAPTER_OWNED_KEYS = [
68
74
  'routes',
69
75
  'compatibility_date',
70
76
  'version_metadata',
77
+ 'secrets',
71
78
  ];
72
79
  /**
73
80
  * Deep-merge the dev's raw wrangler overlay over the generated config, after
@@ -83,4 +90,3 @@ function mergeUserConfig(base, user) {
83
90
  }
84
91
  return deepMergeConfig(base, user);
85
92
  }
86
- //# sourceMappingURL=wrangler.js.map
@@ -1,4 +1,5 @@
1
1
  import type { CloudflareParams } from '../params.js';
2
+ export declare function deploymentAddressing(parameters: CloudflareParams): string | undefined;
2
3
  export declare function workerName(parameters: CloudflareParams, origin: string): string;
3
4
  export declare function resolveRouter(input: CloudflareParams['router']): {
4
5
  readonly binding: string;
@@ -6,4 +7,3 @@ export declare function resolveRouter(input: CloudflareParams['router']): {
6
7
  readonly hostSuffix: string;
7
8
  readonly minLabels: number;
8
9
  } | undefined;
9
- //# sourceMappingURL=configuration.d.ts.map
@@ -1,4 +1,16 @@
1
- const WORKER_NAME = /^[a-z0-9][a-z0-9-]*$/u;
1
+ import { addressing } from '@astrale-os/sdk/deployment/release';
2
+ import { createHash } from 'node:crypto';
3
+ const WORKER_NAME = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u;
4
+ export function deploymentAddressing(parameters) {
5
+ const routed = parameters.route === undefined ? undefined : addressing(`https://${parameters.route}`).issuer;
6
+ if (parameters.addressing === undefined)
7
+ return routed;
8
+ const configured = addressing(parameters.addressing).issuer;
9
+ if (routed !== undefined && configured !== routed) {
10
+ throw new TypeError('Cloudflare route and addressing identify different origins.');
11
+ }
12
+ return configured;
13
+ }
2
14
  export function workerName(parameters, origin) {
3
15
  if (parameters.workerName !== undefined) {
4
16
  if (!WORKER_NAME.test(parameters.workerName) || parameters.workerName.length > 63) {
@@ -6,11 +18,14 @@ export function workerName(parameters, origin) {
6
18
  }
7
19
  return parameters.workerName;
8
20
  }
9
- return origin
21
+ const readable = origin
10
22
  .toLowerCase()
11
23
  .replace(/[^a-z0-9]+/gu, '-')
12
- .slice(0, 54)
13
- .replace(/^-+|-+$/gu, '');
24
+ .slice(0, 12)
25
+ .replace(/^-+|-+$/gu, '') || 'domain';
26
+ const hexadecimal = createHash('sha256').update(origin).digest('hex');
27
+ const identity = BigInt(`0x${hexadecimal}`).toString(36).padStart(50, '0');
28
+ return `${readable}-${identity}`;
14
29
  }
15
30
  export function resolveRouter(input) {
16
31
  if (input === false)
@@ -23,4 +38,3 @@ export function resolveRouter(input) {
23
38
  minLabels: value.minLabels ?? 4,
24
39
  });
25
40
  }
26
- //# sourceMappingURL=configuration.js.map
@@ -14,4 +14,3 @@ export declare function startFrontend(input: {
14
14
  readonly projectDir: string;
15
15
  readonly onLog?: (line: string) => void;
16
16
  }): Promise<FrontendDevHandle | undefined>;
17
- //# sourceMappingURL=frontend-v1.d.ts.map
@@ -131,4 +131,3 @@ function stop(child) {
131
131
  child.kill('SIGTERM');
132
132
  });
133
133
  }
134
- //# sourceMappingURL=frontend-v1.js.map
@@ -3,5 +3,6 @@ export { resolveRouter, workerName } from './configuration.js';
3
3
  export { frontendFiles, startFrontend, type FrontendDevHandle } from './frontend-v1.js';
4
4
  export { qualifyWorkerBundle } from './qualification.js';
5
5
  export { assertSingletonRuntimeRoots } from './roots.js';
6
- export { bulkPutSecrets, runWranglerBundle, runWranglerDeploy, runWranglerDeploymentStatus, runWranglerDev, runWranglerTypes, } from './wrangler-cli.js';
7
- //# sourceMappingURL=index.d.ts.map
6
+ export { signingIdentity } from '../identity/source.js';
7
+ export { signingIdentitySecrets } from '../identity/secret.js';
8
+ export { runWranglerBundle, runWranglerDeploy, runWranglerDeploymentStatus, runWranglerDev, runWranglerTypes, } from './wrangler-cli.js';