@vinext/cloudflare 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,10 +4,4 @@
4
4
  * payload, the two parts Next.js keeps in one entry, rather than a variant.
5
5
  */
6
6
  export declare function isCanonicalAppPage(responseStageProps: unknown, isRscRequest: boolean): boolean;
7
- /**
8
- * Whether a canonical RSC request has a document part. A `.rsc` path reaches
9
- * its page's HTML path only through the app's trailingSlash policy, and
10
- * vinext's client never sends one, so it stores its payload alone.
11
- */
12
- export declare function hasDocumentPart(rscRequestUrl: string): boolean;
13
7
  //#endregion
@@ -6,13 +6,5 @@
6
6
  function isCanonicalAppPage(responseStageProps, isRscRequest) {
7
7
  return responseStageProps !== null && typeof responseStageProps === "object" && Reflect.get(responseStageProps, "kind") === "app-page" && Reflect.get(responseStageProps, "isRscRequest") === isRscRequest && (Reflect.get(responseStageProps, "matchKind") === "request" || Reflect.get(responseStageProps, "matchKind") === "resolved") && (!isRscRequest || Reflect.get(responseStageProps, "renderMode") === "navigation") && Reflect.get(responseStageProps, "interceptionContext") === null && Reflect.get(responseStageProps, "interceptionId") === null && Reflect.get(responseStageProps, "mountedSlotsHeader") === null;
8
8
  }
9
- /**
10
- * Whether a canonical RSC request has a document part. A `.rsc` path reaches
11
- * its page's HTML path only through the app's trailingSlash policy, and
12
- * vinext's client never sends one, so it stores its payload alone.
13
- */
14
- function hasDocumentPart(rscRequestUrl) {
15
- return !new URL(rscRequestUrl).pathname.endsWith(".rsc");
16
- }
17
9
  //#endregion
18
- export { hasDocumentPart, isCanonicalAppPage };
10
+ export { isCanonicalAppPage };
@@ -1,5 +1,5 @@
1
1
  import { VINEXT_CDN_BUILD_ID_HEADER, getVinextCdnBuildIdentity } from "./cdn-build-id.js";
2
- import { hasDocumentPart, isCanonicalAppPage } from "./app-page-parts.js";
2
+ import { isCanonicalAppPage } from "./app-page-parts.js";
3
3
  import { SHARED_RESPONSE_STAGE_HEADER, finalizeGatewayResponse } from "./browser-cache-policy.js";
4
4
  import { hasCacheMethod, invalidateOrPurge } from "./workers-cache-invalidation.js";
5
5
  import { VINEXT_PRERENDER_READINESS_PATH, VINEXT_RSC_VARY_HEADER } from "vinext/internal/server/headers";
