@vinext/cloudflare 1.0.0-beta.9 → 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 (50) hide show
  1. package/README.md +165 -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-build-id.d.ts +1 -1
  9. package/dist/cache/cdn-build-id.js +1 -1
  10. package/dist/cache/config.d.ts +137 -0
  11. package/dist/cache/config.js +87 -0
  12. package/dist/cache/kv-data-adapter.d.ts +1 -1
  13. package/dist/cache/kv-data-adapter.js +1 -1
  14. package/dist/cache/kv-data-adapter.runtime.js +13 -9
  15. package/dist/cache/kv-key.d.ts +7 -4
  16. package/dist/cache/kv-key.js +16 -5
  17. package/dist/cache/response-store-adapter.d.ts +9 -6
  18. package/dist/cache/response-store-adapter.js +20 -1
  19. package/dist/cache/response-store-adapter.worker.js +100 -43
  20. package/dist/cache/response-store-cdn.runtime.js +1 -0
  21. package/dist/cache/response-store-data.runtime.js +53 -31
  22. package/dist/cache/static-assets-adapter.build.d.ts +6 -0
  23. package/dist/cache/static-assets-adapter.build.js +65 -0
  24. package/dist/cache/static-assets-adapter.d.ts +27 -0
  25. package/dist/cache/static-assets-adapter.js +26 -0
  26. package/dist/cache/static-assets-adapter.runtime.d.ts +26 -0
  27. package/dist/cache/static-assets-adapter.runtime.js +77 -0
  28. package/dist/cache/static-assets-adapter.shared.d.ts +12 -0
  29. package/dist/cache/static-assets-adapter.shared.js +4 -0
  30. package/dist/cache/workers-cache-cdn-adapter.d.ts +58 -0
  31. package/dist/cache/workers-cache-cdn-adapter.js +65 -0
  32. package/dist/cacheability-artifact.d.ts +7 -1
  33. package/dist/cacheability-artifact.js +60 -21
  34. package/dist/cacheability-probe.d.ts +2 -0
  35. package/dist/cacheability-probe.js +107 -13
  36. package/dist/cdn-warm.d.ts +1 -0
  37. package/dist/cdn-warm.js +2 -1
  38. package/dist/deploy-config.d.ts +3 -8
  39. package/dist/deploy-config.js +5 -23
  40. package/dist/deploy-help.js +47 -42
  41. package/dist/deploy.d.ts +18 -16
  42. package/dist/deploy.js +355 -216
  43. package/dist/tpr.d.ts +4 -0
  44. package/dist/tpr.js +16 -7
  45. package/dist/version-deploy.d.ts +27 -0
  46. package/dist/version-deploy.js +121 -3
  47. package/dist/wrangler-version-metadata.js +1 -1
  48. package/package.json +16 -5
  49. package/dist/prerender-kv-populate.d.ts +0 -24
  50. package/dist/prerender-kv-populate.js +0 -153
package/dist/deploy.js CHANGED
@@ -4,11 +4,10 @@ import { CdnOperationProgress, createCdnWarmTargets, createPrerenderWarmPlan, wa
4
4
  import { parseWranglerConfig } from "./wrangler-config.js";
5
5
  import { resolveTPRRoutes, selectRoutes } from "./tpr.js";
6
6
  import { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./version-headers.js";
7
- import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig, resolveKvDataAdapterConfig, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler } from "./deploy-config.js";
7
+ import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler } from "./deploy-config.js";
8
8
  import { assertCdnVersionMetadataConfig } from "./wrangler-version-metadata.js";
9
9
  import { parseWorkerDeploymentUrl } from "./worker-deployment-url.js";
10
- import { runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload } from "./version-deploy.js";
11
- import { buildPrerenderKVPairs } from "./prerender-kv-populate.js";
10
+ import { readBuildOutputWorkerName, runCfDeploymentStatus, runCfTriggersDeploy, runCfVersionDeploy, runCfVersionUpload, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload } from "./version-deploy.js";
12
11
  import { createRequire } from "node:module";
13
12
  import fs from "node:fs";
14
13
  import path from "node:path";
@@ -16,14 +15,15 @@ import { cacheabilityRoutePathname } from "vinext/internal/server/cacheability-m
16
15
  import { setTimeout } from "node:timers/promises";
17
16
  import { DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS, DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS, discoverPrerenderPathManifest, emitPrerenderPathManifest } from "vinext/internal/build/prerender-paths";
18
17
  import { normalizePathTrailingSlash } from "vinext/shims/url-utils";
19
- import os from "node:os";
20
18
  import { spawn } from "node:child_process";
21
19
  import { parseArgs } from "node:util";
22
20
  import { pathToFileURL } from "node:url";
21
+ import { VINEXT_BUILD_LIFECYCLE_CONFIG } from "vinext/internal/build/lifecycle";
23
22
  import { runPrerender } from "vinext/internal/build/run-prerender";
23
+ import { printBuildReport } from "vinext/internal/build/report";
24
24
  import { loadDotenv } from "vinext/internal/config/dotenv";
