@void/deploy-cloudflare 0.26.0 → 0.27.0
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 +8 -2
- package/dist/index.d.mts +7 -6
- package/dist/index.mjs +159 -193
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @void/deploy-cloudflare
|
|
2
2
|
|
|
3
|
-
Cloudflare deployment primitives used by the Void CLI. Provides Worker configuration reads, uploads, activation, and deployment verification.
|
|
3
|
+
Cloudflare deployment primitives used by the [Void CLI](https://void.cloud/reference/cli). Provides Worker configuration reads, uploads, activation, and deployment verification for runtime and adapter authors.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
To deploy an application to your Cloudflare account, run `void deploy --platform cloudflare`.
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
See the [Cloudflare guide](https://void.cloud/integrations/cloudflare) for configuration and credentials, or [Platform Development](https://void.cloud/guide/platform-development) for building a runtime or adapter.
|
|
10
|
+
|
|
11
|
+
Read the [Void documentation](https://void.cloud) online or use the Markdown guides and references in `node_modules/void/docs/`, included with the `void` package.
|
package/dist/index.d.mts
CHANGED
|
@@ -147,6 +147,12 @@ type ApprovedCloudflareKvBinding = Readonly<{
|
|
|
147
147
|
binding: string;
|
|
148
148
|
id: string;
|
|
149
149
|
}>;
|
|
150
|
+
type ExistingCloudflareWorkerOptions = {
|
|
151
|
+
runWrangler: CloudflareCommandRunner;
|
|
152
|
+
configPath: string;
|
|
153
|
+
workerName: string;
|
|
154
|
+
versionId?: string;
|
|
155
|
+
};
|
|
150
156
|
/** A failed remote read, distinct from an invalid or changing Worker configuration. */
|
|
151
157
|
export declare class CloudflareWorkerInspectionError extends Error {
|
|
152
158
|
override name: string;
|
|
@@ -158,12 +164,7 @@ type CloudflareWorkerMigrationTagOptions = {
|
|
|
158
164
|
workerName: string;
|
|
159
165
|
};
|
|
160
166
|
/** Read the deployed version, not the most recently uploaded candidate. */
|
|
161
|
-
export declare function readExistingCloudflareWorker(options:
|
|
162
|
-
runWrangler: CloudflareCommandRunner;
|
|
163
|
-
configPath: string;
|
|
164
|
-
workerName: string;
|
|
165
|
-
versionId?: string;
|
|
166
|
-
}): Promise<ExistingCloudflareWorker>;
|
|
167
|
+
export declare function readExistingCloudflareWorker(options: ExistingCloudflareWorkerOptions): Promise<ExistingCloudflareWorker>;
|
|
167
168
|
/** Parse legacy version-detail shapes; this is not authoritative Worker migration state. */
|
|
168
169
|
export declare function readCloudflareVersionMigrationTag(version: unknown): string | null;
|
|
169
170
|
/** Read the authoritative migration tag from Worker script metadata. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isDeepStrictEqual, stripVTControlCharacters } from "node:util";
|
|
2
|
+
import { isRecord } from "@void/deploy-core";
|
|
2
3
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { SyntaxKind, applyEdits, createScanner, modify, parse, parseTree } from "jsonc-parser";
|
|
4
|
-
import { isRecord } from "@void/deploy-core";
|
|
5
5
|
import nodePath from "node:path";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
@@ -22,34 +22,26 @@ function parseRootWranglerConfig(configPath) {
|
|
|
22
22
|
return parsed;
|
|
23
23
|
}
|
|
24
24
|
function readWranglerTopLevelString(config, field) {
|
|
25
|
-
|
|
26
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
25
|
+
return readConfigEntryString(config, field);
|
|
27
26
|
}
|
|
28
|
-
|
|
27
|
+
/** The first entry of `config[field]` whose `binding` matches. */
|
|
28
|
+
function findBindingEntry(config, field, binding) {
|
|
29
29
|
const list = config[field];
|
|
30
30
|
if (!Array.isArray(list)) return;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
return list.find((entry) => entry && typeof entry === "object" && entry.binding === binding);
|
|
32
|
+
}
|
|
33
|
+
function readStoredResourceName(config, field, binding, nameField) {
|
|
34
|
+
return readConfigEntryString(findBindingEntry(config, field, binding), nameField);
|
|
35
35
|
}
|
|
36
36
|
function readBindingFieldPresence(config, field, binding, key) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
present: false,
|
|
40
|
-
value: void 0
|
|
41
|
-
};
|
|
42
|
-
for (const entry of list) if (entry && typeof entry === "object" && entry.binding === binding) return Object.hasOwn(entry, key) ? {
|
|
37
|
+
const entry = findBindingEntry(config, field, binding);
|
|
38
|
+
return entry && Object.hasOwn(entry, key) ? {
|
|
43
39
|
present: true,
|
|
44
40
|
value: entry[key]
|
|
45
41
|
} : {
|
|
46
42
|
present: false,
|
|
47
43
|
value: void 0
|
|
48
44
|
};
|
|
49
|
-
return {
|
|
50
|
-
present: false,
|
|
51
|
-
value: void 0
|
|
52
|
-
};
|
|
53
45
|
}
|
|
54
46
|
function readConfigEntryString(entry, field) {
|
|
55
47
|
if (!entry || typeof entry !== "object") return;
|
|
@@ -82,6 +74,36 @@ function resolveD1MigrateTarget(config, binding) {
|
|
|
82
74
|
};
|
|
83
75
|
}
|
|
84
76
|
//#endregion
|
|
77
|
+
//#region src/execute.ts
|
|
78
|
+
/** Upload the already-verified Worker artifact without Wrangler autoconfiguration. */
|
|
79
|
+
async function executeCloudflareDeploy(options) {
|
|
80
|
+
if (!options.verifyUploader()) return {
|
|
81
|
+
ok: false,
|
|
82
|
+
reason: "uploader-changed"
|
|
83
|
+
};
|
|
84
|
+
const result = await options.runWrangler({
|
|
85
|
+
type: "worker.deploy",
|
|
86
|
+
...options.configPath ? { configPath: options.configPath } : {}
|
|
87
|
+
}, { capture: false });
|
|
88
|
+
if (!isCleanCommandExit(result)) return {
|
|
89
|
+
ok: false,
|
|
90
|
+
reason: "deploy-failed",
|
|
91
|
+
status: result.status
|
|
92
|
+
};
|
|
93
|
+
return { ok: true };
|
|
94
|
+
}
|
|
95
|
+
/** The command ran to completion, whatever its exit status. */
|
|
96
|
+
function isCompletedCommand(result) {
|
|
97
|
+
return Number.isSafeInteger(result.status) && result.status >= 0 && result.signal == null && (result.error == null || result.error === "");
|
|
98
|
+
}
|
|
99
|
+
function isCleanCommandExit(result) {
|
|
100
|
+
return result.status === 0 && isCompletedCommand(result);
|
|
101
|
+
}
|
|
102
|
+
/** Cloudflare reported that the Worker or its deployment does not exist (code 10007). */
|
|
103
|
+
function isWorkerNotFound(result) {
|
|
104
|
+
return isCompletedCommand(result) && (result.failure === "not-found" || result.errorCode === 10007);
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
85
107
|
//#region src/secret-draft.ts
|
|
86
108
|
/**
|
|
87
109
|
* `wrangler secret put` creates a fetch-only draft before attaching a first secret to a Worker.
|
|
@@ -156,14 +178,11 @@ async function readCloudflareWorker(options, allowMissing, proveSecretDraft = fa
|
|
|
156
178
|
};
|
|
157
179
|
const read = async (operation, missingIsNull = false) => {
|
|
158
180
|
const result = await options.runWrangler(operation, { capture: true });
|
|
159
|
-
if (result
|
|
160
|
-
if (missingIsNull &&
|
|
181
|
+
if (!isCleanCommandExit(result)) {
|
|
182
|
+
if (missingIsNull && isWorkerNotFound(result)) return null;
|
|
161
183
|
throw new CloudflareWorkerInspectionError(`Could not verify existing Cloudflare Worker "${options.workerName}". Check the account, Worker name, and Cloudflare permissions before retrying.`);
|
|
162
184
|
}
|
|
163
|
-
|
|
164
|
-
const value = result.data;
|
|
165
|
-
if (record$1(value)) return value;
|
|
166
|
-
} catch {}
|
|
185
|
+
if (isRecord(result.data)) return result.data;
|
|
167
186
|
throw new Error("Cloudflare returned an invalid existing Worker response.");
|
|
168
187
|
};
|
|
169
188
|
const deployment = options.versionId ? { versions: [{
|
|
@@ -176,7 +195,7 @@ async function readCloudflareWorker(options, allowMissing, proveSecretDraft = fa
|
|
|
176
195
|
if (deployment === null) return null;
|
|
177
196
|
const versions = deployment.versions;
|
|
178
197
|
if (allowMissing && Array.isArray(versions) && versions.length === 0) return null;
|
|
179
|
-
if (!Array.isArray(versions) || versions.length !== 1 || !
|
|
198
|
+
if (!Array.isArray(versions) || versions.length !== 1 || !isRecord(versions[0]) || versions[0].percentage !== 100 || typeof versions[0].version_id !== "string") throw new Error("The existing Worker must have one deployed version receiving all traffic. Finish any gradual rollout before linking.");
|
|
180
199
|
const versionId = versions[0].version_id;
|
|
181
200
|
const version = await read({
|
|
182
201
|
type: "versions.view",
|
|
@@ -185,9 +204,9 @@ async function readCloudflareWorker(options, allowMissing, proveSecretDraft = fa
|
|
|
185
204
|
});
|
|
186
205
|
if (version === null) throw new Error("Cloudflare did not return the existing Worker configuration.");
|
|
187
206
|
const resources = version.resources;
|
|
188
|
-
if (version.id !== versionId || !
|
|
207
|
+
if (version.id !== versionId || !isRecord(resources) || !Array.isArray(resources.bindings) || !resources.bindings.every(isRecord) || !isRecord(resources.script_runtime) || !isRecord(resources.script)) throw new Error("Cloudflare did not return the existing Worker configuration.");
|
|
189
208
|
let isSecretOnlyDraft = isWranglerSecretOnlyDraft(version);
|
|
190
|
-
if (proveSecretDraft && !isSecretOnlyDraft &&
|
|
209
|
+
if (proveSecretDraft && !isSecretOnlyDraft && isRecord(version.annotations) && Object.keys(version.annotations).length === 1 && version.annotations["workers/triggered_by"] === "secret") {
|
|
191
210
|
const source = await read({
|
|
192
211
|
type: "versions.view",
|
|
193
212
|
versionId,
|
|
@@ -213,12 +232,12 @@ async function readCloudflareWorker(options, allowMissing, proveSecretDraft = fa
|
|
|
213
232
|
}
|
|
214
233
|
/** Parse legacy version-detail shapes; this is not authoritative Worker migration state. */
|
|
215
234
|
function readCloudflareVersionMigrationTag(version) {
|
|
216
|
-
if (!
|
|
217
|
-
const resources =
|
|
235
|
+
if (!isRecord(version)) return null;
|
|
236
|
+
const resources = isRecord(version.resources) ? version.resources : void 0;
|
|
218
237
|
const tag = [
|
|
219
|
-
resources &&
|
|
220
|
-
resources &&
|
|
221
|
-
|
|
238
|
+
resources && isRecord(resources.script_runtime) ? resources.script_runtime.migration_tag : null,
|
|
239
|
+
resources && isRecord(resources.script) ? resources.script.migration_tag : null,
|
|
240
|
+
isRecord(version.script) ? version.script.migration_tag : null,
|
|
222
241
|
version.migration_tag
|
|
223
242
|
].find((candidate) => typeof candidate === "string");
|
|
224
243
|
return typeof tag === "string" && tag.length > 0 ? tag : null;
|
|
@@ -243,23 +262,18 @@ async function readCloudflareWorkerMigrationTag(options) {
|
|
|
243
262
|
} catch {
|
|
244
263
|
throw new Error(`Cloudflare returned an invalid Durable Object migration response for Worker "${options.workerName}".`);
|
|
245
264
|
}
|
|
246
|
-
if (!response.ok || !
|
|
247
|
-
const worker = body.result.find((candidate) =>
|
|
248
|
-
if (!
|
|
265
|
+
if (!response.ok || !isRecord(body) || body.success !== true || !Array.isArray(body.result)) throw new Error(`Could not verify Durable Object migration state for Cloudflare Worker "${options.workerName}".`);
|
|
266
|
+
const worker = body.result.find((candidate) => isRecord(candidate) && candidate.id === options.workerName);
|
|
267
|
+
if (!isRecord(worker)) throw new Error(`Cloudflare did not return migration state for Worker "${options.workerName}".`);
|
|
249
268
|
if (worker.migration_tag === void 0 || worker.migration_tag === null) return null;
|
|
250
269
|
if (typeof worker.migration_tag !== "string" || worker.migration_tag.length === 0) throw new Error(`Cloudflare returned an invalid Durable Object migration response for Worker "${options.workerName}".`);
|
|
251
270
|
return worker.migration_tag;
|
|
252
271
|
}
|
|
253
272
|
async function readCloudflareApiAuthentication(runWrangler) {
|
|
254
273
|
const result = await runWrangler({ type: "auth.token" }, { capture: true });
|
|
255
|
-
if (result
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
value = result.data;
|
|
259
|
-
} catch {
|
|
260
|
-
throw new Error("Cloudflare returned an invalid authentication response.");
|
|
261
|
-
}
|
|
262
|
-
if (!record$1(value)) throw new Error("Cloudflare returned an invalid authentication response.");
|
|
274
|
+
if (!isCleanCommandExit(result)) throw new Error("Could not read the authenticated Cloudflare session.");
|
|
275
|
+
const value = result.data;
|
|
276
|
+
if (!isRecord(value)) throw new Error("Cloudflare returned an invalid authentication response.");
|
|
263
277
|
if ((value.type === "oauth" || value.type === "api_token") && typeof value.token === "string" && value.token.length > 0) return { Authorization: `Bearer ${value.token}` };
|
|
264
278
|
if (value.type === "api_key" && typeof value.key === "string" && value.key.length > 0 && typeof value.email === "string" && value.email.length > 0) return {
|
|
265
279
|
"X-Auth-Key": value.key,
|
|
@@ -306,7 +320,7 @@ function parseDurableObjectMigrations(value) {
|
|
|
306
320
|
if (value === void 0) return [];
|
|
307
321
|
if (!Array.isArray(value)) throw new Error("deploy: generated Cloudflare config has a malformed migrations field.");
|
|
308
322
|
return value.map((migration) => {
|
|
309
|
-
if (!
|
|
323
|
+
if (!isRecord(migration) || typeof migration.tag !== "string") throw new Error("deploy: generated Cloudflare config has a malformed class migration.");
|
|
310
324
|
const fields = [
|
|
311
325
|
migration.new_classes,
|
|
312
326
|
migration.new_sqlite_classes,
|
|
@@ -323,7 +337,7 @@ function parseDurableObjectMigrations(value) {
|
|
|
323
337
|
}
|
|
324
338
|
/** Cloudflare's declarative exports replace the legacy migration tag after an atomic publish. */
|
|
325
339
|
function declarativeClassesMatch(migrations, actualValue) {
|
|
326
|
-
if (!
|
|
340
|
+
if (!isRecord(actualValue)) return false;
|
|
327
341
|
const desired = /* @__PURE__ */ new Map();
|
|
328
342
|
for (const { step } of migrations) {
|
|
329
343
|
for (const [field, storage] of [["new_classes", "legacy-kv"], ["new_sqlite_classes", "sqlite"]]) for (const name of step[field] ?? []) {
|
|
@@ -331,7 +345,7 @@ function declarativeClassesMatch(migrations, actualValue) {
|
|
|
331
345
|
desired.set(name, storage);
|
|
332
346
|
}
|
|
333
347
|
for (const item of step.renamed_classes ?? []) {
|
|
334
|
-
if (!
|
|
348
|
+
if (!isRecord(item) || typeof item.from !== "string" || typeof item.to !== "string") return false;
|
|
335
349
|
const storage = desired.get(item.from);
|
|
336
350
|
if (storage !== "sqlite" && storage !== "legacy-kv") return false;
|
|
337
351
|
desired.set(item.from, "deleted");
|
|
@@ -345,8 +359,8 @@ function declarativeClassesMatch(migrations, actualValue) {
|
|
|
345
359
|
if (desired.size === 0) return false;
|
|
346
360
|
return [...desired].every(([name, storage]) => {
|
|
347
361
|
const current = actualValue[name];
|
|
348
|
-
if (storage === "deleted") return current === void 0 ||
|
|
349
|
-
return
|
|
362
|
+
if (storage === "deleted") return current === void 0 || isRecord(current) && current.state === "deleted";
|
|
363
|
+
return isRecord(current) && current.type === "durable-object" && current.storage === storage;
|
|
350
364
|
});
|
|
351
365
|
}
|
|
352
366
|
function assertCloudflareBindingsPreserved(before, after, approvedKv = [], options = {}) {
|
|
@@ -373,7 +387,7 @@ function assertCloudflareBindingsPreserved(before, after, approvedKv = [], optio
|
|
|
373
387
|
}
|
|
374
388
|
function isAssetsOnlyWorker(worker) {
|
|
375
389
|
const handlers = worker.script.handlers;
|
|
376
|
-
return
|
|
390
|
+
return isRecord(worker.runtime.assets) && (handlers === null || Array.isArray(handlers) && handlers.length === 0);
|
|
377
391
|
}
|
|
378
392
|
function existingWorkerHandlers(worker) {
|
|
379
393
|
return isAssetsOnlyWorker(worker) ? [] : worker.script.handlers;
|
|
@@ -384,12 +398,12 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
384
398
|
if (additions.length > 0) {
|
|
385
399
|
const entries = config.kv_namespaces;
|
|
386
400
|
for (const addition of additions) {
|
|
387
|
-
const matches = Array.isArray(entries) ? entries.filter((entry) =>
|
|
401
|
+
const matches = Array.isArray(entries) ? entries.filter((entry) => isRecord(entry) && entry.binding === addition.binding) : [];
|
|
388
402
|
if ((built || matches.length > 0) && (matches.length !== 1 || matches[0].id !== addition.id)) throw new Error(`Binding ${addition.binding} must reference its approved KV namespace when linking.`);
|
|
389
403
|
}
|
|
390
404
|
if (Array.isArray(entries)) config = {
|
|
391
405
|
...config,
|
|
392
|
-
kv_namespaces: entries.filter((entry) => !
|
|
406
|
+
kv_namespaces: entries.filter((entry) => !isRecord(entry) || !additions.some((addition) => addition.binding === entry.binding))
|
|
393
407
|
};
|
|
394
408
|
}
|
|
395
409
|
const handlers = existingWorkerHandlers(existing);
|
|
@@ -406,7 +420,7 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
406
420
|
const value = config[field];
|
|
407
421
|
if (hasContent(value)) throw new Error(`The existing Worker handoff cannot change ${field}. Keep this deployment limited to the existing site.`);
|
|
408
422
|
}
|
|
409
|
-
if (
|
|
423
|
+
if (isRecord(existing.runtime.exports) && Object.values(existing.runtime.exports).some((value) => isRecord(value) && value.type !== "worker")) throw new Error("The existing Worker exports stateful classes. Migrate those classes separately before linking.");
|
|
410
424
|
for (const field of [
|
|
411
425
|
"compatibility_date",
|
|
412
426
|
"compatibility_flags",
|
|
@@ -417,9 +431,9 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
417
431
|
const equal = field === "compatibility_flags" ? stringSetEqual(actual, expected) : isDeepStrictEqual(actual, expected);
|
|
418
432
|
if ((built || config[field] !== void 0) && !equal) throw new Error(`Keep the existing Worker's ${field} when linking. Update it in a later deployment.`);
|
|
419
433
|
}
|
|
420
|
-
const vars =
|
|
434
|
+
const vars = isRecord(config.vars) ? config.vars : {};
|
|
421
435
|
const metadataBindings = existing.bindings.filter((binding) => binding.type === "version_metadata");
|
|
422
|
-
const metadata =
|
|
436
|
+
const metadata = isRecord(config.version_metadata) ? config.version_metadata : void 0;
|
|
423
437
|
if (metadataBindings.length > 1 || metadataBindings.length === 1 && metadata?.binding !== metadataBindings[0].name || metadataBindings.length === 0 && config.version_metadata !== void 0) throw new Error("Keep the existing Worker version_metadata binding when linking; linking cannot add or replace it.");
|
|
424
438
|
const remote = new Map(existing.bindings.map((binding) => [binding.name, binding]));
|
|
425
439
|
for (const [name, value] of Object.entries(vars)) {
|
|
@@ -465,21 +479,21 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
465
479
|
].includes(String(binding.type))) continue;
|
|
466
480
|
if (binding.type === "version_metadata") continue;
|
|
467
481
|
if (binding.type === "assets") {
|
|
468
|
-
if (built && (!
|
|
482
|
+
if (built && (!isRecord(config.assets) || config.assets.binding !== binding.name)) throw new Error(`Keep the existing assets binding ${binding.name} when linking.`);
|
|
469
483
|
continue;
|
|
470
484
|
}
|
|
471
485
|
const mapping = supported[String(binding.type)];
|
|
472
486
|
if (!mapping) throw new Error(`The existing binding ${binding.name} (${String(binding.type)}) is not yet supported when linking.`);
|
|
473
487
|
const [field, localId, remoteId] = mapping;
|
|
474
488
|
const entries = config[field];
|
|
475
|
-
const matches = Array.isArray(entries) ? entries.filter((entry) =>
|
|
489
|
+
const matches = Array.isArray(entries) ? entries.filter((entry) => isRecord(entry) && entry.binding === binding.name) : [];
|
|
476
490
|
const entry = matches[0];
|
|
477
|
-
if (matches.length !== 1 || !
|
|
491
|
+
if (matches.length !== 1 || !isRecord(entry) || typeof binding[remoteId] !== "string" || entry[localId] !== binding[remoteId] || binding.type === "service" && ((entry.environment ?? "production") !== (binding.environment ?? "production") || entry.entrypoint !== binding.entrypoint) || binding.type === "r2_bucket" && (entry.jurisdiction ?? "default") !== (binding.jurisdiction ?? "default")) throw new Error(`Binding ${binding.name} must reference the existing Cloudflare resource when linking.`);
|
|
478
492
|
found.add(binding.name);
|
|
479
493
|
}
|
|
480
494
|
for (const [field] of Object.values(supported)) {
|
|
481
495
|
const entries = config[field];
|
|
482
|
-
if (Array.isArray(entries) && entries.some((entry) => !
|
|
496
|
+
if (Array.isArray(entries) && entries.some((entry) => !isRecord(entry) || !found.has(String(entry.binding)))) throw new Error(`Linking cannot add or replace ${field}. Use the existing resource bindings.`);
|
|
483
497
|
}
|
|
484
498
|
}
|
|
485
499
|
function newApprovedKvBindings(existing, approved) {
|
|
@@ -502,38 +516,13 @@ function stringSetEqual(left, right) {
|
|
|
502
516
|
if (!Array.isArray(left) || !left.every((value) => typeof value === "string") || !Array.isArray(right) || !right.every((value) => typeof value === "string")) return false;
|
|
503
517
|
return isDeepStrictEqual([...new Set(left)].sort(), [...new Set(right)].sort());
|
|
504
518
|
}
|
|
505
|
-
function record$1(value) {
|
|
506
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
507
|
-
}
|
|
508
519
|
function hasContent(value) {
|
|
509
520
|
if (value === void 0 || value === null) return false;
|
|
510
521
|
if (Array.isArray(value)) return value.length > 0;
|
|
511
|
-
if (
|
|
522
|
+
if (isRecord(value)) return Object.values(value).some(hasContent);
|
|
512
523
|
return true;
|
|
513
524
|
}
|
|
514
525
|
//#endregion
|
|
515
|
-
//#region src/execute.ts
|
|
516
|
-
/** Upload the already-verified Worker artifact without Wrangler autoconfiguration. */
|
|
517
|
-
async function executeCloudflareDeploy(options) {
|
|
518
|
-
if (!options.verifyUploader()) return {
|
|
519
|
-
ok: false,
|
|
520
|
-
reason: "uploader-changed"
|
|
521
|
-
};
|
|
522
|
-
const result = await Promise.resolve(options.runWrangler({
|
|
523
|
-
type: "worker.deploy",
|
|
524
|
-
...options.configPath ? { configPath: options.configPath } : {}
|
|
525
|
-
}, { capture: false }));
|
|
526
|
-
if (!isCleanCommandExit$1(result)) return {
|
|
527
|
-
ok: false,
|
|
528
|
-
reason: "deploy-failed",
|
|
529
|
-
status: result.status
|
|
530
|
-
};
|
|
531
|
-
return { ok: true };
|
|
532
|
-
}
|
|
533
|
-
function isCleanCommandExit$1(result) {
|
|
534
|
-
return result.status === 0 && result.signal == null && (result.error == null || result.error === "");
|
|
535
|
-
}
|
|
536
|
-
//#endregion
|
|
537
526
|
//#region ../../node_modules/.pnpm/pathslash@0.1.0/node_modules/pathslash/dist/index.mjs
|
|
538
527
|
const BACKSLASH_RE = /\\/g;
|
|
539
528
|
const isWindows = process.platform === "win32";
|
|
@@ -989,6 +978,10 @@ async function stabilizeCloudflareVersionTriggers(options) {
|
|
|
989
978
|
reason: "status-failed"
|
|
990
979
|
};
|
|
991
980
|
}
|
|
981
|
+
function triggerRepairOutcome(result) {
|
|
982
|
+
if (result.ok) return "succeeded";
|
|
983
|
+
return result.reason === "metadata-unavailable" ? "unavailable" : "failed";
|
|
984
|
+
}
|
|
992
985
|
function mergeTriggerCleanupBaselines(...configs) {
|
|
993
986
|
const present = configs.filter((config) => config !== void 0);
|
|
994
987
|
const unique = (values) => {
|
|
@@ -1088,6 +1081,11 @@ function triggerConfigFromWrangler(config) {
|
|
|
1088
1081
|
...addresses === void 0 ? {} : { addresses }
|
|
1089
1082
|
};
|
|
1090
1083
|
}
|
|
1084
|
+
/** Trigger state recorded by a schema-2 version message, otherwise read from local config. */
|
|
1085
|
+
function desiredTriggerConfigFor(metadata, configPath) {
|
|
1086
|
+
if (metadata?.schema === 2) return metadata.triggerConfig;
|
|
1087
|
+
return configPath ? readCloudflareTriggerConfig(configPath) : triggerConfigFromWrangler({});
|
|
1088
|
+
}
|
|
1091
1089
|
/** A well-formed `addresses` array, or `undefined` when the field is absent or malformed. */
|
|
1092
1090
|
function readEmailAddresses(value) {
|
|
1093
1091
|
return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : void 0;
|
|
@@ -1271,7 +1269,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1271
1269
|
inheritanceBaseline = recent;
|
|
1272
1270
|
}
|
|
1273
1271
|
const desiredMetadata = parseCloudflareVersionMessage(options.message);
|
|
1274
|
-
let desiredTriggerConfig = desiredMetadata
|
|
1272
|
+
let desiredTriggerConfig = desiredTriggerConfigFor(desiredMetadata, options.configPath);
|
|
1275
1273
|
let previousVersion = previousVersionId && desiredMetadata?.schema === 2 ? await readCloudflareVersionInspection(options, configPath, previousVersionId, inheritanceBaseline?.map((version) => version.inspection)) : null;
|
|
1276
1274
|
async function previousIsSecretOnlyDraft() {
|
|
1277
1275
|
if (!previousVersionId) return false;
|
|
@@ -1409,7 +1407,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1409
1407
|
};
|
|
1410
1408
|
}
|
|
1411
1409
|
options.onProgress?.("Uploading the Worker and assets...");
|
|
1412
|
-
const upload = await
|
|
1410
|
+
const upload = await options.runWrangler({
|
|
1413
1411
|
type: "versions.upload",
|
|
1414
1412
|
configPath,
|
|
1415
1413
|
workerName: options.workerName,
|
|
@@ -1417,7 +1415,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1417
1415
|
secretsFilePath: options.candidateSecretsFilePath,
|
|
1418
1416
|
assetsDirectory: options.assetsDirectoryOverride,
|
|
1419
1417
|
previewAlias: alias
|
|
1420
|
-
}, { capture: true })
|
|
1418
|
+
}, { capture: true });
|
|
1421
1419
|
if (!isCleanCommandExit(upload)) {
|
|
1422
1420
|
const cloudflareErrorCode = upload.errorCode;
|
|
1423
1421
|
const isBootstrapError = isCompletedCommand(upload) && (upload.failure === "durable-migration" || upload.failure === "not-found" || cloudflareErrorCode === DURABLE_MIGRATION_VERSION_ERROR || cloudflareErrorCode === 10007);
|
|
@@ -1495,64 +1493,23 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1495
1493
|
};
|
|
1496
1494
|
const fallbackSubdomain = extractWorkersDevSubdomain(readinessUrl);
|
|
1497
1495
|
if (fallbackSubdomain && fallbackSubdomain === options.readinessHeadersWorkersDevSubdomain) authenticatedWorkersDevSubdomain = fallbackSubdomain;
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
reason: "uploader-changed",
|
|
1501
|
-
versionId,
|
|
1502
|
-
previousVersionId: previous.versionId,
|
|
1503
|
-
rollback: "not-needed"
|
|
1504
|
-
};
|
|
1505
|
-
const stagingOwnerFailure = await verifyReadinessStagingOwner(options, configPath, previous.versionId, versionId);
|
|
1506
|
-
if (stagingOwnerFailure) return stagingOwnerFailure;
|
|
1507
|
-
const staged = await deployVersionPercentages(options, configPath, [`${previous.versionId}@100`, `${versionId}@0`], message);
|
|
1508
|
-
if (!isCleanCommandExit(staged)) {
|
|
1509
|
-
const cloudflareErrorCode = staged.errorCode;
|
|
1510
|
-
return {
|
|
1511
|
-
ok: false,
|
|
1512
|
-
reason: "readiness-staging-failed",
|
|
1513
|
-
status: staged.status,
|
|
1514
|
-
...commandDiagnosticFields(staged),
|
|
1515
|
-
...cloudflareErrorCode === void 0 ? {} : { cloudflareErrorCode },
|
|
1516
|
-
versionId,
|
|
1517
|
-
previousVersionId: previous.versionId,
|
|
1518
|
-
rollback: "not-needed"
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1496
|
+
const stagingFailure = await stageCandidateForReadiness(options, configPath, previous.versionId, versionId, message);
|
|
1497
|
+
if (stagingFailure) return stagingFailure;
|
|
1521
1498
|
stagedVersionOverride = true;
|
|
1522
1499
|
}
|
|
1500
|
+
const probe = (url) => probeReadiness(`${url.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, stagedVersionOverride ? versionId : void 0, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? 6, Number.POSITIVE_INFINITY, options.requireVersionMetadata ? versionId : void 0);
|
|
1523
1501
|
options.onProgress?.("Waiting for the Worker to become ready...");
|
|
1524
|
-
let ready = await
|
|
1502
|
+
let ready = await probe(readinessUrl);
|
|
1525
1503
|
if (ready === "access-denied" && !stagedVersionOverride && previous.versionId !== null && !options.requirePreviewForReadiness) {
|
|
1526
1504
|
const stableReadinessUrl = desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, extractWorkersDevSubdomain(readinessUrl) ?? options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes);
|
|
1527
1505
|
if (stableReadinessUrl && stableReadinessUrl !== readinessUrl) {
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
reason: "uploader-changed",
|
|
1531
|
-
versionId,
|
|
1532
|
-
previousVersionId: previous.versionId,
|
|
1533
|
-
rollback: "not-needed"
|
|
1534
|
-
};
|
|
1535
|
-
const stagingOwnerFailure = await verifyReadinessStagingOwner(options, configPath, previous.versionId, versionId);
|
|
1536
|
-
if (stagingOwnerFailure) return stagingOwnerFailure;
|
|
1537
|
-
const staged = await deployVersionPercentages(options, configPath, [`${previous.versionId}@100`, `${versionId}@0`], message);
|
|
1538
|
-
if (!isCleanCommandExit(staged)) {
|
|
1539
|
-
const cloudflareErrorCode = staged.errorCode;
|
|
1540
|
-
return {
|
|
1541
|
-
ok: false,
|
|
1542
|
-
reason: "readiness-staging-failed",
|
|
1543
|
-
status: staged.status,
|
|
1544
|
-
...commandDiagnosticFields(staged),
|
|
1545
|
-
...cloudflareErrorCode === void 0 ? {} : { cloudflareErrorCode },
|
|
1546
|
-
versionId,
|
|
1547
|
-
previousVersionId: previous.versionId,
|
|
1548
|
-
rollback: "not-needed"
|
|
1549
|
-
};
|
|
1550
|
-
}
|
|
1506
|
+
const stagingFailure = await stageCandidateForReadiness(options, configPath, previous.versionId, versionId, message);
|
|
1507
|
+
if (stagingFailure) return stagingFailure;
|
|
1551
1508
|
readinessUrl = stableReadinessUrl;
|
|
1552
1509
|
authenticatedWorkersDevSubdomain = extractWorkersDevSubdomain(stableReadinessUrl);
|
|
1553
1510
|
readinessUsesCustomRoute = !desiredTriggerConfig.workers_dev;
|
|
1554
1511
|
stagedVersionOverride = true;
|
|
1555
|
-
ready = await
|
|
1512
|
+
ready = await probe(readinessUrl);
|
|
1556
1513
|
}
|
|
1557
1514
|
}
|
|
1558
1515
|
if (ready !== "ready") return {
|
|
@@ -1658,7 +1615,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1658
1615
|
previousVersionId: previous.versionId,
|
|
1659
1616
|
activeVersionId: triggers.activeVersionId,
|
|
1660
1617
|
rollback: "not-needed",
|
|
1661
|
-
triggerRepair: triggers
|
|
1618
|
+
triggerRepair: triggerRepairOutcome(triggers)
|
|
1662
1619
|
};
|
|
1663
1620
|
if (!triggers.activeVersionId) return {
|
|
1664
1621
|
ok: false,
|
|
@@ -1697,7 +1654,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1697
1654
|
previousVersionId: previous.versionId,
|
|
1698
1655
|
activeVersionId: repair.activeVersionId ?? ownerBeforeCompensation.versionId,
|
|
1699
1656
|
rollback: "not-needed",
|
|
1700
|
-
triggerRepair: repair
|
|
1657
|
+
triggerRepair: triggerRepairOutcome(repair)
|
|
1701
1658
|
};
|
|
1702
1659
|
}
|
|
1703
1660
|
const rollback = await restorePreviousVersionAndTriggers(options, configPath, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
|
|
@@ -1783,13 +1740,13 @@ async function readCloudflareVersionInspection(options, configPath, versionId, k
|
|
|
1783
1740
|
const message = annotations?.["workers/message"];
|
|
1784
1741
|
let draft = entry;
|
|
1785
1742
|
if (annotations?.["workers/triggered_by"] === "secret" && Object.keys(annotations).length === 1 && !isWranglerSecretOnlyDraft(entry)) {
|
|
1786
|
-
const inspection = await
|
|
1743
|
+
const inspection = await options.runWrangler({
|
|
1787
1744
|
type: "versions.view",
|
|
1788
1745
|
versionId,
|
|
1789
1746
|
configPath,
|
|
1790
1747
|
workerName: options.workerName,
|
|
1791
1748
|
includeSource: true
|
|
1792
|
-
}, { capture: true })
|
|
1749
|
+
}, { capture: true });
|
|
1793
1750
|
if (isCleanCommandExit(inspection)) {
|
|
1794
1751
|
const inspected = inspection.data;
|
|
1795
1752
|
if (isRecord(inspected) && inspected.id === versionId) draft = inspected;
|
|
@@ -1809,26 +1766,22 @@ async function readCloudflareVersionInspection(options, configPath, versionId, k
|
|
|
1809
1766
|
return null;
|
|
1810
1767
|
}
|
|
1811
1768
|
async function readRecentCloudflareVersionIds(options, configPath) {
|
|
1812
|
-
const result = await
|
|
1769
|
+
const result = await options.runWrangler({
|
|
1813
1770
|
type: "versions.list",
|
|
1814
1771
|
configPath,
|
|
1815
1772
|
workerName: options.workerName
|
|
1816
|
-
}, { capture: true })
|
|
1773
|
+
}, { capture: true });
|
|
1817
1774
|
if (!isCleanCommandExit(result)) {
|
|
1818
|
-
if (
|
|
1819
|
-
return null;
|
|
1820
|
-
}
|
|
1821
|
-
try {
|
|
1822
|
-
const versions = result.data;
|
|
1823
|
-
if (!Array.isArray(versions) || !versions.every((version) => isRecord(version) && typeof version.id === "string" && typeof version.number === "number" && Number.isSafeInteger(version.number))) return null;
|
|
1824
|
-
return versions.map((version) => ({
|
|
1825
|
-
id: version.id,
|
|
1826
|
-
number: version.number,
|
|
1827
|
-
inspection: version
|
|
1828
|
-
}));
|
|
1829
|
-
} catch {
|
|
1775
|
+
if (isWorkerNotFound(result)) return [];
|
|
1830
1776
|
return null;
|
|
1831
1777
|
}
|
|
1778
|
+
const versions = result.data;
|
|
1779
|
+
if (!Array.isArray(versions) || !versions.every((version) => isRecord(version) && typeof version.id === "string" && typeof version.number === "number" && Number.isSafeInteger(version.number))) return null;
|
|
1780
|
+
return versions.map((version) => ({
|
|
1781
|
+
id: version.id,
|
|
1782
|
+
number: version.number,
|
|
1783
|
+
inspection: version
|
|
1784
|
+
}));
|
|
1832
1785
|
}
|
|
1833
1786
|
function arraysEqual(left, right) {
|
|
1834
1787
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
@@ -1844,31 +1797,27 @@ async function candidateReplacesAllRemoteSecrets(options, configPath, activeVers
|
|
|
1844
1797
|
return secretBindings.every((bindings) => bindings.every((binding) => binding.type === "secret_text" && Object.hasOwn(options.candidateSecrets ?? {}, binding.name)));
|
|
1845
1798
|
}
|
|
1846
1799
|
async function readCloudflareVersionSecretBindings(options, configPath, versionId) {
|
|
1847
|
-
const result = await
|
|
1800
|
+
const result = await options.runWrangler({
|
|
1848
1801
|
type: "versions.view",
|
|
1849
1802
|
versionId,
|
|
1850
1803
|
configPath,
|
|
1851
1804
|
workerName: options.workerName
|
|
1852
|
-
}, { capture: true })
|
|
1805
|
+
}, { capture: true });
|
|
1853
1806
|
if (!isCleanCommandExit(result)) return null;
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
return secrets;
|
|
1869
|
-
} catch {
|
|
1870
|
-
return null;
|
|
1807
|
+
const version = result.data;
|
|
1808
|
+
if (!isRecord(version) || version.id !== versionId || !isRecord(version.resources)) return null;
|
|
1809
|
+
const bindings = version.resources.bindings;
|
|
1810
|
+
if (!Array.isArray(bindings) || !bindings.every(isRecord)) return null;
|
|
1811
|
+
const secrets = [];
|
|
1812
|
+
for (const binding of bindings) {
|
|
1813
|
+
if (binding.type !== "secret_text" && binding.type !== "secret_key") continue;
|
|
1814
|
+
if (typeof binding.name !== "string") return null;
|
|
1815
|
+
secrets.push({
|
|
1816
|
+
name: binding.name,
|
|
1817
|
+
type: binding.type
|
|
1818
|
+
});
|
|
1871
1819
|
}
|
|
1820
|
+
return secrets;
|
|
1872
1821
|
}
|
|
1873
1822
|
/**
|
|
1874
1823
|
* The Versions API cannot create a Worker or its initial Durable Object migration history, and
|
|
@@ -1899,14 +1848,14 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
|
|
|
1899
1848
|
};
|
|
1900
1849
|
}
|
|
1901
1850
|
options.onProgress?.(atomic ? "Publishing the Worker atomically..." : "Publishing the first Worker deployment...");
|
|
1902
|
-
const bootstrap = await
|
|
1851
|
+
const bootstrap = await options.runWrangler({
|
|
1903
1852
|
type: "worker.deploy",
|
|
1904
1853
|
configPath,
|
|
1905
1854
|
workerName: options.workerName,
|
|
1906
1855
|
message: options.message,
|
|
1907
1856
|
secretsFilePath: options.candidateSecretsFilePath,
|
|
1908
1857
|
assetsDirectory: options.assetsDirectoryOverride
|
|
1909
|
-
}, { capture: true })
|
|
1858
|
+
}, { capture: true });
|
|
1910
1859
|
if (!isCleanCommandExit(bootstrap)) {
|
|
1911
1860
|
const cloudflareErrorCode = bootstrap.errorCode;
|
|
1912
1861
|
return {
|
|
@@ -1920,8 +1869,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
|
|
|
1920
1869
|
}
|
|
1921
1870
|
const published = readUploadResult(bootstrap);
|
|
1922
1871
|
const versionId = published?.versionId;
|
|
1923
|
-
const
|
|
1924
|
-
const desiredTriggerConfig = desiredMetadata?.schema === 2 ? desiredMetadata.triggerConfig : options.configPath ? readCloudflareTriggerConfig(options.configPath) : triggerConfigFromWrangler({});
|
|
1872
|
+
const desiredTriggerConfig = desiredTriggerConfigFor(parseCloudflareVersionMessage(options.message), options.configPath);
|
|
1925
1873
|
const reportedOrConfiguredUrl = published?.previewUrl ?? published?.workersDevUrl ?? (desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes));
|
|
1926
1874
|
if (!versionId || !reportedOrConfiguredUrl) return {
|
|
1927
1875
|
ok: false,
|
|
@@ -2020,7 +1968,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
|
|
|
2020
1968
|
previousVersionId,
|
|
2021
1969
|
activeVersionId: triggers.activeVersionId,
|
|
2022
1970
|
rollback: superseded ? "not-needed" : triggers.activeVersionId ? "unavailable" : "unsafe",
|
|
2023
|
-
...superseded ? { triggerRepair: triggers
|
|
1971
|
+
...superseded ? { triggerRepair: triggerRepairOutcome(triggers) } : {}
|
|
2024
1972
|
};
|
|
2025
1973
|
}
|
|
2026
1974
|
const previewUrl = publishedCloudflareUrl(options.workerName, desiredTriggerConfig, reportedOrConfiguredUrl);
|
|
@@ -2062,7 +2010,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
|
|
|
2062
2010
|
previousVersionId,
|
|
2063
2011
|
activeVersionId: repair.activeVersionId,
|
|
2064
2012
|
rollback: "not-needed",
|
|
2065
|
-
triggerRepair: repair
|
|
2013
|
+
triggerRepair: triggerRepairOutcome(repair)
|
|
2066
2014
|
};
|
|
2067
2015
|
}
|
|
2068
2016
|
return {
|
|
@@ -2101,13 +2049,13 @@ function isContainersUnavailable(result) {
|
|
|
2101
2049
|
return result.failure === "containers-unavailable" || (result.errors?.some(({ message }) => /Cloudflare Containers[^\n]*(?:Workers Paid|not (?:enabled|available)|subscription)/i.test(message) || /\/containers\/me(?:\b|\?)/i.test(message) && /\b403\b/.test(message)) ?? false);
|
|
2102
2050
|
}
|
|
2103
2051
|
async function readCurrentProductionVersion(options, configPath) {
|
|
2104
|
-
const result = await
|
|
2052
|
+
const result = await options.runWrangler({
|
|
2105
2053
|
type: "deployments.status",
|
|
2106
2054
|
configPath,
|
|
2107
2055
|
workerName: options.workerName
|
|
2108
|
-
}, { capture: true })
|
|
2056
|
+
}, { capture: true });
|
|
2109
2057
|
if (!isCleanCommandExit(result)) {
|
|
2110
|
-
if (
|
|
2058
|
+
if (isWorkerNotFound(result)) return {
|
|
2111
2059
|
kind: "ok",
|
|
2112
2060
|
versionId: null,
|
|
2113
2061
|
versions: []
|
|
@@ -2152,6 +2100,33 @@ function stagedVersionPercentages(previousVersionId, versionId) {
|
|
|
2152
2100
|
percentage: 0
|
|
2153
2101
|
}] : [];
|
|
2154
2102
|
}
|
|
2103
|
+
/** Stage the candidate at 0% beside the unchanged previous version so readiness can select it. */
|
|
2104
|
+
async function stageCandidateForReadiness(options, configPath, previousVersionId, versionId, message) {
|
|
2105
|
+
if (!options.verifyUploader()) return {
|
|
2106
|
+
ok: false,
|
|
2107
|
+
reason: "uploader-changed",
|
|
2108
|
+
versionId,
|
|
2109
|
+
previousVersionId,
|
|
2110
|
+
rollback: "not-needed"
|
|
2111
|
+
};
|
|
2112
|
+
const ownerFailure = await verifyReadinessStagingOwner(options, configPath, previousVersionId, versionId);
|
|
2113
|
+
if (ownerFailure) return ownerFailure;
|
|
2114
|
+
const staged = await deployVersionPercentages(options, configPath, [`${previousVersionId}@100`, `${versionId}@0`], message);
|
|
2115
|
+
if (!isCleanCommandExit(staged)) {
|
|
2116
|
+
const cloudflareErrorCode = staged.errorCode;
|
|
2117
|
+
return {
|
|
2118
|
+
ok: false,
|
|
2119
|
+
reason: "readiness-staging-failed",
|
|
2120
|
+
status: staged.status,
|
|
2121
|
+
...commandDiagnosticFields(staged),
|
|
2122
|
+
...cloudflareErrorCode === void 0 ? {} : { cloudflareErrorCode },
|
|
2123
|
+
versionId,
|
|
2124
|
+
previousVersionId,
|
|
2125
|
+
rollback: "not-needed"
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2155
2130
|
async function verifyReadinessStagingOwner(options, configPath, previousVersionId, versionId) {
|
|
2156
2131
|
const owner = await readCurrentProductionVersion(options, configPath);
|
|
2157
2132
|
if (owner.kind === "failed") return {
|
|
@@ -2315,12 +2290,6 @@ function workersDevSubdomainResult(url) {
|
|
|
2315
2290
|
const workersDevSubdomain = extractWorkersDevSubdomain(url);
|
|
2316
2291
|
return workersDevSubdomain ? { workersDevSubdomain } : {};
|
|
2317
2292
|
}
|
|
2318
|
-
function isCompletedCommand(result) {
|
|
2319
|
-
return Number.isSafeInteger(result.status) && result.status >= 0 && result.signal == null && (result.error == null || result.error === "");
|
|
2320
|
-
}
|
|
2321
|
-
function isCleanCommandExit(result) {
|
|
2322
|
-
return result.status === 0 && isCompletedCommand(result);
|
|
2323
|
-
}
|
|
2324
2293
|
function defaultSleep(milliseconds) {
|
|
2325
2294
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
2326
2295
|
}
|
|
@@ -2372,7 +2341,7 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2372
2341
|
if (response.status === 401 || response.status === 403) tokenPromise = void 0;
|
|
2373
2342
|
if (response.ok) {
|
|
2374
2343
|
const body = await response.json();
|
|
2375
|
-
if (
|
|
2344
|
+
if (isRecord(body) && body.success === true && isRecord(body.result)) {
|
|
2376
2345
|
const result = body.result;
|
|
2377
2346
|
if (kind === "deployment" && Array.isArray(result.deployments)) {
|
|
2378
2347
|
const latest = result.deployments[0];
|
|
@@ -2382,7 +2351,7 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2382
2351
|
stderr: `The Worker ${options.workerName} has no deployments.`,
|
|
2383
2352
|
errorCode: 10007
|
|
2384
2353
|
};
|
|
2385
|
-
if (
|
|
2354
|
+
if (isRecord(latest) && Array.isArray(latest.versions)) return {
|
|
2386
2355
|
status: 0,
|
|
2387
2356
|
stdout: "",
|
|
2388
2357
|
data: latest,
|
|
@@ -2397,7 +2366,7 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2397
2366
|
};
|
|
2398
2367
|
if (kind === "versions" && Array.isArray(result.items)) {
|
|
2399
2368
|
const items = result.items;
|
|
2400
|
-
if (items.every((item) =>
|
|
2369
|
+
if (items.every((item) => isRecord(item) && isRecord(item.metadata) && typeof item.metadata.created_on === "string")) return {
|
|
2401
2370
|
status: 0,
|
|
2402
2371
|
stdout: "",
|
|
2403
2372
|
data: items.sort((a, b) => a.metadata.created_on.localeCompare(b.metadata.created_on)).slice(-10),
|
|
@@ -2415,8 +2384,5 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2415
2384
|
return fallback(operation, runOptions);
|
|
2416
2385
|
};
|
|
2417
2386
|
}
|
|
2418
|
-
function record(value) {
|
|
2419
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2420
|
-
}
|
|
2421
2387
|
//#endregion
|
|
2422
2388
|
export { CloudflareWorkerInspectionError, VOID_SECRET_DRAFT_SOURCE, activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, createCloudflareMetadataRunner, deployCloudflareVersionTraffic, deployCloudflareVersionTriggers, encodeCloudflareVersionMessage, executeCloudflareDeploy, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseCloudflareVersionMessage, parseRootWranglerConfig, readBindingFieldPresence, readCloudflareTriggerConfig, readCloudflareVersionMigrationTag, readCloudflareWorkerMigrationTag, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stabilizeCloudflareVersionTriggers, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@void/deploy-cloudflare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
|
+
"description": "Cloudflare deployment primitives for Void runtimes and deployment adapters.",
|
|
5
|
+
"homepage": "https://void.cloud",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/voidzero-dev/void/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
4
10
|
"repository": {
|
|
5
11
|
"type": "git",
|
|
6
12
|
"url": "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -20,15 +26,15 @@
|
|
|
20
26
|
"access": "public"
|
|
21
27
|
},
|
|
22
28
|
"dependencies": {
|
|
23
|
-
"@void/deploy-core": "0.
|
|
24
|
-
"jsonc-parser": "3.3.1"
|
|
29
|
+
"@void/deploy-core": "0.27.0",
|
|
30
|
+
"jsonc-parser": "^3.3.1"
|
|
25
31
|
},
|
|
26
32
|
"devDependencies": {
|
|
27
|
-
"@cloudflare/workers-types": "^
|
|
33
|
+
"@cloudflare/workers-types": "^5.20261009.1",
|
|
28
34
|
"@types/node": "^26.6.4",
|
|
29
35
|
"pathslash": "^0.1.0",
|
|
30
36
|
"typescript": "7.0.2",
|
|
31
|
-
"vite-plus": "1.
|
|
37
|
+
"vite-plus": "1.1.0"
|
|
32
38
|
},
|
|
33
39
|
"scripts": {
|
|
34
40
|
"build": "vp pack",
|