@vinext/cloudflare 1.0.0-beta.8 → 1.0.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.
Files changed (59) hide show
  1. package/README.md +174 -37
  2. package/dist/cache/cdn-adapter-config.d.ts +2 -1
  3. package/dist/cache/cdn-adapter-config.js +13 -5
  4. package/dist/cache/cdn-adapter.d.ts +5 -56
  5. package/dist/cache/cdn-adapter.js +3 -61
  6. package/dist/cache/cdn-adapter.runtime.d.ts +1 -0
  7. package/dist/cache/cdn-adapter.runtime.js +17 -3
  8. package/dist/cache/cdn-adapter.worker.d.ts +1 -0
  9. package/dist/cache/cdn-adapter.worker.js +6 -4
  10. package/dist/cache/cdn-build-id.d.ts +1 -1
  11. package/dist/cache/cdn-build-id.js +1 -1
  12. package/dist/cache/config.d.ts +137 -0
  13. package/dist/cache/config.js +87 -0
  14. package/dist/cache/kv-data-adapter.d.ts +5 -1
  15. package/dist/cache/kv-data-adapter.js +6 -2
  16. package/dist/cache/kv-data-adapter.runtime.js +13 -9
  17. package/dist/cache/kv-key.d.ts +7 -4
  18. package/dist/cache/kv-key.js +16 -5
  19. package/dist/cache/response-store-adapter.d.ts +36 -0
  20. package/dist/cache/response-store-adapter.js +26 -1
  21. package/dist/cache/response-store-adapter.self-contained.worker.d.ts +1 -0
  22. package/dist/cache/response-store-adapter.self-contained.worker.js +3 -1
  23. package/dist/cache/response-store-adapter.service-binding.worker.d.ts +1 -0
  24. package/dist/cache/response-store-adapter.service-binding.worker.js +3 -1
  25. package/dist/cache/response-store-adapter.worker.d.ts +1 -1
  26. package/dist/cache/response-store-adapter.worker.js +148 -81
  27. package/dist/cache/response-store-cdn.runtime.js +1 -0
  28. package/dist/cache/response-store-data.runtime.js +53 -31
  29. package/dist/cache/static-assets-adapter.build.d.ts +6 -0
  30. package/dist/cache/static-assets-adapter.build.js +65 -0
  31. package/dist/cache/static-assets-adapter.d.ts +27 -0
  32. package/dist/cache/static-assets-adapter.js +26 -0
  33. package/dist/cache/static-assets-adapter.runtime.d.ts +26 -0
  34. package/dist/cache/static-assets-adapter.runtime.js +77 -0
  35. package/dist/cache/static-assets-adapter.shared.d.ts +12 -0
  36. package/dist/cache/static-assets-adapter.shared.js +4 -0
  37. package/dist/cache/workers-cache-cdn-adapter.d.ts +58 -0
  38. package/dist/cache/workers-cache-cdn-adapter.js +65 -0
  39. package/dist/cacheability-artifact.d.ts +7 -1
  40. package/dist/cacheability-artifact.js +60 -21
  41. package/dist/cacheability-probe.d.ts +2 -0
  42. package/dist/cacheability-probe.js +107 -13
  43. package/dist/cdn-warm.d.ts +2 -1
  44. package/dist/cdn-warm.js +25 -8
  45. package/dist/deploy-config.d.ts +3 -8
  46. package/dist/deploy-config.js +5 -23
  47. package/dist/deploy-help.js +58 -47
  48. package/dist/deploy.d.ts +31 -21
  49. package/dist/deploy.js +501 -286
  50. package/dist/tpr.d.ts +29 -72
  51. package/dist/tpr.js +52 -601
  52. package/dist/version-deploy.d.ts +27 -0
  53. package/dist/version-deploy.js +125 -5
  54. package/dist/wrangler-config.d.ts +19 -0
  55. package/dist/wrangler-config.js +294 -0
  56. package/dist/wrangler-version-metadata.js +1 -1
  57. package/package.json +16 -9
  58. package/dist/prerender-kv-populate.d.ts +0 -24
  59. package/dist/prerender-kv-populate.js +0 -153
@@ -25,19 +25,46 @@ type WranglerVersionArgs = {
25
25
  args: string[];
26
26
  env: string | undefined;
27
27
  };
28
+ type CfVersionArgs = {
29
+ args: string[];
30
+ mode: string | undefined;
31
+ };
32
+ export declare function readBuildOutputWorkerName(root: string): string;
28
33
  export declare function parseVersionId(output: string): string | null;