25
25
  import { findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "vinext/internal/config/next-config";
26
- import { cacheWarmupStatusSource, findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup } from "vinext/internal/config/prerender";
26
+ import { cacheWarmupStatusSource, finalizeCacheAdapterPrerenderOutput, findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasCacheAdapterPrerenderOutput, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup } from "vinext/internal/config/prerender";
27
27
  import { detectProject, findInNodeModules, formatMissingCloudflarePluginError, getMissingDeps } from "vinext/internal/utils/project";
28
28
  import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
29
29
  //#region src/deploy.ts
@@ -37,6 +37,17 @@ import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
37
37
  * 3. Deploys to Cloudflare Workers via Wrangler
38
38
  */
39
39
  const DEFAULT_CDN_WARM_PROMOTION_DELAY_MS = 15e3;
40
+ /** The typed cf Vite plugin emits Worker and asset bundles into Build Output. */
41
+ function resolvePrerenderOutputDirs(root, deploymentTool, configured) {
42
+ if (deploymentTool !== "cf") return configured;
43
+ const workerDir = path.join(root, ".cloudflare", "output", "v0", "workers", "default");
44
+ if (!fs.existsSync(path.join(workerDir, "worker.config.json"))) return configured;
45
+ return {
46
+ ...configured,
47
+ rscOutDir: path.join(workerDir, "bundle"),
48
+ clientOutDir: path.join(workerDir, "assets")
49
+ };
50
+ }
40
51
  function parsePositiveIntegerArg(raw, flag) {
41
52
  if (raw === "") throw new Error(`${flag} requires a value, but none was provided.`);
42
53
  const parsed = Number(raw);
@@ -56,7 +67,7 @@ function validateTimerDelay(value, flag, raw = String(value)) {
56
67
  return value;
57
68
  }
58
69
  function validatePromotionDelay(value, raw = String(value)) {
59
- return validateTimerDelay(value, "--warm-cdn-promotion-delay", raw);
70
+ return validateTimerDelay(value, "--warm-cache-promotion-delay", raw);
60
71
  }
61
72
  function validateCdnWarmTarget(raw) {
62
73
  const value = raw.trim();
@@ -64,9 +75,9 @@ function validateCdnWarmTarget(raw) {
64
75
  try {
65
76
  url = new URL(value);
66
77
  } catch {
67
- throw new Error(`--warm-cdn-target expects an HTTPS origin, but got "${raw}".`);
78
+ throw new Error(`--warm-cache-target expects an HTTPS origin, but got "${raw}".`);
68
79
  }
69
- if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") throw new Error(`--warm-cdn-target expects an HTTPS origin without a path, query, credentials, or port, but got "${raw}".`);
80
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") throw new Error(`--warm-cache-target expects an HTTPS origin without a path, query, credentials, or port, but got "${raw}".`);
70
81
  return url.origin;
71
82
  }
72
83
  function formatUnknownError(error) {
@@ -105,6 +116,54 @@ const deployArgOptions = {
105
116
  default: false
106
117
  },
107
118
  "prerender-concurrency": { type: "string" },
119
+ "warm-cache": {
120
+ type: "boolean",
121
+ default: false
122
+ },
123
+ "warm-cache-target": { type: "string" },
124
+ "warm-cache-concurrency": { type: "string" },
125
+ "warm-cache-timeout": { type: "string" },
126
+ "warm-cache-retries": { type: "string" },
127
+ "warm-cache-discovery-timeout": { type: "string" },
128
+ "warm-cache-discovery-retries": { type: "string" },
129
+ "warm-cache-probe-timeout": { type: "string" },
130
+ "warm-cache-probe-retries": { type: "string" },
131
+ "warm-cache-certify": {
132
+ type: "boolean",
133
+ default: false
134
+ },
135
+ "warm-cache-readiness-timeout": { type: "string" },
136
+ "warm-cache-readiness-retries": { type: "string" },
137
+ "warm-cache-readiness-probes": { type: "string" },
138
+ "warm-cache-readiness-probe-delay": { type: "string" },
139
+ "dangerously-promote-on-warm-cache-error": {
140
+ type: "boolean",
141
+ default: false
142
+ },
143
+ "no-promote": {
144
+ type: "boolean",
145
+ default: false
146
+ },
147
+ "warm-cache-no-promote": {
148
+ type: "boolean",
149
+ default: false
150
+ },
151
+ "warm-cache-promotion-delay": { type: "string" },
152
+ "warm-cache-include-fallbacks": {
153
+ type: "boolean",
154
+ default: false
155
+ },
156
+ "traffic-aware-warm-cache": {
157
+ type: "boolean",
158
+ default: false
159
+ },
160
+ "traffic-aware-coverage": { type: "string" },
161
+ "traffic-aware-limit": { type: "string" },
162
+ "traffic-aware-window": { type: "string" },
163
+ "dangerously-promote-on-cdn-warm-error": {
164
+ type: "boolean",
165
+ default: false
166
+ },
108
167
  "experimental-warm-cdn-cache": {
109
168
  type: "boolean",
110
169
  default: false
@@ -125,14 +184,6 @@ const deployArgOptions = {
125
184
  "warm-cdn-readiness-retries": { type: "string" },
126
185
  "warm-cdn-readiness-probes": { type: "string" },
127
186
  "warm-cdn-readiness-probe-delay": { type: "string" },
128
- "dangerously-promote-on-cdn-warm-error": {
129
- type: "boolean",
130
- default: false
131
- },
132
- "no-promote": {
133
- type: "boolean",
134
- default: false
135
- },
136
187
  "warm-cdn-no-promote": {
137
188
  type: "boolean",
138
189
  default: false
@@ -146,9 +197,6 @@ const deployArgOptions = {
146
197
  type: "boolean",
147
198
  default: false
148
199
  },
149
- "traffic-aware-coverage": { type: "string" },
150
- "traffic-aware-limit": { type: "string" },
151
- "traffic-aware-window": { type: "string" },
152
200
  "experimental-tpr": {
153
201
  type: "boolean",
154
202
  default: false
@@ -163,8 +211,29 @@ function parseDeployArgs(args) {
163
211
  options: deployArgOptions,
164
212
  strict: true
165
213
  });
166
- if (values["warm-cdn-certify"] && !values["experimental-warm-cdn-cache"]) throw new Error("--warm-cdn-certify requires --experimental-warm-cdn-cache.");
167
- if (values["warm-cdn-target"] && !values["experimental-warm-cdn-cache"]) throw new Error("--warm-cdn-target requires --experimental-warm-cdn-cache.");
214
+ values["dangerously-promote-on-warm-cache-error"] ||= values["dangerously-promote-on-cdn-warm-error"];
215
+ values["warm-cache"] ||= values["experimental-warm-cdn-cache"];
216
+ values["warm-cache-target"] ??= values["warm-cdn-target"];
217
+ values["warm-cache-concurrency"] ??= values["warm-cdn-concurrency"];
218
+ values["warm-cache-timeout"] ??= values["warm-cdn-timeout"];
219
+ values["warm-cache-retries"] ??= values["warm-cdn-retries"];
220
+ values["warm-cache-discovery-timeout"] ??= values["warm-cdn-discovery-timeout"];
221
+ values["warm-cache-discovery-retries"] ??= values["warm-cdn-discovery-retries"];
222
+ values["warm-cache-probe-timeout"] ??= values["warm-cdn-probe-timeout"];
223
+ values["warm-cache-probe-retries"] ??= values["warm-cdn-probe-retries"];
224
+ values["warm-cache-certify"] ||= values["warm-cdn-certify"];
225
+ values["warm-cache-readiness-timeout"] ??= values["warm-cdn-readiness-timeout"];
226
+ values["warm-cache-readiness-retries"] ??= values["warm-cdn-readiness-retries"];
227
+ values["warm-cache-readiness-probes"] ??= values["warm-cdn-readiness-probes"];
228
+ values["warm-cache-readiness-probe-delay"] ??= values["warm-cdn-readiness-probe-delay"];
229
+ values["warm-cache-no-promote"] ||= values["warm-cdn-no-promote"];
230
+ values["warm-cache-promotion-delay"] ??= values["warm-cdn-promotion-delay"];
231
+ values["warm-cache-include-fallbacks"] ||= values["warm-cdn-include-fallbacks"];
232
+ values["traffic-aware-warm-cache"] ||= values["experimental-traffic-aware-warm-cache"];
233
+ const trafficAwareWarmCache = values["traffic-aware-warm-cache"] || values["experimental-tpr"];
234
+ const warming = values["warm-cache"] || trafficAwareWarmCache;
235
+ if (values["warm-cache-certify"] && !warming) throw new Error("--warm-cache-certify requires --warm-cache or --traffic-aware-warm-cache.");
236
+ if (values["warm-cache-target"] && !warming) throw new Error("--warm-cache-target requires --warm-cache or --traffic-aware-warm-cache.");
168
237
  function parseIntArg(name, raw) {
169
238
  if (!raw) return void 0;
170
239
  const n = parseInt(raw, 10);
@@ -185,25 +254,25 @@ function parseDeployArgs(args) {
185
254
  verbose: values.verbose,
186
255
  prerenderAll: values["prerender-all"],
187
256
  prerenderConcurrency: values["prerender-concurrency"] === void 0 ? void 0 : parsePositiveIntegerArg(values["prerender-concurrency"], "--prerender-concurrency"),
188
- warmCdnCache: values["experimental-warm-cdn-cache"],
189
- warmCdnTarget: values["warm-cdn-target"] === void 0 ? void 0 : validateCdnWarmTarget(values["warm-cdn-target"]),
190
- warmCdnConcurrency: values["warm-cdn-concurrency"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-concurrency"], "--warm-cdn-concurrency"),
191
- warmCdnTimeout: values["warm-cdn-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-timeout"], "--warm-cdn-timeout"),
192
- warmCdnRetries: values["warm-cdn-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cdn-retries"], "--warm-cdn-retries"),
193
- warmCdnDiscoveryTimeout: values["warm-cdn-discovery-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-discovery-timeout"], "--warm-cdn-discovery-timeout"),
194
- warmCdnDiscoveryRetries: values["warm-cdn-discovery-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cdn-discovery-retries"], "--warm-cdn-discovery-retries"),
195
- warmCdnProbeTimeout: values["warm-cdn-probe-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-probe-timeout"], "--warm-cdn-probe-timeout"),
196
- warmCdnProbeRetries: values["warm-cdn-probe-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cdn-probe-retries"], "--warm-cdn-probe-retries"),
197
- warmCdnCertify: values["warm-cdn-certify"],
198
- warmCdnReadinessTimeout: values["warm-cdn-readiness-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-readiness-timeout"], "--warm-cdn-readiness-timeout"),
199
- warmCdnReadinessRetries: values["warm-cdn-readiness-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cdn-readiness-retries"], "--warm-cdn-readiness-retries"),
200
- warmCdnReadinessProbes: values["warm-cdn-readiness-probes"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cdn-readiness-probes"], "--warm-cdn-readiness-probes"),
201
- warmCdnReadinessProbeDelay: values["warm-cdn-readiness-probe-delay"] === void 0 ? void 0 : validateTimerDelay(parseNonNegativeIntegerArg(values["warm-cdn-readiness-probe-delay"], "--warm-cdn-readiness-probe-delay"), "--warm-cdn-readiness-probe-delay", values["warm-cdn-readiness-probe-delay"]),
202
- dangerouslyPromoteOnCdnWarmError: values["dangerously-promote-on-cdn-warm-error"],
203
- warmCdnPromote: !values["no-promote"] && !values["warm-cdn-no-promote"],
204
- warmCdnPromotionDelay: values["warm-cdn-promotion-delay"] === void 0 ? void 0 : validatePromotionDelay(parseNonNegativeIntegerArg(values["warm-cdn-promotion-delay"], "--warm-cdn-promotion-delay"), values["warm-cdn-promotion-delay"]),
205
- warmCdnIncludeFallbacks: values["warm-cdn-include-fallbacks"],
206
- experimentalTPR: values["experimental-traffic-aware-warm-cache"] || values["experimental-tpr"],
257
+ warmCdnCache: values["warm-cache"],
258
+ warmCdnTarget: values["warm-cache-target"] === void 0 ? void 0 : validateCdnWarmTarget(values["warm-cache-target"]),
259
+ warmCdnConcurrency: values["warm-cache-concurrency"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-concurrency"], "--warm-cache-concurrency"),
260
+ warmCdnTimeout: values["warm-cache-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-timeout"], "--warm-cache-timeout"),
261
+ warmCdnRetries: values["warm-cache-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-retries"], "--warm-cache-retries"),
262
+ warmCdnDiscoveryTimeout: values["warm-cache-discovery-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-discovery-timeout"], "--warm-cache-discovery-timeout"),
263
+ warmCdnDiscoveryRetries: values["warm-cache-discovery-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-discovery-retries"], "--warm-cache-discovery-retries"),
264
+ warmCdnProbeTimeout: values["warm-cache-probe-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-probe-timeout"], "--warm-cache-probe-timeout"),
265
+ warmCdnProbeRetries: values["warm-cache-probe-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-probe-retries"], "--warm-cache-probe-retries"),
266
+ warmCdnCertify: values["warm-cache-certify"],
267
+ warmCdnReadinessTimeout: values["warm-cache-readiness-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-readiness-timeout"], "--warm-cache-readiness-timeout"),
268
+ warmCdnReadinessRetries: values["warm-cache-readiness-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-readiness-retries"], "--warm-cache-readiness-retries"),
269
+ warmCdnReadinessProbes: values["warm-cache-readiness-probes"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-readiness-probes"], "--warm-cache-readiness-probes"),
270
+ warmCdnReadinessProbeDelay: values["warm-cache-readiness-probe-delay"] === void 0 ? void 0 : validateTimerDelay(parseNonNegativeIntegerArg(values["warm-cache-readiness-probe-delay"], "--warm-cache-readiness-probe-delay"), "--warm-cache-readiness-probe-delay", values["warm-cache-readiness-probe-delay"]),
271
+ dangerouslyPromoteOnCdnWarmError: values["dangerously-promote-on-warm-cache-error"],
272
+ warmCdnPromote: !values["no-promote"] && !values["warm-cache-no-promote"],
273
+ warmCdnPromotionDelay: values["warm-cache-promotion-delay"] === void 0 ? void 0 : validatePromotionDelay(parseNonNegativeIntegerArg(values["warm-cache-promotion-delay"], "--warm-cache-promotion-delay"), values["warm-cache-promotion-delay"]),
274
+ warmCdnIncludeFallbacks: values["warm-cache-include-fallbacks"],
275
+ experimentalTPR: trafficAwareWarmCache,
207
276
  tprCoverage: parseIntArg("traffic-aware-coverage", values["traffic-aware-coverage"] ?? values["tpr-coverage"]),
208
277
  tprLimit: parseIntArg("traffic-aware-limit", values["traffic-aware-limit"] ?? values["tpr-limit"]),
209
278
  tprWindow: parseIntArg("traffic-aware-window", values["traffic-aware-window"] ?? values["tpr-window"])
@@ -256,10 +325,13 @@ async function loadProjectWranglerApi(root) {
256
325
  pathToFileURL(wranglerPath).href
257
326
  );
258
327
  }
