@vinext/cloudflare 1.0.0-beta.7 → 1.0.0-beta.8

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 (52) hide show
  1. package/README.md +55 -22
  2. package/dist/cache/cdn-adapter-config.d.ts +16 -8
  3. package/dist/cache/cdn-adapter-config.js +57 -17
  4. package/dist/cache/cdn-adapter.d.ts +25 -24
  5. package/dist/cache/cdn-adapter.js +24 -20
  6. package/dist/cache/cdn-adapter.runtime.d.ts +9 -3
  7. package/dist/cache/cdn-adapter.runtime.js +63 -40
  8. package/dist/cache/cdn-adapter.worker.d.ts +30 -0
  9. package/dist/cache/cdn-adapter.worker.js +371 -0
  10. package/dist/cache/cdn-build-id.d.ts +4 -3
  11. package/dist/cache/cdn-build-id.js +5 -1
  12. package/dist/cache/kv-data-adapter.d.ts +21 -5
  13. package/dist/cache/kv-data-adapter.runtime.d.ts +38 -4
  14. package/dist/cache/kv-data-adapter.runtime.js +115 -41
  15. package/dist/cache/kv-key.d.ts +4 -5
  16. package/dist/cache/response-store-adapter.d.ts +37 -0
  17. package/dist/cache/response-store-adapter.js +39 -0
  18. package/dist/cache/response-store-adapter.self-contained.worker.d.ts +17 -0
  19. package/dist/cache/response-store-adapter.self-contained.worker.js +10 -0
  20. package/dist/cache/response-store-adapter.service-binding.worker.d.ts +15 -0
  21. package/dist/cache/response-store-adapter.service-binding.worker.js +9 -0
  22. package/dist/cache/response-store-adapter.worker.d.ts +14 -0
  23. package/dist/cache/response-store-adapter.worker.js +254 -0
  24. package/dist/cache/response-store-cdn.runtime.d.ts +5 -0
  25. package/dist/cache/response-store-cdn.runtime.js +41 -0
  26. package/dist/cache/response-store-data.runtime.d.ts +34 -0
  27. package/dist/cache/response-store-data.runtime.js +289 -0
  28. package/dist/cacheability-artifact.d.ts +2 -3
  29. package/dist/cacheability-artifact.js +27 -1
  30. package/dist/cacheability-manifest-limits.d.ts +3 -4
  31. package/dist/cacheability-manifest-limits.js +1 -1
  32. package/dist/cacheability-probe.d.ts +8 -9
  33. package/dist/cacheability-probe.js +255 -91
  34. package/dist/cdn-warm.d.ts +31 -25
  35. package/dist/cdn-warm.js +208 -50
  36. package/dist/deploy-config.d.ts +11 -12
  37. package/dist/deploy-config.js +8 -3
  38. package/dist/deploy-help.d.ts +3 -4
  39. package/dist/deploy.d.ts +23 -24
  40. package/dist/deploy.js +44 -11
  41. package/dist/images/images-optimizer.d.ts +3 -4
  42. package/dist/prerender-kv-populate.d.ts +3 -4
  43. package/dist/prerender-kv-populate.js +3 -2
  44. package/dist/tpr.d.ts +9 -10
  45. package/dist/tpr.js +1 -1
  46. package/dist/utils/cache-control-metadata.d.ts +3 -4
  47. package/dist/version-deploy.d.ts +17 -17
  48. package/dist/version-deploy.js +6 -3
  49. package/dist/worker-deployment-url.d.ts +3 -4
  50. package/dist/workers-dev-url.d.ts +2 -3
  51. package/dist/wrangler-version-metadata.d.ts +2 -3
  52. package/package.json +13 -7
@@ -86,13 +86,18 @@ function viteConfigHasCacheAdapter(root) {
86
86
  return true;
87
87
  }
88
88
  const block = extractCacheBlock(content);
89
- if (!block) return false;
89
+ if (!block) {
90
+ const assigned = /\bcache\s*:\s*([^,}\n]+)/.exec(content)?.[1].trim();
91
+ return Boolean(assigned && assigned !== "undefined" && assigned !== "null");
92
+ }
90
93
  return cacheFieldAssigned(block, "cdn") || cacheFieldAssigned(block, "data");
91
94
  }
92
95
  function isCloudflareCdnAdapterPath(adapter) {
93
96
  const normalized = adapter.replace(/\\/g, "/");
94
- const bundledRuntime = fileURLToPath(new URL("./cache/cdn-adapter.runtime.js", import.meta.url)).replace(/\\/g, "/");
95
- return normalized === "@vinext/cloudflare/cache/cdn-adapter.runtime" || normalized === "@vinext/cloudflare/cache/cdn-adapter.runtime.js" || normalized === bundledRuntime;
97
+ return ["cdn-adapter.runtime", "response-store-cdn.runtime"].some((runtime) => {
98
+ const bundledRuntime = fileURLToPath(new URL(`./cache/${runtime}.js`, import.meta.url)).replace(/\\/g, "/");
99
+ return normalized === `@vinext/cloudflare/cache/${runtime}` || normalized === `@vinext/cloudflare/cache/${runtime}.js` || normalized === bundledRuntime;
100
+ });
96
101
  }
