@vinext/cloudflare 0.2.1 → 1.0.0-beta.1

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/dist/tpr.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ENTRY_PREFIX } from "./cache/kv-data-adapter.runtime.js";
2
2
  import { createRequire } from "node:module";
3
- import fs from "node:fs";
4
3
  import path from "node:path";
4
+ import fs from "node:fs";
5
5
  import { spawn } from "node:child_process";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import { VINEXT_REVALIDATE_HEADER } from "vinext/internal/server/headers";
@@ -33,13 +33,24 @@ import { buildAppPageCacheTags } from "vinext/internal/server/app-page-cache";
33
33
  * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:
34
34
  * account_id, VINEXT_KV_CACHE KV namespace ID, and custom domain.
35
35
  */
36
- function parseWranglerConfig(root) {
36
+ function parseWranglerConfig(root, configPath) {
37
+ if (configPath) {
38
+ const filepath = path.resolve(root, configPath);
39
+ if (!fs.existsSync(filepath)) return null;
40
+ const content = fs.readFileSync(filepath, "utf-8");
41
+ if (filepath.endsWith(".toml")) return extractFromTOML(content);
42
+ try {
43
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
37
48
  for (const filename of ["wrangler.jsonc", "wrangler.json"]) {
38
49
  const filepath = path.join(root, filename);
39
50
  if (fs.existsSync(filepath)) {
40
51
  const content = fs.readFileSync(filepath, "utf-8");
41
52
  try {
42
- return extractFromJSON(JSON.parse(stripJsonComments(content)));
53
+ return extractFromJSON(JSON.parse(stripJsonCommentsAndTrailingCommas(content)));
43
54
  } catch {
44
55
  continue;
45
56
  }
@@ -50,10 +61,10 @@ function parseWranglerConfig(root) {
50
61
  return null;
51
62
  }
52
63
  /**
53
- * Strip single-line (//) and multi-line comments from JSONC while
54
- * preserving strings that contain slashes.
64
+ * Strip single-line (//), multi-line comments, and trailing commas from JSONC
65
+ * while preserving strings that contain comment-like text or commas.
55
66
  */
56
- function stripJsonComments(str) {
67
+ function stripJsonCommentsAndTrailingCommas(str) {
57
68
  let result = "";
58
69
  let inString = false;
59
70
  let inSingleLine = false;
@@ -106,12 +117,41 @@ function stripJsonComments(str) {
106
117
  i++;
107
118
  continue;
108
119
  }
120
+ if (!inString && ch === "," && isJsonTrailingComma(str, i + 1)) continue;
109
121
  result += ch;
110
122
  }
111
123
  return result;
112
124
  }
125
+ function isJsonTrailingComma(str, start) {
126
+ for (let i = start; i < str.length; i++) {
127
+ const ch = str[i];
128
+ const next = str[i + 1];
129
+ if (ch === void 0) return false;
130
+ if (/\s/.test(ch)) continue;
131
+ if (ch === "/" && next === "/") {
132
+ i += 2;
133
+ while (i < str.length && str[i] !== "\n") i++;
134
+ continue;
135
+ }
136
+ if (ch === "/" && next === "*") {
137
+ i += 2;
138
+ while (i < str.length) {
139
+ if (str[i] === "*" && str[i + 1] === "/") {
140
+ i++;
141
+ break;
142
+ }
143
+ i++;
144
+ }
145
+ continue;
146
+ }
147
+ return ch === "}" || ch === "]";
148
+ }
149
+ return false;
150
+ }
113
151
  function extractFromJSON(config) {
114
152
  const result = {};
153
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
154
+ if (typeof config.legacy_env === "boolean") result.legacyEnv = config.legacy_env;
115
155
  if (typeof config.account_id === "string") result.accountId = config.account_id;
116
156
  if (Array.isArray(config.kv_namespaces)) {
117
157
  const vinextKV = config.kv_namespaces.find((ns) => ns && typeof ns === "object" && (ns.binding === "VINEXT_KV_CACHE" || ns.binding === "VINEXT_CACHE"));
@@ -119,6 +159,25 @@ function extractFromJSON(config) {
119
159
  }
120
160
  const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
121
161
  if (domain) result.customDomain = domain;
162
+ const env = extractEnvConfigs(config.env);
163
+ if (env) result.env = env;
164
+ return result;
165
+ }
166
+ function extractEnvConfigs(envs) {
167
+ if (!envs || typeof envs !== "object" || Array.isArray(envs)) return void 0;
168
+ const result = {};
169
+ for (const [envName, rawConfig] of Object.entries(envs)) {
170
+ if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) continue;
171
+ const envConfig = extractEnvironmentConfig(rawConfig);
172
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
173
+ }
174
+ return Object.keys(result).length > 0 ? result : void 0;
175
+ }
176
+ function extractEnvironmentConfig(config) {
177
+ const result = {};
178
+ if (typeof config.name === "string" && config.name.length > 0) result.name = config.name;
179
+ const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);
180
+ if (domain) result.customDomain = domain;
122
181
  return result;
123
182
  }
124
183
  function extractDomainFromRoutes(routes) {
@@ -152,6 +211,10 @@ function cleanDomain(raw) {
152
211
  */
153
212
  function extractFromTOML(content) {
154
213
  const result = {};
214
+ const nameMatch = content.match(/^name\s*=\s*"([^"]+)"/m);
215
+ if (nameMatch) result.name = nameMatch[1];
216
+ const legacyEnvMatch = content.match(/^legacy_env\s*=\s*(true|false)\s*$/m);
217
+ if (legacyEnvMatch) result.legacyEnv = legacyEnvMatch[1] === "true";
155
218
  const accountMatch = content.match(/^account_id\s*=\s*"([^"]+)"/m);
156
219
  if (accountMatch) result.accountId = accountMatch[1];
157
220
  const kvBlocks = content.split(/\[\[kv_namespaces\]\]/);
@@ -179,8 +242,83 @@ function extractFromTOML(content) {
179
242
  }
180
243
  }
181
244
  }
245
+ const env = extractEnvConfigsFromTOML(content);
246
+ if (env) result.env = env;
182
247
  return result;
183
248
  }
249
+ function extractEnvConfigsFromTOML(content) {
250
+ const result = {};
251
+ for (const section of getTomlSections(content)) {
252
+ const envName = section.header.match(/^env\.([^.]+)$/)?.[1];
253
+ if (envName) {
254
+ const envConfig = result[envName] ?? {};
255
+ const nameMatch = section.body.match(/^name\s*=\s*"([^"]+)"/m);
256
+ if (nameMatch) envConfig.name = nameMatch[1];
257
+ const domain = extractTomlScalarRouteDomain(section.body) ?? extractTomlRoutesArrayDomain(section.body);
258
+ if (domain) envConfig.customDomain = domain;
259
+ if (envConfig.name || envConfig.customDomain) result[envName] = envConfig;
260
+ continue;
261
+ }
262
+ const routesEnvName = section.header.match(/^env\.([^.]+)\.routes$/)?.[1];
263
+ if (routesEnvName) {
264
+ const envConfig = result[routesEnvName] ?? {};
265
+ const domain = extractTomlRouteBlockDomain(section.body);
266
+ if (domain) envConfig.customDomain = domain;
267
+ if (envConfig.name || envConfig.customDomain) result[routesEnvName] = envConfig;
268
+ }
269
+ }
270
+ return Object.keys(result).length > 0 ? result : void 0;
271
+ }
272
+ function getTomlSections(content) {
273
+ const sections = [];
274
+ let currentHeader = null;
275
+ let currentBody = [];
276
+ for (const line of content.split("\n")) {
277
+ const header = parseTomlSectionHeader(line);
278
+ if (header) {
279
+ if (currentHeader) sections.push({
280
+ header: currentHeader,
281
+ body: currentBody.join("\n")
282
+ });
283
+ currentHeader = header;
284
+ currentBody = [];
285
+ } else if (currentHeader) currentBody.push(line);
286
+ }
287
+ if (currentHeader) sections.push({
288
+ header: currentHeader,
289
+ body: currentBody.join("\n")
290
+ });
291
+ return sections;
292
+ }
293
+ function parseTomlSectionHeader(line) {
294
+ const trimmed = line.trim();
295
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null;
296
+ const isArrayHeader = trimmed.startsWith("[[") && trimmed.endsWith("]]");
297
+ const start = isArrayHeader ? 2 : 1;
298
+ const end = isArrayHeader ? trimmed.length - 2 : trimmed.length - 1;
299
+ const header = trimmed.slice(start, end).trim();
300
+ return header.length > 0 ? header : null;
301
+ }
302
+ function extractTomlScalarRouteDomain(section) {
303
+ const routeMatch = section.match(/^route\s*=\s*"([^"]+)"/m);
304
+ if (!routeMatch) return null;
305
+ const domain = cleanDomain(routeMatch[1]);
306
+ return domain && !domain.includes("workers.dev") ? domain : null;
307
+ }
308
+ function extractTomlRoutesArrayDomain(section) {
309
+ const routesMatch = section.match(/^routes\s*=\s*\[([\s\S]*?)\]/m);
310
+ if (!routesMatch) return null;
311
+ const patternMatch = (routesMatch[1] ?? "").match(/(?:pattern\s*=\s*)?"([^"]+)"/);
312
+ if (!patternMatch) return null;
313
+ const domain = cleanDomain(patternMatch[1]);
314
+ return domain && !domain.includes("workers.dev") ? domain : null;
315
+ }
316
+ function extractTomlRouteBlockDomain(section) {
317
+ const patternMatch = section.match(/^(?:pattern|zone_name)\s*=\s*"([^"]+)"/m);
318
+ if (!patternMatch) return null;
319
+ const domain = cleanDomain(patternMatch[1]);
320
+ return domain && !domain.includes("workers.dev") ? domain : null;
321
+ }
184
322
  /**
185
323
  * Generate zone lookup candidates from shortest (2-part) to longest.
186
324
  * Tries the most common case first (e.g., "example.com") and progressively
@@ -507,7 +645,7 @@ const DEFAULT_REVALIDATE_SECONDS = 3600;
507
645
  */
