@void/deploy-cloudflare 0.24.0 → 0.26.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 +2 -25
- package/dist/index.mjs +16 -21
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
# @void/deploy-cloudflare
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cloudflare deployment primitives used by the Void CLI. Provides Worker configuration reads, uploads, activation, and deployment verification.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
Cloudflare upload boundary. Source inference and app builds remain in `void`;
|
|
7
|
-
provider-neutral contracts and plans remain in `@void/deploy-core`.
|
|
8
|
-
|
|
9
|
-
Existing Worker handoffs read the active version, validate resource identities,
|
|
10
|
-
and check the uploaded bindings before activation. Traffic-only activation uses
|
|
11
|
-
an isolated config to retain Worker settings and triggers. Trigger snapshots
|
|
12
|
-
record when configuration was preserved, so rollback can keep those settings
|
|
13
|
-
for versions originally deployed outside Void.
|
|
14
|
-
|
|
15
|
-
Handoff verifiers can accept an explicit list of new KV binding identities.
|
|
16
|
-
Only those exact namespaces may be added; existing bindings, variables, secrets,
|
|
17
|
-
and handlers must remain unchanged. New bindings cannot alias an existing KV
|
|
18
|
-
namespace. The Void CLI uses this for the migration's explicit ISR cache choice.
|
|
19
|
-
|
|
20
|
-
First-deployment readiness allows up to one minute for the new Worker's public
|
|
21
|
-
route to propagate, with bounded requests and backoff. A successful check still
|
|
22
|
-
requires the ready response, and Cloudflare Access denials fail immediately.
|
|
23
|
-
Subsequent version previews retain the shorter retry window.
|
|
24
|
-
|
|
25
|
-
Failed version uploads and first-deployment bootstraps return a bounded diagnostic
|
|
26
|
-
alongside the exit status and Cloudflare error code. It retains validation messages
|
|
27
|
-
and stack locations, strips terminal formatting, excludes stdout binding tables,
|
|
28
|
-
and redacts common credential formats before callers display or log it.
|
|
5
|
+
Applications normally deploy with `void deploy --platform cloudflare`. See the [Cloudflare guide](https://void.cloud/integrations/cloudflare) for configuration and credentials, or [Platform Development](https://void.cloud/guide/platform-development) for runtime and adapter work.
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isDeepStrictEqual, stripVTControlCharacters } from "node:util";
|
|
2
2
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { SyntaxKind, applyEdits, createScanner, modify, parse, parseTree } from "jsonc-parser";
|
|
4
|
+
import { isRecord } from "@void/deploy-core";
|
|
4
5
|
import nodePath from "node:path";
|
|
5
6
|
import { createHash } from "node:crypto";
|
|
6
7
|
import { tmpdir } from "node:os";
|
|
@@ -88,16 +89,16 @@ function resolveD1MigrateTarget(config, binding) {
|
|
|
88
89
|
* application code configuration or non-secret resource that an ordinary deploy could own.
|
|
89
90
|
*/
|
|
90
91
|
function isWranglerSecretOnlyDraft(entry) {
|
|
91
|
-
if (!isRecord
|
|
92
|
+
if (!isRecord(entry.annotations)) return false;
|
|
92
93
|
const annotationKeys = Object.keys(entry.annotations);
|
|
93
94
|
if (entry.annotations["workers/triggered_by"] !== "secret" || annotationKeys.some((key) => key !== "workers/triggered_by")) return false;
|
|
94
|
-
if (!isRecord
|
|
95
|
+
if (!isRecord(entry.resources)) return false;
|
|
95
96
|
const { bindings, script, script_runtime: scriptRuntime } = entry.resources;
|
|
96
|
-
if (!Array.isArray(bindings) || bindings.length === 0 || !bindings.every((binding) => isRecord
|
|
97
|
-
if (!isRecord
|
|
98
|
-
if (!isRecord
|
|
97
|
+
if (!Array.isArray(bindings) || bindings.length === 0 || !bindings.every((binding) => isRecord(binding) && typeof binding.name === "string" && binding.name.length > 0 && binding.type === "secret_text" && Object.keys(binding).every((key) => key === "name" || key === "type"))) return false;
|
|
98
|
+
if (!isRecord(script) || !Array.isArray(script.handlers) || script.handlers.length !== 1 || script.handlers[0] !== "fetch" || script.placement_mode !== void 0) return false;
|
|
99
|
+
if (!isRecord(scriptRuntime)) return false;
|
|
99
100
|
const runtimeKeys = Object.keys(scriptRuntime);
|
|
100
|
-
return scriptRuntime.usage_model === "standard" && (scriptRuntime.limits === void 0 || isRecord
|
|
101
|
+
return scriptRuntime.usage_model === "standard" && (scriptRuntime.limits === void 0 || isRecord(scriptRuntime.limits) && Object.keys(scriptRuntime.limits).length === 0) && runtimeKeys.every((key) => key === "usage_model" || key === "limits");
|
|
101
102
|
}
|
|
102
103
|
const VOID_SECRET_DRAFT_SOURCE = "export default { fetch() { return new Response(\"\"); } };\n";
|
|
103
104
|
/** Prove a cf-created placeholder from the exact immutable version's source. */
|
|
@@ -120,25 +121,22 @@ function isVoidSecretOnlyDraft(entry) {
|
|
|
120
121
|
"env",
|
|
121
122
|
"resources"
|
|
122
123
|
]);
|
|
123
|
-
if (Object.keys(entry).some((key) => !metadataFields.has(key)) || entry.source !== "cf_cli" || !isRecord
|
|
124
|
+
if (Object.keys(entry).some((key) => !metadataFields.has(key)) || entry.source !== "cf_cli" || !isRecord(entry.annotations) || Object.keys(entry.annotations).length !== 1 || entry.annotations["workers/triggered_by"] !== "secret" || entry.main_module !== "index.js" || !Array.isArray(entry.urls) || entry.urls.length !== 0 || !Array.isArray(entry.modules) || entry.modules.length !== 1 || !Array.isArray(entry.bindings) || entry.bindings.length === 0) return false;
|
|
124
125
|
const module = entry.modules[0];
|
|
125
|
-
if (!isRecord
|
|
126
|
+
if (!isRecord(module) || Object.keys(module).length !== 3 || module.name !== "index.js" || module.content_type !== "application/javascript+module" || module.content_base64 !== Buffer.from("export default { fetch() { return new Response(\"\"); } };\n").toString("base64")) return false;
|
|
126
127
|
const names = /* @__PURE__ */ new Set();
|
|
127
128
|
for (const binding of entry.bindings) {
|
|
128
|
-
if (!isRecord
|
|
129
|
+
if (!isRecord(binding) || Object.keys(binding).length !== 2 || typeof binding.name !== "string" || binding.name.length === 0 || names.has(binding.name) || binding.type !== "secret_text") return false;
|
|
129
130
|
names.add(binding.name);
|
|
130
131
|
}
|
|
131
|
-
if (entry.env !== void 0 && (!isRecord
|
|
132
|
+
if (entry.env !== void 0 && (!isRecord(entry.env) || Object.keys(entry.env).length !== names.size || Object.entries(entry.env).some(([name, binding]) => !names.has(name) || !isRecord(binding) || Object.keys(binding).length !== 1 || binding.type !== "secret_text"))) return false;
|
|
132
133
|
if (entry.resources !== void 0) {
|
|
133
|
-
if (!isRecord
|
|
134
|
+
if (!isRecord(entry.resources) || Object.keys(entry.resources).length !== 1) return false;
|
|
134
135
|
const bindings = entry.resources.bindings;
|
|
135
136
|
if (!Array.isArray(bindings) || !isDeepStrictEqual(bindings, entry.bindings)) return false;
|
|
136
137
|
}
|
|
137
138
|
return true;
|
|
138
139
|
}
|
|
139
|
-
function isRecord$1(value) {
|
|
140
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
141
|
-
}
|
|
142
140
|
//#endregion
|
|
143
141
|
//#region src/existing.ts
|
|
144
142
|
/** A failed remote read, distinct from an invalid or changing Worker configuration. */
|
|
@@ -1058,9 +1056,10 @@ function hasCustomDomains(routes) {
|
|
|
1058
1056
|
/** Select a configured HTTPS route that is guaranteed to cover /__void/ready. */
|
|
1059
1057
|
function customRouteReadinessUrl(routes) {
|
|
1060
1058
|
for (const route of routes) {
|
|
1061
|
-
const
|
|
1059
|
+
const record = isRecord(route) ? route : void 0;
|
|
1060
|
+
const pattern = typeof route === "string" ? route : typeof record?.pattern === "string" ? record.pattern : void 0;
|
|
1062
1061
|
if (!pattern) continue;
|
|
1063
|
-
const customDomain =
|
|
1062
|
+
const customDomain = record?.custom_domain === true;
|
|
1064
1063
|
const withoutScheme = pattern.replace(/^https?:\/\//i, "");
|
|
1065
1064
|
const slash = withoutScheme.indexOf("/");
|
|
1066
1065
|
const hostname = (slash < 0 ? withoutScheme : withoutScheme.slice(0, slash)).trim();
|
|
@@ -1108,7 +1107,6 @@ function stableJson(value) {
|
|
|
1108
1107
|
return JSON.stringify(value);
|
|
1109
1108
|
}
|
|
1110
1109
|
function parseTriggerConfig(value) {
|
|
1111
|
-
if (value === void 0) return null;
|
|
1112
1110
|
if (!isRecord(value)) return null;
|
|
1113
1111
|
if ([
|
|
1114
1112
|
"preserve",
|
|
@@ -1165,9 +1163,6 @@ function resolvePreservedTraffic(desired, previous, workerExists) {
|
|
|
1165
1163
|
...desired.addresses === void 0 ? {} : { addresses: desired.addresses }
|
|
1166
1164
|
};
|
|
1167
1165
|
}
|
|
1168
|
-
function isRecord(value) {
|
|
1169
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1170
|
-
}
|
|
1171
1166
|
function isCandidatePreviewUrl(value, workerName, versionId, alias) {
|
|
1172
1167
|
try {
|
|
1173
1168
|
const url = new URL(value);
|
|
@@ -1803,7 +1798,7 @@ async function readCloudflareVersionInspection(options, configPath, versionId, k
|
|
|
1803
1798
|
const isVoidDraft = isVoidSecretOnlyDraft(draft);
|
|
1804
1799
|
return {
|
|
1805
1800
|
metadata: typeof message === "string" ? parseCloudflareVersionMessage(message) : null,
|
|
1806
|
-
isSecretOnlyDraft: isWranglerSecretOnlyDraft(draft) ||
|
|
1801
|
+
isSecretOnlyDraft: isWranglerSecretOnlyDraft(draft) || isVoidDraft,
|
|
1807
1802
|
isVoidSecretOnlyDraft: isVoidDraft,
|
|
1808
1803
|
voidDraftSecretNames: isVoidDraft ? draft.bindings.map((binding) => binding.name) : null
|
|
1809
1804
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@void/deploy-cloudflare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@void/deploy-core": "0.
|
|
23
|
+
"@void/deploy-core": "0.26.0",
|
|
24
24
|
"jsonc-parser": "3.3.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@cloudflare/workers-types": "^4.20260702.1",
|
|
28
|
-
"@types/node": "^26.6.
|
|
28
|
+
"@types/node": "^26.6.4",
|
|
29
29
|
"pathslash": "^0.1.0",
|
|
30
30
|
"typescript": "7.0.2",
|
|
31
31
|
"vite-plus": "1.0.0"
|