@@ -383,7 +383,6 @@ function getResponseStageInvocation(value, expectedCache) {
383
383
  function otherPagePartDispatch(request, props) {
384
384
  const isRscRequest = isCanonicalAppPage(props, true);
385
385
  if (!isRscRequest && !isCanonicalAppPage(props, false)) return null;
386
- if (isRscRequest && !hasDocumentPart(request.url)) return null;
387
386
  const headers = new Headers(request.headers);
388
387
  for (const name of FRAMEWORK_RESPONSE_VARY_FIELDS) headers.delete(name);
389
388
  for (const name of [
@@ -25,6 +25,14 @@ import { getRequestExecutionContext } from "vinext/shims/request-context";
25
25
  */
26
26
  /** Default KV namespace binding name read from the Worker `env`. */
27
27
  const DEFAULT_BINDING = "VINEXT_KV_CACHE";
28
+ function toStoredLifetime(seconds) {
29
+ if (seconds === Infinity) return "Infinity";
30
+ if (seconds === -Infinity) return "-Infinity";
31
+ return seconds;
32
+ }
33
+ function isStoredLifetime(value) {
34
+ return typeof value === "number" || value === "Infinity" || value === "-Infinity";
35
+ }
28
36
  function parseTagMarker(raw) {
29
37
  if (raw === null || raw === void 0) return {};
30
38
  if (!raw.startsWith("{")) return { expired: /^\d+$/.test(raw) ? Number(raw) : NaN };
@@ -313,8 +321,8 @@ var KVCacheHandler = class {
313
321
  const expireAt = typeof effectiveExpire === "number" && effectiveExpire > 0 ? now + effectiveExpire * 1e3 : null;
314
322
  const cacheControl = typeof effectiveRevalidate === "number" ? {
315
323
  revalidate: Number.isFinite(effectiveRevalidate) ? effectiveRevalidate : false,
316
- ...effectiveExpire === void 0 ? {} : { expire: effectiveExpire },
317
- ...effectiveStale === void 0 ? {} : { stale: effectiveStale }
324
+ ...effectiveExpire === void 0 ? {} : { expire: toStoredLifetime(effectiveExpire) },
325
+ ...effectiveStale === void 0 ? {} : { stale: toStoredLifetime(effectiveStale) }
318
326
  } : void 0;
319
327
  const entry = {
320
328
  value: data ? serializeForJSON(data) : null,
@@ -469,18 +477,24 @@ function validateCacheEntry(raw) {
469
477
  if (obj.cacheControl !== void 0) {
470
478
  if (!isUnknownRecord(obj.cacheControl)) return null;
471
479
  if (typeof obj.cacheControl.revalidate !== "number" && obj.cacheControl.revalidate !== false) return null;
472
- if (obj.cacheControl.expire !== void 0 && typeof obj.cacheControl.expire !== "number") return null;
473
- if (obj.cacheControl.stale !== void 0 && typeof obj.cacheControl.stale !== "number") return null;
480
+ for (const field of ["expire", "stale"]) {
481
+ const seconds = obj.cacheControl[field];
482
+ if (seconds !== void 0 && !isStoredLifetime(seconds)) return null;
483
+ }
474
484
  }
475
485
  if (obj.value !== null) {
476
486
  if (!obj.value || typeof obj.value !== "object") return null;
477
487
  const value = obj.value;
478
488
  if (typeof value.kind !== "string" || !VALID_KINDS.has(value.kind)) return null;
479
489
  }
480
- if (obj.cacheControl?.revalidate === false) obj.cacheControl = {
481
- ...obj.cacheControl,
482
- revalidate: Infinity
483
- };
490
+ if (obj.cacheControl !== void 0) {
491
+ const { revalidate, expire, stale } = obj.cacheControl;
492
+ obj.cacheControl = {
493
+ revalidate: revalidate === false ? Infinity : revalidate,
494
+ ...expire === void 0 ? {} : { expire: Number(expire) },
495
+ ...stale === void 0 ? {} : { stale: Number(stale) }
496
+ };
497
+ }
484
498
  return raw;
485
499
  }
486
500
  /**
@@ -1,6 +1,6 @@
1
- import { hasDocumentPart, isCanonicalAppPage } from "./app-page-parts.js";
1
+ import { isCanonicalAppPage } from "./app-page-parts.js";
2
2
  import { SHARED_RESPONSE_STAGE_HEADER, finalizeGatewayResponse } from "./browser-cache-policy.js";
3
- import { captureResponseStoreDataRegeneration, runWithResponseStoreInvocation, setResponseStore } from "./response-store-data.runtime.js";
3
+ import { captureResponseStoreDataRegeneration, runWithResponseStoreInvocation, setResponseStore, trackResponseStoreRegenerationWork } from "./response-store-data.runtime.js";
4
4
  import { NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_RSC_COMPLETION_METADATA_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER, VINEXT_STALE_TIME_PENDING_HEADER } from "vinext/internal/server/headers";
5
5
  import { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER as VINEXT_RSC_VARY_HEADER$1, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, stripRscCacheBustingSearchParam } from "vinext/internal/server/app-rsc-cache-busting";
6
6
  import { hasSharedCacheCredentials, isNonCacheableCacheControl } from "vinext/shims/cdn-cache";
@@ -25,7 +25,10 @@ function stageContext(ctx, env) {
25
25
  hostRuntime: "worker",
26
26
  passThroughOnException: () => ctx.passThroughOnException(),
27
27
  ...ctx.props === void 0 ? {} : { props: ctx.props },
28
- waitUntil: (promise) => ctx.waitUntil(promise)
28
+ waitUntil: (promise) => {
29
+ trackResponseStoreRegenerationWork(promise);
30
+ ctx.waitUntil(promise);
31
+ }
29
32
  });
30
33
  }
31
34
  function safeProps(props) {
@@ -263,7 +266,7 @@ function otherPagePart(identityRequest, identityProps) {
263
266
  invocation: rscPartInvocation(identityRequest, identityProps),
264
267
  kind: "rsc"
265
268
  };
266
- if (isCanonicalAppPage(identityProps, true) && hasDocumentPart(identityRequest.url)) return {
269
+ if (isCanonicalAppPage(identityProps, true)) return {
267
270
  invocation: documentPartInvocation(identityRequest, identityProps),
268
271
  kind: "document"
269
272
  };
@@ -31,6 +31,8 @@ export declare function captureResponseStoreAppPageDocument(): ((document: CdnAp
31
31
  export declare function deferResponseStoreNotModified(): boolean;
32
32
  /** Stream the foreground body while retaining an independent admission branch. */
33
33
  export declare function deferResponseStoreAdmission(response: Response, complete: (response: Response) => Promise<Response>): Response | null;
34
+ /** Keeps work a regeneration hands to waitUntil inside the regeneration. */
35
+ export declare function trackResponseStoreRegenerationWork(work: Promise<unknown>): void;
34
36
  /** Re-render an invocation and return the exact rewritten data-cache entry. */
35
37
  export declare function captureResponseStoreDataRegeneration(key: string, callback: () => Promise<void>): Promise<Response>;
36
38
  export declare class WorkersResponseStoreCacheHandler implements CacheHandler {
@@ -157,6 +157,10 @@ function deferResponseStoreAdmission(response, complete) {
157
157
  writer.closed.catch((error) => finishAdmission({ reason: error }));
158
158
  return new Response(foreground, response);
159
159
  }
160
+ /** Keeps work a regeneration hands to waitUntil inside the regeneration. */
161
+ function trackResponseStoreRegenerationWork(work) {
162
+ regenerationStorage.getStore()?.sideWrites.push(work.then(() => void 0, () => void 0));
163
+ }
160
164
  /** Re-render an invocation and return the exact rewritten data-cache entry. */
161
165
  async function captureResponseStoreDataRegeneration(key, callback) {
162
166
  const scope = {
@@ -295,8 +299,7 @@ var WorkersResponseStoreCacheHandler = class {
295
299
  }
296
300
  set(key, value, context) {
297
301
  const write = this.write(key, value, context);
298
- const regeneration = regenerationStorage.getStore();
299
- if (regeneration && regeneration.targetKey !== key) regeneration.sideWrites.push(write);
302
+ regenerationStorage.getStore()?.sideWrites.push(write);
300
303
  return write;
301
304
  }
302
305
  async write(key, value, context) {
@@ -374,4 +377,4 @@ function createResponseStoreDataCacheAdapter() {
374
377
  return new WorkersResponseStoreCacheHandler();
375
378
  }
376
379
  //#endregion
377
- export { CACHE_FUNCTION_REVALIDATOR_ID, DATA_REVALIDATOR_ID, WorkersResponseStoreCacheHandler, captureResponseStoreAppPageDocument, captureResponseStoreDataRegeneration, captureResponseStoreRscData, createResponseStoreDataCacheAdapter as default, deferResponseStoreAdmission, deferResponseStoreNotModified, runWithResponseStoreInvocation, setResponseStore };
380
+ export { CACHE_FUNCTION_REVALIDATOR_ID, DATA_REVALIDATOR_ID, WorkersResponseStoreCacheHandler, captureResponseStoreAppPageDocument, captureResponseStoreDataRegeneration, captureResponseStoreRscData, createResponseStoreDataCacheAdapter as default, deferResponseStoreAdmission, deferResponseStoreNotModified, runWithResponseStoreInvocation, setResponseStore, trackResponseStoreRegenerationWork };
package/dist/tpr.js CHANGED
@@ -102,7 +102,6 @@ function filterTrafficPaths(entries) {
102
102
  if (/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|webp|avif)$/i.test(e.path)) return false;
103
103
  if (e.path.startsWith("/api/")) return false;
104
104
  if (e.path.startsWith("/_next/") || e.path.startsWith("/__vinext/")) return false;
105
- if (e.path.endsWith(".rsc")) return false;
106
105
  return true;
107
106
  });
108
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinext/cloudflare",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Cloudflare cache and image adapters for vinext.",
5
5
  "homepage": "https://vinext.dev/",
6
6
  "license": "MIT",
@@ -56,12 +56,12 @@
56
56
  "miniflare": "5.20260730.0-alpha",
57
57
  "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
58
58
  "vite-plus": "1.3.0",
59
- "vinext": "1.4.0"
59
+ "vinext": "1.4.1"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@cloudflare/vite-plugin": "*",
63
63
  "cf": "*",
64
- "vinext": "^1.4.0"
64
+ "vinext": "^1.4.1"
65
65
  },
66
66
  "peerDependenciesMeta": {
67
67
  "@cloudflare/vite-plugin": {