vinext 1.2.1 → 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.
Files changed (212) hide show
  1. package/README.md +12 -9
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/pages-client-assets-module.js +1 -1
  13. package/dist/build/prerender-paths.js +5 -2
  14. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  15. package/dist/build/server-actions-encryption-key.js +101 -0
  16. package/dist/build/ssr-manifest.d.ts +3 -0
  17. package/dist/build/ssr-manifest.js +10 -1
  18. package/dist/client/client-rewrite-params.d.ts +9 -0
  19. package/dist/client/client-rewrite-params.js +20 -0
  20. package/dist/client/dev-error-overlay.js +2 -1
  21. package/dist/client/navigation-runtime.d.ts +25 -2
  22. package/dist/client/navigation-runtime.js +42 -11
  23. package/dist/client/vinext-next-data.d.ts +0 -1
  24. package/dist/config/config-matchers.d.ts +15 -40
  25. package/dist/config/config-matchers.js +183 -255
  26. package/dist/config/config-source.d.ts +34 -0
  27. package/dist/config/config-source.js +141 -0
  28. package/dist/config/header-params.d.ts +29 -0
  29. package/dist/config/header-params.js +106 -0
  30. package/dist/config/next-config.d.ts +7 -5
  31. package/dist/config/next-config.js +120 -7
  32. package/dist/entries/app-browser-entry.d.ts +14 -1
  33. package/dist/entries/app-browser-entry.js +26 -36
  34. package/dist/entries/app-rsc-entry.d.ts +2 -0
  35. package/dist/entries/app-rsc-entry.js +92 -57
  36. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  37. package/dist/entries/app-rsc-manifest.js +20 -1
  38. package/dist/entries/app-ssr-entry.d.ts +4 -1
  39. package/dist/entries/app-ssr-entry.js +9 -2
  40. package/dist/entries/pages-client-entry.d.ts +1 -0
  41. package/dist/entries/pages-client-entry.js +6 -6
  42. package/dist/entries/pages-server-entry.js +17 -14
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.js +239 -83
  45. package/dist/init.js +17 -0
  46. package/dist/plugins/optimize-imports.d.ts +25 -2
  47. package/dist/plugins/optimize-imports.js +106 -20
  48. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  49. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  50. package/dist/plugins/use-cache-callable.d.ts +5 -0
  51. package/dist/plugins/use-cache-callable.js +30 -8
  52. package/dist/plugins/worker-image-imports.d.ts +1 -0
  53. package/dist/plugins/worker-image-imports.js +1 -1
  54. package/dist/routing/app-route-graph.d.ts +1 -1
  55. package/dist/routing/browser-route-manifest.d.ts +43 -0
  56. package/dist/routing/browser-route-manifest.js +195 -0
  57. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  58. package/dist/routing/hashed-route-patterns.js +22 -0
  59. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  60. package/dist/routing/optimistic-route-trie.js +102 -0
  61. package/dist/routing/route-validation.d.ts +6 -1
  62. package/dist/routing/route-validation.js +26 -10
  63. package/dist/server/app-action-forwarding.d.ts +8 -0
  64. package/dist/server/app-action-forwarding.js +15 -1
  65. package/dist/server/app-browser-entry.js +147 -60
  66. package/dist/server/app-browser-error.d.ts +3 -1
  67. package/dist/server/app-browser-error.js +7 -2
  68. package/dist/server/app-browser-interception-context.d.ts +2 -2
  69. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  70. package/dist/server/app-browser-mpa-navigation.js +6 -5
  71. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  72. package/dist/server/app-browser-navigation-controller.js +88 -26
  73. package/dist/server/app-browser-state.d.ts +2 -2
  74. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  75. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  76. package/dist/server/app-client-reference-preloader.js +30 -7
  77. package/dist/server/app-fallback-renderer.js +2 -1
  78. package/dist/server/app-middleware.d.ts +6 -0
  79. package/dist/server/app-middleware.js +8 -10
  80. package/dist/server/app-optimistic-routing.d.ts +8 -10
  81. package/dist/server/app-optimistic-routing.js +4 -95
  82. package/dist/server/app-page-boundary-render.js +8 -1
  83. package/dist/server/app-page-cache-render.js +1 -0
  84. package/dist/server/app-page-dispatch.js +2 -0
  85. package/dist/server/app-page-render.js +3 -1
  86. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  87. package/dist/server/app-page-rsc-render-status.js +1 -0
  88. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  89. package/dist/server/app-page-search-params-observation.js +8 -10
  90. package/dist/server/app-page-stream.d.ts +7 -0
  91. package/dist/server/app-page-stream.js +1 -0
  92. package/dist/server/app-pages-bridge.d.ts +2 -1
  93. package/dist/server/app-pages-bridge.js +11 -7
  94. package/dist/server/app-prerender-static-params.js +3 -2
  95. package/dist/server/app-render-dependency.js +42 -2
  96. package/dist/server/app-request-stage-independent-entry.js +2 -2
  97. package/dist/server/app-response-stage-entry.js +3 -3
  98. package/dist/server/app-route-handler-dispatch.js +3 -1
  99. package/dist/server/app-route-handler-execution.d.ts +2 -0
  100. package/dist/server/app-route-handler-execution.js +9 -2
  101. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  102. package/dist/server/app-route-handler-middleware-context.js +3 -3
  103. package/dist/server/app-route-handler-response.d.ts +2 -1
  104. package/dist/server/app-route-handler-response.js +2 -2
  105. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  106. package/dist/server/app-route-handler-runtime.js +20 -3
  107. package/dist/server/app-route-module-loader.js +7 -6
  108. package/dist/server/app-route-tree.d.ts +20 -0
  109. package/dist/server/app-route-tree.js +18 -0
  110. package/dist/server/app-router-entry.js +2 -2
  111. package/dist/server/app-rsc-combined-handler.js +8 -1
  112. package/dist/server/app-rsc-errors.d.ts +7 -0
  113. package/dist/server/app-rsc-errors.js +9 -2
  114. package/dist/server/app-rsc-handler.d.ts +4 -1
  115. package/dist/server/app-rsc-handler.js +146 -130
  116. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  117. package/dist/server/app-rsc-response-finalizer.js +4 -1
  118. package/dist/server/app-rsc-response-stage.js +3 -1
  119. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  120. package/dist/server/app-rsc-route-matching.js +1 -1
  121. package/dist/server/app-server-action-execution.d.ts +23 -6
  122. package/dist/server/app-server-action-execution.js +50 -56
  123. package/dist/server/app-ssr-entry.d.ts +6 -0
  124. package/dist/server/app-ssr-entry.js +16 -7
  125. package/dist/server/app-ssr-stream.d.ts +7 -0
  126. package/dist/server/app-ssr-stream.js +13 -1
  127. package/dist/server/config-headers.js +12 -3
  128. package/dist/server/isolate-shared-promise.d.ts +10 -0
  129. package/dist/server/isolate-shared-promise.js +33 -0
  130. package/dist/server/isr-cache.js +3 -2
  131. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  132. package/dist/server/middleware-matcher-pattern.js +11 -140
  133. package/dist/server/middleware-matcher.js +5 -6
  134. package/dist/server/middleware-response-headers.d.ts +31 -0
  135. package/dist/server/middleware-response-headers.js +57 -1
  136. package/dist/server/middleware-runtime.js +26 -13
  137. package/dist/server/navigation-planner.d.ts +2 -2
  138. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  139. package/dist/server/nitro-public-files-plugin.js +106 -0
  140. package/dist/server/nitro-public-files.d.ts +21 -0
  141. package/dist/server/nitro-public-files.js +39 -0
  142. package/dist/server/pages-asset-tags.d.ts +5 -0
  143. package/dist/server/pages-asset-tags.js +9 -2
  144. package/dist/server/pages-client-assets.d.ts +4 -1
  145. package/dist/server/pages-i18n.d.ts +18 -0
  146. package/dist/server/pages-i18n.js +18 -2
  147. package/dist/server/pages-node-compat.d.ts +5 -3
  148. package/dist/server/pages-node-compat.js +35 -16
  149. package/dist/server/pages-request-pipeline.d.ts +6 -1
  150. package/dist/server/pages-request-pipeline.js +31 -35
  151. package/dist/server/pages-request-stage-entry.js +16 -6
  152. package/dist/server/pages-response-stage-entry.js +1 -1
  153. package/dist/server/pages-revalidate.js +1 -0
  154. package/dist/server/pages-router-entry.js +1 -1
  155. package/dist/server/prod-server.d.ts +2 -2
  156. package/dist/server/prod-server.js +71 -33
  157. package/dist/server/proxy-trust.d.ts +6 -0
  158. package/dist/server/proxy-trust.js +12 -6
  159. package/dist/server/request-pipeline.d.ts +5 -0
  160. package/dist/server/request-pipeline.js +12 -1
  161. package/dist/server/server-reference-loader.js +10 -1
  162. package/dist/server/static-file-cache.js +15 -3
  163. package/dist/server/worker-utils.js +1 -1
  164. package/dist/shims/cache-handler.js +3 -2
  165. package/dist/shims/cache-request-state.d.ts +40 -3
  166. package/dist/shims/cache-request-state.js +70 -5
  167. package/dist/shims/cache-runtime.js +47 -19
  168. package/dist/shims/cache.d.ts +2 -2
  169. package/dist/shims/cache.js +17 -8
  170. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  171. package/dist/shims/cdn-purge-routes.js +77 -0
  172. package/dist/shims/dynamic.js +17 -4
  173. package/dist/shims/form.js +8 -3
  174. package/dist/shims/image-props.d.ts +93 -0
  175. package/dist/shims/image-props.js +323 -0
  176. package/dist/shims/image.d.ts +4 -18
  177. package/dist/shims/image.js +4 -319
  178. package/dist/shims/internal/headers-state.d.ts +7 -0
  179. package/dist/shims/internal/headers-state.js +14 -2
  180. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  181. package/dist/shims/internal/hybrid-client-route-owner-direct.js +31 -14
  182. package/dist/shims/internal/hybrid-client-route-owner.js +8 -8
  183. package/dist/shims/link.js +5 -3
  184. package/dist/shims/navigation.d.ts +1 -1
  185. package/dist/shims/navigation.js +17 -5
  186. package/dist/shims/og.js +35 -10
  187. package/dist/shims/request-context.d.ts +13 -0
  188. package/dist/shims/router.js +19 -40
  189. package/dist/shims/server.d.ts +31 -4
  190. package/dist/shims/server.js +58 -10
  191. package/dist/shims/thenable-params.d.ts +6 -1
  192. package/dist/shims/thenable-params.js +11 -2
  193. package/dist/shims/unified-request-context.d.ts +5 -0
  194. package/dist/shims/unified-request-context.js +2 -0
  195. package/dist/utils/asset-prefix.d.ts +7 -0
  196. package/dist/utils/asset-prefix.js +10 -1
  197. package/dist/utils/client-build-manifest.js +12 -5
  198. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  199. package/dist/utils/client-runtime-metadata.js +15 -2
  200. package/dist/utils/lazy-chunks.d.ts +4 -0
  201. package/dist/utils/manifest-paths.d.ts +14 -0
  202. package/dist/utils/manifest-paths.js +22 -1
  203. package/dist/utils/path-to-regexp.d.ts +21 -0
  204. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  205. package/dist/utils/plugin-react-version.d.ts +15 -0
  206. package/dist/utils/plugin-react-version.js +64 -0
  207. package/dist/utils/public-routes.d.ts +2 -0
  208. package/dist/utils/public-routes.js +18 -7
  209. package/package.json +1 -1
  210. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  211. package/dist/utils/regex-safety.d.ts +0 -17
  212. package/dist/utils/regex-safety.js +0 -789
