@vinext/cloudflare 1.2.0 → 1.3.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.
@@ -16,6 +16,7 @@ function formatDeployHelp() {
16
16
  --env <name> Cloudflare mode for typed config; Wrangler environment otherwise
17
17
  --name <name> Custom Worker name for Wrangler config projects
18
18
  --config <path> Wrangler config path (default: wrangler.jsonc/json/toml)
19
+ --vite-config <path> Vite config file to build with (default: vite.config.*)
19
20
  --skip-build Skip the build step (use existing dist/)
20
21
  --dry-run Validate setup without building or deploying
21
22
  --verbose Print raw output from internal Cloudflare CLI commands
@@ -129,9 +130,10 @@ function formatPreviewsDeployHelp() {
129
130
  preview-name Optional Preview name (cf uses the CI or Git branch if omitted)
130
131
 
131
132
  Options:
132
- --mode <mode> Vite mode to build and deploy in (default: production)
133
- --skip-build Deploy existing Preview Build Output without rebuilding
134
- -h, --help Show this help
133
+ --mode <mode> Vite mode to build and deploy in (default: production)
134
+ --skip-build Deploy existing Preview Build Output without rebuilding
135
+ --vite-config <path> Vite config file to build with (default: vite.config.*)
136
+ -h, --help Show this help
135
137
 
136
138
  Examples:
137
139
  vinext-cloudflare previews deploy
package/dist/deploy.d.ts CHANGED
@@ -23,6 +23,8 @@ export type DeployOptions = {
23
23
  name?: string;
24
24
  /** Wrangler config path, relative to root unless absolute */
25
25
  config?: string;
26
+ /** Vite config file used to build and read deploy metadata, relative to root unless absolute */
27
+ viteConfig?: string;
26
28
  /** Skip the build step (assume already built) */
27
29
  skipBuild?: boolean;
28
30
  /** Dry run — validate setup but don't build or deploy */
@@ -85,6 +87,7 @@ export declare function parseDeployArgs(args: string[]): {
85
87
  env: string | undefined;
86
88
  name: string | undefined;
87
89
  config: string | undefined;
90
+ viteConfig: string | undefined;
88
91
  skipBuild: boolean;
89
92
  dryRun: boolean;
90
93
  verbose: boolean;
@@ -192,4 +195,5 @@ export declare function resolveDeploymentControlPlaneOptions(options: Deployment
192
195
  export declare function resolveWorkerNameForVersionOverride(config: ParsedWranglerConfig | null, options: Pick<DeployOptions, "preview" | "env" | "name">): string | undefined;
193
196
  export declare function buildVersionOverrideHeaders(workerName: string | undefined, versionId: string): HeadersInit | undefined;
194
197
  export declare function deploy(options: DeployOptions): Promise<void>;
195
- //#endregion
198
+ //#endregion
199
+ export {};
package/dist/deploy.js CHANGED
@@ -99,6 +99,7 @@ const deployArgOptions = {
99
99
  env: { type: "string" },
100
100
  name: { type: "string" },
101
101
  config: { type: "string" },
102
+ "vite-config": { type: "string" },
102
103
  "skip-build": {
103
104
  type: "boolean",
104
105
  default: false
@@ -249,6 +250,7 @@ function parseDeployArgs(args) {
249
250
  env: values.env?.trim() || void 0,
250
251
  name: values.name?.trim() || void 0,
251
252
  config: values.config?.trim() || void 0,
253
+ viteConfig: values["vite-config"]?.trim() || void 0,
252
254
  skipBuild: values["skip-build"],
253
255
  dryRun: values["dry-run"],
254
256
  verbose: values.verbose,
@@ -339,11 +341,11 @@ async function loadProjectWranglerApi(root) {
339
341
  function resolveViteBuildMode(deploymentTool, env) {
340
342
  return deploymentTool === "cf" ? env ?? "production" : "production";
341
343
  }
342
- async function loadDeployViteConfigMetadata(root, mode) {
344
+ async function loadDeployViteConfigMetadata(root, mode, configFile) {
343
345
  const plugins = (await (await loadProjectViteApi(root)).loadConfigFromFile({
344
346
  command: "build",
345
347
  mode
346
- }, void 0, root))?.config.plugins;
348
+ }, configFile, root))?.config.plugins;
347
349
  return {
348
350
  cacheConfig: await findVinextCacheConfigInPlugins(plugins),
349
351
  nextConfig: await findVinextNextConfigInPlugins(plugins),
@@ -351,7 +353,7 @@ async function loadDeployViteConfigMetadata(root, mode) {
351
353
  routeRootConfig: await findVinextRouteRootConfigInPlugins(plugins)
352
354
  };
353
355
  }
354
- async function runBuild(info, env, mode) {
356
+ async function runBuild(info, env, mode, configFile) {
355
357
  console.log("\n Building for Cloudflare Workers...\n");
356
358
  const { createBuilder } = await loadProjectViteApi(info.root);
357
359
  let completed = false;
@@ -362,6 +364,7 @@ async function runBuild(info, env, mode) {
362
364
  await (await createBuilder({
363
365
  root: info.root,
364
366
  mode,
367
+ configFile,
365
368
  [VINEXT_BUILD_LIFECYCLE_CONFIG]: invocation
366
369
  })).buildApp();
367
370
  });
@@ -1190,7 +1193,9 @@ async function deploy(options) {
1190
1193
  if (isPreview && deploymentTool !== "cf") throw new Error("Worker Previews require a cloudflare.config.ts project and the cf CLI.");
1191
1194
  if (deploymentTool === "cf" && options.name) throw new Error("--name is not supported for cloudflare.config.ts projects. Set `name` in cloudflare.config.ts instead.");
1192
1195
  const viteMode = resolveViteBuildMode(deploymentTool, deployEnv);
1196
+ const viteConfigFile = options.viteConfig ? path.resolve(root, options.viteConfig) : void 0;
1193
1197
  const wranglerFallbackEnv = deploymentTool === "cf" ? void 0 : deployEnv;
1198
+ if (!process.env.NODE_ENV) Reflect.set(process.env, "NODE_ENV", "production");
1194
1199
  loadDotenv({
1195
1200
  root,
1196
1201
  mode: viteMode
@@ -1209,16 +1214,25 @@ async function deploy(options) {
1209
1214
  console.log(` Project: ${info.projectName}`);
1210
1215
  console.log(` Router: ${info.isAppRouter ? "App Router" : "Pages Router"}`);
1211
1216
  console.log(` ISR: ${info.hasISR ? "detected" : "none"}`);
1212
- const missingScaffolding = [!info.hasViteConfig && "Vite config", !info.hasWranglerConfig && "Wrangler config"].filter((value) => Boolean(value));
1217
+ if (viteConfigFile && !fs.existsSync(viteConfigFile)) throw new Error(`Vite config file not found: ${viteConfigFile}`);
1218
+ const hasViteConfig = Boolean(viteConfigFile) || info.hasViteConfig;
1219
+ const missingScaffolding = [!hasViteConfig && "Vite config", !info.hasWranglerConfig && "Wrangler config"].filter((value) => Boolean(value));
1213
1220
  if (missingScaffolding.length > 0) throw new Error(`Missing Cloudflare deployment setup: ${missingScaffolding.join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
1214
1221
  const missingDeps = getMissingDeps(info);
1215
1222
  if (missingDeps.length > 0) throw new Error(`Missing deployment dependencies: ${missingDeps.map((dependency) => dependency.name).join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
1216
1223
  if (deploymentTool === "cf" && !isCfCliInstalled(root)) throw new Error("Missing deployment dependencies: cf. Run `vinext init --platform=cloudflare` first.");
1217
- if (info.hasViteConfig && !viteConfigHasCloudflarePlugin(root)) throw new Error(formatMissingCloudflarePluginError({ isAppRouter: info.isAppRouter }));
1218
- if (info.hasISR && !viteConfigHasCacheAdapter(root) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({ typedConfig: deploymentTool === "cf" }));
1219
- if (!viteConfigHasImageAdapter(root)) {
1224
+ if (hasViteConfig && !viteConfigHasCloudflarePlugin(root, viteConfigFile)) throw new Error(formatMissingCloudflarePluginError({
1225
+ isAppRouter: info.isAppRouter,
1226
+ configFile: viteConfigFile,
1227
+ initUpdatesConfig: !viteConfigFile
1228
+ }));
1229
+ if (info.hasISR && !viteConfigHasCacheAdapter(root, viteConfigFile) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({
1230
+ configFile: viteConfigFile,
1231
+ typedConfig: deploymentTool === "cf"
1232
+ }));
1233
+ if (!viteConfigHasImageAdapter(root, viteConfigFile)) {
1220
1234
  console.log();
1221
- console.log(formatImageOptimizationHint(deploymentTool === "cf"));
1235
+ console.log(formatImageOptimizationHint(deploymentTool === "cf", viteConfigFile));
1222
1236
  }
1223
1237
  if (options.dryRun) {
1224
1238
  console.log("\n Dry run complete. No build or deploy performed.\n");
@@ -1232,7 +1246,7 @@ async function deploy(options) {
1232
1246
  }));
1233
1247
  return;
1234
1248
  }
1235
- const viteConfigMetadata = await withBuildContext(() => loadDeployViteConfigMetadata(info.root, viteMode));
1249
+ const viteConfigMetadata = await withBuildContext(() => loadDeployViteConfigMetadata(info.root, viteMode, viteConfigFile));
1236
1250
  const cdnAdapterConfig = resolveCdnAdapterConfig(viteConfigMetadata.cacheConfig);
1237
1251
  const nextConfig = await withBuildContext(async () => {
1238
1252
  const inlineNextConfig = viteConfigMetadata.nextConfig;
@@ -1258,7 +1272,7 @@ async function deploy(options) {
1258
1272
  const replacement = isPreview ? "Preview deployments render these routes on request." : 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.";
1259
1273
  console.warn(`\n Warning: ${trigger} is ignored by Cloudflare deploy. ${replacement}`);
1260
1274
  }
1261
- if (!options.skipBuild) await withBuildContext(() => runBuild(info, cloudflareEnv, viteMode));
1275
+ if (!options.skipBuild) await withBuildContext(() => runBuild(info, cloudflareEnv, viteMode, viteConfigFile));
1262
1276
  else console.log("\n Skipping build (--skip-build)");
1263
1277
  const prerenderOutputDirs = resolvePrerenderOutputDirs(info.root, deploymentTool, viteConfigMetadata.routeRootConfig);
1264
1278
  const canWarmTpr = options.experimentalTPR && !shouldPrerenderLocally && hasBuildIdentityHeader;
@@ -5,5 +5,6 @@ export declare function parsePreviewsDeployArgs(args: string[]): {
5
5
  name: string | undefined;
6
6
  mode: string | undefined;
7
7
  skipBuild: boolean;
8
+ viteConfig: string | undefined;
8
9
  };
9
10
  //#endregion
@@ -28,7 +28,8 @@ function parsePreviewsDeployArgs(args) {
28
28
  "skip-build": {
29
29
  type: "boolean",
30
30
  default: false
31
- }
31
+ },
32
+ "vite-config": { type: "string" }
32
33
  }
33
34
  });
34
35
  if (positionals.length > 1) throw new Error("Expected at most one Preview name: previews deploy [preview-name].");
@@ -36,7 +37,8 @@ function parsePreviewsDeployArgs(args) {
36
37
  help: values.help,
37
38
  name: positionals[0] === void 0 ? void 0 : validatePreviewName(positionals[0]),
38
39
  mode: values.mode === void 0 ? void 0 : validateMode(values.mode),
39
- skipBuild: values["skip-build"]
40
+ skipBuild: values["skip-build"],
41
+ viteConfig: values["vite-config"]?.trim() || void 0
40
42
  };
41
43
  }
42
44
  //#endregion
@@ -6,5 +6,10 @@
6
6
  * helpers in the vinext core).
7
7
  */
8
8
  export declare function isUnknownRecord(value: unknown): value is Record<string, unknown>;
9
+ /**
10
+ * When a `"use cache"` entry's generation started (`ctx.timestamp`), which dates
11
+ * the entry like Next.js does. Absent, malformed or future values fall back to `now`.
12
+ */
13
+ export declare function readCacheTimestamp(ctx: Record<string, unknown> | undefined, now: number): number;
9
14
  export declare function readCacheControlNumberField(ctx: Record<string, unknown> | undefined, field: string): number | undefined;
10
15
  //#endregion
@@ -12,9 +12,17 @@ function readRecordField(ctx, field) {
12
12
  const value = ctx?.[field];
13
13
  return isUnknownRecord(value) ? value : void 0;
14
14
  }
15
+ /**
16
+ * When a `"use cache"` entry's generation started (`ctx.timestamp`), which dates
17
+ * the entry like Next.js does. Absent, malformed or future values fall back to `now`.
18
+ */
19
+ function readCacheTimestamp(ctx, now) {
20
+ const value = ctx?.timestamp;
21
+ return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= now ? value : now;
22
+ }
15
23
  function readCacheControlNumberField(ctx, field) {
16
24
  const value = readRecordField(ctx, "cacheControl")?.[field] ?? ctx?.[field];
17
25
  return typeof value === "number" ? value : void 0;
18
26
  }
19
27
  //#endregion
20
- export { isUnknownRecord, readCacheControlNumberField };
28
+ export { isUnknownRecord, readCacheControlNumberField, readCacheTimestamp };
@@ -1,2 +1 @@
1
- import { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "vinext/internal/server/headers";
2
- export { VINEXT_EXPECTED_WORKER_VERSION_HEADER };
1
+ export { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "vinext/internal/server/headers";
@@ -16,4 +16,5 @@ type WranglerEnvironmentConfig = {
16
16
  * Parse the Wrangler fields used by TPR and staged CDN warming.
17
17
  */
18
18
  export declare function parseWranglerConfig(root: string, configPath?: string): WranglerConfig | null;
19
- //#endregion
19
+ //#endregion
20
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Cloudflare cache and image adapters for vinext.",
5
5
  "homepage": "https://vinext.dev/",
6
6
  "license": "MIT",
@@ -48,21 +48,20 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@cloudflare/workers-response-store": "1.1.2"
51
+ "@cloudflare/workers-response-store": "1.1.4"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^25.9.2",
55
55
  "cf": "1.0.0-beta.1",
56
56
  "miniflare": "5.20260730.0-alpha",
57
- "vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
58
- "vite-plus": "1.1.0",
59
- "vitest": "5.0.3",
60
- "vinext": "1.3.0"
57
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
58
+ "vite-plus": "1.3.0",
59
+ "vinext": "1.4.0"
61
60
  },
62
61
  "peerDependencies": {
63
62
  "@cloudflare/vite-plugin": "*",
64
63
  "cf": "*",
65
- "vinext": "^1.3.0"
64
+ "vinext": "^1.4.0"
66
65
  },
67
66
  "peerDependenciesMeta": {
68
67
  "@cloudflare/vite-plugin": {
@@ -78,6 +77,6 @@
78
77
  "scripts": {
79
78
  "build": "vp pack",
80
79
  "dev": "vp pack --watch",
81
- "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained VINEXT_RESPONSE_STORE_LOCATION_HINT=weur pnpm --filter response-store-demo run build && VINEXT_RESPONSE_STORE_LOCATION_HINT=wnam pnpm --filter response-store-demo run build && vitest run"
80
+ "test": "vp run vinext#build && vp run @cloudflare/workers-response-store#build && vp run @vinext/cloudflare#build && VINEXT_RESPONSE_STORE_MODE=self-contained VINEXT_RESPONSE_STORE_LOCATION_HINT=weur pnpm --filter response-store-demo run build && VINEXT_RESPONSE_STORE_LOCATION_HINT=wnam pnpm --filter response-store-demo run build && vp test run"
82
81
  }
83
82
  }