508
646
  async function runTPR(options) {
509
647
  const startTime = Date.now();
510
- const { root, coverage, limit, window: windowHours } = options;
648
+ const { root, config, coverage, limit, window: windowHours } = options;
511
649
  const skip = (reason) => ({
512
650
  totalPaths: 0,
513
651
  prerenderedCount: 0,
@@ -517,7 +655,7 @@ async function runTPR(options) {
517
655
  });
518
656
  const apiToken = process.env.CLOUDFLARE_API_TOKEN;
519
657
  if (!apiToken) return skip("no CLOUDFLARE_API_TOKEN set");
520
- const wranglerConfig = parseWranglerConfig(root);
658
+ const wranglerConfig = parseWranglerConfig(root, config);
521
659
  if (!wranglerConfig) return skip("could not parse wrangler config");
522
660
  if (!wranglerConfig.customDomain) return skip("no custom domain — zone analytics unavailable");
523
661
  if (!wranglerConfig.kvNamespaceId) return skip("no VINEXT_KV_CACHE KV namespace configured");
@@ -0,0 +1,43 @@
1
+ import { parseWorkersDevUrl } from "./workers-dev-url.js";
2
+ import { DeployOptions } from "./deploy.js";
3
+ import { execFileSync } from "node:child_process";
4
+
5
+ //#region src/version-deploy.d.ts
6
+ type WranglerVersionUploadResult = {
7
+ versionId: string;
8
+ previewUrl: string | null;
9
+ output: string;
10
+ };
11
+ type WranglerVersionDeployResult = {
12
+ deployedUrl: string | null;
13
+ output: string;
14
+ };
15
+ type WranglerVersionTraffic = {
16
+ versionId: string;
17
+ percentage: number;
18
+ };
19
+ type WranglerDeploymentStatus = {
20
+ versions: WranglerVersionTraffic[];
21
+ output: string;
22
+ };
23
+ type WranglerVersionArgs = {
24
+ args: string[];
25
+ env: string | undefined;
26
+ };
27
+ declare function parseVersionId(output: string): string | null;
28
+ declare function parseWranglerVersionUploadOutput(output: string): WranglerVersionUploadResult;
29
+ declare function buildWranglerVersionUploadArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config"> & {
30
+ previewAlias?: string;
31
+ }): WranglerVersionArgs;
32
+ declare function buildWranglerVersionDeployArgs(versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config">): WranglerVersionArgs;
33
+ declare function buildWranglerDeploymentsStatusArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config">): WranglerVersionArgs;
34
+ declare function buildWranglerTriggersDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config">): WranglerVersionArgs;
35
+ declare function parseWranglerDeploymentStatusOutput(output: string): WranglerDeploymentStatus;
36
+ declare function runWranglerVersionUpload(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config"> & {
37
+ previewAlias?: string;
38
+ }, execute?: typeof execFileSync): WranglerVersionUploadResult;
39
+ declare function runWranglerVersionDeploy(root: string, versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, phase?: "stage" | "promote-warmed" | "promote-uploaded", execute?: typeof execFileSync): WranglerVersionDeployResult;
40
+ declare function runWranglerDeploymentStatus(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, execute?: typeof execFileSync): WranglerDeploymentStatus;
41
+ declare function runWranglerTriggersDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, execute?: typeof execFileSync): WranglerVersionDeployResult;
42
+ //#endregion
43
+ export { WranglerDeploymentStatus, WranglerVersionDeployResult, WranglerVersionTraffic, WranglerVersionUploadResult, buildWranglerDeploymentsStatusArgs, buildWranglerTriggersDeployArgs, buildWranglerVersionDeployArgs, buildWranglerVersionUploadArgs, parseVersionId, parseWorkersDevUrl, parseWranglerDeploymentStatusOutput, parseWranglerVersionUploadOutput, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload };
@@ -0,0 +1,223 @@
1
+ import { parseWorkersDevUrl } from "./workers-dev-url.js";
2
+ import { buildNodeCliInvocation, resolveWranglerBin, validateWranglerEnvName } from "./deploy.js";
3
+ import { execFileSync } from "node:child_process";
4
+ //#region src/version-deploy.ts
5
+ function isRecord(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ function parseJsonObject(output) {
9
+ const trimmed = output.trim();
10
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
11
+ try {
12
+ const parsed = JSON.parse(trimmed);
13
+ return isRecord(parsed) || Array.isArray(parsed) ? parsed : null;
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+ function findStringInRecord(value, keys) {
19
+ if (!isRecord(value)) return null;
20
+ for (const key of keys) {
21
+ const field = value[key];
22
+ if (typeof field === "string" && field.length > 0) return field;
23
+ }
24
+ return null;
25
+ }
26
+ function findVersionIdInUploadJson(parsed) {
27
+ if (!isRecord(parsed)) return null;
28
+ return findStringInRecord(parsed, [
29
+ "version_id",
30
+ "versionId",
31
+ "id"
32
+ ]) ?? findStringInRecord(parsed.version, [
33
+ "version_id",
34
+ "versionId",
35
+ "id"
36
+ ]) ?? findStringInRecord(parsed.result, [
37
+ "version_id",
38
+ "versionId",
39
+ "id"
40
+ ]);
41
+ }
42
+ function findPreviewUrlInUploadJson(parsed) {
43
+ if (!isRecord(parsed)) return null;
44
+ return findStringInRecord(parsed, [
45
+ "preview_url",
46
+ "previewUrl",
47
+ "url"
48
+ ]) ?? findStringInRecord(parsed.version, [
49
+ "preview_url",
50
+ "previewUrl",
51
+ "url"
52
+ ]) ?? findStringInRecord(parsed.result, [
53
+ "preview_url",
54
+ "previewUrl",
55
+ "url"
56
+ ]);
57
+ }
58
+ function parseVersionId(output) {
59
+ return output.match(/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/)?.[0] ?? null;
60
+ }
61
+ function parseWranglerVersionUploadOutput(output) {
62
+ const parsed = parseJsonObject(output);
63
+ const versionId = findVersionIdInUploadJson(parsed) ?? parseVersionId(output);
64
+ const previewUrl = findPreviewUrlInUploadJson(parsed) ?? parseWorkersDevUrl(output);
65
+ if (!versionId) throw new Error("Could not detect Worker version ID from `wrangler versions upload` output.");
66
+ return {
67
+ versionId,
68
+ previewUrl,
69
+ output
70
+ };
71
+ }
72
+ function buildWranglerVersionUploadArgs(options) {
73
+ const args = ["versions", "upload"];
74
+ const env = options.env || (options.preview ? "preview" : void 0);
75
+ if (options.config) args.push("--config", options.config);
76
+ if (options.name) args.push("--name", options.name);
77
+ if (env) args.push("--env", validateWranglerEnvName(env));
78
+ if (options.previewAlias) args.push("--preview-alias", options.previewAlias);
79
+ return {
80
+ args,
81
+ env
82
+ };
83
+ }
84
+ function buildWranglerVersionDeployArgs(versionTraffic, options) {
85
+ const args = [
86
+ "versions",
87
+ "deploy",
88
+ ...versionTraffic.map(({ versionId, percentage }) => `${versionId}@${percentage}%`),
89
+ "--yes"
90
+ ];
91
+ const env = options.env || (options.preview ? "preview" : void 0);
92
+ if (options.config) args.push("--config", options.config);
93
+ if (options.name) args.push("--name", options.name);
94
+ if (env) args.push("--env", validateWranglerEnvName(env));
95
+ return {
96
+ args,
97
+ env
98
+ };
99
+ }
100
+ function buildWranglerDeploymentsStatusArgs(options) {
101
+ const args = [
102
+ "deployments",
103
+ "status",
104
+ "--json"
105
+ ];
106
+ const env = options.env || (options.preview ? "preview" : void 0);
107
+ if (options.config) args.push("--config", options.config);
108
+ if (options.name) args.push("--name", options.name);
109
+ if (env) args.push("--env", validateWranglerEnvName(env));
110
+ return {
111
+ args,
112
+ env
113
+ };
114
+ }
115
+ function buildWranglerTriggersDeployArgs(options) {
116
+ const args = ["triggers", "deploy"];
117
+ const env = options.env || (options.preview ? "preview" : void 0);
118
+ if (options.config) args.push("--config", options.config);
119
+ if (options.name) args.push("--name", options.name);
120
+ if (env) args.push("--env", validateWranglerEnvName(env));
121
+ return {
122
+ args,
123
+ env
124
+ };
125
+ }
126
+ function runWranglerCommand(root, args, execute = execFileSync) {
127
+ const invocation = buildNodeCliInvocation(resolveWranglerBin(root), args);
128
+ const execOpts = {
129
+ cwd: root,
130
+ stdio: "pipe",
131
+ encoding: "utf-8",
132
+ shell: false
133
+ };
134
+ const output = execute(invocation.file, invocation.args, execOpts);
135
+ if (output.trim()) for (const line of output.trim().split("\n")) console.log(` ${line}`);
136
+ return output;
137
+ }
138
+ function errorText(error) {
139
+ if (!error || typeof error !== "object") return String(error);
140
+ const parts = error instanceof Error ? [error.message] : [];
141
+ const record = error;
142
+ for (const field of [
143
+ "stdout",
144
+ "stderr",
145
+ "output"
146
+ ]) {
147
+ const value = record[field];
148
+ if (Array.isArray(value)) parts.push(...value.filter((entry) => typeof entry === "string" || Buffer.isBuffer(entry)).map((entry) => entry.toString()));
149
+ else if (typeof value === "string" || Buffer.isBuffer(value)) parts.push(value.toString());
150
+ }
151
+ return parts.join("\n");
152
+ }
153
+ function isMissingWorkerVersionUploadError(error) {
154
+ return /cannot upload a new version of a Worker that does not yet exist/i.test(errorText(error));
155
+ }
156
+ function withInitialDeployRequiredMessage() {
157
+ 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.");
158
+ }
159
+ function parseDeploymentVersions(value) {
160
+ const deployment = Array.isArray(value) ? value.at(-1) : value;
161
+ if (!isRecord(deployment) || !Array.isArray(deployment.versions)) return [];
162
+ const versions = [];
163
+ for (const version of deployment.versions) {
164
+ if (!isRecord(version)) continue;
165
+ const versionId = version.version_id;
166
+ const percentage = version.percentage;
167
+ if (typeof versionId !== "string" || typeof percentage !== "number") continue;
168
+ versions.push({
169
+ versionId,
170
+ percentage
171
+ });
172
+ }
173
+ return versions;
174
+ }
175
+ function parseWranglerDeploymentStatusOutput(output) {
176
+ const parsed = parseJsonObject(output);
177
+ if (!parsed) throw new Error("Could not parse `wrangler deployments status --json` output.");
178
+ return {
179
+ versions: parseDeploymentVersions(parsed),
180
+ output
181
+ };
182
+ }
183
+ function runWranglerVersionUpload(root, options, execute = execFileSync) {
184
+ const { args, env } = buildWranglerVersionUploadArgs(options);
185
+ if (env) console.log(`\n Uploading Worker version for env: ${env}...`);
186
+ else console.log("\n Uploading Worker version for production...");
187
+ try {
188
+ return parseWranglerVersionUploadOutput(runWranglerCommand(root, args, execute));
189
+ } catch (error) {
190
+ if (isMissingWorkerVersionUploadError(error)) throw withInitialDeployRequiredMessage();
191
+ throw error;
192
+ }
193
+ }
194
+ function runWranglerVersionDeploy(root, versionTraffic, options, phase = "promote-uploaded", execute = execFileSync) {
195
+ const { args, env } = buildWranglerVersionDeployArgs(versionTraffic, options);
196
+ const target = env ? `env: ${env}` : "production";
197
+ if (phase === "stage") console.log(`\n Staging uploaded Worker version at 0% for CDN warmup in ${target}...`);
198
+ else if (phase === "promote-warmed") console.log(`\n Promoting warmed Worker version to ${target}...`);
199
+ else console.log(`\n Promoting uploaded Worker version to ${target}...`);
200
+ const output = runWranglerCommand(root, args, execute);
201
+ return {
202
+ deployedUrl: parseWorkersDevUrl(output),
203
+ output
204
+ };
205
+ }
206
+ function runWranglerDeploymentStatus(root, options, execute = execFileSync) {
207
+ const { args, env } = buildWranglerDeploymentsStatusArgs(options);
208
+ if (env) console.log(`\n Reading current Worker deployment for env: ${env}...`);
209
+ else console.log("\n Reading current Worker deployment...");
210
+ return parseWranglerDeploymentStatusOutput(runWranglerCommand(root, args, execute));
211
+ }
212
+ function runWranglerTriggersDeploy(root, options, execute = execFileSync) {
213
+ const { args, env } = buildWranglerTriggersDeployArgs(options);
214
+ if (env) console.log(`\n Applying Worker triggers for env: ${env}...`);
215
+ else console.log("\n Applying Worker triggers...");
216
+ const output = runWranglerCommand(root, args, execute);
217
+ return {
218
+ deployedUrl: parseWorkersDevUrl(output),
219
+ output
220
+ };
221
+ }
222
+ //#endregion
223
+ export { buildWranglerDeploymentsStatusArgs, buildWranglerTriggersDeployArgs, buildWranglerVersionDeployArgs, buildWranglerVersionUploadArgs, parseVersionId, parseWorkersDevUrl, parseWranglerDeploymentStatusOutput, parseWranglerVersionUploadOutput, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload };
@@ -0,0 +1,4 @@
1
+ //#region src/workers-dev-url.d.ts
2
+ declare function parseWorkersDevUrl(output: string): string | null;
3
+ //#endregion
4
+ export { parseWorkersDevUrl };
@@ -0,0 +1,42 @@
1
+ //#region src/workers-dev-url.ts
2
+ function parseWorkersDevUrl(output) {
3
+ for (const rawToken of splitWhitespace(output)) {
4
+ const candidate = trimUrlPunctuation(rawToken);
5
+ if (!candidate.startsWith("https://")) continue;
6
+ try {
7
+ const url = new URL(candidate);
8
+ if (url.protocol !== "https:") continue;
9
+ if (url.hostname !== "workers.dev" && !url.hostname.endsWith(".workers.dev")) continue;
10
+ if (url.pathname === "/" && url.search === "" && url.hash === "") return url.origin;
11
+ return url.toString();
12
+ } catch {
13
+ continue;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ function splitWhitespace(value) {
19
+ const tokens = [];
20
+ let tokenStart = null;
21
+ for (let i = 0; i < value.length; i++) {
22
+ const char = value[i];
23
+ if (char === void 0) continue;
24
+ if (char.trim() === "") {
25
+ if (tokenStart !== null) {
26
+ tokens.push(value.slice(tokenStart, i));
27
+ tokenStart = null;
28
+ }
29
+ } else if (tokenStart === null) tokenStart = i;
30
+ }
31
+ if (tokenStart !== null) tokens.push(value.slice(tokenStart));
32
+ return tokens;
33
+ }
34
+ function trimUrlPunctuation(value) {
35
+ let start = 0;
36
+ let end = value.length;
37
+ while (start < end && "\"'(<".includes(value[start])) start++;
38
+ while (end > start && "\"')>.,;".includes(value[end - 1])) end--;
39
+ return value.slice(start, end);
40
+ }
41
+ //#endregion
42
+ export { parseWorkersDevUrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "0.2.1",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "Cloudflare adapters for vinext (KV data cache and Images-backed image optimization).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,6 +33,14 @@
33
33
  "types": "./dist/tpr.d.ts",
34
34
  "import": "./dist/tpr.js"
35
35
  },
36
+ "./internal/cdn-warm": {
37
+ "types": "./dist/cdn-warm.d.ts",
38
+ "import": "./dist/cdn-warm.js"
39
+ },
40
+ "./internal/version-deploy": {
41
+ "types": "./dist/version-deploy.d.ts",
42
+ "import": "./dist/version-deploy.js"
43
+ },
36
44
  "./cache/*": {
37
45
  "types": "./dist/cache/*.d.ts",
38
46
  "import": "./dist/cache/*.js"
@@ -44,8 +52,9 @@
44
52
  },
45
53
  "devDependencies": {
46
54
  "@types/node": "^25.9.2",
47
- "vite-plus": "0.2.1",
48
- "vinext": "0.2.1"
55
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.2",
56
+ "vite-plus": "0.2.2",
57
+ "vinext": "1.0.0-beta.1"
49
58
  },
50
59
  "peerDependencies": {
51
60
  "vinext": ">=0.0.0"