@@ -3,17 +3,19 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
3
3
  import { VINEXT_RSC_MARKER_HEADER } from "../server/headers.js";
4
4
  import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
5
5
  import { isRouteCacheabilityProbe, recordRouteCacheabilityProbeBailout } from "./cacheability-classification.js";
6
+ import { shareIsolatePromise } from "../server/isolate-shared-promise.js";
6
7
  import { getDataCacheHandler } from "./cache-handler.js";
7
8
  import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache-state.js";
8
9
  import { suppressHangingPromiseAbortRejections } from "./internal/make-hanging-promise.js";
9
10
  import { createPprFallbackShellSuspensePromise, trackPprFallbackShellCacheTask } from "./ppr-fallback-shell.js";
10
- import { markDynamicUsage, throwIfInsideCacheScope } from "./internal/headers-state.js";
11
+ import { createUseCacheAccessError, markDynamicUsage, recordInvalidDynamicUsageError } from "./internal/headers-state.js";
11
12
  import { isDraftModeEnabled } from "./headers.js";
12
13
  import { _registerCacheContextAccessor } from "./internal/cache-context-accessor.js";
13
14
  import { _hasPendingRevalidatedTag, _setRequestScopedCacheLife, cacheLifeProfiles, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
14
15
  import "./fetch-cache.js";
15
16
  import { hasUseCacheLayoutMarker, hasUseCachePageMarker, isUseCacheFunctionReference, withoutUseCacheSegmentMarker } from "./internal/app-page-props-cache-key.js";
16
- import { getFallbackParamsSnapshot, makeThenableParams, restoreThenableParams } from "./thenable-params.js";
17
+ import { isWellKnownProperty } from "./internal/thenable-well-known-properties.js";
18
+ import { getFallbackParamsSnapshot, restoreThenableParams } from "./thenable-params.js";
17
19
  import { getCurrentRootParams } from "./root-params.js";
18
20
  import { flightArgumentsKey, restoreFlightReply, snapshotFlightReply } from "./cache-flight-arguments.js";
19
21
  import { cache } from "react";
@@ -132,7 +134,7 @@ function buildUseCacheKey(id, keySeed, argsKey) {
132
134
  }
133
135
  let _rscModule;
134
136
  function getRscModule() {
135
- return _rscModule ??= import("@vitejs/plugin-rsc/react/rsc");
137
+ return _rscModule ??= shareIsolatePromise(import("@vitejs/plugin-rsc/react/rsc"));
136
138
  }
137
139
  /** Collect a ReadableStream<Uint8Array> into a single Uint8Array. */
138
140
  async function collectStream(stream) {
@@ -365,9 +367,9 @@ function registerCachedFunction(fn, id, variant, options = {}) {
365
367
  ...props,
366
368
  params: restoreThenableParams(await props.params, outerParams)
367
369
  });
368
- if (pagePropsIndex !== void 0) callArgs = withErroringPageSearchParams(callArgs, pagePropsIndex);
369
370
  }
