@astrale-os/adapter-cloudflare 0.5.0-beta.165 → 0.5.0-beta.167
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 +29 -5
- package/dist/adapter.d.ts +5 -4
- package/dist/adapter.js +2 -0
- package/dist/build/artifact.js +132 -149
- package/dist/build/bundler.d.ts +21 -0
- package/dist/build/bundler.js +96 -0
- package/dist/build/frontend/readiness.d.ts +2 -2
- package/dist/build/index.d.ts +2 -0
- package/dist/build/index.js +2 -0
- package/dist/build/worker/execution.prepare.d.ts +3 -3
- 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 +8 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- 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/entry.js +2 -2
- package/dist/worker/frontend.d.ts +1 -1
- package/dist/worker/frontend.js +1 -1
- package/package.json +3 -3
- package/template/astrale.config.ts +2 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ must emit the same JavaScript bytes. `cloudflare({ wrangler: { minify: false } }
|
|
|
23
23
|
One watcher serializes its own updates. For an existing Worker, it uploads a candidate, reconciles
|
|
24
24
|
configured triggers, and stages the candidate at 0% while the previous version retains 100% of normal
|
|
25
25
|
HTTP traffic. Exact-version probes verify Publication, Bundle, and serving identity before promotion;
|
|
26
|
-
serving the Publication also initializes the
|
|
26
|
+
serving the Publication also initializes the Domain Runtime. After promotion, normal requests
|
|
27
27
|
must prove that exact version again. A failed candidate remains at 0% and can be replaced on retry.
|
|
28
28
|
Bundled View routes must also serve the prepared browser-file generation before readiness passes.
|
|
29
29
|
This covers frontend-only changes without changing the Schema or reinstalling the Domain. HTML is
|
|
@@ -44,7 +44,7 @@ protects the HTTP implementation, not an atomic rollback of external resources o
|
|
|
44
44
|
When an Environment also declares `installation`, the SDK excludes another local checkout that
|
|
45
45
|
targets the same resolved `Kernel issuer + Domain origin` (including bookmark aliases), reconciles
|
|
46
46
|
exact installed Release evidence, and opens
|
|
47
|
-
the default View when the
|
|
47
|
+
the default View when the Domain has a frontend. These are Project-tooling behaviors rather
|
|
48
48
|
than Cloudflare adapter responsibilities.
|
|
49
49
|
|
|
50
50
|
## Frontend files
|
|
@@ -108,6 +108,30 @@ an overlay key the bundler reads (`alias`, `build`, `define`, `jsx_factory`, `js
|
|
|
108
108
|
`upload_source_maps`) and a compatibility flag it reads (Node.js, `navigator`, fetch iterable
|
|
109
109
|
typing, Python) beyond the adapter's own `nodejs_compat`.
|
|
110
110
|
|
|
111
|
+
## Build digest
|
|
112
|
+
|
|
113
|
+
`cloudflare()` and `astrale()` bundle through one bundler, `cloudflare-worker` version `1`, so
|
|
114
|
+
every Environment of either adapter shares one build: `astrale-domain build` prints its build
|
|
115
|
+
digest, and `deploy` places that same Bundle. Two installed versions of this package are two
|
|
116
|
+
copies of the bundler: when their code differs, `build` prints one build digest per copy and warns
|
|
117
|
+
until the adapter versions are aligned.
|
|
118
|
+
|
|
119
|
+
Services receives the placed modules as they are, so there the digest names the bytes the
|
|
120
|
+
deployment runs. Direct mode runs `wrangler deploy`, which bundles the placed modules again: there
|
|
121
|
+
the digest names the portable Worker the deployment was made from, not the bytes Cloudflare runs.
|
|
122
|
+
A host that receives a Worker upload recomputes the digest from the exact upload with the same
|
|
123
|
+
function:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { workerBuildManifest } from '@astrale-os/adapter-cloudflare/release'
|
|
127
|
+
import { buildDigest } from '@astrale-os/sdk/deployment/build/manifest'
|
|
128
|
+
|
|
129
|
+
const digest = buildDigest(workerBuildManifest({ origin, revision, bundle, entry, modules, assets }))
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Modules keep their uploaded name and an asset `/<path>` is the file `assets/<path>`. The bundler
|
|
133
|
+
version names this layout, not a package release. Both subpaths are runtime-safe.
|
|
134
|
+
|
|
111
135
|
## Material for a custom Worker entrypoint
|
|
112
136
|
|
|
113
137
|
Workers with provider-specific routes or environment initialization can reuse the adapter's
|
|
@@ -117,19 +141,19 @@ material emission without adopting the entire generated entrypoint:
|
|
|
117
141
|
import { generateBuildMaterialModule } from '@astrale-os/adapter-cloudflare/build'
|
|
118
142
|
import { writeFile } from 'node:fs/promises'
|
|
119
143
|
|
|
120
|
-
// build is an admitted Build returned by compile(
|
|
144
|
+
// build is an admitted Build returned by compile(domain).
|
|
121
145
|
await writeFile('src/build-material.gen.ts', generateBuildMaterialModule(build))
|
|
122
146
|
```
|
|
123
147
|
|
|
124
148
|
The generated TypeScript module exports `loadBuildMaterial()`. Call it from the
|
|
125
|
-
`load` callback of `generatedCloudflareWorkerEntry` alongside the
|
|
149
|
+
`load` callback of `generatedCloudflareWorkerEntry` alongside the Domain's Runtime.
|
|
126
150
|
Such an entrypoint states its execution settings (`invocationTimeoutMs`, `maximumRequestBytes`,
|
|
127
151
|
`tokenExchange`, `routeSubrequest`, `identityIssuer`) in its configuration, or reads them from its
|
|
128
152
|
deployment bindings with `settings: deploymentSettings`; one Worker never takes both.
|
|
129
153
|
It constructs the same verified, deduplicated material as the adapter's generated Service;
|
|
130
154
|
allocation is deferred until the factory is called and the SDK deep-freezes it before use.
|
|
131
155
|
The generated file needs only a type import from the SDK. Keep its compiler and runtime SDK
|
|
132
|
-
versions aligned, and regenerate it when either the
|
|
156
|
+
versions aligned, and regenerate it when either the Domain or that SDK version changes.
|
|
133
157
|
|
|
134
158
|
Such an entrypoint can keep the same fast frontend path by answering from
|
|
135
159
|
`cloudflareFrontDoor()` (`@astrale-os/adapter-cloudflare/worker/front`, which reaches no SDK
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Deployment } from '@astrale-os/sdk/deployment';
|
|
2
|
-
import type {
|
|
2
|
+
import type { LegacyAdapter } from '@astrale-os/sdk/deployment/adapter';
|
|
3
|
+
import type { legacy } from '@astrale-os/sdk/deployment/release';
|
|
3
4
|
import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
|
|
4
5
|
import type { CloudflareParams } from './params.js';
|
|
5
6
|
import { artifact } from './build/artifact.js';
|
|
@@ -9,6 +10,6 @@ export interface CloudflareDependencies extends CloudflareDeployDependencies {
|
|
|
9
10
|
readonly artifact: typeof artifact;
|
|
10
11
|
readonly signingIdentity: typeof signingIdentity;
|
|
11
12
|
}
|
|
12
|
-
export declare function cloudflare(parameters?: CloudflareParams): Deployment<CloudflareParams
|
|
13
|
-
export declare function cloudflareWithDependencies(parameters: CloudflareParams, dependencies: CloudflareDependencies): Deployment<CloudflareParams
|
|
14
|
-
export declare function waitForReadiness(verify: typeof verifyReadiness, release: Release, signal?: AbortSignal): Promise<void>;
|
|
13
|
+
export declare function cloudflare(parameters?: CloudflareParams): Deployment<CloudflareParams, LegacyAdapter<CloudflareParams>>;
|
|
14
|
+
export declare function cloudflareWithDependencies(parameters: CloudflareParams, dependencies: CloudflareDependencies): Deployment<CloudflareParams, LegacyAdapter<CloudflareParams>>;
|
|
15
|
+
export declare function waitForReadiness(verify: typeof verifyReadiness, release: legacy.Release, signal?: AbortSignal): Promise<void>;
|
package/dist/adapter.js
CHANGED
|
@@ -2,6 +2,7 @@ import { defineAdapter, defineDeployment } from '@astrale-os/sdk/deployment/adap
|
|
|
2
2
|
import { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { artifact, materialize } from './build/artifact.js';
|
|
5
|
+
import { cloudflareWorkerBundler } from './build/bundler.js';
|
|
5
6
|
import { verifyWorkerFrontend } from './build/frontend/readiness.js';
|
|
6
7
|
import { deployCloudflare } from './deploy/index.js';
|
|
7
8
|
import { versionReadinessFetch } from './deploy/readiness.js';
|
|
@@ -31,6 +32,7 @@ export function cloudflareWithDependencies(parameters, dependencies) {
|
|
|
31
32
|
const adapter = defineAdapter({
|
|
32
33
|
name: 'cloudflare',
|
|
33
34
|
version: packageVersion,
|
|
35
|
+
bundler: cloudflareWorkerBundler,
|
|
34
36
|
prepare: dependencies.artifact,
|
|
35
37
|
deploy: (parameters, context) => deployCloudflare(parameters, context, dependencies),
|
|
36
38
|
secretsFile: (parameters) => parameters.secrets,
|
package/dist/build/artifact.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { addressing } from '@astrale-os/sdk/deployment/release';
|
|
2
|
-
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
2
|
import { SIGNING_IDENTITY_BINDING } from '../identity/binding.js';
|
|
5
3
|
import { workerDeployment } from '../release/index.js';
|
|
4
|
+
import { bundledWorker, bundleWorker } from './bundler.js';
|
|
6
5
|
import { generateWranglerConfig } from './codegen/wrangler.js';
|
|
7
6
|
import { deploymentAddressing, deploymentVars, resolveRouter, workerName } from './configuration.js';
|
|
8
|
-
import { frontendFiles } from './frontend/files.js';
|
|
9
|
-
import { frontendRevision } from './frontend/revision.js';
|
|
10
7
|
import { encodeWorkerArtifactManifest, inferMediaType, workerContentDigest, WORKER_MANIFEST_PATH, } from './worker/artifact.manifest.js';
|
|
11
|
-
import {
|
|
8
|
+
import { RELEASE_ENTRY } from './worker/execution.prepare.js';
|
|
12
9
|
import { workerModules } from './worker/modules.js';
|
|
13
10
|
import { admitWorkerRuntimeConfiguration } from './worker/runtime.js';
|
|
11
|
+
import { recordPlacedBundle } from './worker/upload.js';
|
|
14
12
|
export { materialize } from './materialize.js';
|
|
15
13
|
const encoder = new TextEncoder();
|
|
16
14
|
/** Prepare one portable Worker whose public provider address remains stable across builds. */
|
|
@@ -22,151 +20,136 @@ export async function prepareWorkerArtifact(params, context) {
|
|
|
22
20
|
return prepare(params, context, false);
|
|
23
21
|
}
|
|
24
22
|
async function prepare(params, context, direct) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
const manifest = encodeWorkerArtifactManifest({
|
|
108
|
-
origin: context.build.schema.compiled.root.origin,
|
|
109
|
-
revision,
|
|
110
|
-
deployment,
|
|
111
|
-
release: {
|
|
112
|
-
entrypoint: release.entrypoint,
|
|
113
|
-
modules: release.modules.map(({ path, kind, content }) => ({
|
|
114
|
-
path,
|
|
115
|
-
kind,
|
|
116
|
-
digest: workerContentDigest(content),
|
|
117
|
-
})),
|
|
118
|
-
},
|
|
119
|
-
runtime: {
|
|
120
|
-
compatibilityDate: runtime.compatibilityDate,
|
|
121
|
-
compatibilityFlags: runtime.compatibilityFlags,
|
|
122
|
-
},
|
|
123
|
-
bindings: {
|
|
124
|
-
vars: runtime.vars,
|
|
125
|
-
services: runtime.services,
|
|
126
|
-
requiredSecrets: [SIGNING_IDENTITY_BINDING],
|
|
127
|
-
},
|
|
128
|
-
...(frontend.length === 0
|
|
129
|
-
? {}
|
|
130
|
-
: {
|
|
131
|
-
assets: {
|
|
132
|
-
files: frontend.map((file) => {
|
|
133
|
-
const contentType = file.mediaType ?? inferMediaType(file.path);
|
|
134
|
-
return {
|
|
135
|
-
path: `/${file.path}`,
|
|
136
|
-
artifactPath: `frontend/${file.path}`,
|
|
137
|
-
digest: workerContentDigest(file.bytes()),
|
|
138
|
-
...(contentType === undefined ? {} : { contentType }),
|
|
139
|
-
};
|
|
140
|
-
}),
|
|
141
|
-
notFound: 'none',
|
|
142
|
-
runWorkerFirst: true,
|
|
143
|
-
htmlHandling: 'none',
|
|
144
|
-
},
|
|
145
|
-
}),
|
|
146
|
-
});
|
|
147
|
-
const files = [
|
|
148
|
-
...release.modules.map(({ path, content }) => ({ path, content })),
|
|
149
|
-
{ path: WORKER_MANIFEST_PATH, content: manifest },
|
|
150
|
-
...frontend.map((file) => ({
|
|
151
|
-
path: `frontend/${file.path}`,
|
|
152
|
-
content: file.bytes(),
|
|
23
|
+
const router = resolveRouter(params.router);
|
|
24
|
+
const name = workerName(params, context.build.schema.compiled.root.origin, context.environment);
|
|
25
|
+
const revision = context.build.schema.compiled.root.revision;
|
|
26
|
+
const configuredIssuer = deploymentAddressing(params);
|
|
27
|
+
// The Environment enters only as the deployment's bindings, never the bundled bytes.
|
|
28
|
+
const vars = deploymentVars(params, {
|
|
29
|
+
...(configuredIssuer === undefined ? {} : { configuredIssuer }),
|
|
30
|
+
...(direct && configuredIssuer === undefined ? { providerAssignedWorker: name } : {}),
|
|
31
|
+
});
|
|
32
|
+
// Preparation places the environment-free Worker bytes: the Bundle `deploy` already produced
|
|
33
|
+
// with this adapter's bundler, or the same bundling run here.
|
|
34
|
+
const worker = context.bundle === undefined
|
|
35
|
+
? await bundleWorker(context)
|
|
36
|
+
: bundledWorker(context.bundle, context.build);
|
|
37
|
+
if (context.bundle !== undefined)
|
|
38
|
+
recordPlacedBundle(context.build);
|
|
39
|
+
const { frontend } = worker;
|
|
40
|
+
const release = {
|
|
41
|
+
entrypoint: RELEASE_ENTRY,
|
|
42
|
+
modules: [
|
|
43
|
+
{ path: RELEASE_ENTRY, kind: 'esm', content: worker.entry },
|
|
44
|
+
...worker.modules,
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
const releaseConfig = generateWranglerConfig({
|
|
48
|
+
workerName: name,
|
|
49
|
+
main: `./${RELEASE_ENTRY}`,
|
|
50
|
+
...(params.route === undefined ? {} : { route: params.route }),
|
|
51
|
+
vars,
|
|
52
|
+
secretBindings: [SIGNING_IDENTITY_BINDING],
|
|
53
|
+
modules: workerModules(release),
|
|
54
|
+
...(context.build.frontend?.source.kind === 'vite'
|
|
55
|
+
? {
|
|
56
|
+
frontend: {
|
|
57
|
+
directory: './frontend',
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
61
|
+
...(router === undefined
|
|
62
|
+
? {}
|
|
63
|
+
: { router: { binding: router.binding, service: router.service } }),
|
|
64
|
+
...(params.wrangler === undefined ? {} : { wrangler: params.wrangler }),
|
|
65
|
+
selfBinding: false,
|
|
66
|
+
});
|
|
67
|
+
const runtime = admitWorkerRuntimeConfiguration(releaseConfig);
|
|
68
|
+
const deployment = workerDeployment({
|
|
69
|
+
release,
|
|
70
|
+
runtime,
|
|
71
|
+
bindings: {
|
|
72
|
+
vars: runtime.vars,
|
|
73
|
+
services: runtime.services,
|
|
74
|
+
requiredSecrets: [SIGNING_IDENTITY_BINDING],
|
|
75
|
+
},
|
|
76
|
+
...(frontend.length === 0
|
|
77
|
+
? {}
|
|
78
|
+
: {
|
|
79
|
+
assets: {
|
|
80
|
+
files: frontend.map((file) => {
|
|
81
|
+
const contentType = file.mediaType ?? inferMediaType(file.path);
|
|
82
|
+
return {
|
|
83
|
+
path: `/${file.path}`,
|
|
84
|
+
content: file.bytes(),
|
|
85
|
+
...(contentType === undefined ? {} : { contentType }),
|
|
86
|
+
};
|
|
87
|
+
}),
|
|
88
|
+
notFound: 'none',
|
|
89
|
+
runWorkerFirst: true,
|
|
90
|
+
htmlHandling: 'none',
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
const manifest = encodeWorkerArtifactManifest({
|
|
95
|
+
origin: context.build.schema.compiled.root.origin,
|
|
96
|
+
revision,
|
|
97
|
+
deployment,
|
|
98
|
+
release: {
|
|
99
|
+
entrypoint: release.entrypoint,
|
|
100
|
+
modules: release.modules.map(({ path, kind, content }) => ({
|
|
101
|
+
path,
|
|
102
|
+
kind,
|
|
103
|
+
digest: workerContentDigest(content),
|
|
153
104
|
})),
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
105
|
+
},
|
|
106
|
+
runtime: {
|
|
107
|
+
compatibilityDate: runtime.compatibilityDate,
|
|
108
|
+
compatibilityFlags: runtime.compatibilityFlags,
|
|
109
|
+
},
|
|
110
|
+
bindings: {
|
|
111
|
+
vars: runtime.vars,
|
|
112
|
+
services: runtime.services,
|
|
113
|
+
requiredSecrets: [SIGNING_IDENTITY_BINDING],
|
|
114
|
+
},
|
|
115
|
+
...(frontend.length === 0
|
|
116
|
+
? {}
|
|
117
|
+
: {
|
|
118
|
+
assets: {
|
|
119
|
+
files: frontend.map((file) => {
|
|
120
|
+
const contentType = file.mediaType ?? inferMediaType(file.path);
|
|
121
|
+
return {
|
|
122
|
+
path: `/${file.path}`,
|
|
123
|
+
artifactPath: `frontend/${file.path}`,
|
|
124
|
+
digest: workerContentDigest(file.bytes()),
|
|
125
|
+
...(contentType === undefined ? {} : { contentType }),
|
|
126
|
+
};
|
|
165
127
|
}),
|
|
128
|
+
notFound: 'none',
|
|
129
|
+
runWorkerFirst: true,
|
|
130
|
+
htmlHandling: 'none',
|
|
131
|
+
},
|
|
132
|
+
}),
|
|
133
|
+
});
|
|
134
|
+
const files = [
|
|
135
|
+
...release.modules.map(({ path, content }) => ({ path, content })),
|
|
136
|
+
{ path: WORKER_MANIFEST_PATH, content: manifest },
|
|
137
|
+
...frontend.map((file) => ({
|
|
138
|
+
path: `frontend/${file.path}`,
|
|
139
|
+
content: file.bytes(),
|
|
140
|
+
})),
|
|
141
|
+
...(direct ? [{ path: 'wrangler.jsonc', content: encoder.encode(releaseConfig) }] : []),
|
|
142
|
+
];
|
|
143
|
+
return Object.freeze({
|
|
144
|
+
entrypoint: RELEASE_ENTRY,
|
|
145
|
+
files: Object.freeze(files),
|
|
146
|
+
addressing: configuredIssuer === undefined
|
|
147
|
+
? Object.freeze({ kind: 'provider-assigned', claim: name })
|
|
148
|
+
: Object.freeze({
|
|
149
|
+
kind: 'configured',
|
|
150
|
+
addressing: addressing(params.identityIssuer ?? configuredIssuer, {
|
|
151
|
+
publicUrl: configuredIssuer,
|
|
166
152
|
}),
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
await rm(directory, { recursive: true, force: true });
|
|
171
|
-
}
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
172
155
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Bundle, BundleContext, Bundler } from '@astrale-os/sdk/deployment/adapter';
|
|
2
|
+
import type { frontend as frontendBuild } from '@astrale-os/sdk/deployment/build';
|
|
3
|
+
import type { ReleaseModule } from './worker/execution.prepare.js';
|
|
4
|
+
/**
|
|
5
|
+
* Environment-free bytes of one generated Worker: its entry, the modules it loads (the execution
|
|
6
|
+
* Service, the deferred workflow engine and their WASM) and its frontend.
|
|
7
|
+
*/
|
|
8
|
+
export interface WorkerBytes {
|
|
9
|
+
readonly entry: Uint8Array;
|
|
10
|
+
readonly modules: readonly ReleaseModule[];
|
|
11
|
+
readonly frontend: readonly frontendBuild.FrontendFile[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Bundles every generated Cloudflare Worker, for adapter-cloudflare and adapter-astrale alike. It
|
|
15
|
+
* reads no Environment: settings, address, issuer and key are bound at deploy.
|
|
16
|
+
*/
|
|
17
|
+
export declare const cloudflareWorkerBundler: Bundler;
|
|
18
|
+
/** Bundle the Worker modules and build the frontend they serve, in one scratch directory. */
|
|
19
|
+
export declare function bundleWorker(context: BundleContext): Promise<WorkerBytes>;
|
|
20
|
+
/** Read back the Worker bytes of a Bundle this bundler produced for the same Build. */
|
|
21
|
+
export declare function bundledWorker(bundle: Bundle, build: Bundle['build']): WorkerBytes;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { CLOUDFLARE_WORKER_BUNDLER, workerAssetFile } from '../release/build.js';
|
|
4
|
+
import { frontendFiles } from './frontend/files.js';
|
|
5
|
+
import { frontendRevision } from './frontend/revision.js';
|
|
6
|
+
import { prepareExecution, RELEASE_ENTRY, RELEASE_SERVICE } from './worker/execution.prepare.js';
|
|
7
|
+
/** Worker modules live beside the entry; WASM is the only non-ESM kind preparation emits. */
|
|
8
|
+
const MODULE_DIRECTORY = 'bundle/';
|
|
9
|
+
/**
|
|
10
|
+
* Bundles every generated Cloudflare Worker, for adapter-cloudflare and adapter-astrale alike. It
|
|
11
|
+
* reads no Environment: settings, address, issuer and key are bound at deploy.
|
|
12
|
+
*/
|
|
13
|
+
export const cloudflareWorkerBundler = Object.freeze({
|
|
14
|
+
id: CLOUDFLARE_WORKER_BUNDLER.id,
|
|
15
|
+
version: CLOUDFLARE_WORKER_BUNDLER.version,
|
|
16
|
+
async bundle(context) {
|
|
17
|
+
const worker = await bundleWorker(context);
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
entrypoint: RELEASE_ENTRY,
|
|
20
|
+
files: Object.freeze([
|
|
21
|
+
{ path: RELEASE_ENTRY, content: worker.entry },
|
|
22
|
+
...worker.modules.map(({ path, content }) => ({ path, content })),
|
|
23
|
+
...worker.frontend.map((file) => ({
|
|
24
|
+
path: workerAssetFile(`/${file.path}`),
|
|
25
|
+
content: file.bytes(),
|
|
26
|
+
})),
|
|
27
|
+
]),
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
/** Bundle the Worker modules and build the frontend they serve, in one scratch directory. */
|
|
32
|
+
export async function bundleWorker(context) {
|
|
33
|
+
const stateDirectory = join(context.projectDir, '.astrale');
|
|
34
|
+
await mkdir(stateDirectory, { recursive: true });
|
|
35
|
+
const directory = await mkdtemp(join(stateDirectory, 'prepare-'));
|
|
36
|
+
try {
|
|
37
|
+
// `frontend` is the served file list; `addressed` rides alongside it into the Worker, where it
|
|
38
|
+
// decides which of those files a browser may retain.
|
|
39
|
+
const { files: frontend, addressed } = await frontendFiles({
|
|
40
|
+
frontend: context.build.frontend,
|
|
41
|
+
projectDir: context.projectDir,
|
|
42
|
+
output: join(directory, 'frontend'),
|
|
43
|
+
recordSource: context.recordSource,
|
|
44
|
+
signal: context.signal,
|
|
45
|
+
});
|
|
46
|
+
const modules = await prepareExecution({
|
|
47
|
+
context,
|
|
48
|
+
directory,
|
|
49
|
+
...(frontend.length === 0 ? {} : { frontendRevision: frontendRevision(frontend) }),
|
|
50
|
+
...(addressed.length === 0 ? {} : { frontendAddressed: addressed }),
|
|
51
|
+
});
|
|
52
|
+
return Object.freeze({ entry: modules.entry, modules: modules.modules, frontend });
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
await rm(directory, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Read back the Worker bytes of a Bundle this bundler produced for the same Build. */
|
|
59
|
+
export function bundledWorker(bundle, build) {
|
|
60
|
+
const { id, version } = bundle.manifest.bundler;
|
|
61
|
+
if (bundle.build !== build ||
|
|
62
|
+
id !== CLOUDFLARE_WORKER_BUNDLER.id ||
|
|
63
|
+
version !== CLOUDFLARE_WORKER_BUNDLER.version ||
|
|
64
|
+
bundle.entrypoint !== RELEASE_ENTRY) {
|
|
65
|
+
throw new TypeError('Cloudflare preparation requires the Bundle of its Worker bundler.');
|
|
66
|
+
}
|
|
67
|
+
let entry;
|
|
68
|
+
const modules = [];
|
|
69
|
+
const frontend = [];
|
|
70
|
+
for (const file of bundle.files) {
|
|
71
|
+
if (file.path === RELEASE_ENTRY)
|
|
72
|
+
entry = file.bytes();
|
|
73
|
+
else if (file.path.startsWith(MODULE_DIRECTORY) && /\.(?:mjs|wasm)$/u.test(file.path)) {
|
|
74
|
+
modules.push(Object.freeze({
|
|
75
|
+
path: file.path,
|
|
76
|
+
kind: file.path.endsWith('.wasm') ? 'wasm' : 'esm',
|
|
77
|
+
content: file.bytes(),
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
else if (file.path.startsWith('assets/')) {
|
|
81
|
+
const content = file.bytes();
|
|
82
|
+
frontend.push(Object.freeze({ path: file.path.slice('assets/'.length), bytes: () => content.slice() }));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new TypeError(`Cloudflare Worker Bundle file ${file.path} is not a Worker file.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (entry === undefined || !modules.some((module) => module.path === RELEASE_SERVICE)) {
|
|
89
|
+
throw new TypeError('Cloudflare Worker Bundle lacks its execution modules.');
|
|
90
|
+
}
|
|
91
|
+
return Object.freeze({
|
|
92
|
+
entry,
|
|
93
|
+
modules: Object.freeze(modules),
|
|
94
|
+
frontend: Object.freeze(frontend),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { legacy } from '@astrale-os/sdk/deployment/release';
|
|
2
2
|
import type { verifyReadiness } from '@astrale-os/sdk/deployment/verify';
|
|
3
3
|
import type { WorkerArtifact } from '../worker/artifact.js';
|
|
4
4
|
type ReadinessFetch = NonNullable<NonNullable<Parameters<typeof verifyReadiness>[1]>['fetch']>;
|
|
5
5
|
/** Publication equality alone cannot prove a frontend-only deployment has propagated. */
|
|
6
|
-
export declare function verifyWorkerFrontend(release: Release, worker: Pick<WorkerArtifact, 'assets'>, options?: {
|
|
6
|
+
export declare function verifyWorkerFrontend(release: legacy.Release, worker: Pick<WorkerArtifact, 'assets'>, options?: {
|
|
7
7
|
readonly fetch?: ReadinessFetch;
|
|
8
8
|
readonly signal?: AbortSignal;
|
|
9
9
|
}): Promise<void>;
|
package/dist/build/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { generateBuildMaterialModule } from './material.js';
|
|
2
2
|
export { artifact, materialize, prepareWorkerArtifact } from './artifact.js';
|
|
3
|
+
export { cloudflareWorkerBundler } from './bundler.js';
|
|
3
4
|
export { loadWorkerArtifact } from './worker/index.js';
|
|
4
5
|
export type { WorkerArtifact } from './worker/index.js';
|
|
6
|
+
export { uploadBuildDigest, uploadBuildEvidence, workerUpload } from './worker/upload.js';
|
|
5
7
|
export { isAdapterVar, resolveRouter, workerName } from './configuration.js';
|
|
6
8
|
export { frontendFiles } from './frontend/files.js';
|
|
7
9
|
export { verifyWorkerFrontend } from './frontend/readiness.js';
|
package/dist/build/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { generateBuildMaterialModule } from './material.js';
|
|
2
2
|
export { artifact, materialize, prepareWorkerArtifact } from './artifact.js';
|
|
3
|
+
export { cloudflareWorkerBundler } from './bundler.js';
|
|
3
4
|
export { loadWorkerArtifact } from './worker/index.js';
|
|
5
|
+
export { uploadBuildDigest, uploadBuildEvidence, workerUpload } from './worker/upload.js';
|
|
4
6
|
export { isAdapterVar, resolveRouter, workerName } from './configuration.js';
|
|
5
7
|
export { frontendFiles } from './frontend/files.js';
|
|
6
8
|
export { verifyWorkerFrontend } from './frontend/readiness.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BundleContext } from '@astrale-os/sdk/deployment/adapter';
|
|
2
2
|
export declare const RELEASE_ENTRY = "bundle/index.mjs";
|
|
3
3
|
export declare const RELEASE_SERVICE = "bundle/service.mjs";
|
|
4
4
|
export declare const RELEASE_RESTATE = "bundle/restate.mjs";
|
|
@@ -9,7 +9,7 @@ export interface ReleaseModule {
|
|
|
9
9
|
readonly content: Uint8Array;
|
|
10
10
|
}
|
|
11
11
|
export declare function prepareExecution(input: {
|
|
12
|
-
readonly context:
|
|
12
|
+
readonly context: BundleContext;
|
|
13
13
|
readonly directory: string;
|
|
14
14
|
readonly frontendRevision?: string;
|
|
15
15
|
readonly frontendAddressed?: readonly string[];
|
|
@@ -17,4 +17,4 @@ export declare function prepareExecution(input: {
|
|
|
17
17
|
readonly entry: Uint8Array;
|
|
18
18
|
readonly modules: readonly ReleaseModule[];
|
|
19
19
|
}>;
|
|
20
|
-
export declare function declaresDurable(build:
|
|
20
|
+
export declare function declaresDurable(build: BundleContext['build']): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PreparedArtifact } from '@astrale-os/sdk/deployment/adapter';
|
|
2
|
+
import type { Build } from '@astrale-os/sdk/deployment/build';
|
|
3
|
+
import type { BuildDigest } from '@astrale-os/sdk/deployment/build/manifest';
|
|
4
|
+
import type { WorkerArtifact } from './artifact.js';
|
|
5
|
+
import { type WorkerUpload } from '../../release/build.js';
|
|
6
|
+
/** The portable upload of one prepared Worker: exactly the modules and assets Services receives. */
|
|
7
|
+
export declare function workerUpload(artifact: PreparedArtifact, worker: WorkerArtifact): WorkerUpload;
|
|
8
|
+
/** Build digest of the portable upload of one prepared Worker. */
|
|
9
|
+
export declare function uploadBuildDigest(artifact: PreparedArtifact, worker: WorkerArtifact): BuildDigest;
|
|
10
|
+
/** Record that preparation placed the CLI's Bundle for this Build. */
|
|
11
|
+
export declare function recordPlacedBundle(build: Build): void;
|
|
12
|
+
/**
|
|
13
|
+
* The `build` field of one prepared Worker's provider evidence: the build digest of its portable
|
|
14
|
+
* upload, present only when its preparation placed the CLI's Bundle.
|
|
15
|
+
*/
|
|
16
|
+
export declare function uploadBuildEvidence(artifact: PreparedArtifact, worker: WorkerArtifact): {
|
|
17
|
+
readonly build?: BuildDigest;
|
|
18
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { buildDigest } from '@astrale-os/sdk/deployment/build/manifest';
|
|
2
|
+
import { workerBuildManifest } from '../../release/build.js';
|
|
3
|
+
/** The portable upload of one prepared Worker: exactly the modules and assets Services receives. */
|
|
4
|
+
export function workerUpload(artifact, worker) {
|
|
5
|
+
const root = artifact.build.schema.compiled.root;
|
|
6
|
+
if (worker.origin !== root.origin || worker.revision !== root.revision) {
|
|
7
|
+
throw new TypeError('Worker artifact differs from its prepared Build.');
|
|
8
|
+
}
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
origin: root.origin,
|
|
11
|
+
revision: root.revision,
|
|
12
|
+
bundle: artifact.build.schema.bundle.ref.digest,
|
|
13
|
+
entry: worker.release.entrypoint,
|
|
14
|
+
modules: worker.release.modules.map((module) => ({ name: module.path, bytes: module.bytes() })),
|
|
15
|
+
...(worker.assets === undefined
|
|
16
|
+
? {}
|
|
17
|
+
: { assets: worker.assets.files.map((file) => ({ path: file.path, bytes: file.bytes() })) }),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Build digest of the portable upload of one prepared Worker. */
|
|
21
|
+
export function uploadBuildDigest(artifact, worker) {
|
|
22
|
+
return buildDigest(workerBuildManifest(workerUpload(artifact, worker)));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds whose preparation placed the Bundle `astrale-domain deploy` passed (`PrepareContext.bundle`).
|
|
26
|
+
* Only a CLI that passes a Bundle reads `ProviderDeploymentEvidence.build`: an older one refuses an
|
|
27
|
+
* evidence field it does not know, after the provider has applied the upload.
|
|
28
|
+
*/
|
|
29
|
+
const placedBuilds = new WeakSet();
|
|
30
|
+
/** Record that preparation placed the CLI's Bundle for this Build. */
|
|
31
|
+
export function recordPlacedBundle(build) {
|
|
32
|
+
placedBuilds.add(build);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The `build` field of one prepared Worker's provider evidence: the build digest of its portable
|
|
36
|
+
* upload, present only when its preparation placed the CLI's Bundle.
|
|
37
|
+
*/
|
|
38
|
+
export function uploadBuildEvidence(artifact, worker) {
|
|
39
|
+
return placedBuilds.has(artifact.build) ? { build: uploadBuildDigest(artifact, worker) } : {};
|
|
40
|
+
}
|
package/dist/deploy/deploy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DeployContext, DeployResult } from '@astrale-os/sdk/deployment/adapter';
|
|
2
|
-
import
|
|
2
|
+
import { legacy } from '@astrale-os/sdk/deployment/release';
|
|
3
3
|
import type { materialize } from '../build/artifact.js';
|
|
4
4
|
import type { WorkerArtifact } from '../build/worker/artifact.js';
|
|
5
5
|
import type { signingIdentity } from '../identity/source.js';
|
|
@@ -10,7 +10,7 @@ export interface CloudflareDeployDependencies {
|
|
|
10
10
|
readonly materialize: typeof materialize;
|
|
11
11
|
readonly runWranglerRollout: typeof runWranglerRollout;
|
|
12
12
|
readonly runWranglerDeploymentStatus: typeof runWranglerDeploymentStatus;
|
|
13
|
-
readonly waitForReadiness: (release: Release, signal: AbortSignal, version: string, worker: WorkerArtifact, workerName?: string) => Promise<void>;
|
|
13
|
+
readonly waitForReadiness: (release: legacy.Release, signal: AbortSignal, version: string, worker: WorkerArtifact, workerName?: string) => Promise<void>;
|
|
14
14
|
readonly signingIdentity: typeof signingIdentity;
|
|
15
15
|
}
|
|
16
16
|
/** Deploy one stable Worker target and verify its exact serving implementation. */
|
package/dist/deploy/deploy.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { addressing,
|
|
1
|
+
import { addressing, legacy } from '@astrale-os/sdk/deployment/release';
|
|
2
2
|
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { isAdapterVar, workerName } from '../build/configuration.js';
|
|
5
5
|
import { admitDirectPlacement } from '../build/direct.js';
|
|
6
6
|
import { loadWorkerArtifact } from '../build/worker/index.js';
|
|
7
|
+
import { uploadBuildEvidence } from '../build/worker/upload.js';
|
|
7
8
|
import { signingIdentitySecrets } from '../identity/secret.js';
|
|
8
9
|
import { WranglerDeployError } from '../wrangler/deploy.js';
|
|
9
10
|
import { WranglerRolloutError } from '../wrangler/rollout.js';
|
|
@@ -24,8 +25,10 @@ export async function deployCloudflare(parameters, context, dependencies) {
|
|
|
24
25
|
return failed('prerequisite', progress({}), cause);
|
|
25
26
|
}
|
|
26
27
|
let worker;
|
|
28
|
+
let build;
|
|
27
29
|
try {
|
|
28
30
|
worker = loadWorkerArtifact(context.artifact);
|
|
31
|
+
build = uploadBuildEvidence(context.artifact, worker);
|
|
29
32
|
const occupied = new Set([
|
|
30
33
|
...Object.keys(worker.bindings.vars),
|
|
31
34
|
...worker.bindings.services.map((binding) => binding.name),
|
|
@@ -60,7 +63,7 @@ export async function deployCloudflare(parameters, context, dependencies) {
|
|
|
60
63
|
workerName: name,
|
|
61
64
|
verifyCandidate: async (candidate) => {
|
|
62
65
|
const selected = observeAddressing(context.artifact, candidate.url, name);
|
|
63
|
-
const release = assemble(context.artifact.build, selected);
|
|
66
|
+
const release = legacy.assemble(context.artifact.build, selected);
|
|
64
67
|
await dependencies.waitForReadiness(release, context.signal, candidate.deploymentVersion, worker, name);
|
|
65
68
|
},
|
|
66
69
|
secrets,
|
|
@@ -91,6 +94,7 @@ export async function deployCloudflare(parameters, context, dependencies) {
|
|
|
91
94
|
provider: 'cloudflare',
|
|
92
95
|
deployment: deployed.deploymentVersion,
|
|
93
96
|
artifact: context.artifact.digest,
|
|
97
|
+
...build,
|
|
94
98
|
}),
|
|
95
99
|
});
|
|
96
100
|
let selected;
|
|
@@ -121,7 +125,7 @@ export async function deployCloudflare(parameters, context, dependencies) {
|
|
|
121
125
|
}
|
|
122
126
|
let release;
|
|
123
127
|
try {
|
|
124
|
-
release = assemble(context.artifact.build, selected);
|
|
128
|
+
release = legacy.assemble(context.artifact.build, selected);
|
|
125
129
|
}
|
|
126
130
|
catch (cause) {
|
|
127
131
|
return failed('release', progress({ provider: retained, configuration }), cause);
|
|
@@ -138,6 +142,7 @@ export async function deployCloudflare(parameters, context, dependencies) {
|
|
|
138
142
|
provider: 'cloudflare',
|
|
139
143
|
deployment: deployed.deploymentVersion,
|
|
140
144
|
artifact: context.artifact.digest,
|
|
145
|
+
...build,
|
|
141
146
|
issuer: selected.issuer,
|
|
142
147
|
}),
|
|
143
148
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@astrale-os/adapter-cloudflare` — deploy an Astrale
|
|
2
|
+
* `@astrale-os/adapter-cloudflare` — deploy an Astrale Domain through
|
|
3
3
|
* Cloudflare Workers on YOUR OWN Cloudflare account.
|
|
4
4
|
*
|
|
5
5
|
* import { cloudflare } from '@astrale-os/adapter-cloudflare'
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@astrale-os/adapter-cloudflare` — deploy an Astrale
|
|
2
|
+
* `@astrale-os/adapter-cloudflare` — deploy an Astrale Domain through
|
|
3
3
|
* Cloudflare Workers on YOUR OWN Cloudflare account.
|
|
4
4
|
*
|
|
5
5
|
* import { cloudflare } from '@astrale-os/adapter-cloudflare'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BuildManifestV1 } from '@astrale-os/sdk/deployment/build/manifest';
|
|
2
|
+
/**
|
|
3
|
+
* The bundler of every generated Cloudflare Worker, whichever adapter deploys it. Its version names
|
|
4
|
+
* the upload layout below, not a package release: a Services host recomputes the same build digest
|
|
5
|
+
* from the same bytes whatever SDK it runs.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CLOUDFLARE_WORKER_BUNDLER: Readonly<{
|
|
8
|
+
id: "cloudflare-worker";
|
|
9
|
+
version: "1";
|
|
10
|
+
}>;
|
|
11
|
+
/** Portable Worker upload: what Services receives, and what a dispatch namespace upload carries. */
|
|
12
|
+
export interface WorkerUpload {
|
|
13
|
+
readonly origin: string;
|
|
14
|
+
readonly revision: BuildManifestV1['schema']['revision'];
|
|
15
|
+
/** Digest of the Domain Schema bundle. */
|
|
16
|
+
readonly bundle: BuildManifestV1['schema']['bundle'];
|
|
17
|
+
readonly entry: string;
|
|
18
|
+
readonly modules: readonly {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly bytes: Uint8Array;
|
|
21
|
+
}[];
|
|
22
|
+
/** Static assets by their absolute Worker asset path (`/index.html`). */
|
|
23
|
+
readonly assets?: readonly {
|
|
24
|
+
readonly path: string;
|
|
25
|
+
readonly bytes: Uint8Array;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The one build manifest of a Worker upload, computed on the exact upload the deploy sends; the
|
|
30
|
+
* SDK, Services and namespace mode all identify Worker code through it. Modules keep their uploaded
|
|
31
|
+
* name; a static asset `/<path>` is the file `assets/<path>`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function workerBuildManifest(upload: WorkerUpload): BuildManifestV1;
|
|
34
|
+
/** The build-manifest file of one Worker asset path. */
|
|
35
|
+
export declare function workerAssetFile(path: string): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { buildManifest } from '@astrale-os/sdk/deployment/build/manifest';
|
|
2
|
+
/**
|
|
3
|
+
* The bundler of every generated Cloudflare Worker, whichever adapter deploys it. Its version names
|
|
4
|
+
* the upload layout below, not a package release: a Services host recomputes the same build digest
|
|
5
|
+
* from the same bytes whatever SDK it runs.
|
|
6
|
+
*/
|
|
7
|
+
export const CLOUDFLARE_WORKER_BUNDLER = Object.freeze({
|
|
8
|
+
id: 'cloudflare-worker',
|
|
9
|
+
version: '1',
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* The one build manifest of a Worker upload, computed on the exact upload the deploy sends; the
|
|
13
|
+
* SDK, Services and namespace mode all identify Worker code through it. Modules keep their uploaded
|
|
14
|
+
* name; a static asset `/<path>` is the file `assets/<path>`.
|
|
15
|
+
*/
|
|
16
|
+
export function workerBuildManifest(upload) {
|
|
17
|
+
if (upload === null || typeof upload !== 'object' || !Array.isArray(upload.modules)) {
|
|
18
|
+
throw new TypeError('Worker upload is invalid.');
|
|
19
|
+
}
|
|
20
|
+
if (upload.assets !== undefined && !Array.isArray(upload.assets)) {
|
|
21
|
+
throw new TypeError('Worker upload assets are invalid.');
|
|
22
|
+
}
|
|
23
|
+
return buildManifest({
|
|
24
|
+
origin: upload.origin,
|
|
25
|
+
revision: upload.revision,
|
|
26
|
+
bundle: upload.bundle,
|
|
27
|
+
bundler: CLOUDFLARE_WORKER_BUNDLER,
|
|
28
|
+
entrypoint: upload.entry,
|
|
29
|
+
files: [
|
|
30
|
+
...upload.modules.map((module) => ({ path: module.name, content: module.bytes })),
|
|
31
|
+
...(upload.assets ?? []).map((asset) => ({
|
|
32
|
+
path: workerAssetFile(asset.path),
|
|
33
|
+
content: asset.bytes,
|
|
34
|
+
})),
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** The build-manifest file of one Worker asset path. */
|
|
39
|
+
export function workerAssetFile(path) {
|
|
40
|
+
if (typeof path !== 'string' || !path.startsWith('/')) {
|
|
41
|
+
throw new TypeError('Worker asset path must be absolute.');
|
|
42
|
+
}
|
|
43
|
+
return `assets${path}`;
|
|
44
|
+
}
|
package/dist/release/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
export { CLOUDFLARE_WORKER_BUNDLER, workerBuildManifest, type WorkerUpload } from './build.js';
|
|
1
2
|
export { acceptWorkerDeployment, workerDeployment, workerDeploymentMaterial, type WorkerDeploymentId, type WorkerDeploymentInput, } from './deployment.js';
|
|
2
3
|
export { stagedWorkerName } from './staged-worker-name.js';
|
package/dist/release/index.js
CHANGED
package/dist/worker/entry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { issuer } from '@astrale-os/sdk/auth';
|
|
2
2
|
import { restoreBuild, restoreGeneratedBuild } from '@astrale-os/sdk/deployment/build/material';
|
|
3
|
-
import { addressing,
|
|
3
|
+
import { addressing, legacy } from '@astrale-os/sdk/deployment/release/runtime';
|
|
4
4
|
import { createIdentity, serve } from '@astrale-os/sdk/execution';
|
|
5
5
|
import { dispatchCloudflareRequest, prepareCloudflareRequest } from './fetch.js';
|
|
6
6
|
import { cloudflareFrontDoor, withProviderVersion } from './front.js';
|
|
@@ -49,7 +49,7 @@ function createCloudflareWorkerEntry(restore) {
|
|
|
49
49
|
if (frontDoor.current() !== environment.publicUrl) {
|
|
50
50
|
throw new TypeError('Cloudflare Worker request origin differs from its current Release.');
|
|
51
51
|
}
|
|
52
|
-
return assemble(build, addressing(settings.identityIssuer ?? environment.publicUrl, {
|
|
52
|
+
return legacy.assemble(build, addressing(settings.identityIssuer ?? environment.publicUrl, {
|
|
53
53
|
publicUrl: environment.publicUrl,
|
|
54
54
|
}));
|
|
55
55
|
},
|
|
@@ -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;
|
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.167",
|
|
4
|
+
"description": "Deploy an Astrale Domain through Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
7
7
|
"astrale",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"registry": "https://registry.npmjs.org/"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@astrale-os/sdk": "0.6.0-beta.
|
|
64
|
+
"@astrale-os/sdk": "0.6.0-beta.12",
|
|
65
65
|
"@noble/hashes": "2.3.0",
|
|
66
66
|
"@restatedev/restate-sdk-cloudflare-workers": "1.17.0",
|
|
67
67
|
"hono": "^4.6.20",
|
|
@@ -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: {
|