259
- async function loadDeployViteConfigMetadata(root) {
328
+ function resolveViteBuildMode(deploymentTool, env) {
329
+ return deploymentTool === "cf" ? env ?? "production" : "production";
330
+ }
331
+ async function loadDeployViteConfigMetadata(root, mode) {
260
332
  const plugins = (await (await loadProjectViteApi(root)).loadConfigFromFile({
261
333
  command: "build",
262
- mode: "production"
334
+ mode
263
335
  }, void 0, root))?.config.plugins;
264
336
  return {
265
337
  cacheConfig: await findVinextCacheConfigInPlugins(plugins),
@@ -268,32 +340,22 @@ async function loadDeployViteConfigMetadata(root) {
268
340
  routeRootConfig: await findVinextRouteRootConfigInPlugins(plugins)
269
341
  };
270
342
  }
271
- async function runBuild(info, env) {
343
+ async function runBuild(info, env, mode) {
272
344
  console.log("\n Building for Cloudflare Workers...\n");
273
345
  const { createBuilder } = await loadProjectViteApi(info.root);
346
+ let completed = false;
274
347
  await withCloudflareEnv(env, async () => {
275
- await (await createBuilder({ root: info.root })).buildApp();
276
- });
277
- }
278
- async function populateKVCacheFromPrerenderedArtifacts(root, wranglerEnv, cacheConfig) {
279
- const kvConfig = resolveKvDataAdapterConfig(cacheConfig);
280
- if (!kvConfig) return;
281
- const { routeCount, pairs } = buildPrerenderKVPairs(path.join(root, "dist", "server"), {
282
- appPrefix: kvConfig.appPrefix,
283
- ttlSeconds: kvConfig.ttlSeconds
284
- });
285
- if (pairs.length === 0) {
286
- console.log(" KV cache: Skipping prerender upload (no App Router prerendered cache entries found).");
287
- return;
288
- }
289
- await runWranglerKVBulkPut(root, {
290
- binding: kvConfig.binding,
291
- env: wranglerEnv,
292
- pairs
348
+ const invocation = { onComplete() {
349
+ completed = true;
350
+ } };
351
+ await (await createBuilder({
352
+ root: info.root,
353
+ mode,
354
+ [VINEXT_BUILD_LIFECYCLE_CONFIG]: invocation
355
+ })).buildApp();
293
356
  });
294
- console.log(` KV cache: Uploaded ${pairs.length} entr${pairs.length === 1 ? "y" : "ies"} for ${routeCount} prerendered route${routeCount === 1 ? "" : "s"}.`);
357
+ if (!completed) throw new Error("[vinext] The Cloudflare build lifecycle did not complete.");
295
358
  }
296
- const KV_BULK_PUT_CHUNK_SIZE = 25;
297
359
  function validateWranglerEnvName(env) {
298
360
  if (env.includes("\0")) throw new Error("Wrangler environment names cannot contain null bytes.");
299
361
  return env;
@@ -309,21 +371,25 @@ function buildWranglerDeployArgs(options) {
309
371
  env
310
372
  };
311
373
  }
312
- function buildWranglerKVBulkPutArgs(options) {
313
- const env = options.env || void 0;
314
- const args = [
315
- "kv",
316
- "bulk",
317
- "put",
318
- options.filePath,
319
- "--binding",
320
- options.binding,
321
- "--remote"
322
- ];
323
- if (env) args.push("--env", validateWranglerEnvName(env));
374
+ function resolveDeploymentTool(root) {
375
+ return fs.existsSync(path.join(root, "cloudflare.config.ts")) ? "cf" : "wrangler";
376
+ }
377
+ function isCfCliInstalled(root, resolvePackageJson = (projectRoot) => {
378
+ try {
379
+ return createRequire(path.join(projectRoot, "package.json")).resolve("cf/package.json");
380
+ } catch {
381
+ return findInNodeModules(projectRoot, "cf/package.json");
382
+ }
383
+ }) {
384
+ return resolvePackageJson(root) !== null;
385
+ }
386
+ function buildCfDeployArgs(options) {
387
+ const mode = options.env || (options.preview ? "preview" : void 0);
388
+ const args = ["deploy", "--prebuilt"];
389
+ if (mode) args.push("--mode", validateWranglerEnvName(mode));
324
390
  return {
325
391
  args,
326
- env
392
+ mode
327
393
  };
328
394
  }
329
395
  /**
@@ -347,6 +413,21 @@ function resolveWranglerBin(root, resolvePackageJson = (projectRoot) => {
347
413
  }
348
414
  return path.join(root, "node_modules", "wrangler", "bin", "wrangler.js");
349
415
  }
416
+ function resolveCfBin(root, resolvePackageJson = (projectRoot) => {
417
+ try {
418
+ return createRequire(path.join(projectRoot, "package.json")).resolve("cf/package.json");
419
+ } catch {
420
+ return findInNodeModules(projectRoot, "cf/package.json");
421
+ }
422
+ }) {
423
+ const packageJsonPath = resolvePackageJson(root);
424
+ if (packageJsonPath) {
425
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
426
+ const bin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.cf;
427
+ if (bin) return path.resolve(path.dirname(packageJsonPath), bin);
428
+ }
429
+ return path.join(root, "node_modules", "cf", "bin", "cf");
430
+ }
350
431
  function buildNodeCliInvocation(scriptPath, args, nodeExecutable = process.execPath) {
351
432
  return {
352
433
  file: nodeExecutable,
@@ -361,45 +442,6 @@ function buildWranglerInvocation(root, options, nodeExecutable = process.execPat
361
442
  env
362
443
  };
363
444
  }
364
- async function runWranglerKVBulkPut(root, options, execute = spawn, nodeExecutable = process.execPath) {
365
- const tempDir = fs.mkdtempSync(path.join(options.tempDir ?? os.tmpdir(), "vinext-kv-bulk-"));
366
- try {
367
- const wranglerBin = resolveWranglerBin(root);
368
- const totalChunks = Math.ceil(options.pairs.length / KV_BULK_PUT_CHUNK_SIZE);
369
- for (let i = 0; i < totalChunks; i++) {
370
- const filePath = path.join(tempDir, `prerender-kv-${i}.json`);
371
- const chunk = options.pairs.slice(i * KV_BULK_PUT_CHUNK_SIZE, (i + 1) * KV_BULK_PUT_CHUNK_SIZE);
372
- fs.writeFileSync(filePath, JSON.stringify(chunk), "utf-8");
373
- const { args } = buildWranglerKVBulkPutArgs({
374
- binding: options.binding,
375
- env: options.env,
376
- filePath
377
- });
378
- const invocation = buildNodeCliInvocation(wranglerBin, args, nodeExecutable);
379
- const child = execute(invocation.file, invocation.args, {
380
- cwd: root,
381
- stdio: "inherit",
382
- shell: false
383
- });
384
- await new Promise((resolve, reject) => {
385
- child.once("error", reject);
386
- child.once("close", (code, signal) => {
387
- if (code === 0) {
388
- resolve();
389
- return;
390
- }
391
- const exitReason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
392
- reject(/* @__PURE__ */ new Error(`Wrangler KV bulk put failed with ${exitReason}.`));
393
- });
394
- });
395
- }
396
- } finally {
397
- fs.rmSync(tempDir, {
398
- recursive: true,
399
- force: true
400
- });
401
- }
402
- }
403
445
  async function runWranglerDeploy(root, options, execute = spawn) {
404
446
  if (options.promote === false) return runWranglerVersionUpload(root, options).previewUrl ?? "(Preview URL not detected in wrangler output)";
405
447
  const spawnOptions = {
@@ -439,6 +481,38 @@ async function runWranglerDeploy(root, options, execute = spawn) {
439
481
  });
440
482
  return parseWorkerDeploymentUrl(output) ?? "(URL not detected in wrangler output)";
441
483
  }