370
- if (fallbackParams) return (await executeWithContext(fn, callArgs, cacheVariant, rsc)).result;
371
+ const callFn = segmentPropsIndex !== -1 && pagePropsIndex !== void 0 ? withErroringPageSearchParams(fn, pagePropsIndex) : fn;
372
+ if (fallbackParams) return (await executeWithContext(callFn, callArgs, cacheVariant, rsc)).result;
371
373
  if (cacheVariant === "private") {
372
374
  const privateCache = _getPrivateState()._privateCache;
373
375
  const privateHit = privateCache.get(cacheKey);
@@ -375,11 +377,11 @@ function registerCachedFunction(fn, id, variant, options = {}) {
375
377
  if (privateHit.serialized) return rsc.createFromReadableStream(uint8ToStream(base64ToUint8(privateHit.serialized.body)), {}, { preserveServerReferences: true });
376
378
  return privateHit.result;
377
379
  }
378
- const execution = await executeWithContext(fn, callArgs, cacheVariant, rsc);
380
+ const execution = await executeWithContext(callFn, callArgs, cacheVariant, rsc);
379
381
  if (execution.cacheable) privateCache.set(cacheKey, execution);
380
382
  return execution.result;
381
383
  }
382
- if (isDev || isDraftModeEnabled()) return (await executeWithContext(fn, callArgs, cacheVariant, rsc)).result;
384
+ if (isDev || isDraftModeEnabled()) return (await executeWithContext(callFn, callArgs, cacheVariant, rsc)).result;
383
385
  const handler = getDataCacheHandler();
