@vinext/cloudflare 1.0.0-beta.3 → 1.0.0-beta.5

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.
@@ -1,6 +1,5 @@
1
1
  import { CdnCacheAdapter, CdnCacheableHeaderInput, CdnResponseHeaders } from "vinext/shims/cdn-cache";
2
2
  import { CacheHandlerValue, IncrementalCacheValue } from "vinext/shims/cache";
3
-
4
3
  //#region src/cache/cdn-adapter.runtime.d.ts
5
4
  declare class CloudflareCdnCacheAdapter implements CdnCacheAdapter {
6
5
  readonly ownsBackgroundRevalidation = false;
@@ -2,9 +2,13 @@
2
2
  declare const DEFAULT_KV_DATA_CACHE_BINDING = "VINEXT_KV_CACHE";
3
3
  /** Options accepted by {@link kvDataAdapter}, forwarded to the runtime factory. */
4
4
  type KvDataAdapterOptions = {
5
- /** KV namespace binding name on the Worker `env`. @default "VINEXT_KV_CACHE" */binding?: string; /** Namespace prefix for cache keys (isolates multiple apps in one namespace). */
6
- appPrefix?: string; /** Default KV `expirationTtl` in seconds. @default 2592000 (30 days) */
7
- ttlSeconds?: number; /** TTL in milliseconds for the in-memory tag-invalidation cache. @default 5000 */
5
+ /** KV namespace binding name on the Worker `env`. @default "VINEXT_KV_CACHE" */
6
+ binding?: string;
7
+ /** Namespace prefix for cache keys (isolates multiple apps in one namespace). */
8
+ appPrefix?: string;
9
+ /** Default KV `expirationTtl` in seconds. @default 2592000 (30 days) */
10
+ ttlSeconds?: number;
11
+ /** TTL in milliseconds for the in-memory tag-invalidation cache. @default 5000 */
8
12
  tagCacheTtlMs?: number;
9
13
  };
10
14
  /**
@@ -2,7 +2,6 @@ import { KvDataAdapterOptions } from "./kv-data-adapter.js";
2
2
  import { ENTRY_PREFIX } from "./kv-key.js";
3
3
  import { ExecutionContextLike } from "vinext/shims/request-context";
4
4
  import { CacheHandler, CacheHandlerValue, IncrementalCacheValue } from "vinext/shims/cache";
5
-
6
5
  //#region src/cache/kv-data-adapter.runtime.d.ts
7
6
  type KVNamespace = {
8
7
  get(key: string, options?: {
@@ -62,7 +61,8 @@ declare class KVCacheHandler implements CacheHandler {
62
61
  constructor(kvNamespace: KVNamespace, options?: {
63
62
  appPrefix?: string;
64
63
  ctx?: ExecutionContextLike;
65
- ttlSeconds?: number; /** TTL in milliseconds for the local tag cache. Defaults to 5000ms. */
64
+ ttlSeconds?: number;
65
+ /** TTL in milliseconds for the local tag cache. Defaults to 5000ms. */
66
66
  tagCacheTtlMs?: number;
67
67
  });
68
68
  private _entryKey;
@@ -125,10 +125,7 @@ declare class KVCacheHandler implements CacheHandler {
125
125
  */
126
126
  private _put;
127
127
  }