97
102
  function resolveCdnAdapterConfig(cache) {
98
103
  const cdn = cache?.cdn;
@@ -1,5 +1,4 @@
1
1
  //#region src/deploy-help.d.ts
2
- declare function formatDeployHelp(): string;
3
- declare function printDeployHelp(): void;
4
- //#endregion
5
- export { formatDeployHelp, printDeployHelp };
2
+ export declare function formatDeployHelp(): string;
3
+ export declare function printDeployHelp(): void;
4
+ //#endregion
package/dist/deploy.d.ts CHANGED
@@ -6,8 +6,8 @@ import { spawn } from "node:child_process";
6
6
  import { VinextCacheConfig } from "vinext/internal/config/prerender";
7
7
  import { ProjectInfo } from "vinext/internal/utils/project";
8
8
  //#region src/deploy.d.ts
9
- declare const DEFAULT_CDN_WARM_PROMOTION_DELAY_MS = 15000;
10
- type DeployOptions = {
9
+ export declare const DEFAULT_CDN_WARM_PROMOTION_DELAY_MS = 15000;
10
+ export type DeployOptions = {
11
11
  /** Project root directory */
12
12
  root: string;
13
13
  /** Deploy to preview environment (default: production) */
@@ -73,7 +73,7 @@ type DeployOptions = {
73
73
  /** TPR: analytics lookback window in hours (default: 24) */
74
74
  tprWindow?: number;
75
75
  };
76
- declare function parseDeployArgs(args: string[]): {
76
+ export declare function parseDeployArgs(args: string[]): {
77
77
  help: boolean;
78
78
  preview: boolean;
79
79
  env: string | undefined;
@@ -119,7 +119,7 @@ declare function parseDeployArgs(args: string[]): {
119
119
  *
120
120
  * Passing `undefined` is a no-op; the callback runs with `process.env` untouched.
121
121
  */
122
- declare function withCloudflareEnv<T>(env: string | undefined, fn: () => Promise<T>): Promise<T>;
122
+ export declare function withCloudflareEnv<T>(env: string | undefined, fn: () => Promise<T>): Promise<T>;
123
123
  type WranglerDeployArgs = {
124
124
  args: string[];
125
125
  env: string | undefined;
@@ -128,9 +128,9 @@ type WranglerKVBulkPutArgs = {
128
128
  args: string[];
129
129
  env: string | undefined;
130
130
  };
131
- declare function validateWranglerEnvName(env: string): string;
132
- declare function buildWranglerDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config">): WranglerDeployArgs;
133
- declare function buildWranglerKVBulkPutArgs(options: {
131
+ export declare function validateWranglerEnvName(env: string): string;
132
+ export declare function buildWranglerDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config">): WranglerDeployArgs;
133
+ export declare function buildWranglerKVBulkPutArgs(options: {
134
134
  binding: string;
135
135
  env?: string;
136
136
  filePath: string;
@@ -141,28 +141,28 @@ declare function buildWranglerKVBulkPutArgs(options: {
141
141
  * Invoking the JavaScript file through `process.execPath` avoids the `.cmd`
142
142
  * shim and command shell that package managers create on Windows.
143
143
  */
144
- declare function resolveWranglerBin(root: string, resolvePackageJson?: (root: string) => string | null): string;
145
- declare function buildNodeCliInvocation(scriptPath: string, args: string[], nodeExecutable?: string): {
144
+ export declare function resolveWranglerBin(root: string, resolvePackageJson?: (root: string) => string | null): string;
145
+ export declare function buildNodeCliInvocation(scriptPath: string, args: string[], nodeExecutable?: string): {
146
146
  file: string;
147
147
  args: string[];
148
148
  };
149
- declare function buildWranglerInvocation(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, nodeExecutable?: string): {
149
+ export declare function buildWranglerInvocation(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, nodeExecutable?: string): {
150
150
  file: string;
151
151
  args: string[];
152
152
  env: string | undefined;
153
153
  };
154
- declare function runWranglerKVBulkPut(root: string, options: {
154
+ export declare function runWranglerKVBulkPut(root: string, options: {
155
155
  binding: string;
156
156
  env?: string;
157
157
  pairs: KVBulkPair[];
158
158
  tempDir?: string;
159
159
  }, execute?: typeof spawn, nodeExecutable?: string): Promise<void>;
160
- declare function runWranglerDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, execute?: typeof spawn): Promise<string>;
161
- declare function hasCdnWarmRequests(plan: Omit<CdnWarmRequestPlan, "pagesDataPaths"> & {
160
+ export declare function runWranglerDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config">, execute?: typeof spawn): Promise<string>;
161
+ export declare function hasCdnWarmRequests(plan: Omit<CdnWarmRequestPlan, "pagesDataPaths"> & {
162
162
  pagesDataPaths?: readonly string[];
163
163
  }): boolean;
164
- declare function projectRequiresRouteCacheabilityProbeManifest(project: Pick<ProjectInfo, "isAppRouter" | "isPagesRouter">, cacheConfig: VinextCacheConfig | null): boolean;
165
- type CdnWarmDeployOptions = Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose" | "warmCdnTarget" | "warmCdnConcurrency" | "warmCdnTimeout" | "warmCdnRetries" | "warmCdnDiscoveryTimeout" | "warmCdnDiscoveryRetries" | "warmCdnProbeTimeout" | "warmCdnProbeRetries" | "warmCdnCertify" | "warmCdnReadinessTimeout" | "warmCdnReadinessRetries" | "warmCdnReadinessProbes" | "warmCdnReadinessProbeDelay" | "dangerouslyPromoteOnCdnWarmError" | "warmCdnPromote" | "warmCdnPromotionDelay"> & Pick<CdnWarmOptions, "deploymentId" | "expectedBuildId" | "expectedRscBuildId" | "loadingShellPaths" | "pagesDataPaths" | "routeHandlerPaths" | "routePatterns" | "rscPaths"> & {
164
+ export declare function projectRequiresRouteCacheabilityProbeManifest(project: Pick<ProjectInfo, "isAppRouter" | "isPagesRouter">, cacheConfig: VinextCacheConfig | null): boolean;
165
+ type CdnWarmDeployOptions = Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose" | "warmCdnTarget" | "warmCdnConcurrency" | "warmCdnTimeout" | "warmCdnRetries" | "warmCdnDiscoveryTimeout" | "warmCdnDiscoveryRetries" | "warmCdnProbeTimeout" | "warmCdnProbeRetries" | "warmCdnCertify" | "warmCdnReadinessTimeout" | "warmCdnReadinessRetries" | "warmCdnReadinessProbes" | "warmCdnReadinessProbeDelay" | "dangerouslyPromoteOnCdnWarmError" | "warmCdnPromote" | "warmCdnPromotionDelay"> & Pick<CdnWarmOptions, "deploymentId" | "expectedBuildId" | "expectedRscBuildId" | "loadingShellPaths" | "pagesDataPaths" | "routeHandlerPaths" | "routePatterns" | "rscPaths" | "statusSource"> & {
166
166
  /** Probe a staged Worker and upload the resulting manifest as a second version. */
167
167
  cacheabilityProbe?: boolean;
168
168
  discoverWarmPlan?: (target: {
@@ -170,13 +170,12 @@ type CdnWarmDeployOptions = Pick<DeployOptions, "preview" | "env" | "name" | "co
170
170
  targetUrl: string;
171
171
  }) => Promise<PrerenderWarmPlan>;
172
172
  };
173
- declare function deployWithCdnWarmup(root: string, paths: readonly string[], options: CdnWarmDeployOptions): Promise<string>;
174
- declare function resolveCdnWarmupTargetUrl(root: string, deployedUrl: string | null): string | null;
175
- declare function resolveCdnWarmupTargetUrl(root: string, deployedUrl: string | null, options: Pick<DeployOptions, "preview" | "env" | "config" | "warmCdnTarget">): string | null;
176
- declare function getZeroPercentStagingTraffic(deployment: WranglerDeploymentStatus | null, versionId: string): WranglerVersionTraffic[] | null;
173
+ export declare function deployWithCdnWarmup(root: string, paths: readonly string[], options: CdnWarmDeployOptions): Promise<string>;
174
+ export declare function resolveCdnWarmupTargetUrl(root: string, deployedUrl: string | null): string | null;
175
+ export declare function resolveCdnWarmupTargetUrl(root: string, deployedUrl: string | null, options: Pick<DeployOptions, "preview" | "env" | "config" | "warmCdnTarget">): string | null;
176
+ export declare function getZeroPercentStagingTraffic(deployment: WranglerDeploymentStatus | null, versionId: string): WranglerVersionTraffic[] | null;
177
177
  type ParsedWranglerConfig = NonNullable<ReturnType<typeof parseWranglerConfig>>;
178
- declare function resolveWorkerNameForVersionOverride(config: ParsedWranglerConfig | null, options: Pick<DeployOptions, "preview" | "env" | "name">): string | undefined;
179
- declare function buildVersionOverrideHeaders(workerName: string | undefined, versionId: string): HeadersInit | undefined;
180
- declare function deploy(options: DeployOptions): Promise<void>;
181
- //#endregion
182
- export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, DeployOptions, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, buildWranglerKVBulkPutArgs, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveWorkerNameForVersionOverride, resolveWranglerBin, runWranglerDeploy, runWranglerKVBulkPut, validateWranglerEnvName, withCloudflareEnv };
178
+ export declare function resolveWorkerNameForVersionOverride(config: ParsedWranglerConfig | null, options: Pick<DeployOptions, "preview" | "env" | "name">): string | undefined;
179
+ export declare function buildVersionOverrideHeaders(workerName: string | undefined, versionId: string): HeadersInit | undefined;
180
+ export declare function deploy(options: DeployOptions): Promise<void>;
181
+ //#endregion
package/dist/deploy.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { writeCacheabilityManifestArtifact } from "./cacheability-artifact.js";
2
2
  import { DEFAULT_CACHEABILITY_PROBE_RETRY_DELAY_MS, probeStagedWorkerCacheability, readPrerenderSecret } from "./cacheability-probe.js";
3
- import { CdnOperationProgress, createCdnWarmTargets, readPrerenderWarmPlan, waitForCdnWarmTargetReadiness, warmCdnCache } from "./cdn-warm.js";
3
+ import { CdnOperationProgress, createCdnWarmTargets, createPrerenderWarmPlan, waitForCdnWarmTargetReadiness, warmCdnCache } from "./cdn-warm.js";
4
4
  import { parseWranglerConfig, runTPR } from "./tpr.js";
5
5
  import { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./version-headers.js";
6
6
  import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig, resolveKvDataAdapterConfig, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler } from "./deploy-config.js";
@@ -13,7 +13,7 @@ import fs from "node:fs";
13
13
  import path from "node:path";
14
14
  import { cacheabilityRoutePathname } from "vinext/internal/server/cacheability-manifest";
15
15
  import { setTimeout } from "node:timers/promises";
16
- import { DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS, DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS, emitPrerenderPathManifest } from "vinext/internal/build/prerender-paths";
16
+ import { DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS, DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS, discoverPrerenderPathManifest, emitPrerenderPathManifest } from "vinext/internal/build/prerender-paths";
17
17
  import os from "node:os";
18
18
  import { spawn } from "node:child_process";
19
19
  import { parseArgs } from "node:util";
@@ -21,7 +21,7 @@ import { pathToFileURL } from "node:url";
21
21
  import { runPrerender } from "vinext/internal/build/run-prerender";
22
22
  import { loadDotenv } from "vinext/internal/config/dotenv";
23
23
  import { findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "vinext/internal/config/next-config";
24
- import { findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasVerbatimResponseVary, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision } from "vinext/internal/config/prerender";
24
+ import { findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup, usesVinextCacheWarmupStatus } from "vinext/internal/config/prerender";
25
25
  import { detectProject, findInNodeModules, formatMissingCloudflarePluginError, getMissingDeps } from "vinext/internal/utils/project";
26
26
  import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
27
27
  //#region src/deploy.ts
@@ -234,7 +234,8 @@ async function loadProjectWranglerApi(root) {
234
234
  try {
235
235
  wranglerPath = req.resolve("wrangler");
236
236
  } catch {
237
- wranglerPath = createRequire(req.resolve("@cloudflare/vite-plugin")).resolve("wrangler");
237
+ const cloudflarePluginPath = req.resolve("@cloudflare/vite-plugin");
238
+ wranglerPath = createRequire(cloudflarePluginPath).resolve("wrangler");
238
239
  }
239
240
  return await import(
240
241
  /* @vite-ignore */
@@ -432,6 +433,17 @@ function projectRequiresRouteCacheabilityProbeManifest(project, cacheConfig) {
432
433
  function cdnWarmTargetKey(target) {
433
434
  return `${target.kind}\0${target.sourcePathname}`;
434
435
  }
436
+ function requiredCdnWarmTargetKeys(plan, optionalTargetKeys) {
437
+ const keys = /* @__PURE__ */ new Set([
438
+ ...plan.paths.map((pathname) => `html\0${pathname}`),
439
+ ...plan.pagesDataPaths.map((pathname) => `pages-data\0${pathname}`),
440
+ ...(plan.routeHandlerPaths ?? []).map((pathname) => `app-route\0${pathname}`),
441
+ ...plan.rscPaths.map((pathname) => `rsc-full\0${pathname}`),
442
+ ...plan.loadingShellPaths.map((pathname) => `rsc-loading-shell\0${pathname}`)
443
+ ]);
444
+ if (optionalTargetKeys) for (const key of optionalTargetKeys) keys.delete(key);
445
+ return keys;
446
+ }
435
447
  async function deployWithCdnWarmup(root, paths, options) {
436
448
  if (options.warmCdnTarget !== void 0) options = {
437
449
  ...options,
@@ -524,8 +536,10 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
524
536
  concurrency: options.warmCdnConcurrency,
525
537
  timeoutMs: options.warmCdnTimeout,
526
538
  retries: options.warmCdnRetries,
539
+ retrySkippedTargetKeys: propagatingTarget && hasPreparedWarmPlan ? requiredCdnWarmTargetKeys(plan, options.optionalWarmTargetKeys) : void 0,
527
540
  requireCacheHit,
528
- strict: requireCacheHit || !allowUnverifiedPromotion
541
+ strict: requireCacheHit || !allowUnverifiedPromotion,
542
+ statusSource: options.statusSource
529
543
  });
530
544
  const wranglerConfig = parseWranglerConfig(root, options.config);
531
545
  const deploymentStatus = runWranglerDeploymentStatus(root, options);
@@ -577,6 +591,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
577
591
  pagesDataPaths: remainingWarmPlan.pagesDataPaths,
578
592
  paths: remainingWarmPlan.paths,
579
593
  routeHandlerPaths: remainingWarmPlan.routeHandlerPaths,
594
+ routePatterns: remainingWarmPlan.routePatterns,
580
595
  rscPaths: remainingWarmPlan.rscPaths
581
596
  };
582
597
  const stagedWarmRequests = stagedWarmPlan.paths.length + stagedWarmPlan.pagesDataPaths.length + (stagedWarmPlan.routeHandlerPaths?.length ?? 0) + stagedWarmPlan.rscPaths.length + stagedWarmPlan.loadingShellPaths.length;
@@ -673,7 +688,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
673
688
  }];
674
689
  let promotionAttempted = false;
675
690
  try {
676
- if (stagedCacheFilled) {
691
+ if (stagedCacheFilled && options.statusSource !== "vinext") {
677
692
  const promotionDelay = options.warmCdnPromotionDelay ?? 15e3;
678
693
  if (promotionDelay > 0) {
679
694
  console.log(` CDN warmup: waiting ${promotionDelay / 1e3} seconds for cache propagation before promotion...`);
@@ -871,8 +886,9 @@ async function deployWithCacheabilityProbe(root, options) {
871
886
  rscPaths: probe.cacheableTargets.filter((target) => target.kind === "rsc-full").map((target) => target.sourcePathname)
872
887
  };
873
888
  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.");
889
+ const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest);
874
890
  const finalUpload = runWranglerVersionUpload(root, {
875
- config: writeCacheabilityManifestArtifact(root, options.config, probe.manifest),
891
+ config: finalConfig,
876
892
  env: options.env,
877
893
  name: options.name,
878
894
  preview: options.preview,
@@ -994,7 +1010,8 @@ async function deploy(options) {
994
1010
  const cdnAdapterConfig = resolveCdnAdapterConfig(viteConfigMetadata.cacheConfig);
995
1011
  const nextConfig = await withCloudflareEnv(buildEnv, async () => {
996
1012
  const inlineNextConfig = viteConfigMetadata.nextConfig;
997
- return resolveNextConfig(inlineNextConfig ? await resolveNextConfigInput(inlineNextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(info.root, PHASE_PRODUCTION_BUILD), info.root);
1013
+ const rawNextConfig = inlineNextConfig ? await resolveNextConfigInput(inlineNextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(info.root, PHASE_PRODUCTION_BUILD);
1014
+ return resolveNextConfig(rawNextConfig, info.root);
998
1015
  });
999
1016
  const vinextPrerenderConfig = !options.prerenderAll && nextConfig.output !== "export" ? viteConfigMetadata.prerenderConfig : null;
1000
1017
  const prerenderDecision = resolveVinextPrerenderDecision({
@@ -1003,7 +1020,10 @@ async function deploy(options) {
1003
1020
  nextOutput: nextConfig.output
1004
1021
  });
1005
1022
  const hasStrictResponseVary = hasVerbatimResponseVary(viteConfigMetadata.cacheConfig);
1023
+ const hasStagedRequestRouting = hasUncachedRequestRouting(viteConfigMetadata.cacheConfig);
1006
1024
  const hasBuildIdentityHeader = hasBuildIdentityResponseHeader(viteConfigMetadata.cacheConfig);
1025
+ const hasCanonicalRscWarmup = supportsCanonicalRscWarmup(viteConfigMetadata.cacheConfig);
1026
+ const hasVinextCacheWarmupStatus = usesVinextCacheWarmupStatus(viteConfigMetadata.cacheConfig);
1007
1027
  const needsCacheabilityProbeManifest = projectRequiresRouteCacheabilityProbeManifest(info, viteConfigMetadata.cacheConfig);
1008
1028
  const shouldEmitPrerenderPathManifest = !options.skipBuild && prerenderDecision;
1009
1029
  if (!options.skipBuild) await runBuild(info, buildEnv);
@@ -1034,7 +1054,9 @@ async function deploy(options) {
1034
1054
  root: info.root,
1035
1055
  nextConfig,
1036
1056
  buildIdentity: hasBuildIdentityHeader ? "response-header" : void 0,
1057
+ requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
1037
1058
  responseVary: hasStrictResponseVary ? "verbatim" : void 0,
1059
+ isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
1038
1060
  routeRootConfig: viteConfigMetadata.routeRootConfig
1039
1061
  });
1040
1062
  let ranPrerender = false;
@@ -1047,7 +1069,8 @@ async function deploy(options) {
1047
1069
  await runPrerender({
1048
1070
  root: info.root,
1049
1071
  concurrency: options.prerenderConcurrency,
1050
- nextConfig
1072
+ nextConfig,
1073
+ routeRootConfig: viteConfigMetadata.routeRootConfig
1051
1074
  });
1052
1075
  ranPrerender = true;
1053
1076
  }
@@ -1078,11 +1101,14 @@ async function deploy(options) {
1078
1101
  ...wranglerOptions,
1079
1102
  cacheabilityProbe: needsCacheabilityProbeManifest,
1080
1103
  discoverWarmPlan: async ({ headers, targetUrl }) => {
1081
- await emitPrerenderPathManifest({
1104
+ const discovery = await discoverPrerenderPathManifest({
1082
1105
  root: info.root,
1083
1106
  nextConfig,
1084
1107
  buildIdentity: hasBuildIdentityHeader ? "response-header" : void 0,
1108
+ includeCanonicalRsc: hasCanonicalRscWarmup,
1109
+ requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
1085
1110
  responseVary: hasStrictResponseVary ? "verbatim" : void 0,
1111
+ isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
1086
1112
  routeRootConfig: viteConfigMetadata.routeRootConfig,
1087
1113
  pathDiscoveryTarget: {
1088
1114
  baseUrl: targetUrl,
@@ -1092,11 +1118,18 @@ async function deploy(options) {
1092
1118
  retryDelayMs: DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS
1093
1119
  }
1094
1120
  });
1095
- return readPrerenderWarmPlan(root, {
1121
+ if (!discovery) return {
1122
+ loadingShellPaths: [],
1123
+ paths: [],
1124
+ rscPaths: []
1125
+ };
1126
+ return createPrerenderWarmPlan(root, discovery, {
1127
+ includeCanonicalRsc: hasCanonicalRscWarmup,
1096
1128
  includeFallbackShells: options.warmCdnIncludeFallbacks,
1097
1129
  strict: options.warmCdnCertify === true || !options.dangerouslyPromoteOnCdnWarmError
1098
1130
  });
1099
1131
  },
1132
+ statusSource: hasVinextCacheWarmupStatus ? "vinext" : "cloudflare",
1100
1133
  warmCdnConcurrency: options.warmCdnConcurrency,
1101
1134
  warmCdnTarget,
1102
1135
  warmCdnTimeout: options.warmCdnTimeout,
@@ -1,6 +1,6 @@
1
1
  //#region src/images/images-optimizer.d.ts
2
2
  /** Options accepted by {@link imagesOptimizer}, forwarded to the runtime factory. */
3
- type ImagesOptimizerOptions = {
3
+ export type ImagesOptimizerOptions = {
4
4
  /** Cloudflare Images binding name on the Worker `env`. @default "IMAGES" */
5
5
  binding?: string;
6
6
  };
@@ -21,9 +21,8 @@ type ImagesOptimizerOptions = {
21
21
  * plugins: [vinext({ images: { optimizer: imagesOptimizer() } })],
22
22
  * });
23
23
  */
24
- declare function imagesOptimizer(options?: ImagesOptimizerOptions): {
24
+ export declare function imagesOptimizer(options?: ImagesOptimizerOptions): {
25
25
  adapter: string;
26
26
  options: ImagesOptimizerOptions | undefined;
27
27
  };
28
- //#endregion
29
- export { ImagesOptimizerOptions, imagesOptimizer };
28
+ //#endregion
@@ -7,13 +7,13 @@
7
7
  * KVCacheEntry shape written by KVCacheHandler.set(), and returns Wrangler KV
8
8
  * bulk import records for deploy-time upload.
9
9
  */
10
- type KVBulkPair = {
10
+ export type KVBulkPair = {
11
11
  key: string;
12
12
  value: string;
13
13
  expiration_ttl?: number;
14
14
  metadata?: Record<string, unknown>;
15
15
  };
16
- declare function buildPrerenderKVPairs(serverDir: string, options?: {
16
+ export declare function buildPrerenderKVPairs(serverDir: string, options?: {
17
17
  appPrefix?: string;
18
18
  now?: number;
19
19
  ttlSeconds?: number;
@@ -21,5 +21,4 @@ declare function buildPrerenderKVPairs(serverDir: string, options?: {
21
21
  routeCount: number;
22
22
  pairs: KVBulkPair[];
23
23
  };
24
- //#endregion
25
- export { KVBulkPair, buildPrerenderKVPairs };
24
+ //#endregion
@@ -16,7 +16,7 @@ import { getAppRouteOutputPath, getOutputPath, getRscOutputPath } from "vinext/i
16
16
  * bulk import records for deploy-time upload.
17
17
  */
18
18
  /** Default KV expiration TTL used by KVCacheHandler for revalidating entries. */
19
- const DEFAULT_KV_TTL_SECONDS = 720 * 3600;
19
+ const DEFAULT_KV_TTL_SECONDS = 2592e3;
20
20
  function resolveContainedFile(rootDir, relativePath) {
21
21
  const resolvedRoot = path.resolve(rootDir);
22
22
  const resolvedFile = path.resolve(resolvedRoot, relativePath);
@@ -48,7 +48,8 @@ function buildMetadata(tags) {
48
48
  return JSON.stringify(metadata).length <= 1024 ? metadata : void 0;
49
49
  }
50
50
  function buildPrerenderKVPairs(serverDir, options) {
51
- const manifest = readPrerenderManifest(path.join(serverDir, "vinext-prerender.json"));
51
+ const manifestPath = path.join(serverDir, "vinext-prerender.json");
52
+ const manifest = readPrerenderManifest(manifestPath);
52
53
  if (!manifest?.buildId || !Array.isArray(manifest.routes)) return {
53
54
  routeCount: 0,
54
55
  pairs: []
package/dist/tpr.d.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  * gracefully skips when no custom domain, no API token, no traffic data,
21
21
  * or no KV namespace is configured.
22
22
  */
23
- type TPROptions = {
23
+ export type TPROptions = {
24
24
  /** Project root directory. */
25
25
  root: string;
26
26
  /** Wrangler config path, relative to root unless absolute. */
@@ -32,7 +32,7 @@ type TPROptions = {
32
32
  /** Analytics lookback window in hours. Default: 24. */
33
33
  window: number;
34
34
  };
35
- type TPRResult = {
35
+ export type TPRResult = {
36
36
  /** Total unique page paths found in analytics. */
37
37
  totalPaths: number;
38
38
  /** Number of pages successfully pre-rendered and uploaded. */
@@ -57,7 +57,7 @@ type WranglerConfig = {
57
57
  legacyEnv?: boolean;
58
58
  env?: Record<string, WranglerEnvironmentConfig>;
59
59
  };
60
- type WranglerEnvironmentConfig = {
60
+ export type WranglerEnvironmentConfig = {
61
61
  customDomain?: string;
62
62
  name?: string;
63
63
  };
@@ -65,7 +65,7 @@ type WranglerEnvironmentConfig = {
65
65
  * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:
66
66
  * account_id, VINEXT_KV_CACHE KV namespace ID, and custom domain.
67
67
  */
68
- declare function parseWranglerConfig(root: string, configPath?: string): WranglerConfig | null;
68
+ export declare function parseWranglerConfig(root: string, configPath?: string): WranglerConfig | null;
69
69
  /**
70
70
  * Generate zone lookup candidates from shortest (2-part) to longest.
71
71
  * Tries the most common case first (e.g., "example.com") and progressively
@@ -75,8 +75,8 @@ declare function parseWranglerConfig(root: string, configPath?: string): Wrangle
75
75
  * "shop.example.co.uk" → ["co.uk", "example.co.uk", "shop.example.co.uk"]
76
76
  * "example.com" → ["example.com"]
77
77
  */
78
- declare function domainCandidates(domain: string): string[];
79
- declare function resolveVinextProdServerPath(root: string): string;
78
+ export declare function domainCandidates(domain: string): string[];
79
+ export declare function resolveVinextProdServerPath(root: string): string;
80
80
  /**
81
81
  * Build KV bulk API pairs from pre-rendered entries.
82
82
  *
@@ -84,7 +84,7 @@ declare function resolveVinextProdServerPath(root: string): string;
84
84
  * createKvKeySpace().entryKey(isrCacheKey("app", pathname, buildId) + ":html")
85
85
  * → "cache:app:<buildId>:<pathname>:html"
86
86
  */
87
- declare function buildTprKVPairs(entries: Map<string, PrerenderResult>, buildId: string | undefined, defaultRevalidateSeconds: number): Array<{
87
+ export declare function buildTprKVPairs(entries: Map<string, PrerenderResult>, buildId: string | undefined, defaultRevalidateSeconds: number): Array<{
88
88
  key: string;
89
89
  value: string;
90
90
  expiration_ttl: number;
@@ -96,6 +96,5 @@ declare function buildTprKVPairs(entries: Map<string, PrerenderResult>, buildId:
96
96
  * `vinext-cloudflare deploy` pipeline. Gracefully skips (never errors) when
97
97
  * the prerequisites aren't met.
98
98
  */
99
- declare function runTPR(options: TPROptions): Promise<TPRResult>;
100
- //#endregion
101
- export { TPROptions, TPRResult, WranglerEnvironmentConfig, buildTprKVPairs, domainCandidates, parseWranglerConfig, resolveVinextProdServerPath, runTPR };
99
+ export declare function runTPR(options: TPROptions): Promise<TPRResult>;
100
+ //#endregion
package/dist/tpr.js CHANGED
@@ -573,7 +573,7 @@ async function waitForServer(port, timeoutMs) {
573
573
  /** KV bulk API accepts up to 10,000 pairs per request */
574
574
  const KV_BATCH_SIZE = 1e4;
575
575
  /** Maximum KV expiration TTL: 30 days */
576
- const MAX_KV_TTL_SECONDS = 720 * 3600;
576
+ const MAX_KV_TTL_SECONDS = 2592e3;
577
577
  /**
578
578
  * Build KV bulk API pairs from pre-rendered entries.
579
579
  *
@@ -5,7 +5,6 @@
5
5
  * so the Cloudflare adapters stay self-contained (these mirror the equivalent
6
6
  * helpers in the vinext core).
7
7
  */
8
- declare function isUnknownRecord(value: unknown): value is Record<string, unknown>;
9
- declare function readCacheControlNumberField(ctx: Record<string, unknown> | undefined, field: string): number | undefined;
10
- //#endregion
11
- export { isUnknownRecord, readCacheControlNumberField };
8
+ export declare function isUnknownRecord(value: unknown): value is Record<string, unknown>;
9
+ export declare function readCacheControlNumberField(ctx: Record<string, unknown> | undefined, field: string): number | undefined;
10
+ //#endregion
@@ -2,21 +2,21 @@ import { parseWorkersDevUrl } from "./workers-dev-url.js";
2
2
  import { DeployOptions } from "./deploy.js";
3
3
  import { execFileSync } from "node:child_process";
4
4
  //#region src/version-deploy.d.ts
5
- type WranglerVersionUploadResult = {
5
+ export type WranglerVersionUploadResult = {
6
6
  versionId: string;
7
7
  previewUrl: string | null;
8
8
  workerName: string | null;
9
9
  output: string;
10
10
  };
11
- type WranglerVersionDeployResult = {
11
+ export type WranglerVersionDeployResult = {
12
12
  deployedUrl: string | null;
13
13
  output: string;
14
14
  };
15
- type WranglerVersionTraffic = {
15
+ export type WranglerVersionTraffic = {
16
16
  versionId: string;
17
17
  percentage: number;
18
18
  };
19
- type WranglerDeploymentStatus = {
19
+ export type WranglerDeploymentStatus = {
20
20
  deploymentId: string | null;
21
21
  versions: WranglerVersionTraffic[];
22
22
  output: string;
@@ -25,21 +25,21 @@ type WranglerVersionArgs = {
25
25
  args: string[];
26
26
  env: string | undefined;
27
27
  };
28
- declare function parseVersionId(output: string): string | null;
29
- declare function parseUploadedWorkerName(output: string): string | null;
30
- declare function parseWranglerVersionUploadOutput(output: string): WranglerVersionUploadResult;
31
- declare function buildWranglerVersionUploadArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
28
+ export declare function parseVersionId(output: string): string | null;
29
+ export declare function parseUploadedWorkerName(output: string): string | null;
30
+ export declare function parseWranglerVersionUploadOutput(output: string): WranglerVersionUploadResult;
31
+ export declare function buildWranglerVersionUploadArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
32
32
  previewAlias?: string;
33
33
  }): WranglerVersionArgs;
34
- declare function buildWranglerVersionDeployArgs(versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
35
- declare function buildWranglerDeploymentsStatusArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
36
- declare function buildWranglerTriggersDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
37
- declare function parseWranglerDeploymentStatusOutput(output: string): WranglerDeploymentStatus;
38
- declare function runWranglerVersionUpload(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
34
+ export declare function buildWranglerVersionDeployArgs(versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
35
+ export declare function buildWranglerDeploymentsStatusArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
36
+ export declare function buildWranglerTriggersDeployArgs(options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">): WranglerVersionArgs;
37
+ export declare function parseWranglerDeploymentStatusOutput(output: string): WranglerDeploymentStatus;
38
+ export declare function runWranglerVersionUpload(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose"> & {
39
39
  previewAlias?: string;
40
40
  }, execute?: typeof execFileSync): WranglerVersionUploadResult;
41
- declare function runWranglerVersionDeploy(root: string, versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, phase?: "stage" | "promote-warmed" | "promote-uploaded", execute?: typeof execFileSync): WranglerVersionDeployResult;
42
- declare function runWranglerDeploymentStatus(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerDeploymentStatus;
43
- declare function runWranglerTriggersDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerVersionDeployResult;
41
+ export declare function runWranglerVersionDeploy(root: string, versionTraffic: readonly WranglerVersionTraffic[], options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, phase?: "stage" | "promote-warmed" | "promote-uploaded", execute?: typeof execFileSync): WranglerVersionDeployResult;
42
+ export declare function runWranglerDeploymentStatus(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerDeploymentStatus;
43
+ export declare function runWranglerTriggersDeploy(root: string, options: Pick<DeployOptions, "preview" | "env" | "name" | "config" | "verbose">, execute?: typeof execFileSync): WranglerVersionDeployResult;
44
44
  //#endregion
45
- export { WranglerDeploymentStatus, WranglerVersionDeployResult, WranglerVersionTraffic, WranglerVersionUploadResult, buildWranglerDeploymentsStatusArgs, buildWranglerTriggersDeployArgs, buildWranglerVersionDeployArgs, buildWranglerVersionUploadArgs, parseUploadedWorkerName, parseVersionId, parseWorkersDevUrl, parseWranglerDeploymentStatusOutput, parseWranglerVersionUploadOutput, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload };
45
+ export { parseWorkersDevUrl };
@@ -133,7 +133,8 @@ function buildWranglerTriggersDeployArgs(options) {
133
133
  };
134
134
  }
135
135
  function runWranglerCommand(root, args, execute = execFileSync, verbose = false) {
136
- const invocation = buildNodeCliInvocation(resolveWranglerBin(root), args);
136
+ const wranglerBin = resolveWranglerBin(root);
137
+ const invocation = buildNodeCliInvocation(wranglerBin, args);
137
138
  const execOpts = {
138
139
  cwd: root,
139
140
  stdio: "pipe",
@@ -219,8 +220,10 @@ function runWranglerVersionDeploy(root, versionTraffic, options, phase = "promot
219
220
  }
220
221
  function runWranglerDeploymentStatus(root, options, execute = execFileSync) {
221
222
  const { args, env } = buildWranglerDeploymentsStatusArgs(options);
222
- if (options.verbose) if (env) console.log(`\n Reading current Worker deployment for env: ${env}...`);
223
- else console.log("\n Reading current Worker deployment...");
223
+ if (options.verbose) {
224
+ if (env) console.log(`\n Reading current Worker deployment for env: ${env}...`);
225
+ else console.log("\n Reading current Worker deployment...");
226
+ }
224
227
  return parseWranglerDeploymentStatusOutput(runWranglerCommand(root, args, execute, options.verbose === true));
225
228
  }
226
229
  function runWranglerTriggersDeploy(root, options, execute = execFileSync) {
@@ -1,10 +1,9 @@
1
1
  //#region src/worker-deployment-url.d.ts
2
- declare function parseWorkerDeploymentUrl(output: string): string | null;
2
+ export declare function parseWorkerDeploymentUrl(output: string): string | null;
3
3
  /**
4
4
  * Parse the concrete hostname that Wrangler reports after applying Worker
5
5
  * triggers. Catch-all routes are valid warmup targets even though they are not
6
6
  * canonical deployment URLs for general CLI reporting.
7
7
  */
8
- declare function parseCdnWarmupDeploymentUrl(output: string): string | null;
9
- //#endregion
10
- export { parseCdnWarmupDeploymentUrl, parseWorkerDeploymentUrl };
8
+ export declare function parseCdnWarmupDeploymentUrl(output: string): string | null;
9
+ //#endregion
@@ -1,4 +1,3 @@
1
1
  //#region src/workers-dev-url.d.ts
2
- declare function parseWorkersDevUrl(output: string): string | null;
3
- //#endregion
4
- export { parseWorkersDevUrl };
2
+ export declare function parseWorkersDevUrl(output: string): string | null;
3
+ //#endregion
@@ -1,8 +1,7 @@
1
1
  //#region src/wrangler-version-metadata.d.ts
2
- declare function assertCdnVersionMetadataConfig({ binding, configuredBinding, configPath }: {
2
+ export declare function assertCdnVersionMetadataConfig({ binding, configuredBinding, configPath }: {
3
3
  binding: string;
4
4
  configuredBinding: string | undefined;
5
5
  configPath: string | undefined;
6
6
  }): void;
7
- //#endregion
8
- export { assertCdnVersionMetadataConfig };
7
+ //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.0.0-beta.7",
4
- "description": "Cloudflare adapters for vinext (KV data cache and Images-backed image optimization).",
3
+ "version": "1.0.0-beta.8",
4
+ "description": "Cloudflare cache and image adapters for vinext.",
5
5
  "homepage": "https://vinext.dev/",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -51,20 +51,26 @@
51
51
  "import": "./dist/images/*.js"
52
52
  }
53
53
  },
54
+ "dependencies": {
55
+ "@cloudflare/workers-response-store": "0.1.0-beta.0"
56
+ },
54
57
  "devDependencies": {
55
58
  "@types/node": "^25.9.2",
56
- "vite": "npm:@voidzero-dev/vite-plus-core@0.2.6",
57
- "vite-plus": "0.2.6",
58
- "vinext": "1.0.0-beta.9"
59
+ "miniflare": "5.20260730.0-alpha",
60
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.3.2",
61
+ "vite-plus": "0.3.2",
62
+ "vitest": "4.1.11",
63
+ "vinext": "1.0.0-beta.10"
59
64
  },
60
65
  "peerDependencies": {
61
- "vinext": "^1.0.0-beta.9"
66
+ "vinext": "^1.0.0-beta.10"
62
67
  },
63
68
  "engines": {
64
69
  "node": ">=22"
65
70
  },
66
71
  "scripts": {
67
72
  "build": "vp pack",
68
- "dev": "vp pack --watch"
73
+ "dev": "vp pack --watch",
74
+ "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained pnpm --filter response-store-demo run build && pnpm --filter response-store-demo run build && vitest run"
69
75
  }
70
76
  }