384
386
  const rootParams = getCurrentRootParams();
385
387
  const knownRootParamNames = knownRootParamsByFunctionId.get(id);
@@ -409,7 +411,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
409
411
  }
410
412
  }
411
413
  const generate = async (propagate) => {
412
- const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(fn, callArgs, cacheVariant, (value) => serializeCacheResult(value, rsc));
414
+ const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(callFn, callArgs, cacheVariant, (value) => serializeCacheResult(value, rsc));
413
415
  const rootParamNames = ctx.readRootParamNames && ctx.readRootParamNames.size > 0 ? addKnownRootParamNames(id, ctx.readRootParamNames) : knownRootParamsByFunctionId.get(id);
414
416
  if (propagate) {
415
417
  recordRequestScopedCacheLife(effectiveLife);
@@ -631,18 +633,44 @@ function toReplayablePageArgs(args, index) {
631
633
  return replaceArgument(args, index, pageProps);
632
634
  }
633
635
  /**
634
- * Give page props at `index` without `searchParams` (a Response Store replay of
635
- * args encoded by `toReplayablePageArgs`) a value that throws on
636
- * access inside the cache scope, like Next.js's
637
- * `makeErroringSearchParamsForUseCache`, instead of `undefined`.
636
+ * Run `fn` with an erroring `searchParams` in the page props at `index` when
637
+ * they have none (they are omitted from a public page cache's arguments, and
638
+ * from a Response Store replay of them), instead of `undefined`.
638
639
  */
639
- function withErroringPageSearchParams(args, index) {
640
- const props = args[index];
641
- if (!isPagePropsObject(props) || "searchParams" in props) return args;
642
- return replaceArgument(args, index, {
643
- ...props,
644
- searchParams: makeThenableParams({}, { observeParamAccess: () => throwIfInsideCacheScope("searchParams") })
645
- });
640
+ function withErroringPageSearchParams(fn, index) {
641
+ return (...args) => {
642
+ const props = args[index];
643
+ if (!isPagePropsObject(props) || "searchParams" in props) return fn(...args);
644
+ return fn(...replaceArgument(args, index, {
645
+ ...props,
646
+ searchParams: makeErroringPageSearchParams()
647
+ }));
648
+ };
649
+ }
650
+ function isNextWellKnownProperty(prop) {
651
+ return prop !== "value" && prop !== "error" && isWellKnownProperty(prop);
652
+ }
653
+ /**
654
+ * Ported from Next.js's `makeErroringSearchParamsForUseCache`
655
+ * (server/request/search-params.ts): reading `then` or a param throws, and
656
+ * everything else reads the underlying promise, with methods bound to it.
657
+ */
658
+ function makeErroringPageSearchParams() {
659
+ const cacheContext = cacheContextStorage.getStore() ?? null;
660
+ const requestContext = isInsideUnifiedScope() ? getRequestContext() : null;
661
+ const promise = Promise.resolve({});
662
+ return new Proxy(promise, { get(target, prop, receiver) {
663
+ if (!Object.hasOwn(target, prop) && typeof prop === "string" && (prop === "then" || !isNextWellKnownProperty(prop))) {
664
+ const error = createUseCacheAccessError("searchParams");
665
+ if (cacheContext) cacheContext.invalidDynamicUsageError ??= error;
666
+ const activeCacheContext = cacheContextStorage.getStore();
667
+ if (activeCacheContext && activeCacheContext !== cacheContext) activeCacheContext.invalidDynamicUsageError ??= error;
668
+ if (requestContext) recordInvalidDynamicUsageError(requestContext, error);
669
+ throw error;
670
+ }
671
+ const value = Reflect.get(target, prop, receiver);
672
+ return typeof value === "function" ? value.bind(target) : value;
673
+ } });
646
674
  }
647
675
  //#endregion
648
676
  export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isUseCacheFunction, memoizeInCacheScope, registerCachedFunction, replayCachedFunction, runWithPrivateCache };
@@ -1,6 +1,6 @@
1
1
  import { ExecutionContextLike, getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
2
2
  import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
3
- import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
3
+ import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, PendingCdnTagInvalidation, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
4
4
  import { CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
5
5
  //#region src/shims/cache.d.ts
6
6
  /**
@@ -142,4 +142,4 @@ type UnstableCacheOptions = {
142
142
  */
143
143
  export declare function unstable_cache<T extends (...args: any[]) => Promise<any>>(fn: T, keyParts?: string[], options?: UnstableCacheOptions): T;
144
144
  //#endregion
145
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheLifeSink, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
145
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheLifeSink, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, PendingCdnTagInvalidation, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
@@ -3,7 +3,6 @@ import { getRequestContext, isInsideUnifiedScope } from "./unified-request-conte
3
3
  import { getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
4
4
  import { isInsideWorkStoreScope } from "./internal/work-store-scope.js";
5
5
  import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
6
- import { getCdnCacheAdapter } from "./cdn-cache.js";
7
6
  import { isStagedCacheabilityProbeActive } from "./cacheability-classification.js";
8
7
  import { MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
9
8
  import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
@@ -13,7 +12,8 @@ import { makeHangingPromise } from "./internal/make-hanging-promise.js";
13
12
  import { getHeadersAccessPhase, markDynamicUsage } from "./internal/headers-state.js";
14
13
  import { isDraftModeEnabled } from "./headers.js";
15
14
  import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
16
- import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
15
+ import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
16
+ import { isPathKnownNotEdgeCached } from "./cdn-purge-routes.js";
17
17
  //#region src/shims/cache.ts
18
18
  /**
19
19
  * next/cache shim
@@ -69,7 +69,7 @@ function revalidateTag(tag, profile) {
69
69
  if (!profile || !durations || durations.expire === 0) markActionRevalidation(1);
70
70
  const encodedTag = encodeCacheTag(tag);
71
71
  _markPendingRevalidatedTag(encodedTag);
72
- return scheduleRevalidation(_invalidateEncodedTag(encodedTag, durations));
72
+ return scheduleTagInvalidation(encodedTag, durations);
73
73
  }
74
74
  /**
75
75
  * Invalidate one already-encoded tag across both cache layers.
@@ -79,10 +79,18 @@ function revalidateTag(tag, profile) {
79
79
  * default CDN adapter), THEN ask the CDN adapter to purge its edge (a no-op for
80
80
  * the default adapter). Purging the edge before the store is invalidated would
81
81
  * let the edge re-fetch and re-cache stale data.
82
+ *
83
+ * The data cache is invalidated right away, so reads later in the same action
84
+ * see it. Inside a Server Action or Route Handler the purge waits for the
85
+ * request boundary, which sends one batched adapter call per profile.
82
86
  */
83
- async function _invalidateEncodedTag(encoded, durations) {
87
+ function scheduleTagInvalidation(encoded, durations) {
88
+ const dataInvalidation = invalidateDataCacheTag(encoded, durations);
89
+ if (_queuePendingCdnTagInvalidation(encoded, durations, dataInvalidation)) return scheduleRevalidation(dataInvalidation);
90
+ return scheduleRevalidation(dataInvalidation.then(() => _revalidateCdnTags(encoded, durations)));
91
+ }
92
+ async function invalidateDataCacheTag(encoded, durations) {
84
93
  await getDataCacheHandler().revalidateTag(encoded, durations);
85
- await getCdnCacheAdapter().revalidateTag(encoded, durations);
86
94
  }
87
95
  /**
88
96
  * Revalidate cached data associated with a specific path.
@@ -109,7 +117,8 @@ function revalidatePath(path, type) {
109
117
  const tag = type ? `_N_T_${stem}/${type}` : `_N_T_${stem || "/"}`;
110
118
  const encodedTag = encodeCacheTag(tag);
111
119
  _markPendingRevalidatedTag(encodedTag);
112
- return scheduleRevalidation(_invalidateEncodedTag(encodedTag));
120
+ if (isPathKnownNotEdgeCached(stem || "/")) return scheduleRevalidation(invalidateDataCacheTag(encodedTag));
121
+ return scheduleTagInvalidation(encodedTag);
113
122
  }
114
123
  /**
115
124
  * No-op shim for API compatibility.
@@ -140,7 +149,7 @@ function updateTag(tag) {
140
149
  markActionRevalidation(1);
141
150
  const encodedTag = encodeCacheTag(tag);
142
151
  _markPendingRevalidatedTag(encodedTag);
143
- return scheduleRevalidation(_invalidateEncodedTag(encodedTag));
152
+ return scheduleTagInvalidation(encodedTag);
144
153
  }
145
154
  /**
146
155
  * Opt out of static rendering and indicate a particular component should not be cached.
@@ -464,4 +473,4 @@ function unstable_cache(fn, keyParts, options) {
464
473
  return cachedFn;
465
474
  }
466
475
  //#endregion
467
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
476
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
@@ -0,0 +1,24 @@
1
+ //#region src/shims/cdn-purge-routes.d.ts
2
+ type CdnPurgeRoute = {
3
+ patternParts: readonly string[];
4
+ routeSegments: readonly string[];
5
+ };
6
+ type CdnPurgeRoutes = {
7
+ metadataRoutes: readonly (Omit<CdnPurgeRoute, "patternParts"> & {
8
+ patternParts: readonly string[] | null;
9
+ servedUrl: string;
10
+ })[];
11
+ routes: readonly (CdnPurgeRoute & {
12
+ forceDynamic?: boolean;
13
+ })[];
14
+ };
15
+ /** Register the App Router's routes. Apps with a Pages Router never register. */
16
+ export declare function registerCdnPurgeRoutes(routes: CdnPurgeRoutes): void;
17
+ /**
18
+ * Whether no edge-cacheable response can carry the implicit tags of
19
+ * `revalidatePath(path)`, for any `type`. Paths that need encoding, the
20
+ * `/index` alias, and paths ending in a derived tag suffix (`/docs/page` is
21
+ * also the `/docs` page tag) always purge.
22
+ */
23
+ export declare function isPathKnownNotEdgeCached(path: string): boolean;
24
+ //#endregion
@@ -0,0 +1,77 @@
1
+ import { matchRoutePatternPrefix, routePatternParts } from "../routing/route-pattern.js";
2
+ //#region src/shims/cdn-purge-routes.ts
3
+ /**
4
+ * Build-time route facts that let `revalidatePath()` skip a CDN purge no
5
+ * edge-cached response could match.
6
+ *
7
+ * Edge purges are rate limited (Workers Cache allows 5 a minute per account),
8
+ * and a `dynamic = "force-dynamic"` App route never stores a response the
9
+ * edge can serve. The check is conservative: it only skips a path when at
10
+ * least one App route could serve it and every such route is force-dynamic.
11
+ * The data cache is always invalidated.
12
+ */
13
+ const CDN_PURGE_ROUTES_KEY = Symbol.for("vinext.cdnPurgeRoutes");
14
+ const globals = globalThis;
15
+ const DERIVED_TAG_SUFFIXES = /* @__PURE__ */ new Set([
16
+ "layout",
17
+ "page",
18
+ "route"
19
+ ]);
20
+ /** Register the App Router's routes. Apps with a Pages Router never register. */
21
+ function registerCdnPurgeRoutes(routes) {
22
+ globals[CDN_PURGE_ROUTES_KEY] = routes;
23
+ }
24
+ /** Whether some URL matched by `patternParts` starts with `pathParts`. */
25
+ function canServeUnder(pathParts, patternParts) {
26
+ const last = patternParts.at(-1) ?? "";
27
+ const endsInCatchAll = last.startsWith(":") && (last.endsWith("+") || last.endsWith("*"));
28
+ if (patternParts.length < pathParts.length && !endsInCatchAll) return false;
29
+ return matchRoutePatternPrefix(pathParts, patternParts.slice(0, pathParts.length));
30
+ }
31
+ /**
32
+ * Whether a response from `route` could carry a `revalidatePath(path)` tag.
33
+ * Implicit tags use either the URL (`/blog/a`) or the route's segments
34
+ * (`/(site)/blog/[slug]`), so check both as prefixes.
35
+ */
36
+ function couldCarryPathTag(pathParts, route) {
37
+ return canServeUnder(pathParts, route.patternParts) || canServeUnder(pathParts, routePatternParts(route.routeSegments.join("/")));
38
+ }
39
+ /**
40
+ * Whether a metadata route, or a child it generates (`/icon/small` from
41
+ * `generateImageMetadata`, `/sitemap/0.xml` from `generateSitemaps`), could
42
+ * carry a `revalidatePath(path)` tag.
43
+ */
44
+ function metadataCouldCarryPathTag(pathParts, route) {
45
+ const patternParts = route.patternParts ?? routePatternParts(route.servedUrl);
46
+ const childParts = [
47
+ ...patternParts.slice(0, -1),
48
+ (patternParts.at(-1) ?? "").replace(/\.[^.]*$/, ""),
49
+ ":children*"
50
+ ];
51
+ return couldCarryPathTag(pathParts, {
52
+ patternParts,
53
+ routeSegments: route.routeSegments
54
+ }) || canServeUnder(pathParts, childParts);
55
+ }
56
+ /**
57
+ * Whether no edge-cacheable response can carry the implicit tags of
58
+ * `revalidatePath(path)`, for any `type`. Paths that need encoding, the
59
+ * `/index` alias, and paths ending in a derived tag suffix (`/docs/page` is
60
+ * also the `/docs` page tag) always purge.
61
+ */
62
+ function isPathKnownNotEdgeCached(path) {
63
+ const registered = globals[CDN_PURGE_ROUTES_KEY];
64
+ if (!registered || path === "/index" || /[^\x21-\x7e]|%/.test(path)) return false;
65
+ const pathParts = path.split("/").filter(Boolean);
66
+ if (DERIVED_TAG_SUFFIXES.has(pathParts.at(-1) ?? "")) return false;
67
+ if (registered.metadataRoutes.some((route) => metadataCouldCarryPathTag(pathParts, route))) return false;
68
+ let matched = false;
69
+ for (const route of registered.routes) {
70
+ if (!couldCarryPathTag(pathParts, route)) continue;
71
+ if (route.forceDynamic !== true) return false;
72
+ matched = true;
73
+ }
74
+ return matched;
75
+ }
76
+ //#endregion
77
+ export { isPathKnownNotEdgeCached, registerCdnPurgeRoutes };
@@ -52,13 +52,26 @@ function normalizeDynamicOptions(dynamicInput, options) {
52
52
  ...options
53
53
  };
54
54
  }
55
- function createLazyComponent(loader) {
56
- return React.lazy(async () => {
55
+ function createLazyComponent(loader, share = (load) => load) {
56
+ return React.lazy(() => share((async () => {
57
57
  const mod = await loader();
58
58
  if (hasDefaultExport(mod)) return mod;
59
59
  return { default: mod };
60
- });
60
+ })()));
61
61
  }
62
+ const SHARE_ISOLATE_PROMISE_KEY = Symbol.for("vinext.shareIsolatePromise");
63
+ /**
64
+ * The server React.lazy is created once per dynamic() call, so every request
65
+ * in the isolate renders the same load. On Workers, the request that starts it
66
+ * owns its I/O; if that request is canceled first, the load never settles and
67
+ * every later render of the component hangs. The server installs
68
+ * `shareIsolatePromise` on a global symbol, which keeps the starting request
69
+ * alive until the load settles, without this shim importing request state.
70
+ */
71
+ const shareServerLoad = (load) => {
72
+ const share = globalThis[SHARE_ISOLATE_PROMISE_KEY];
73
+ return share ? share(load) : load;
74
+ };
62
75
  function useRetryableLazyComponent(loader, initialLazyComponent) {
63
76
  const [LazyComponent, setLazyComponent] = React.useState(() => initialLazyComponent);
64
77
  const [retryKey, setRetryKey] = React.useState(0);
@@ -218,7 +231,7 @@ function dynamic(dynamicInput, options) {
218
231
  AsyncServerDynamic.displayName = "DynamicAsyncServer";
219
232
  return AsyncServerDynamic;
220
233
  }
221
- const LazyServer = createLazyComponent(loader);
234
+ const LazyServer = createLazyComponent(loader, shareServerLoad);
222
235
  const ServerDynamic = (props) => {
223
236
  const isAppRouterTree = useIsAppRouterTree();
224
237
  const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps()) : null;
@@ -8,7 +8,7 @@ import { withBasePath } from "./url-utils.js";
8
8
  import { AppElementsWire } from "../server/app-elements-wire.js";
9
9
  import "../server/app-elements.js";
10
10
  import { createRscRequestHeaders, createRscRequestUrl } from "../server/app-rsc-cache-busting.js";
11
- import { hasAppNavigationRuntime } from "../client/navigation-runtime.js";
11
+ import { hasAppNavigationRuntime, loadNavigationRuntimeRouteManifest } from "../client/navigation-runtime.js";
12
12
  import { getMountedSlotsHeader, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, navigateClientSide, prefetchRscResponse } from "./navigation.js";
13
13
  import { useMergedRef } from "./use-merged-ref.js";
14
14
  import { forwardRef, useActionState, useCallback, useEffect, useRef } from "react";
@@ -145,14 +145,19 @@ const Form = forwardRef(function Form(props, ref) {
145
145
  for (const entry of entries) if (entry.isIntersecting || entry.intersectionRatio > 0) {
146
146
  (async () => {
147
147
  if (isBotUserAgent(window.navigator?.userAgent ?? "")) return;
148
- const interceptionContext = getPrefetchInterceptionContext(actionHref);
148
+ const currentPathname = window.location.pathname;
149
+ const resolvedAction = new URL(actionHref, window.location.href);
150
+ const prefetchHref = resolvedAction.pathname + resolvedAction.search;
149
151
  const mountedSlotsHeader = getMountedSlotsHeader();
152
+ const routeManifestLoad = loadNavigationRuntimeRouteManifest();
153
+ if (routeManifestLoad !== null && !await routeManifestLoad) return;
154
+ const interceptionContext = getPrefetchInterceptionContext(prefetchHref, currentPathname);
150
155
  const headers = createRscRequestHeaders({
151
156
  interceptionContext,
152
157
  renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
153
158
  });
154
159
  if (mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
155
- const rscUrl = await createRscRequestUrl(actionHref, headers);
160
+ const rscUrl = await createRscRequestUrl(prefetchHref, headers);
156
161
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
157
162
  const prefetched = getPrefetchedUrls();
158
163
  if (prefetched.has(cacheKey)) return;
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { ImageProps, ImgProps, StaticImport } from "@vinext/types/next/upstream/dist/shared/lib/get-img-props";
3
+ //#region src/shims/image-props.d.ts
4
+ export declare const __isDev: boolean;
5
+ /**
6
+ * Whether dangerouslyAllowSVG is enabled in next.config.js.
7
+ * When false (default), .svg sources auto-skip the optimization endpoint
8
+ * and are served directly, matching Next.js behavior.
9
+ * When true, .svg sources are routed through the optimizer (served as-is
10
+ * with security headers).
11
+ */
12
+ export declare const __dangerouslyAllowSVG: boolean;
13
+ export declare const __globallyUnoptimized: boolean;
14
+ /**
15
+ * Validate that a remote URL is allowed by the configured remote patterns.
16
+ * Returns true if the URL is allowed, false otherwise.
17
+ *
18
+ * When no remotePatterns/domains are configured, all remote URLs are allowed
19
+ * (backwards-compatible — user hasn't opted into restriction).
20
+ *
21
+ * When patterns ARE configured, only matching URLs are allowed.
22
+ * In development, non-matching URLs produce a console warning.
23
+ * In production, non-matching URLs are blocked (src replaced with empty string).
24
+ *
25
+ * Private-IP hostnames are additionally rejected unless dangerouslyAllowLocalIP
26
+ * is set, mirroring Next.js's fetchExternalImage guard.
27
+ */
28
+ export declare function validateRemoteUrl(src: string): {
29
+ allowed: boolean;
30
+ reason?: string;
31
+ };
32
+ /**
33
+ * Sanitize a blurDataURL to prevent CSS injection.
34
+ *
35
+ * A crafted data URL containing `)` can break out of the `url()` CSS function,
36
+ * allowing injection of arbitrary CSS properties or rules. Characters like `{`,
37
+ * `}`, and `\` can also assist in crafting injection payloads.
38
+ *
39
+ * This validates the URL starts with `data:image/` and rejects characters that
40
+ * could escape the `url()` context. Semicolons are allowed since they're part
41
+ * of valid data URLs (`data:image/png;base64,...`) and harmless inside `url()`.
42
+ *
43
+ * Returns undefined for invalid URLs, which causes the blur placeholder to be
44
+ * skipped gracefully.
45
+ */
46
+ export declare function sanitizeBlurDataURL(url: string): string | undefined;
47
+ /**
48
+ * Determine if a src is a remote URL (CDN-optimizable) or local.
49
+ */
50
+ export declare function isRemoteUrl(src: string): boolean;
51
+ export declare function isSvgUrl(src: string): boolean;
52
+ export declare function getFillStyle(style?: React.CSSProperties, backgroundStyle?: React.CSSProperties): React.CSSProperties;
53
+ /**
54
+ * Resolve src, width, height, blurDataURL from Image props (string or StaticImageData).
55
+ * Shared by the Image component and getImageProps to keep behavior in sync.
56
+ */
57
+ export declare function resolveImageSource(v: {
58
+ src: string | StaticImport;
59
+ width?: number | `${number}`;
60
+ height?: number | `${number}`;
61
+ blurDataURL?: string;
62
+ }): {
63
+ src: string;
64
+ width?: number;
65
+ height?: number;
66
+ blurDataURL?: string;
67
+ };
68
+ /**
69
+ * Responsive image widths matching Next.js's device sizes config.
70
+ * These are the breakpoints used for srcSet generation.
71
+ * Configurable via `images.deviceSizes` in next.config.js.
72
+ */
73
+ export declare const RESPONSIVE_WIDTHS: number[];
74
+ /**
75
+ * Build a `/_next/image` optimization URL.
76
+ *
77
+ * In production (Cloudflare Workers), the worker intercepts this path and uses
78
+ * the Images binding to resize/transcode on the fly. In dev, the Vite dev
79
+ * server handles it as a passthrough (serves the original file).
80
+ */
81
+ export declare function imageOptimizationUrl(src: string, width: number, quality?: number): string;
82
+ export declare function generateImageAttributes(src: string, width: number, quality?: number, sizes?: string): {
83
+ src: string;
84
+ srcSet: string;
85
+ };
86
+ /**
87
+ * getImageProps — for advanced use cases (picture elements, background images).
88
+ * Returns the props that would be passed to the underlying <img> element.
89
+ */
90
+ export declare function getImageProps(props: ImageProps): {
91
+ props: ImgProps;
92
+ };
93
+ //#endregion