29
34
  export declare function parseUploadedWorkerName(output: string): string | null;
30
35
  export declare function parseWranglerVersionUploadOutput(output: string): WranglerVersionUploadResult;
31
36
  export declare function buildWranglerVersionUploadArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
32
37
  previewAlias?: string;
33
38
  }): WranglerVersionArgs;
39
+ export declare function buildCfVersionUploadArgs(options: Pick<DeployOptions, "preview" | "env"> & {
40
+ previewAlias?: string;
41
+ }): CfVersionArgs;
34
42
  export declare function buildWranglerVersionDeployArgs(versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
35
43
  export declare function buildWranglerDeploymentsStatusArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
36
44
  export declare function buildWranglerTriggersDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
37
45
  export declare function parseWranglerDeploymentStatusOutput(output: string): WranglerDeploymentStatus;
46
+ /** The first entry is the deployment currently serving traffic. */
47
+ export declare function parseCfDeploymentStatusOutput(output: string): WranglerDeploymentStatus;
48
+ export declare function runCfDeploymentStatus(root: string, options: {
49
+ name: string;
50
+ env?: string;
51
+ verbose?: boolean;
52
+ }, execute?: typeof execFileSync): WranglerDeploymentStatus;
53
+ export declare function runCfVersionDeploy(root: string, versionTraffic: readonly WranglerVersionTraffic[], options: {
54
+ name: string;
55
+ env?: string;
56
+ verbose?: boolean;
57
+ }, _phase?: "stage" | "promote-warmed" | "promote-uploaded", execute?: typeof execFileSync): WranglerVersionDeployResult;
58
+ export declare function runCfTriggersDeploy(root: string, options: {
59
+ env?: string;
60
+ verbose?: boolean;
61
+ }, execute?: typeof execFileSync): WranglerVersionDeployResult;
38
62
  export declare function runWranglerVersionUpload(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
39
63
  previewAlias?: string;
40
64
  }, execute?: typeof execFileSync): WranglerVersionUploadResult;
65
+ export declare function runCfVersionUpload(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
66
+ previewAlias?: string;
67
+ }, execute?: typeof execFileSync): WranglerVersionUploadResult;
41
68
  export declare function runWranglerVersionDeploy(root: string, versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, phase?: "stage" | "promote-warmed" | "promote-uploaded", execute?: typeof execFileSync): WranglerVersionDeployResult;