484
+ async function runCfDeploy(root, options, execute = spawn) {
485
+ const { args, mode } = buildCfDeployArgs(options);
486
+ console.log(mode ? `\n Deploying Build Output in mode: ${mode}...` : "\n Deploying Build Output...");
487
+ const child = execute(process.execPath, [resolveCfBin(root), ...args], {
488
+ cwd: root,
489
+ stdio: [
490
+ "inherit",
491
+ "pipe",
492
+ "pipe"
493
+ ],
494
+ shell: false
495
+ });
496
+ let output = "";
497
+ child.stdout?.on("data", (chunk) => {
498
+ const text = chunk.toString();
499
+ output += text;
500
+ process.stdout.write(text);
501
+ });
502
+ child.stderr?.on("data", (chunk) => {
503
+ const text = chunk.toString();
504
+ output += text;
505
+ process.stderr.write(text);
506
+ });
507
+ await new Promise((resolve, reject) => {
508
+ child.once("error", reject);
509
+ child.once("close", (code, signal) => {
510
+ if (code === 0) resolve();
511
+ else reject(/* @__PURE__ */ new Error(`cf deploy failed with ${signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`}.`));
512
+ });
513
+ });
514
+ return parseWorkerDeploymentUrl(output) ?? "(URL not detected in cf output)";
515
+ }
442
516
  function hasCdnWarmRequests(plan) {
443
517
  return plan.paths.length + (plan.pagesDataPaths?.length ?? 0) + (plan.routeHandlerPaths?.length ?? 0) + plan.rscPaths.length + plan.loadingShellPaths.length > 0;
444
518
  }
@@ -472,6 +546,30 @@ function selectTPRWarmPlan(plan, traffic, coverage, limit) {
472
546
  function projectRequiresRouteCacheabilityProbeManifest(project, cacheConfig) {
473
547
  return (project.isAppRouter || project.isPagesRouter) && requiresRouteCacheabilityProbeManifest(cacheConfig);
474
548
  }
549
+ function deploymentWorkerName(options) {
550
+ if (!options.name) throw new Error("Could not detect the Worker name for its deployment.");
551
+ return options.name;
552
+ }
553
+ function runDeploymentStatus(root, options) {
554
+ return options.deploymentTool === "cf" ? runCfDeploymentStatus(root, {
555
+ name: deploymentWorkerName(options),
556
+ env: options.env,
557
+ verbose: options.verbose
558
+ }) : runWranglerDeploymentStatus(root, options);
559
+ }
560
+ function runVersionDeploy(root, traffic, options, phase) {
561
+ return options.deploymentTool === "cf" ? runCfVersionDeploy(root, traffic, {
562
+ name: deploymentWorkerName(options),
563
+ env: options.env,
564
+ verbose: options.verbose
565
+ }, phase) : runWranglerVersionDeploy(root, traffic, options, phase);
566
+ }
567
+ function runTriggersDeploy(root, options) {
568
+ return options.deploymentTool === "cf" ? runCfTriggersDeploy(root, options) : runWranglerTriggersDeploy(root, options);
569
+ }
570
+ function runVersionUpload(root, options) {
571
+ return options.deploymentTool === "cf" ? runCfVersionUpload(root, options) : runWranglerVersionUpload(root, options);
572
+ }
475
573
  function cdnWarmTargetKey(target) {
476
574
  return `${target.kind}\0${target.sourcePathname}`;
477
575
  }
@@ -491,14 +589,14 @@ async function deployWithCdnWarmup(root, paths, options) {
491
589
  ...options,
492
590
  warmCdnTarget: validateCdnWarmTarget(options.warmCdnTarget)
493
591
  };
494
- if (options.warmCdnDiscoveryTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnDiscoveryTimeout), "--warm-cdn-discovery-timeout");
495
- if (options.warmCdnDiscoveryRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnDiscoveryRetries), "--warm-cdn-discovery-retries");
496
- if (options.warmCdnProbeTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnProbeTimeout), "--warm-cdn-probe-timeout");
497
- if (options.warmCdnProbeRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnProbeRetries), "--warm-cdn-probe-retries");
498
- if (options.warmCdnReadinessTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessTimeout), "--warm-cdn-readiness-timeout");
499
- if (options.warmCdnReadinessRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnReadinessRetries), "--warm-cdn-readiness-retries");
500
- if (options.warmCdnReadinessProbes !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessProbes), "--warm-cdn-readiness-probes");
501
- if (options.warmCdnReadinessProbeDelay !== void 0) validateTimerDelay(options.warmCdnReadinessProbeDelay, "--warm-cdn-readiness-probe-delay");
592
+ if (options.warmCdnDiscoveryTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnDiscoveryTimeout), "--warm-cache-discovery-timeout");
593
+ if (options.warmCdnDiscoveryRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnDiscoveryRetries), "--warm-cache-discovery-retries");
594
+ if (options.warmCdnProbeTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnProbeTimeout), "--warm-cache-probe-timeout");
595
+ if (options.warmCdnProbeRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnProbeRetries), "--warm-cache-probe-retries");
596
+ if (options.warmCdnReadinessTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessTimeout), "--warm-cache-readiness-timeout");
597
+ if (options.warmCdnReadinessRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnReadinessRetries), "--warm-cache-readiness-retries");
598
+ if (options.warmCdnReadinessProbes !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessProbes), "--warm-cache-readiness-probes");
599
+ if (options.warmCdnReadinessProbeDelay !== void 0) validateTimerDelay(options.warmCdnReadinessProbeDelay, "--warm-cache-readiness-probe-delay");
502
600
  if (options.warmCdnPromotionDelay !== void 0) validatePromotionDelay(options.warmCdnPromotionDelay);
503
601
  if (options.cacheabilityProbe) return deployWithCacheabilityProbe(root, options);
504
602
  return deployUploadedVersionWithCdnWarmup(root, paths, options);
@@ -523,7 +621,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
523
621
  if (plan.paths.length === 0 && plan.pagesDataPaths.length === 0 && (plan.routeHandlerPaths?.length ?? 0) === 0 || expectedBuildId !== void 0) return plan;
524
622
  if (!allowUnverifiedPromotion) {
525
623
  const warmupKind = plan.paths.length > 0 ? "CDN HTML warmup" : plan.pagesDataPaths.length > 0 ? "CDN Pages data warmup" : "CDN Route Handler warmup";
526
- throw new Error(`${warmupKind} requires a CDN adapter that declares build-identity response headers. Configure that adapter capability or deploy without --experimental-warm-cdn-cache.`);
624
+ throw new Error(`${warmupKind} requires a CDN adapter that declares build-identity response headers. Configure that adapter capability or deploy without --warm-cache.`);
527
625
  }
528
626
  console.warn(` CDN warmup: skipping ${plan.paths.length} HTML, ${plan.pagesDataPaths.length} Pages data, and ${plan.routeHandlerPaths?.length ?? 0} Route Handler request(s) because the CDN adapter does not declare build-identity response headers.`);
529
627
  return {
@@ -555,7 +653,8 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
555
653
  warmPlanDiscovered = true;
556
654
  };
557
655
  if (!options.discoverWarmPlan || hasPreparedWarmPlan) remainingWarmPlan = prepareWarmPlan(remainingWarmPlan);
558
- const upload = options.uploadedVersion ?? runWranglerVersionUpload(root, options);
656
+ const upload = options.uploadedVersion ?? runVersionUpload(root, options);
657
+ const wranglerOptions = resolveDeploymentControlPlaneOptions(options, upload);
559
658
  const warmUploadedVersion = (targetUrl, headers, propagatingTarget = false, plan = {
560
659
  loadingShellPaths: remainingWarmPlan.loadingShellPaths,
561
660
  pagesDataPaths: remainingWarmPlan.pagesDataPaths,
@@ -584,10 +683,10 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
584
683
  strict: requireCacheHit || !allowUnverifiedPromotion,
585
684
  statusSource: options.statusSource
586
685
  });
587
- const wranglerConfig = parseWranglerConfig(root, options.config);
686
+ const wranglerConfig = options.deploymentTool === "cf" ? null : parseWranglerConfig(root, options.config);
588
687
  let deploymentStatus;
589
688
  try {
590
- deploymentStatus = runWranglerDeploymentStatus(root, options);
689
+ deploymentStatus = runDeploymentStatus(root, wranglerOptions);
591
690
  } catch (error) {
592
691
  if (!hasPreparedWarmPlan) throw error;
593
692
  throw new StagedWarmupError(formatUnknownError(error), { cause: error });
@@ -603,14 +702,14 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
603
702
  let triggersApplied = options.triggersAlreadyApplied === true;
604
703
  function applyTriggers() {
605
704
  if (triggersApplied) return;
606
- triggersDeployedUrl = runWranglerTriggersDeploy(root, options).deployedUrl;
705
+ triggersDeployedUrl = runTriggersDeploy(root, wranglerOptions).deployedUrl;
607
706
  triggersApplied = true;
608
707
  }
609
708
  if (stagingTraffic) {
610
709
  try {
611
- staged = runWranglerVersionDeploy(root, stagingTraffic, options, "stage");
710
+ staged = runVersionDeploy(root, stagingTraffic, wranglerOptions, "stage");
612
711
  } catch (error) {
613
- throw reconcileVersionDeployFailure(root, options, error, {
712
+ throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
614
713
  desiredTraffic: stagingTraffic,
615
714
  desiredDescription: "The uploaded version is staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes were not changed.",
616
715
  priorState: deploymentStatus,
@@ -619,7 +718,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
619
718
  }
620
719
  try {
621
720
  if (hasPreparedWarmPlan) {
622
- stagedDeploymentState = runWranglerDeploymentStatus(root, options);
721
+ stagedDeploymentState = runDeploymentStatus(root, wranglerOptions);
623
722
  if (!deploymentTrafficEquals(stagedDeploymentState.versions, stagingTraffic)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic changed before production triggers could be applied. No final version was promoted.");
624
723
  }
625
724
  applyTriggers();
@@ -627,7 +726,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
627
726
  throw withStagedVersionCleanupNote(error);
628
727
  }
629
728
  const targetUrl = resolveCdnWarmupTargetUrl(root, triggersDeployedUrl, options) ?? staged.deployedUrl;
630
- const headers = buildVersionOverrideHeaders(options.name ?? upload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, options), upload.versionId);
729
+ const headers = buildVersionOverrideHeaders(options.name ?? upload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, wranglerOptions), upload.versionId);
631
730
  if (targetUrl && headers) try {
632
731
  if (!warmPlanDiscovered) {
633
732
  console.log(" CDN warmup: discovering paths from the staged Worker version...");
@@ -669,7 +768,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
669
768
  console.log(" CDN warmup: staged Worker version is stable.");
670
769
  const warmResult = await warmUploadedVersion(targetUrl, headers, true, stagedWarmPlan);
671
770
  const optionalSkipped = options.optionalWarmTargetKeys ? warmResult.skippedTargets.filter((target) => options.optionalWarmTargetKeys.has(cdnWarmTargetKey(target))).length : 0;
672
- if (hasPreparedWarmPlan && options.warmCdnCertify) {
771
+ if ((hasPreparedWarmPlan || options.selectWarmPlan) && options.warmCdnCertify) {
673
772
  if (warmResult.warmed + optionalSkipped !== stagedWarmRequests) throw new Error(`CDN warmup cannot certify the staged cache because only ${warmResult.warmed}/${stagedWarmRequests - optionalSkipped} cacheable entries completed their initial fill.`);
674
773
  }
675
774
  const requiredSkipped = warmResult.skipped - optionalSkipped;
@@ -698,7 +797,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
698
797
  throw withStagedVersionCleanupNote(error);
699
798
  }
700
799
  else if (initialWarmRequests > 0) {
701
- const message = "CDN warmup failed: pre-traffic warmup needs a production URL and Worker name for version overrides. Configure a route/custom domain and Worker name, or deploy without --experimental-warm-cdn-cache.";
800
+ const message = "CDN warmup failed: pre-traffic warmup needs a production URL and Worker name for version overrides. Configure a route/custom domain and Worker name, or deploy without --warm-cache.";
702
801
  if (!allowUnverifiedPromotion) throw new StagedWarmupError(`${message} ${getStagedVersionCleanupNote()}`);
703
802
  console.warn(` ${message} Promoting because the dangerous override is enabled.`);
704
803
  }
@@ -710,6 +809,10 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
710
809
  }
711
810
  console.warn(" CDN warmup: pre-traffic version override skipped because the current deployment is not one version serving 100% traffic.");
712
811
  }
812
+ if (options.selectWarmPlan && options.warmCdnCertify && !stagedCacheFilled) {
813
+ const error = /* @__PURE__ */ new Error("CDN warmup cannot succeed because no cache entries were certified.");
814
+ throw staged ? withStagedVersionCleanupNote(error) : error;
815
+ }
713
816
  const countRemainingWarmRequests = () => remainingWarmPlan.paths.length + remainingWarmPlan.pagesDataPaths.length + (remainingWarmPlan.routeHandlerPaths?.length ?? 0) + remainingWarmPlan.rscPaths.length + remainingWarmPlan.loadingShellPaths.length;
714
817
  if (options.warmCdnPromote === false) {
715
818
  if (!staged) throw new Error("CDN warmup cannot skip promotion because the uploaded Worker version could not be staged at 0% traffic. The current deployment must have exactly one version serving 100% traffic.");
@@ -719,9 +822,9 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
719
822
  if (hasPreparedWarmPlan && stagedDeploymentState) {
720
823
  let currentDeployment;
721
824
  try {
722
- currentDeployment = runWranglerDeploymentStatus(root, options);
825
+ currentDeployment = runDeploymentStatus(root, wranglerOptions);
723
826
  } catch (error) {
724
- throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect \`wrangler deployments status\` before continuing.`, { cause: error });
827
+ throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect the active Worker deployment before continuing.`, { cause: error });
725
828
  }
726
829
  if (!deploymentStateEquals(currentDeployment, stagedDeploymentState)) throw new StagedWarmupError("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the no-promote handoff. The uploaded Worker is not confirmed staged at 0% traffic; production Worker triggers/routes remain applied.");
727
830
  }
@@ -744,13 +847,13 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
744
847
  }
745
848
  }
746
849
  if (hasPreparedWarmPlan && stagingTraffic) {
747
- prePromotionState = runWranglerDeploymentStatus(root, options);
850
+ prePromotionState = runDeploymentStatus(root, wranglerOptions);
748
851
  if (!deploymentTrafficEquals(prePromotionState.versions, stagingTraffic) || stagedDeploymentState && !deploymentStateEquals(prePromotionState, stagedDeploymentState)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the final version could be promoted. No final version was promoted.");
749
852
  }
750
853
  promotionAttempted = true;
751
- deployed = runWranglerVersionDeploy(root, promotionTraffic, options, stagedCacheFilled ? "promote-warmed" : "promote-uploaded");
854
+ deployed = runVersionDeploy(root, promotionTraffic, wranglerOptions, stagedCacheFilled ? "promote-warmed" : "promote-uploaded");
752
855
  } catch (error) {
753
- if (promotionAttempted) throw reconcileVersionDeployFailure(root, options, error, {
856
+ if (promotionAttempted) throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
754
857
  desiredTraffic: promotionTraffic,
755
858
  desiredDescription: "The uploaded version is already promoted to 100%; Worker triggers/routes may already have changed.",
756
859
  priorState: prePromotionState ?? (stagingTraffic ? {
@@ -782,7 +885,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
782
885
  } catch (error) {
783
886
  throw withPromotedVersionWarmupNote(error);
784
887
  }
785
- else if (!allowUnverifiedPromotion) throw withPromotedVersionWarmupNote(/* @__PURE__ */ new Error("CDN warmup failed: no production URL could be inferred from wrangler config or output. Configure a route/custom domain, ensure Wrangler prints a workers.dev URL, or deploy without --experimental-warm-cdn-cache."));
888
+ else if (!allowUnverifiedPromotion) throw withPromotedVersionWarmupNote(/* @__PURE__ */ new Error("CDN warmup failed: no production URL could be inferred from wrangler config or output. Configure a route/custom domain, ensure Wrangler prints a workers.dev URL, or deploy without --warm-cache."));
786
889
  else console.warn(" CDN warmup skipped: no production URL could be inferred after promotion; the dangerous override was enabled.");
787
890
  }
788
891
  return deployed.deployedUrl ?? triggersDeployedUrl ?? staged?.deployedUrl ?? upload.previewUrl ?? "(URL not detected in wrangler output)";
@@ -802,7 +905,7 @@ function reconcileVersionDeployFailure(root, options, error, expected) {
802
905
  let reconciliation;
803
906
  let mayNeedCleanup = true;
804
907
  try {
805
- const current = runWranglerDeploymentStatus(root, options);
908
+ const current = runDeploymentStatus(root, options);
806
909
  if (deploymentTrafficEquals(current.versions, expected.desiredTraffic)) reconciliation = expected.desiredDescription;
807
910
  else if (deploymentStateEquals(current, expected.priorState)) {
808
911
  reconciliation = expected.priorDescription;
@@ -815,20 +918,21 @@ function reconcileVersionDeployFailure(root, options, error, expected) {
815
918
  return mayNeedCleanup ? new StagedWarmupError(detail, { cause: error }) : new Error(detail, { cause: error });
816
919
  }
817
920
  function assertDeploymentStateUnchanged(root, options, expected, message) {
818
- if (!deploymentStateEquals(runWranglerDeploymentStatus(root, options), expected)) throw new Error(message);
921
+ if (!deploymentStateEquals(runDeploymentStatus(root, options), expected)) throw new Error(message);
819
922
  }
820
923
  async function deployWithCacheabilityProbe(root, options) {
821
924
  if (!options.discoverWarmPlan) throw new Error("Two-stage CDN warming requires staged Worker route discovery before cacheability probing.");
822
925
  const prerenderSecret = readPrerenderSecret(root);
823
- const probeUpload = runWranglerVersionUpload(root, options);
824
- const initialDeployment = runWranglerDeploymentStatus(root, options);
926
+ const probeUpload = runVersionUpload(root, options);
927
+ const wranglerOptions = resolveDeploymentControlPlaneOptions(options, probeUpload);
928
+ const initialDeployment = runDeploymentStatus(root, wranglerOptions);
825
929
  const probeTraffic = getZeroPercentStagingTraffic(initialDeployment, probeUpload.versionId);
826
930
  if (!probeTraffic) throw new Error("Two-stage CDN warming cannot stage the probe Worker at 0% because the current deployment is not exactly one version serving 100% traffic. No traffic or triggers were changed.");
827
931
  let stagedProbe;
828
932
  try {
829
- stagedProbe = runWranglerVersionDeploy(root, probeTraffic, options, "stage");
933
+ stagedProbe = runVersionDeploy(root, probeTraffic, wranglerOptions, "stage");
830
934
  } catch (error) {
831
- throw reconcileVersionDeployFailure(root, options, error, {
935
+ throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
832
936
  desiredTraffic: probeTraffic,
833
937
  desiredDescription: "The probe version is staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.",
834
938
  priorState: initialDeployment,
@@ -837,16 +941,16 @@ async function deployWithCacheabilityProbe(root, options) {
837
941
  }
838
942
  let stagedProbeDeployment;
839
943
  try {
840
- stagedProbeDeployment = runWranglerDeploymentStatus(root, options);
944
+ stagedProbeDeployment = runDeploymentStatus(root, wranglerOptions);
841
945
  if (!deploymentTrafficEquals(stagedProbeDeployment.versions, probeTraffic)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic changed immediately after the probe version was staged.");
842
946
  } catch (error) {
843
- throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect \`wrangler deployments status\` and remove the staged probe version if necessary.`, { cause: error });
947
+ throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect the active Worker deployment and remove the staged probe version if necessary.`, { cause: error });
844
948
  }
845
949
  let prepared;
846
950
  try {
847
951
  const targetUrl = resolveCdnWarmupTargetUrl(root, stagedProbe.deployedUrl ?? probeUpload.previewUrl, options);
848
- const wranglerConfig = parseWranglerConfig(root, options.config);
849
- const headers = buildVersionOverrideHeaders(options.name ?? probeUpload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, options), probeUpload.versionId);
952
+ const wranglerConfig = options.deploymentTool === "cf" ? null : parseWranglerConfig(root, wranglerOptions.config);
953
+ const headers = buildVersionOverrideHeaders(options.name ?? probeUpload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, wranglerOptions), probeUpload.versionId);
850
954
  if (!targetUrl || !headers) throw new Error("Two-stage CDN warming needs a production URL and Worker name for version-overridden cacheability probes.");
851
955
  console.log(" CDN warmup: discovering paths from the staged probe Worker...");
852
956
  const discovered = await options.discoverWarmPlan({
@@ -912,6 +1016,7 @@ async function deployWithCacheabilityProbe(root, options) {
912
1016
  concurrency: options.warmCdnConcurrency,
913
1017
  expectedResponseBuildId: plan.buildIdentity,
914
1018
  fallbackRoutePatterns: plan.fallbackRoutePatterns,
1019
+ loadingBoundaryRoutePatterns: plan.loadingBoundaryRoutePatterns,
915
1020
  phaseTimeoutMs: options.warmCdnProbeTimeout ?? 12e4,
916
1021
  retries: options.warmCdnProbeRetries ?? options.warmCdnRetries ?? 2,
917
1022
  retryDelayMs: DEFAULT_CACHEABILITY_PROBE_RETRY_DELAY_MS,
@@ -937,14 +1042,11 @@ async function deployWithCacheabilityProbe(root, options) {
937
1042
  rscPaths: probe.cacheableTargets.filter((target) => target.kind === "rsc-full").map((target) => target.sourcePathname)
938
1043
  };
939
1044
  const selectedFinalPlan = options.selectWarmPlan?.(finalPlan) ?? finalPlan;
940
- assertDeploymentStateUnchanged(root, options, stagedProbeDeployment, "Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed while cacheability was being probed. No final version was promoted.");
941
- const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest);
942
- const finalUpload = runWranglerVersionUpload(root, {
943
- config: finalConfig,
944
- env: options.env,
945
- name: options.name,
946
- preview: options.preview,
947
- verbose: options.verbose
1045
+ assertDeploymentStateUnchanged(root, wranglerOptions, stagedProbeDeployment, "Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed while cacheability was being probed. No final version was promoted.");
1046
+ const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest, options.deploymentTool);
1047
+ const finalUpload = runVersionUpload(root, {
1048
+ ...options,
1049
+ config: options.deploymentTool === "cf" ? options.config : finalConfig
948
1050
  });
949
1051
  prepared = {
950
1052
  optionalWarmTargetKeys: new Set(probe.speculativeTargets.map(cdnWarmTargetKey)),
@@ -986,6 +1088,15 @@ function getZeroPercentStagingTraffic(deployment, versionId) {
986
1088
  function getWranglerTargetEnv(options) {
987
1089
  return options.env || (options.preview ? "preview" : void 0);
988
1090
  }
1091
+ function resolveDeploymentControlPlaneOptions(options, upload) {
1092
+ if (options.deploymentTool !== "cf") return options;
1093
+ const name = upload.workerName ?? options.name;
1094
+ if (!name) throw new Error("Could not detect the uploaded Worker name needed for staged CDN warming.");
1095
+ return {
1096
+ ...options,
1097
+ name
1098
+ };
1099
+ }
989
1100
  function resolveWorkerNameForVersionOverride(config, options) {
990
1101
  if (options.name) return options.name;
991
1102
  const env = getWranglerTargetEnv(options);
@@ -1010,24 +1121,29 @@ function withStagedProbeVersionCleanupNote(error) {
1010
1121
  return new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe version may remain staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.`, { cause: error });
1011
1122
  }
1012
1123
  function getStagedVersionCleanupNote() {
1013
- return "The uploaded version may remain staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes may also have changed because trigger deployment runs before warming. Rerun deploy to promote it or use `wrangler versions deploy` to choose the desired version split.";
1124
+ return "The uploaded version may remain staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes may also have changed because trigger deployment runs before warming. Rerun deploy to promote it or create a deployment with the desired version split.";
1014
1125
  }
1015
1126
  function withPromotedVersionTriggerNote(error) {
1016
1127
  const message = error instanceof Error ? error.message : String(error);
1017
- return new Error(`${message} The uploaded version may already be promoted to 100%, but Worker triggers/routes may not be updated; rerun deploy or \`wrangler triggers deploy\` after fixing the trigger error.`, { cause: error });
1128
+ return new Error(`${message} The uploaded version may already be promoted to 100%, but Worker triggers/routes may not be updated; rerun deploy or apply the Worker triggers after fixing the trigger error.`, { cause: error });
1018
1129
  }
1019
1130
  function withPromotedVersionWarmupNote(error) {
1020
1131
  const message = error instanceof Error ? error.message : String(error);
1021
- return new Error(`${message} The uploaded version is already promoted to 100% and its Worker triggers/routes were updated; rerun deploy to retry cache warming or roll back with \`wrangler versions deploy\`.`, { cause: error });
1132
+ return new Error(`${message} The uploaded version is already promoted to 100% and its Worker triggers/routes were updated; rerun deploy to retry cache warming or create a deployment for the previous version.`, { cause: error });
1022
1133
  }
1023
1134
  async function deploy(options) {
1024
- if (options.warmCdnTarget !== void 0 && !options.warmCdnCache) throw new Error("--warm-cdn-target requires --experimental-warm-cdn-cache.");
1135
+ if (options.warmCdnTarget !== void 0 && !options.warmCdnCache && !options.experimentalTPR) throw new Error("--warm-cache-target requires --warm-cache or --traffic-aware-warm-cache.");
1025
1136
  const warmCdnTarget = options.warmCdnTarget === void 0 ? void 0 : validateCdnWarmTarget(options.warmCdnTarget);
1026
- const deployEnv = validateWranglerEnvName(options.env || (options.preview ? "preview" : "production"));
1137
+ const deployEnv = options.env || (options.preview ? "preview" : void 0);
1138
+ if (deployEnv) validateWranglerEnvName(deployEnv);
1027
1139
  const root = path.resolve(options.root);
1140
+ const deploymentTool = resolveDeploymentTool(root);
1141
+ if (deploymentTool === "cf" && options.name) throw new Error("--name is not supported for cloudflare.config.ts projects. Set `name` in cloudflare.config.ts instead.");
1142
+ const viteMode = resolveViteBuildMode(deploymentTool, deployEnv);
1143
+ const wranglerFallbackEnv = deploymentTool === "cf" ? void 0 : deployEnv;
1028
1144
  loadDotenv({
1029
1145
  root,
1030
- mode: "production"
1146
+ mode: viteMode
1031
1147
  });
1032
1148
  console.log("\n vinext-cloudflare deploy\n");
1033
1149
  const info = detectProject(root);
@@ -1045,20 +1161,20 @@ async function deploy(options) {
1045
1161
  if (missingScaffolding.length > 0) throw new Error(`Missing Cloudflare deployment setup: ${missingScaffolding.join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
1046
1162
  const missingDeps = getMissingDeps(info);
1047
1163
  if (missingDeps.length > 0) throw new Error(`Missing deployment dependencies: ${missingDeps.map((dependency) => dependency.name).join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
1164
+ if (deploymentTool === "cf" && !isCfCliInstalled(root)) throw new Error("Missing deployment dependencies: cf. Run `vinext init --platform=cloudflare` first.");
1048
1165
  if (info.hasViteConfig && !viteConfigHasCloudflarePlugin(root)) throw new Error(formatMissingCloudflarePluginError({ isAppRouter: info.isAppRouter }));
1049
- if (info.hasISR && !viteConfigHasCacheAdapter(root) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({}));
1166
+ if (info.hasISR && !viteConfigHasCacheAdapter(root) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({ typedConfig: deploymentTool === "cf" }));
1050
1167
  if (!viteConfigHasImageAdapter(root)) {
1051
1168
  console.log();
1052
- console.log(formatImageOptimizationHint());
1169
+ console.log(formatImageOptimizationHint(deploymentTool === "cf"));
1053
1170
  }
1054
1171
  if (options.dryRun) {
1055
1172
  console.log("\n Dry run complete. No build or deploy performed.\n");
1056
1173
  return;
1057
1174
  }
1058
- const buildEnv = deployEnv === "production" && !options.env ? void 0 : deployEnv;
1059
- const viteConfigMetadata = await withCloudflareEnv(buildEnv, () => loadDeployViteConfigMetadata(info.root));
1175
+ const viteConfigMetadata = await withCloudflareEnv(deployEnv, () => loadDeployViteConfigMetadata(info.root, viteMode));
1060
1176
  const cdnAdapterConfig = resolveCdnAdapterConfig(viteConfigMetadata.cacheConfig);
1061
- const nextConfig = await withCloudflareEnv(buildEnv, async () => {
1177
+ const nextConfig = await withCloudflareEnv(deployEnv, async () => {
1062
1178
  const inlineNextConfig = viteConfigMetadata.nextConfig;
1063
1179
  const rawNextConfig = inlineNextConfig ? await resolveNextConfigInput(inlineNextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(info.root, PHASE_PRODUCTION_BUILD);
1064
1180
  return resolveNextConfig(rawNextConfig, info.root);
@@ -1069,66 +1185,82 @@ async function deploy(options) {
1069
1185
  vinextPrerenderConfig,
1070
1186
  nextOutput: nextConfig.output
1071
1187
  });
1188
+ const shouldPrerenderLocally = Boolean(prerenderDecision && (nextConfig.output === "export" || hasCacheAdapterPrerenderOutput(viteConfigMetadata.cacheConfig)));
1072
1189
  const hasStrictResponseVary = hasVerbatimResponseVary(viteConfigMetadata.cacheConfig);
1073
1190
  const warmupStatusSource = cacheWarmupStatusSource(viteConfigMetadata.cacheConfig);
1074
1191
  const hasStagedRequestRouting = hasUncachedRequestRouting(viteConfigMetadata.cacheConfig) || warmupStatusSource === "data-cache";
1075
1192
  const hasBuildIdentityHeader = hasBuildIdentityResponseHeader(viteConfigMetadata.cacheConfig);
1076
1193
  const hasCanonicalRscWarmup = supportsCanonicalRscWarmup(viteConfigMetadata.cacheConfig);
1077
1194
  const needsCacheabilityProbeManifest = projectRequiresRouteCacheabilityProbeManifest(info, viteConfigMetadata.cacheConfig);
1078
- const shouldEmitPrerenderPathManifest = !options.skipBuild && prerenderDecision;
1079
- if (!options.skipBuild) await runBuild(info, buildEnv);
1195
+ const shouldEmitPrerenderPathManifest = !options.skipBuild && shouldPrerenderLocally;
1196
+ if (prerenderDecision && !shouldPrerenderLocally) {
1197
+ const trigger = prerenderDecision.reason === "flag" ? "--prerender-all" : "vinext prerender config";
1198
+ const replacement = options.warmCdnCache ? "Routes will be rendered and warmed through the staged Worker instead." : "Use --warm-cache to render and warm routes through the deployed Worker instead.";
1199
+ console.warn(`\n Warning: ${trigger} is ignored by Cloudflare deploy. ${replacement}`);
1200
+ }
1201
+ if (!options.skipBuild) await runBuild(info, deployEnv, viteMode);
1080
1202
  else console.log("\n Skipping build (--skip-build)");
1081
- const canWarmTpr = options.experimentalTPR && !prerenderDecision && hasBuildIdentityHeader;
1082
- if (options.experimentalTPR && prerenderDecision) console.log(" TPR: Skipping route selection (all-route prerendering configured)");
1203
+ const prerenderOutputDirs = resolvePrerenderOutputDirs(info.root, deploymentTool, viteConfigMetadata.routeRootConfig);
1204
+ const canWarmTpr = options.experimentalTPR && !shouldPrerenderLocally && hasBuildIdentityHeader;
1205
+ if (options.experimentalTPR && shouldPrerenderLocally) console.log(" TPR: Skipping route selection (all-route prerendering configured)");
1083
1206
  else if (options.experimentalTPR && !hasBuildIdentityHeader) console.log(workerEntryHasCacheHandler(root) ? " TPR: Skipping pre-warm (legacy imperative cache handlers must migrate to declarative vinext({ cache }) for standard warming)" : " TPR: Skipping pre-warm (configured cache does not expose build identity)");
1084
1207
  const tpr = canWarmTpr ? await resolveTPRRoutes({
1085
1208
  root,
1086
1209
  config: options.config,
1087
- env: buildEnv,
1210
+ env: wranglerFallbackEnv,
1088
1211
  hostname: warmCdnTarget ? new URL(warmCdnTarget).hostname : void 0,
1212
+ typedConfig: deploymentTool === "cf",
1089
1213
  window: Math.max(1, options.tprWindow ?? 24)
1090
1214
  }) : null;
1091
1215
  if (tpr?.skipped) console.log(` TPR: Skipped (${tpr.skipped})`);
1092
1216
  const tprRoutes = tpr?.routes ?? [];
1093
1217
  const wranglerOptions = {
1094
- env: deployEnv === "production" && !options.env ? void 0 : deployEnv,
1095
- name: options.name,
1218
+ env: deploymentTool === "cf" ? viteMode : deployEnv,
1219
+ name: deploymentTool === "cf" ? readBuildOutputWorkerName(root) : options.name,
1096
1220
  config: options.config,
1097
- verbose: options.verbose
1221
+ verbose: options.verbose,
1222
+ deploymentTool
1098
1223
  };
1099
1224
  let shouldWarmTpr = tprRoutes.length > 0;
1100
1225
  if (shouldWarmTpr && !options.warmCdnCache) {
1101
1226
  try {
1102
- shouldWarmTpr = getZeroPercentStagingTraffic(runWranglerDeploymentStatus(root, wranglerOptions), "tpr-preflight") !== null;
1227
+ shouldWarmTpr = getZeroPercentStagingTraffic(runDeploymentStatus(root, wranglerOptions), "tpr-preflight") !== null;
1103
1228
  } catch {
1104
1229
  shouldWarmTpr = false;
1105
1230
  }
1106
1231
  if (!shouldWarmTpr) console.log(" TPR: Skipping pre-warm (current deployment cannot be staged safely)");
1107
1232
  }
1108
1233
  const shouldWarmCdnCache = options.warmCdnCache || shouldWarmTpr;
1234
+ if (options.warmCdnCertify && !shouldWarmCdnCache) throw new Error("Cannot certify traffic-aware warming because pre-warming was skipped.");
1109
1235
  const shouldSelectTpr = shouldWarmTpr && !options.warmCdnCache;
1110
1236
  const candidatePathsOnly = shouldSelectTpr && !needsCacheabilityProbeManifest;
1111
- const shouldPrerenderLocally = prerenderDecision && (!shouldWarmCdnCache || prerenderDecision.reason === "next-export");
1112
1237
  if (shouldWarmCdnCache && cdnAdapterConfig) {
1113
- const wrangler = await loadProjectWranglerApi(info.root);
1114
- const previousCwd = process.cwd();
1115
- try {
1116
- process.chdir(info.root);
1117
- const config = wrangler.unstable_readConfig({
1118
- config: options.config,
1119
- env: buildEnv
1120
- }, {
1121
- hideWarnings: true,
1122
- preserveOriginalMain: true,
1123
- useRedirectIfAvailable: true
1124
- });
1125
- assertCdnVersionMetadataConfig({
1126
- binding: cdnAdapterConfig.versionMetadataBinding,
1127
- configuredBinding: config.version_metadata?.binding,
1128
- configPath: config.configPath
1129
- });
1130
- } finally {
1131
- process.chdir(previousCwd);
1238
+ if (deploymentTool === "cf") {
1239
+ const configPath = path.join(root, ".cloudflare/output/v0/workers/default/worker.config.json");
1240
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
1241
+ const binding = cdnAdapterConfig.versionMetadataBinding;
1242
+ if (config.env?.[binding]?.type !== "version-metadata") throw new Error(`[vinext] Cloudflare CDN warmup requires version metadata binding ${JSON.stringify(binding)} in the generated Build Output Worker config ${configPath}.`);
1243
+ } else {
1244
+ const wrangler = await loadProjectWranglerApi(info.root);
1245
+ const previousCwd = process.cwd();
1246
+ try {
1247
+ process.chdir(info.root);
1248
+ const config = wrangler.unstable_readConfig({
1249
+ config: options.config,
1250
+ env: wranglerFallbackEnv
1251
+ }, {
1252
+ hideWarnings: true,
1253
+ preserveOriginalMain: true,
1254
+ useRedirectIfAvailable: true
1255
+ });
1256
+ assertCdnVersionMetadataConfig({
1257
+ binding: cdnAdapterConfig.versionMetadataBinding,
1258
+ configuredBinding: config.version_metadata?.binding,
1259
+ configPath: config.configPath
1260
+ });
1261
+ } finally {
1262
+ process.chdir(previousCwd);
1263
+ }
1132
1264
  }
1133
1265
  }
1134
1266
  if (shouldEmitPrerenderPathManifest) await emitPrerenderPathManifest({
@@ -1138,27 +1270,30 @@ async function deploy(options) {
1138
1270
  requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
1139
1271
  responseVary: hasStrictResponseVary ? "verbatim" : void 0,
1140
1272
  isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
1141
- routeRootConfig: viteConfigMetadata.routeRootConfig
1273
+ routeRootConfig: prerenderOutputDirs
1142
1274
  });
1143
- let ranPrerender = false;
1144
- if (shouldPrerenderLocally) {
1275
+ let prerenderResult = void 0;
1276
+ if (shouldPrerenderLocally && prerenderDecision) {
1145
1277
  console.log(`\n ${formatVinextPrerenderLabel(prerenderDecision)}`);
1146
1278
  if (nextConfig.enablePrerenderSourceMaps) {
1147
1279
  process.setSourceMapsEnabled(true);
1148
1280
  Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 50);
1149
1281
  }
1150
- await runPrerender({
1282
+ prerenderResult = await runPrerender({
1151
1283
  root: info.root,
1152
- concurrency: options.prerenderConcurrency,
1284
+ concurrency: options.prerenderConcurrency ?? viteConfigMetadata.prerenderConfig?.concurrency,
1153
1285
  nextConfig,
1154
- routeRootConfig: viteConfigMetadata.routeRootConfig
1286
+ routeRootConfig: prerenderOutputDirs
1155
1287
  });
1156
- ranPrerender = true;
1288
+ if (nextConfig.output !== "export") await finalizeCacheAdapterPrerenderOutput(viteConfigMetadata.cacheConfig, info.root, { clientOutDir: prerenderOutputDirs?.clientOutDir });
1157
1289
  }
1158
- if (ranPrerender) try {
1159
- await populateKVCacheFromPrerenderedArtifacts(root, deployEnv === "production" && !options.env ? void 0 : deployEnv, viteConfigMetadata.cacheConfig);
1160
- } catch (error) {
1161
- console.log(` KV cache: Skipping prerender upload (${formatUnknownError(error)}). Continuing with deploy.`);
1290
+ if (!options.skipBuild) {
1291
+ await printBuildReport({
1292
+ root: info.root,
1293
+ pageExtensions: nextConfig.pageExtensions,
1294
+ prerenderResult: prerenderResult ?? void 0
1295
+ });
1296
+ console.log("\n Build complete.\n");
1162
1297
  }
1163
1298
  let url;
1164
1299
  if (shouldWarmCdnCache) try {
@@ -1200,7 +1335,7 @@ async function deploy(options) {
1200
1335
  selectWarmPlan: shouldSelectTpr ? (plan) => selectTPRWarmPlan(plan, tprRoutes, Math.max(1, Math.min(100, options.tprCoverage ?? 90)), Math.max(1, options.tprLimit ?? 1e3)) : void 0,
1201
1336
  statusSource: warmupStatusSource,
1202
1337
  warmCdnConcurrency: options.warmCdnConcurrency,
1203
- warmCdnTarget,
1338
+ warmCdnTarget: warmCdnTarget ?? tpr?.targetUrl,
1204
1339
  warmCdnTimeout: options.warmCdnTimeout,
1205
1340
  warmCdnRetries: options.warmCdnRetries,
1206
1341
  warmCdnDiscoveryTimeout: options.warmCdnDiscoveryTimeout,
@@ -1217,16 +1352,20 @@ async function deploy(options) {
1217
1352
  warmCdnPromotionDelay: options.warmCdnPromotionDelay
1218
1353
  });
1219
1354
  } catch (error) {
1220
- if (options.warmCdnCache || options.warmCdnPromote === false && error instanceof StagedWarmupError) throw error;
1355
+ if (options.warmCdnCache || options.warmCdnCertify || options.warmCdnPromote === false && error instanceof StagedWarmupError) throw error;
1221
1356
  console.log(` TPR: Skipping pre-warm (${formatUnknownError(error)}). Continuing with deploy.`);
1222
1357
  }
1223
- if (url === void 0) url = await runWranglerDeploy(root, {
1224
- ...wranglerOptions,
1225
- promote: options.warmCdnPromote
1226
- });
1358
+ if (url === void 0) {
1359
+ if (deploymentTool === "cf" && options.warmCdnPromote === false) url = runCfVersionUpload(root, wranglerOptions).previewUrl ?? "(Preview URL not detected in cf output)";
1360
+ else if (deploymentTool === "cf") url = await runCfDeploy(root, wranglerOptions);
1361
+ else url = await runWranglerDeploy(root, {
1362
+ ...wranglerOptions,
1363
+ promote: options.warmCdnPromote
1364
+ });
1365
+ }
1227
1366
  console.log("\n ─────────────────────────────────────────");
1228
1367
  console.log(` ${options.warmCdnPromote === false ? "Version URL" : "Deployed to"}: ${url}`);
1229
1368
  console.log(" ─────────────────────────────────────────\n");
1230
1369
  }
1231
1370
  //#endregion
1232
- export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, buildWranglerKVBulkPutArgs, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveWorkerNameForVersionOverride, resolveWranglerBin, runWranglerDeploy, runWranglerKVBulkPut, selectTPRWarmPlan, validateWranglerEnvName, withCloudflareEnv };
1371
+ export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildCfDeployArgs, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, isCfCliInstalled, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveCfBin, resolveDeploymentControlPlaneOptions, resolveDeploymentTool, resolvePrerenderOutputDirs, resolveViteBuildMode, resolveWorkerNameForVersionOverride, resolveWranglerBin, runCfDeploy, runWranglerDeploy, selectTPRWarmPlan, validateWranglerEnvName, withCloudflareEnv };