128
- declare const createKvDataCacheAdapter: ({
129
- env,
130
- options
131
- }: {
128
+ declare const createKvDataCacheAdapter: ({ env, options }: {
132
129
  env?: Record<string, unknown>;
133
130
  options?: KvDataAdapterOptions;
134
131
  }) => CacheHandler;
@@ -213,14 +213,16 @@ var KVCacheHandler = class {
213
213
  let effectiveExpire;
214
214
  effectiveRevalidate = readCacheControlNumberField(ctx, "revalidate");
215
215
  effectiveExpire = readCacheControlNumberField(ctx, "expire");
216
+ const effectiveStale = readCacheControlNumberField(ctx, "stale");
216
217
  if (data && "revalidate" in data && typeof data.revalidate === "number") effectiveRevalidate = data.revalidate;
217
218
  if (effectiveRevalidate === 0) return Promise.resolve();
218
219
  const now = Date.now();
219
220
  const revalidateAt = typeof effectiveRevalidate === "number" && effectiveRevalidate > 0 ? now + effectiveRevalidate * 1e3 : null;
220
221
  const expireAt = typeof effectiveExpire === "number" && effectiveExpire > 0 ? now + effectiveExpire * 1e3 : null;
221
- const cacheControl = typeof effectiveRevalidate === "number" ? effectiveExpire === void 0 ? { revalidate: effectiveRevalidate } : {
222
+ const cacheControl = typeof effectiveRevalidate === "number" ? {
222
223
  revalidate: effectiveRevalidate,
223
- expire: effectiveExpire
224
+ ...effectiveExpire === void 0 ? {} : { expire: effectiveExpire },
225
+ ...effectiveStale === void 0 ? {} : { stale: effectiveStale }
224
226
  } : void 0;
225
227
  const entry = {
226
228
  value: data ? serializeForJSON(data) : null,
@@ -350,6 +352,7 @@ function validateCacheEntry(raw) {
350
352
  if (!isUnknownRecord(obj.cacheControl)) return null;
351
353
  if (typeof obj.cacheControl.revalidate !== "number") return null;
352
354
  if (obj.cacheControl.expire !== void 0 && typeof obj.cacheControl.expire !== "number") return null;
355
+ if (obj.cacheControl.stale !== void 0 && typeof obj.cacheControl.stale !== "number") return null;
353
356
  }
354
357
  if (obj.value !== null) {
355
358
  if (!obj.value || typeof obj.value !== "object") return null;
@@ -2,7 +2,8 @@
2
2
  /** Key prefix for cache entries. */
3
3
  declare const ENTRY_PREFIX = "cache:";
4
4
  type KvKeySpace = {
5
- /** Prefix shared by every cache entry, including entries with hashed logical keys. */entryPrefix: string;
5
+ /** Prefix shared by every cache entry, including entries with hashed logical keys. */
6
+ entryPrefix: string;
6
7
  entryKey(logicalKey: string): string;
7
8
  tagKey(tag: string): string;
8
9
  };
@@ -1,5 +1,4 @@
1
1
  import { PrerenderManifest, PrerenderedPathSelectionOptions } from "vinext/internal/server/prerender-manifest";
2
-
3
2
  //#region src/cdn-warm.d.ts
4
3
  type CdnWarmOptions = {
5
4
  targetUrl: string;
package/dist/cli.d.ts CHANGED
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,5 +1,4 @@
1
1
  import { VinextCacheConfig } from "vinext/internal/cache-adapters";
2
-
3
2
  //#region src/deploy-config.d.ts
4
3
  /**
5
4
  * Check whether an existing vite.config file already imports and uses the
package/dist/deploy.d.ts CHANGED
@@ -2,27 +2,45 @@ import { parseWranglerConfig } from "./tpr.js";
2
2
  import { WranglerDeploymentStatus, WranglerVersionTraffic } from "./version-deploy.js";
3
3
  import { KVBulkPair } from "./prerender-kv-populate.js";
4
4
  import { spawn } from "node:child_process";
5
-
6
5
  //#region src/deploy.d.ts
7
6
  type DeployOptions = {
8
- /** Project root directory */root: string; /** Deploy to preview environment (default: production) */
9
- preview?: boolean; /** Wrangler environment name from wrangler.jsonc env.<name> */
10
- env?: string; /** Custom project name for the Worker */
11
- name?: string; /** Wrangler config path, relative to root unless absolute */
12
- config?: string; /** Skip the build step (assume already built) */
13
- skipBuild?: boolean; /** Dry run — validate setup but don't build or deploy */
14
- dryRun?: boolean; /** Pre-render all discovered routes into the dist output after building */
15
- prerenderAll?: boolean; /** Maximum number of routes to prerender in parallel */
16
- prerenderConcurrency?: number; /** Warm Cloudflare's CDN cache by requesting build-discovered paths for the uploaded version */
17
- warmCdnCache?: boolean; /** Maximum number of CDN warmup requests to issue in parallel */
18
- warmCdnConcurrency?: number; /** Per-request CDN warmup timeout in milliseconds */
19
- warmCdnTimeout?: number; /** Number of CDN warmup retries for transient failures */
20
- warmCdnRetries?: number; /** Fail deployment if any CDN warmup request fails */
21
- warmCdnStrict?: boolean; /** Include PPR fallback-shell placeholder paths during CDN warmup */
22
- warmCdnIncludeFallbacks?: boolean; /** Enable experimental TPR (Traffic-aware Pre-Rendering) */
23
- experimentalTPR?: boolean; /** TPR: traffic coverage percentage target (0–100, default: 90) */
24
- tprCoverage?: number; /** TPR: hard cap on number of pages to pre-render (default: 1000) */
25
- tprLimit?: number; /** TPR: analytics lookback window in hours (default: 24) */
7
+ /** Project root directory */
8
+ root: string;
9
+ /** Deploy to preview environment (default: production) */
10
+ preview?: boolean;
11
+ /** Wrangler environment name from wrangler.jsonc env.<name> */
12
+ env?: string;
13
+ /** Custom project name for the Worker */
14
+ name?: string;
15
+ /** Wrangler config path, relative to root unless absolute */
16
+ config?: string;
17
+ /** Skip the build step (assume already built) */
18
+ skipBuild?: boolean;
19
+ /** Dry run — validate setup but don't build or deploy */
20
+ dryRun?: boolean;
21
+ /** Pre-render all discovered routes into the dist output after building */
22
+ prerenderAll?: boolean;
23
+ /** Maximum number of routes to prerender in parallel */
24
+ prerenderConcurrency?: number;
25
+ /** Warm Cloudflare's CDN cache by requesting build-discovered paths for the uploaded version */
26
+ warmCdnCache?: boolean;
27
+ /** Maximum number of CDN warmup requests to issue in parallel */
28
+ warmCdnConcurrency?: number;
29
+ /** Per-request CDN warmup timeout in milliseconds */
30
+ warmCdnTimeout?: number;
31
+ /** Number of CDN warmup retries for transient failures */
32
+ warmCdnRetries?: number;
33
+ /** Fail deployment if any CDN warmup request fails */
34
+ warmCdnStrict?: boolean;
35
+ /** Include PPR fallback-shell placeholder paths during CDN warmup */
36
+ warmCdnIncludeFallbacks?: boolean;
37
+ /** Enable experimental TPR (Traffic-aware Pre-Rendering) */
38
+ experimentalTPR?: boolean;
39
+ /** TPR: traffic coverage percentage target (0–100, default: 90) */
40
+ tprCoverage?: number;
41
+ /** TPR: hard cap on number of pages to pre-render (default: 1000) */
42
+ tprLimit?: number;
43
+ /** TPR: analytics lookback window in hours (default: 24) */
26
44
  tprWindow?: number;
27
45
  };
28
46
  declare function parseDeployArgs(args: string[]): {
@@ -1,7 +1,8 @@
1
1
  //#region src/images/images-optimizer.d.ts
2
2
  /** Options accepted by {@link imagesOptimizer}, forwarded to the runtime factory. */
3
3
  type ImagesOptimizerOptions = {
4
- /** Cloudflare Images binding name on the Worker `env`. @default "IMAGES" */binding?: string;
4
+ /** Cloudflare Images binding name on the Worker `env`. @default "IMAGES" */
5
+ binding?: string;
5
6
  };
6
7
  /**
7
8
  * Config-time builder: returns a serializable descriptor whose `adapter` is the
@@ -1,14 +1,10 @@
1
1
  import { ImageOptimizer } from "vinext/server/image-optimization";
2
-
3
2
  //#region src/images/images-optimizer.runtime.d.ts
4
3
  /** Options accepted by the optimizer factory (mirrors `ImagesOptimizerOptions`). */
5
4
  type ImagesOptimizerOptions = {
6
5
  binding?: string;
7
6
  };
8
- declare const createCloudflareImageOptimizer: ({
9
- env,
10
- options
11
- }: {
7
+ declare const createCloudflareImageOptimizer: ({ env, options }: {
12
8
  env?: Record<string, unknown>;
13
9
  options?: ImagesOptimizerOptions;
14
10
  }) => ImageOptimizer;
@@ -28,10 +28,11 @@ function formatUnknownError(error) {
28
28
  if (error instanceof Error && error.message) return error.message;
29
29
  return String(error);
30
30
  }
31
- function buildCacheEntry(value, tags, now, revalidateSeconds, expireSeconds) {
32
- const cacheControl = revalidateSeconds === void 0 ? void 0 : expireSeconds === void 0 ? { revalidate: revalidateSeconds } : {
31
+ function buildCacheEntry(value, tags, now, revalidateSeconds, expireSeconds, staleSeconds) {
32
+ const cacheControl = revalidateSeconds === void 0 ? void 0 : {
33
33
  revalidate: revalidateSeconds,
34
- expire: expireSeconds
34
+ ...expireSeconds === void 0 ? {} : { expire: expireSeconds },
35
+ ...staleSeconds === void 0 ? {} : { stale: staleSeconds }
35
36
  };
36
37
  return JSON.stringify({
37
38
  value,
@@ -79,8 +80,9 @@ function buildPrerenderKVPairs(serverDir, options) {
79
80
  if (typeof route.revalidate === "number" && route.revalidate <= 0) continue;
80
81
  const revalidateSeconds = typeof route.revalidate === "number" ? route.revalidate : void 0;
81
82
  const expireSeconds = typeof route.expire === "number" ? route.expire : void 0;
83
+ const staleSeconds = typeof route.stale === "number" && route.stale >= 0 ? route.stale : void 0;
82
84
  const expirationTtl = revalidateSeconds === void 0 ? void 0 : ttlSeconds;
83
- const tags = buildAppPageCacheTags(cachePathname, []);
85
+ const tags = buildAppPageCacheTags(cachePathname, route.tags ?? []);
84
86
  const metadata = buildMetadata(tags);
85
87
  const htmlKey = appIsrCacheKey(cachePathname, "html", manifest.buildId);
86
88
  const rscKey = appIsrCacheKey(cachePathname, "rsc", manifest.buildId);
@@ -90,7 +92,7 @@ function buildPrerenderKVPairs(serverDir, options) {
90
92
  kind: "APP_PAGE",
91
93
  html: fs.readFileSync(htmlPath, "utf-8"),
92
94
  headers: route.headers
93
- }, tags, now, revalidateSeconds, expireSeconds),
95
+ }, tags, now, revalidateSeconds, expireSeconds, staleSeconds),
94
96
  ...expirationTtl !== void 0 ? { expiration_ttl: expirationTtl } : {},
95
97
  ...metadata ? { metadata } : {}
96
98
  });
@@ -102,7 +104,7 @@ function buildPrerenderKVPairs(serverDir, options) {
102
104
  kind: "APP_PAGE",
103
105
  html: "",
104
106
  rscData
105
- }, tags, now, revalidateSeconds, expireSeconds),
107
+ }, tags, now, revalidateSeconds, expireSeconds, staleSeconds),
106
108
  ...expirationTtl !== void 0 ? { expiration_ttl: expirationTtl } : {},
107
109
  ...metadata ? { metadata } : {}
108
110
  });
package/dist/tpr.d.ts CHANGED
@@ -21,17 +21,27 @@
21
21
  * or no KV namespace is configured.
22
22
  */
23
23
  type TPROptions = {
24
- /** Project root directory. */root: string; /** Wrangler config path, relative to root unless absolute. */
25
- config?: string; /** Traffic coverage percentage (0–100). Default: 90. */
26
- coverage: number; /** Hard cap on number of pages to pre-render. Default: 1000. */
27
- limit: number; /** Analytics lookback window in hours. Default: 24. */
24
+ /** Project root directory. */
25
+ root: string;
26
+ /** Wrangler config path, relative to root unless absolute. */
27
+ config?: string;
28
+ /** Traffic coverage percentage (0–100). Default: 90. */
29
+ coverage: number;
30
+ /** Hard cap on number of pages to pre-render. Default: 1000. */
31
+ limit: number;
32
+ /** Analytics lookback window in hours. Default: 24. */
28
33
  window: number;
29
34
  };
30
35
  type TPRResult = {
31
- /** Total unique page paths found in analytics. */totalPaths: number; /** Number of pages successfully pre-rendered and uploaded. */
32
- prerenderedCount: number; /** Actual traffic coverage achieved (percentage). */
33
- coverageAchieved: number; /** Wall-clock duration of the TPR step in milliseconds. */
34
- durationMs: number; /** If TPR was skipped, the reason. */
36
+ /** Total unique page paths found in analytics. */
37
+ totalPaths: number;
38
+ /** Number of pages successfully pre-rendered and uploaded. */
39
+ prerenderedCount: number;
40
+ /** Actual traffic coverage achieved (percentage). */
41
+ coverageAchieved: number;
42
+ /** Wall-clock duration of the TPR step in milliseconds. */
43
+ durationMs: number;
44
+ /** If TPR was skipped, the reason. */
35
45
  skipped?: string;
36
46
  };
37
47
  type PrerenderResult = {
@@ -1,7 +1,6 @@
1
1
  import { parseWorkersDevUrl } from "./workers-dev-url.js";
2
2
  import { DeployOptions } from "./deploy.js";
3
3
  import { execFileSync } from "node:child_process";
4
-
5
4
  //#region src/version-deploy.d.ts
6
5
  type WranglerVersionUploadResult = {
7
6
  versionId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.5",
4
4
  "description": "Cloudflare adapters for vinext (KV data cache and Images-backed image optimization).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -52,12 +52,12 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^25.9.2",
55
- "vite": "npm:@voidzero-dev/vite-plus-core@0.2.2",
56
- "vite-plus": "0.2.2",
57
- "vinext": "1.0.0-beta.3"
55
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.6",
56
+ "vite-plus": "0.2.6",
57
+ "vinext": "1.0.0-beta.5"
58
58
  },
59
59
  "peerDependencies": {
60
- "vinext": "^1.0.0-beta.3"
60
+ "vinext": "^1.0.0-beta.5"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22"