42
69
  export declare function runWranglerDeploymentStatus(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerDeploymentStatus;
43
70
  export declare function runWranglerTriggersDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerVersionDeployResult;
@@ -1,11 +1,26 @@
1
1
  import { parseWorkersDevUrl } from "./workers-dev-url.js";
2
2
  import { parseCdnWarmupDeploymentUrl } from "./worker-deployment-url.js";
3
- import { buildNodeCliInvocation, resolveWranglerBin, validateWranglerEnvName } from "./deploy.js";
3
+ import { buildNodeCliInvocation, resolveCfBin, resolveWranglerBin, validateWranglerEnvName } from "./deploy.js";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
4
6
  import { execFileSync } from "node:child_process";
7
+ import { stripVTControlCharacters } from "node:util";
5
8
  //#region src/version-deploy.ts
6
9
  function isRecord(value) {
7
10
  return typeof value === "object" && value !== null && !Array.isArray(value);
8
11
  }
12
+ function readBuildOutputWorkerName(root) {
13
+ const configPath = path.join(root, ".cloudflare", "output", "v0", "workers", "default", "worker.config.json");
14
+ let config;
15
+ try {
16
+ config = JSON.parse(fs.readFileSync(configPath, "utf8"));
17
+ } catch (cause) {
18
+ throw new Error("Could not read the generated Cloudflare Build Output config. Rebuild the app before deploying.", { cause });
19
+ }
20
+ const name = isRecord(config) ? config.name : void 0;
21
+ if (typeof name !== "string" || name.length === 0) throw new Error("The generated Cloudflare Build Output config does not declare a Worker name.");
22
+ return name;
23
+ }
9
24
  function parseJsonObject(output) {
10
25
  const trimmed = output.trim();
11
26
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
@@ -63,7 +78,7 @@ function parseVersionId(output) {
63
78
  return output.match(new RegExp(`\\b${versionIdPattern}\\b`))?.[0] ?? null;
64
79
  }
65
80
  function parseUploadedWorkerName(output) {
66
- return output.match(/^\s*Uploaded\s+(\S+)\s+\(\d+(?:\.\d+)?\s+sec\)\s*$/im)?.[1] ?? null;
81
+ return stripVTControlCharacters(output).match(/^\s*(?:[│|]\s*)?Uploaded\s+(\S+)\s+\(\d+(?:\.\d+)?\s+sec\)\s*$/im)?.[1] ?? null;
67
82
  }
68
83
  function parseWranglerVersionUploadOutput(output) {
69
84
  const parsed = parseJsonObject(output);
@@ -90,6 +105,21 @@ function buildWranglerVersionUploadArgs(options) {
90
105
  env
91
106
  };
92
107
  }
108
+ function buildCfVersionUploadArgs(options) {
109
+ const mode = options.env || (options.preview ? "preview" : void 0);
110
+ const args = [
111
+ "workers",
112
+ "versions",
113
+ "create",
114
+ "--prebuilt"
115
+ ];
116
+ if (mode) args.push("--mode", validateWranglerEnvName(mode));
117
+ if (options.previewAlias) args.push("--preview-alias", options.previewAlias);
118
+ return {
119
+ args,
120
+ mode
121
+ };
122
+ }
93
123
  function buildWranglerVersionDeployArgs(versionTraffic, options) {
94
124
  const args = [
95
125
  "versions",
@@ -145,6 +175,17 @@ function runWranglerCommand(root, args, execute = execFileSync, verbose = false)
145
175
  if (verbose && output.trim()) for (const line of output.trim().split("\n")) console.log(` ${line}`);
146
176
  return output;
147
177
  }
178
+ function runCfCommand(root, args, execute = execFileSync, verbose = false) {
179
+ const invocation = buildNodeCliInvocation(resolveCfBin(root), args);
180
+ const output = execute(invocation.file, invocation.args, {
181
+ cwd: root,
182
+ stdio: "pipe",
183
+ encoding: "utf-8",
184
+ shell: false
185
+ });
186
+ if (verbose && output.trim()) for (const line of output.trim().split("\n")) console.log(` ${line}`);
187
+ return output;
188
+ }
148
189
  function errorText(error) {
149
190
  if (!error || typeof error !== "object") return String(error);
150
191
  const parts = error instanceof Error ? [error.message] : [];
@@ -164,7 +205,7 @@ function isMissingWorkerVersionUploadError(error) {
164
205
  return /cannot upload a new version of a Worker that does not yet exist/i.test(errorText(error));
165
206
  }
166
207
  function withInitialDeployRequiredMessage() {
167
- return /* @__PURE__ */ new Error("CDN pre-warm needs an existing Cloudflare Worker before it can upload a new Worker version. Run `vinext-cloudflare deploy` once without `--experimental-warm-cdn-cache` to create the Worker, then rerun your pre-warm deploy.");
208
+ return /* @__PURE__ */ new Error("Version upload needs an existing Cloudflare Worker. Run `vinext-cloudflare deploy` once normally to create the Worker, then rerun the version-based deploy.");
168
209
  }
169
210
  function parseDeploymentVersions(value) {
170
211
  const deployment = Array.isArray(value) ? value.at(-1) : value;
@@ -195,12 +236,91 @@ function parseWranglerDeploymentStatusOutput(output) {
195
236
  output
196
237
  };
197
238
  }
239
+ /** The first entry is the deployment currently serving traffic. */
240
+ function parseCfDeploymentStatusOutput(output) {
241
+ const parsed = parseJsonObject(output);
242
+ if (!isRecord(parsed) || !Array.isArray(parsed.deployments) || !parsed.deployments.length) throw new Error("Could not parse the active deployment from `cf workers deployments list` output.");
243
+ const current = parsed.deployments[0];
244
+ const deploymentId = findStringInRecord(current, [
245
+ "id",
246
+ "deployment_id",
247
+ "deploymentId"
248
+ ]);
249
+ const versions = parseDeploymentVersions(current);
250
+ if (!deploymentId || !versions.length) throw new Error("The active `cf workers deployments list` entry is missing its ID or versions.");
251
+ return {
252
+ deploymentId,
253
+ versions,
254
+ output
255
+ };
256
+ }
257
+ function runCfDeploymentStatus(root, options, execute = execFileSync) {
258
+ return parseCfDeploymentStatusOutput(runCfCommand(root, [
259
+ "workers",
260
+ "deployments",
261
+ "list",
262
+ "--worker",
263
+ options.name,
264
+ ...options.env ? ["--mode", validateWranglerEnvName(options.env)] : []
265
+ ], execute, options.verbose));
266
+ }
267
+ function runCfVersionDeploy(root, versionTraffic, options, _phase = "promote-uploaded", execute = execFileSync) {
268
+ const versions = versionTraffic.map(({ versionId, percentage }) => ({
269
+ version_id: versionId,
270
+ percentage
271
+ }));
272
+ const output = runCfCommand(root, [
273
+ "workers",
274
+ "deployments",
275
+ "create",
276
+ "--worker",
277
+ options.name,
278
+ "--strategy",
279
+ "percentage",
280
+ "--versions",
281
+ JSON.stringify(versions),
282
+ ...options.env ? ["--mode", validateWranglerEnvName(options.env)] : []
283
+ ], execute, options.verbose);
284
+ return {
285
+ deployedUrl: parseWorkersDevUrl(output),
286
+ output
287
+ };
288
+ }
289
+ function runCfTriggersDeploy(root, options, execute = execFileSync) {
290
+ const output = runCfCommand(root, [
291
+ "workers",
292
+ "triggers",
293
+ "deploy",
294
+ "--prebuilt",
295
+ ...options.env ? ["--mode", validateWranglerEnvName(options.env)] : []
296
+ ], execute, options.verbose);
297
+ return {
298
+ deployedUrl: parseCdnWarmupDeploymentUrl(output),
299
+ output
300
+ };
301
+ }
198
302
  function runWranglerVersionUpload(root, options, execute = execFileSync) {
199
303
  const { args, env } = buildWranglerVersionUploadArgs(options);
200
304
  if (env) console.log(`\n Uploading Worker version for env: ${env}...`);
201
305
  else console.log("\n Uploading Worker version for production...");
202
306
  try {
203
- return parseWranglerVersionUploadOutput(runWranglerCommand(root, args, execute, options.verbose === true));
307
+ const upload = parseWranglerVersionUploadOutput(runWranglerCommand(root, args, execute, options.verbose === true));
308
+ console.log(` Worker version ID: ${upload.versionId}`);
309
+ return upload;
310
+ } catch (error) {
311
+ if (isMissingWorkerVersionUploadError(error)) throw withInitialDeployRequiredMessage();
312
+ throw error;
313
+ }
314
+ }
315
+ function runCfVersionUpload(root, options, execute = execFileSync) {
316
+ const workerName = readBuildOutputWorkerName(root);
317
+ const { args, mode } = buildCfVersionUploadArgs(options);
318
+ console.log(mode ? `\n Uploading Worker Build Output in mode: ${mode}...` : "\n Uploading Worker Build Output...");
319
+ try {
320
+ return {
321
+ ...parseWranglerVersionUploadOutput(runCfCommand(root, args, execute, options.verbose === true)),
322
+ workerName
323
+ };
204
324
  } catch (error) {
205
325
  if (isMissingWorkerVersionUploadError(error)) throw withInitialDeployRequiredMessage();
206
326
  throw error;
@@ -237,4 +357,4 @@ function runWranglerTriggersDeploy(root, options, execute = execFileSync) {
237
357
  };
238
358
  }
239
359
  //#endregion
240
- export { buildWranglerDeploymentsStatusArgs, buildWranglerTriggersDeployArgs, buildWranglerVersionDeployArgs, buildWranglerVersionUploadArgs, parseUploadedWorkerName, parseVersionId, parseWorkersDevUrl, parseWranglerDeploymentStatusOutput, parseWranglerVersionUploadOutput, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload };
360
+ export { buildCfVersionUploadArgs, buildWranglerDeploymentsStatusArgs, buildWranglerTriggersDeployArgs, buildWranglerVersionDeployArgs, buildWranglerVersionUploadArgs, parseCfDeploymentStatusOutput, parseUploadedWorkerName, parseVersionId, parseWorkersDevUrl, parseWranglerDeploymentStatusOutput, parseWranglerVersionUploadOutput, readBuildOutputWorkerName, runCfDeploymentStatus, runCfTriggersDeploy, runCfVersionDeploy, runCfVersionUpload, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload };
@@ -0,0 +1,19 @@
1
+ //#region src/wrangler-config.d.ts
2
+ /** Narrow Wrangler config projection shared by deploy-time features. */
3
+ type WranglerConfig = {
4
+ accountId?: string;
5
+ kvNamespaceId?: string;
6
+ customDomain?: string;
7
+ name?: string;
8
+ legacyEnv?: boolean;
9
+ env?: Record<string, WranglerEnvironmentConfig>;
10
+ };
11
+ type WranglerEnvironmentConfig = {
12
+ customDomain?: string;
13
+ name?: string;
14
+ };
15
+ /**
16
+ * Parse the Wrangler fields used by TPR and staged CDN warming.
17
+ */
18
+ export declare function parseWranglerConfig(root: string, configPath?: string): WranglerConfig | null;
19
+ //#endregion
@@ -0,0 +1,294 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ //#region src/wrangler-config.ts
4
+ /** Narrow Wrangler config projection shared by deploy-time features. */
5
+ /**
6
+ * Parse the Wrangler fields used by TPR and staged CDN warming.
7
+ */
8
+ function parseWranglerConfig(root, configPath) {
9
+ if (configPath) {
10
+ const filepath = path.resolve(root, configPath);
11
+ if (!fs.existsSync(filepath)) return null;
12
+ const content = fs.readFileSync(filepath, "utf-8");
13
+ if (filepath.endsWith(".toml")) return extractFromTOML(content);
14
+ try {
15
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ for (const filename of ["wrangler.jsonc", "wrangler.json"]) {
21
+ const filepath = path.join(root, filename);
22
+ if (fs.existsSync(filepath)) {
23
+ const content = fs.readFileSync(filepath, "utf-8");
24
+ try {
25
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
26
+ } catch {
27
+ continue;
28
+ }
29
+ }
30
+ }
31
+ const tomlPath = path.join(root, "wrangler.toml");
32
+ if (fs.existsSync(tomlPath)) return extractFromTOML(fs.readFileSync(tomlPath, "utf-8"));
33
+ return null;
34
+ }
35
+ /**
36
+ * Strip single-line (//), multi-line comments, and trailing commas from JSONC
37
+ * while preserving strings that contain comment-like text or commas.
38
+ */
39
+ function stripJsonCommentsAndTrailingCommas(str) {
40
+ let result = "";
41
+ let inString = false;
42
+ let inSingleLine = false;
43
+ let inMultiLine = false;
44
+ let escapeNext = false;
45
+ for (let i = 0; i < str.length; i++) {
46
+ const ch = str[i];
47
+ const next = str[i + 1];
48
+ if (escapeNext) {
49
+ if (!inSingleLine && !inMultiLine) result += ch;
50
+ escapeNext = false;
51
+ continue;
52
+ }
53
+ if (ch === "\\" && inString) {
54
+ result += ch;
55
+ escapeNext = true;
56
+ continue;
57
+ }
58
+ if (inSingleLine) {
59
+ if (ch === "\n") {
60
+ inSingleLine = false;
61
+ result += ch;
62
+ }
63
+ continue;
64
+ }
65
+ if (inMultiLine) {
66
+ if (ch === "*" && next === "/") {
67
+ inMultiLine = false;
68
+ i++;
69
+ }
70
+ continue;
71
+ }
72
+ if (ch === "\"" && !inString) {
73
+ inString = true;
74
+ result += ch;
75
+ continue;
76
+ }
77
+ if (ch === "\"" && inString) {
78
+ inString = false;
79
+ result += ch;
80
+ continue;
81
+ }
82
+ if (!inString && ch === "/" && next === "/") {
83
+ inSingleLine = true;
84
+ i++;
85
+ continue;
86
+ }
87
+ if (!inString && ch === "/" && next === "*") {
88
+ inMultiLine = true;
89
+ i++;
90
+ continue;
91
+ }
92
+ if (!inString && ch === "," && isJsonTrailingComma(str, i + 1)) continue;
93
+ result += ch;
94
+ }
95
+ return result;
96
+ }
97
+ function isJsonTrailingComma(str, start) {
98
+ for (let i = start; i < str.length; i++) {
99
+ const ch = str[i];
100
+ const next = str[i + 1];
101
+ if (ch === void 0) return false;
102
+ if (/\s/.test(ch)) continue;
103
+ if (ch === "/" && next === "/") {
104
+ i += 2;
105
+ while (i < str.length && str[i] !== "\n") i++;
106
+ continue;
107
+ }
108
+ if (ch === "/" && next === "*") {
109
+ i += 2;
110
+ while (i < str.length) {
111
+ if (str[i] === "*" && str[i + 1] === "/") {
112
+ i++;
113
+ break;
114
+ }
115
+ i++;
116
+ }
117
+ continue;
118
+ }
119
+ return ch === "}" || ch === "]";
120
+ }
121
+ return false;
122
+ }
123
+ function extractFromJSON(config) {
124
+ const result = {};
125
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
126
+ if (typeof config.legacy_env === "boolean") result.legacyEnv = config.legacy_env;
127
+ if (typeof config.account_id === "string") result.accountId = config.account_id;
128
+ if (Array.isArray(config.kv_namespaces)) {
129
+ const namespace = config.kv_namespaces.find((value) => value && typeof value === "object" && (value.binding === "VINEXT_KV_CACHE" || value.binding === "VINEXT_CACHE"));
130
+ if (namespace && typeof namespace.id === "string" && namespace.id !== "<your-kv-namespace-id>") result.kvNamespaceId = namespace.id;
131
+ }
132
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
133
+ if (domain) result.customDomain = domain;
134
+ const env = extractEnvConfigs(config.env);
135
+ if (env) result.env = env;
136
+ return result;
137
+ }
138
+ function extractEnvConfigs(envs) {
139
+ if (!envs || typeof envs !== "object" || Array.isArray(envs)) return void 0;
140
+ const result = {};
141
+ for (const [envName, rawConfig] of Object.entries(envs)) {
142
+ if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) continue;
143
+ const envConfig = extractEnvironmentConfig(rawConfig);
144
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
145
+ }
146
+ return Object.keys(result).length > 0 ? result : void 0;
147
+ }
148
+ function extractEnvironmentConfig(config) {
149
+ const result = {};
150
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
151
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
152
+ if (domain) result.customDomain = domain;
153
+ return result;
154
+ }
155
+ function extractDomainFromRoutes(routes) {
156
+ if (!Array.isArray(routes)) return null;
157
+ for (const route of routes) if (typeof route === "string") {
158
+ const domain = cleanDomain(route);
159
+ if (domain && !domain.includes("workers.dev")) return domain;
160
+ } else if (route && typeof route === "object") {
161
+ const r = route;
162
+ const pattern = typeof r.zone_name === "string" ? r.zone_name : typeof r.pattern === "string" ? r.pattern : null;
163
+ if (pattern) {
164
+ const domain = cleanDomain(pattern);
165
+ if (domain && !domain.includes("workers.dev")) return domain;
166
+ }
167
+ }
168
+ return null;
169
+ }
170
+ function extractDomainFromCustomDomains(config) {
171
+ if (Array.isArray(config.custom_domains)) {
172
+ for (const d of config.custom_domains) if (typeof d === "string" && !d.includes("workers.dev")) return cleanDomain(d);
173
+ }
174
+ return null;
175
+ }
176
+ /** Strip protocol and trailing wildcards from a route pattern to get a bare domain. */
177
+ function cleanDomain(raw) {
178
+ return raw.replace(/^https?:\/\//, "").replace(/\/\*$/, "").replace(/\/+$/, "").split("/")[0] || null;
179
+ }
180
+ /**
181
+ * Simple extraction of specific fields from wrangler.toml content.
182
+ * Not a full TOML parser — just enough for the fields we need.
183
+ */
184
+ function extractFromTOML(content) {
185
+ const result = {};
186
+ const nameMatch = content.match(/^name\s*=\s*"([^"]+)"/m);
187
+ if (nameMatch) result.name = nameMatch[1];
188
+ const legacyEnvMatch = content.match(/^legacy_env\s*=\s*(true|false)\s*$/m);
189
+ if (legacyEnvMatch) result.legacyEnv = legacyEnvMatch[1] === "true";
190
+ const accountMatch = content.match(/^account_id\s*=\s*"([^"]+)"/m);
191
+ if (accountMatch) result.accountId = accountMatch[1];
192
+ for (const block of content.split(/\[\[kv_namespaces\]\]/).slice(1)) {
193
+ const section = block.split(/\[\[/)[0];
194
+ const binding = section.match(/binding\s*=\s*"([^"]+)"/)?.[1];
195
+ const id = section.match(/\bid\s*=\s*"([^"]+)"/)?.[1];
196
+ if ((binding === "VINEXT_KV_CACHE" || binding === "VINEXT_CACHE") && id && id !== "<your-kv-namespace-id>") result.kvNamespaceId = id;
197
+ }
198
+ const routeMatch = content.match(/^route\s*=\s*"([^"]+)"/m);
199
+ if (routeMatch) {
200
+ const domain = cleanDomain(routeMatch[1]);
201
+ if (domain && !domain.includes("workers.dev")) result.customDomain = domain;
202
+ }
203
+ if (!result.customDomain) {
204
+ const routeBlocks = content.split(/\[\[routes\]\]/);
205
+ for (let i = 1; i < routeBlocks.length; i++) {
206
+ const patternMatch = routeBlocks[i].split(/\[\[/)[0].match(/pattern\s*=\s*"([^"]+)"/);
207
+ if (patternMatch) {
208
+ const domain = cleanDomain(patternMatch[1]);
209
+ if (domain && !domain.includes("workers.dev")) {
210
+ result.customDomain = domain;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ const env = extractEnvConfigsFromTOML(content);
217
+ if (env) result.env = env;
218
+ return result;
219
+ }
220
+ function extractEnvConfigsFromTOML(content) {
221
+ const result = {};
222
+ for (const section of getTomlSections(content)) {
223
+ const envName = section.header.match(/^env\.([^.]+)$/)?.[1];
224
+ if (envName) {
225
+ const envConfig = result[envName] ?? {};
226
+ const nameMatch = section.body.match(/^name\s*=\s*"([^"]+)"/m);
227
+ if (nameMatch) envConfig.name = nameMatch[1];
228
+ const domain = extractTomlScalarRouteDomain(section.body) ?? extractTomlRoutesArrayDomain(section.body);
229
+ if (domain) envConfig.customDomain = domain;
230
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
231
+ continue;
232
+ }
233
+ const routesEnvName = section.header.match(/^env\.([^.]+)\.routes$/)?.[1];
234
+ if (routesEnvName) {
235
+ const envConfig = result[routesEnvName] ?? {};
236
+ const domain = extractTomlRouteBlockDomain(section.body);
237
+ if (domain) envConfig.customDomain = domain;
238
+ if (envConfig.name || envConfig.customDomain) result[routesEnvName] = envConfig;
239
+ }
240
+ }
241
+ return Object.keys(result).length > 0 ? result : void 0;
242
+ }
243
+ function getTomlSections(content) {
244
+ const sections = [];
245
+ let currentHeader = null;
246
+ let currentBody = [];
247
+ for (const line of content.split("\n")) {
248
+ const header = parseTomlSectionHeader(line);
249
+ if (header) {
250
+ if (currentHeader) sections.push({
251
+ header: currentHeader,
252
+ body: currentBody.join("\n")
253
+ });
254
+ currentHeader = header;
255
+ currentBody = [];
256
+ } else if (currentHeader) currentBody.push(line);
257
+ }
258
+ if (currentHeader) sections.push({
259
+ header: currentHeader,
260
+ body: currentBody.join("\n")
261
+ });
262
+ return sections;
263
+ }
264
+ function parseTomlSectionHeader(line) {
265
+ const trimmed = line.trim();
266
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null;
267
+ const isArrayHeader = trimmed.startsWith("[[") && trimmed.endsWith("]]");
268
+ const start = isArrayHeader ? 2 : 1;
269
+ const end = isArrayHeader ? trimmed.length - 2 : trimmed.length - 1;
270
+ const header = trimmed.slice(start, end).trim();
271
+ return header.length > 0 ? header : null;
272
+ }
273
+ function extractTomlScalarRouteDomain(section) {
274
+ const routeMatch = section.match(/^route\s*=\s*"([^"]+)"/m);
275
+ if (!routeMatch) return null;
276
+ const domain = cleanDomain(routeMatch[1]);
277
+ return domain && !domain.includes("workers.dev") ? domain : null;
278
+ }
279
+ function extractTomlRoutesArrayDomain(section) {
280
+ const routesMatch = section.match(/^routes\s*=\s*\[([\s\S]*?)\]/m);
281
+ if (!routesMatch) return null;
282
+ const patternMatch = (routesMatch[1] ?? "").match(/(?:pattern\s*=\s*)?"([^"]+)"/);
283
+ if (!patternMatch) return null;
284
+ const domain = cleanDomain(patternMatch[1]);
285
+ return domain && !domain.includes("workers.dev") ? domain : null;
286
+ }
287
+ function extractTomlRouteBlockDomain(section) {
288
+ const patternMatch = section.match(/^pattern\s*=\s*"([^"]+)"/m) ?? section.match(/^zone_name\s*=\s*"([^"]+)"/m);
289
+ if (!patternMatch) return null;
290
+ const domain = cleanDomain(patternMatch[1]);
291
+ return domain && !domain.includes("workers.dev") ? domain : null;
292
+ }
293
+ //#endregion
294
+ export { parseWranglerConfig };
@@ -3,7 +3,7 @@ function assertCdnVersionMetadataConfig({ binding, configuredBinding, configPath
3
3
  if (configuredBinding === binding) return;
4
4
  const location = configPath ? ` in ${configPath}` : "";
5
5
  const found = configuredBinding ? ` declares ${JSON.stringify(configuredBinding)} instead` : " does not declare version_metadata";
6
- throw new Error(`[vinext] Cloudflare CDN warmup requires version metadata binding ${JSON.stringify(binding)}, but the effective Wrangler config${location}${found}. Deploy the generated Wrangler config finalized by cdnAdapter(), or add the binding to this effective config and align cdnAdapter({ versionMetadataBinding }) when using a custom name.`);
6
+ throw new Error(`[vinext] Cloudflare CDN warmup requires version metadata binding ${JSON.stringify(binding)}, but the effective Wrangler config${location}${found}. Deploy the generated Wrangler config finalized by workersCacheCdnAdapter(), or add the binding to this effective config and align workersCacheCdnAdapter({ versionMetadataBinding }) when using a custom name.`);
7
7
  }
8
8
  //#endregion
9
9
  export { assertCdnVersionMetadataConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0",
4
4
  "description": "Cloudflare cache and image adapters for vinext.",
5
5
  "homepage": "https://vinext.dev/",
6
6
  "license": "MIT",
@@ -30,10 +30,6 @@
30
30
  "types": "./dist/deploy-config.d.ts",
31
31
  "import": "./dist/deploy-config.js"
32
32
  },
33
- "./internal/tpr": {
34
- "types": "./dist/tpr.d.ts",
35
- "import": "./dist/tpr.js"
36
- },
37
33
  "./internal/cdn-warm": {
38
34
  "types": "./dist/cdn-warm.d.ts",
39
35
  "import": "./dist/cdn-warm.js"
@@ -52,18 +48,29 @@
52
48
  }
53
49
  },
54
50
  "dependencies": {
55
- "@cloudflare/workers-response-store": "0.1.0-beta.0"
51
+ "@cloudflare/workers-response-store": "1.0.0"
56
52
  },
57
53
  "devDependencies": {
58
54
  "@types/node": "^25.9.2",
55
+ "cf": "1.0.0-beta.1",
59
56
  "miniflare": "5.20260730.0-alpha",
60
57
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.2",
61
58
  "vite-plus": "0.3.2",
62
59
  "vitest": "4.1.11",
63
- "vinext": "1.0.0-beta.10"
60
+ "vinext": "1.0.0"
64
61
  },
65
62
  "peerDependencies": {
66
- "vinext": "^1.0.0-beta.10"
63
+ "@cloudflare/vite-plugin": "*",
64
+ "cf": "*",
65
+ "vinext": "^1.0.0"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "@cloudflare/vite-plugin": {
69
+ "optional": true
70
+ },
71
+ "cf": {
72
+ "optional": true
73
+ }
67
74
  },
68
75
  "engines": {
69
76
  "node": ">=22"
@@ -71,6 +78,6 @@
71
78
  "scripts": {
72
79
  "build": "vp pack",
73
80
  "dev": "vp pack --watch",
74
- "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained pnpm --filter response-store-demo run build && pnpm --filter response-store-demo run build && vitest run"
81
+ "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained VINEXT_RESPONSE_STORE_LOCATION_HINT=weur pnpm --filter response-store-demo run build && VINEXT_RESPONSE_STORE_LOCATION_HINT=wnam pnpm --filter response-store-demo run build && vitest run"
75
82
  }
76
83
  }
@@ -1,24 +0,0 @@
1
- //#region src/prerender-kv-populate.d.ts
2
- /**
3
- * Deploy-time KV population for App Router prerendered artifacts.
4
- *
5
- * Reads `dist/server/vinext-prerender.json` and `dist/server/prerendered-routes/*`,
6
- * converts rendered App Router HTML/RSC artifacts into the same serialized
7
- * KVCacheEntry shape written by KVCacheHandler.set(), and returns Wrangler KV
8
- * bulk import records for deploy-time upload.
9
- */
10
- export type KVBulkPair = {
11
- key: string;
12
- value: string;
13
- expiration_ttl?: number;
14
- metadata?: Record<string, unknown>;
15
- };
16
- export declare function buildPrerenderKVPairs(serverDir: string, options?: {
17
- appPrefix?: string;
18
- now?: number;
19
- ttlSeconds?: number;
20
- }): {
21
- routeCount: number;
22
- pairs: KVBulkPair[];
23
- };
24
- //#endregion