vinext 0.1.2 → 0.1.3
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.
- package/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +2 -1
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.js +73 -14
- package/dist/config/next-config.d.ts +46 -4
- package/dist/config/next-config.js +147 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +180 -99
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -5
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +53 -8
- package/dist/entries/pages-server-entry.js +41 -5
- package/dist/index.js +200 -62
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/optimize-imports.d.ts +2 -1
- package/dist/plugins/optimize-imports.js +11 -9
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/routing/app-route-graph.d.ts +2 -1
- package/dist/routing/app-route-graph.js +44 -14
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +22 -1
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +167 -90
- package/dist/server/app-browser-error.d.ts +10 -6
- package/dist/server/app-browser-error.js +43 -8
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +4 -2
- package/dist/server/app-browser-navigation-controller.js +23 -2
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -0
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-optimistic-routing.js +2 -2
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +27 -14
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +62 -1
- package/dist/server/app-page-dispatch.d.ts +26 -0
- package/dist/server/app-page-dispatch.js +149 -92
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +5 -2
- package/dist/server/app-page-execution.d.ts +6 -1
- package/dist/server/app-page-execution.js +21 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +12 -1
- package/dist/server/app-page-render.js +42 -4
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +14 -5
- package/dist/server/app-page-stream.d.ts +15 -3
- package/dist/server/app-page-stream.js +11 -5
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +154 -54
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +42 -13
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +83 -10
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +244 -51
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/navigation-planner.d.ts +133 -30
- package/dist/server/navigation-planner.js +114 -0
- package/dist/server/navigation-trace.d.ts +8 -1
- package/dist/server/navigation-trace.js +8 -1
- package/dist/server/pages-api-route.d.ts +6 -0
- package/dist/server/pages-api-route.js +13 -2
- package/dist/server/pages-asset-tags.d.ts +2 -1
- package/dist/server/pages-asset-tags.js +6 -2
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +11 -2
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.js +2 -2
- package/dist/server/pages-page-data.d.ts +11 -2
- package/dist/server/pages-page-data.js +204 -33
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +59 -22
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +7 -4
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +73 -36
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.js +9 -3
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +3 -2
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.js +6 -4
- package/dist/shims/error-boundary.d.ts +2 -0
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +3 -2
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +45 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/headers.js +29 -4
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.js +8 -17
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +61 -31
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +419 -128
- package/dist/shims/server.d.ts +16 -1
- package/dist/shims/server.js +44 -12
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +7 -1
- package/dist/utils/path.js +9 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -40,6 +40,7 @@ type FetchCacheState = {
|
|
|
40
40
|
currentRequestTags: string[];
|
|
41
41
|
currentFetchSoftTags: string[];
|
|
42
42
|
currentFetchCacheMode: FetchCacheMode | null;
|
|
43
|
+
currentForceDynamicFetchDefault: boolean;
|
|
43
44
|
dynamicFetchUrls: Set<string>;
|
|
44
45
|
isFetchDedupeActive: boolean;
|
|
45
46
|
currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
|
|
@@ -84,6 +85,7 @@ declare function setCurrentFetchSoftTags(tags: string[]): void;
|
|
|
84
85
|
*/
|
|
85
86
|
declare function getCurrentFetchSoftTags(): string[];
|
|
86
87
|
declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
|
|
88
|
+
declare function setCurrentForceDynamicFetchDefault(enabled: boolean): void;
|
|
87
89
|
/**
|
|
88
90
|
* Install the patched fetch and reset per-request tag state.
|
|
89
91
|
* Returns a cleanup function that clears tags.
|
|
@@ -131,4 +133,4 @@ declare function ensureFetchPatch(): void;
|
|
|
131
133
|
*/
|
|
132
134
|
declare function getOriginalFetch(): typeof globalThis.fetch;
|
|
133
135
|
//#endregion
|
|
134
|
-
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
|
136
|
+
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
2
|
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
3
|
import { getRequestExecutionContext } from "./request-context.js";
|
|
4
|
+
import { markDynamicUsage } from "./headers.js";
|
|
4
5
|
import { encodeCacheTags } from "../utils/encode-cache-tag.js";
|
|
5
6
|
import { getDataCacheHandler } from "./cache.js";
|
|
6
7
|
//#region src/shims/fetch-cache.ts
|
|
@@ -32,6 +33,7 @@ import { getDataCacheHandler } from "./cache.js";
|
|
|
32
33
|
const HEADER_BLOCKLIST = ["traceparent", "tracestate"];
|
|
33
34
|
const CACHE_KEY_PREFIX = "v3";
|
|
34
35
|
const MAX_CACHE_KEY_BODY_BYTES = 1024 * 1024;
|
|
36
|
+
const ONE_YEAR_SECONDS = 31536e3;
|
|
35
37
|
var BodyTooLargeForCacheKeyError = class extends Error {
|
|
36
38
|
constructor() {
|
|
37
39
|
super("Fetch body too large for cache key generation");
|
|
@@ -292,6 +294,7 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
|
|
|
292
294
|
currentRequestTags: [],
|
|
293
295
|
currentFetchSoftTags: [],
|
|
294
296
|
currentFetchCacheMode: null,
|
|
297
|
+
currentForceDynamicFetchDefault: false,
|
|
295
298
|
dynamicFetchUrls: /* @__PURE__ */ new Set(),
|
|
296
299
|
isFetchDedupeActive: false,
|
|
297
300
|
currentFetchDedupeEntries: /* @__PURE__ */ new Map()
|
|
@@ -309,6 +312,7 @@ function _resetFallbackState(isFetchDedupeActive) {
|
|
|
309
312
|
_fallbackState.currentRequestTags = [];
|
|
310
313
|
_fallbackState.currentFetchSoftTags = [];
|
|
311
314
|
_fallbackState.currentFetchCacheMode = null;
|
|
315
|
+
_fallbackState.currentForceDynamicFetchDefault = false;
|
|
312
316
|
_fallbackState.dynamicFetchUrls = /* @__PURE__ */ new Set();
|
|
313
317
|
_fallbackState.isFetchDedupeActive = isFetchDedupeActive;
|
|
314
318
|
_fallbackState.currentFetchDedupeEntries = /* @__PURE__ */ new Map();
|
|
@@ -319,6 +323,10 @@ function getFetchObservationUrl(input) {
|
|
|
319
323
|
function recordDynamicFetchObservation(input) {
|
|
320
324
|
_getState().dynamicFetchUrls.add(getFetchObservationUrl(input));
|
|
321
325
|
}
|
|
326
|
+
function markUncachedFetchForPageOutput(input) {
|
|
327
|
+
recordDynamicFetchObservation(input);
|
|
328
|
+
markDynamicUsage();
|
|
329
|
+
}
|
|
322
330
|
function recordCacheableFetchObservation(input) {
|
|
323
331
|
_getState().cacheableFetchUrls.add(getFetchObservationUrl(input));
|
|
324
332
|
}
|
|
@@ -382,16 +390,23 @@ function getCurrentFetchSoftTags() {
|
|
|
382
390
|
function setCurrentFetchCacheMode(mode) {
|
|
383
391
|
_getState().currentFetchCacheMode = mode;
|
|
384
392
|
}
|
|
393
|
+
function setCurrentForceDynamicFetchDefault(enabled) {
|
|
394
|
+
_getState().currentForceDynamicFetchDefault = enabled;
|
|
395
|
+
}
|
|
385
396
|
function isNoStoreFetch(cacheDirective, nextOpts) {
|
|
386
|
-
return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate ===
|
|
397
|
+
return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0;
|
|
387
398
|
}
|
|
388
399
|
function isCacheableFetch(cacheDirective, nextOpts) {
|
|
389
|
-
return cacheDirective === "force-cache" || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0;
|
|
400
|
+
return cacheDirective === "force-cache" || nextOpts?.revalidate === false || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0;
|
|
390
401
|
}
|
|
391
402
|
function hasExplicitRevalidateValue(nextOpts) {
|
|
392
403
|
return nextOpts?.revalidate !== void 0;
|
|
393
404
|
}
|
|
394
|
-
function
|
|
405
|
+
function isFalsyRevalidate(nextOpts) {
|
|
406
|
+
return !nextOpts?.revalidate;
|
|
407
|
+
}
|
|
408
|
+
function resolveSegmentCacheDirective(cacheDirective, nextOpts, mode, forceDynamicFetchDefault) {
|
|
409
|
+
if (forceDynamicFetchDefault && (!mode || mode === "auto") && (cacheDirective === void 0 || cacheDirective === "default") && isFalsyRevalidate(nextOpts)) return "no-store";
|
|
395
410
|
if (!mode || mode === "auto") return cacheDirective;
|
|
396
411
|
switch (mode) {
|
|
397
412
|
case "force-cache": return "force-cache";
|
|
@@ -457,6 +472,20 @@ function cloneDedupeResponse(response) {
|
|
|
457
472
|
const [body1, body2] = response.body.tee();
|
|
458
473
|
return [buildDedupeClone(body1, response), buildDedupeClone(body2, response)];
|
|
459
474
|
}
|
|
475
|
+
function buildCachedFetchResponse(data, input) {
|
|
476
|
+
const response = new Response(data.body, {
|
|
477
|
+
status: data.status ?? 200,
|
|
478
|
+
headers: data.headers
|
|
479
|
+
});
|
|
480
|
+
Object.defineProperty(response, "url", {
|
|
481
|
+
value: data.url ?? getFetchObservationUrl(input),
|
|
482
|
+
configurable: true,
|
|
483
|
+
enumerable: true,
|
|
484
|
+
writable: false
|
|
485
|
+
});
|
|
486
|
+
if (_responseBodyRegistry && response.body) _responseBodyRegistry.register(response, new WeakRef(response.body));
|
|
487
|
+
return response;
|
|
488
|
+
}
|
|
460
489
|
function dedupeFetch(input, init) {
|
|
461
490
|
const state = _getState();
|
|
462
491
|
if (!state.isFetchDedupeActive) return originalFetch(input, init);
|
|
@@ -507,25 +536,26 @@ function dedupeFetch(input, init) {
|
|
|
507
536
|
function createPatchedFetch() {
|
|
508
537
|
return async function patchedFetch(input, init) {
|
|
509
538
|
const nextOpts = init?.next;
|
|
510
|
-
const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode);
|
|
539
|
+
const cacheDirective = resolveSegmentCacheDirective(getFetchCacheDirective(input, init), nextOpts, _getState().currentFetchCacheMode, _getState().currentForceDynamicFetchDefault);
|
|
511
540
|
if (!nextOpts && !cacheDirective) {
|
|
512
541
|
recordDynamicFetchObservation(input);
|
|
513
542
|
return dedupeFetch(input, init);
|
|
514
543
|
}
|
|
515
|
-
if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate ===
|
|
544
|
+
if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0) {
|
|
516
545
|
const cleanInit = stripNextFromInit(init, cacheDirective);
|
|
517
|
-
|
|
546
|
+
markUncachedFetchForPageOutput(input);
|
|
518
547
|
return dedupeFetch(input, cleanInit);
|
|
519
548
|
}
|
|
520
|
-
if (!(cacheDirective === "force-cache" || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) && hasAuthHeaders(input, init)) {
|
|
549
|
+
if (!(cacheDirective === "force-cache" || nextOpts?.revalidate === false || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) && hasAuthHeaders(input, init)) {
|
|
521
550
|
const cleanInit = stripNextFromInit(init, cacheDirective);
|
|
522
551
|
recordDynamicFetchObservation(input);
|
|
523
552
|
return dedupeFetch(input, cleanInit);
|
|
524
553
|
}
|
|
525
554
|
let revalidateSeconds;
|
|
526
|
-
if (cacheDirective === "force-cache") revalidateSeconds = nextOpts?.revalidate && typeof nextOpts.revalidate === "number" ? nextOpts.revalidate :
|
|
555
|
+
if (cacheDirective === "force-cache") revalidateSeconds = nextOpts?.revalidate && typeof nextOpts.revalidate === "number" ? nextOpts.revalidate : ONE_YEAR_SECONDS;
|
|
556
|
+
else if (nextOpts?.revalidate === false) revalidateSeconds = ONE_YEAR_SECONDS;
|
|
527
557
|
else if (typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) revalidateSeconds = nextOpts.revalidate;
|
|
528
|
-
else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds =
|
|
558
|
+
else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = ONE_YEAR_SECONDS;
|
|
529
559
|
else {
|
|
530
560
|
const cleanInit = stripNextFromInit(init, cacheDirective);
|
|
531
561
|
recordDynamicFetchObservation(input);
|
|
@@ -560,10 +590,7 @@ function createPatchedFetch() {
|
|
|
560
590
|
});
|
|
561
591
|
if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState !== "stale") {
|
|
562
592
|
const cachedData = cached.value.data;
|
|
563
|
-
return
|
|
564
|
-
status: cachedData.status ?? 200,
|
|
565
|
-
headers: cachedData.headers
|
|
566
|
-
});
|
|
593
|
+
return buildCachedFetchResponse(cachedData, input);
|
|
567
594
|
}
|
|
568
595
|
if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState === "stale") {
|
|
569
596
|
const staleData = cached.value.data;
|
|
@@ -581,7 +608,7 @@ function createPatchedFetch() {
|
|
|
581
608
|
data: {
|
|
582
609
|
headers: freshHeaders,
|
|
583
610
|
body: freshBody,
|
|
584
|
-
url:
|
|
611
|
+
url: freshResp.url,
|
|
585
612
|
status: freshResp.status
|
|
586
613
|
},
|
|
587
614
|
tags,
|
|
@@ -605,10 +632,7 @@ function createPatchedFetch() {
|
|
|
605
632
|
}, DEDUP_TIMEOUT_MS);
|
|
606
633
|
getRequestExecutionContext()?.waitUntil(refetchPromise);
|
|
607
634
|
}
|
|
608
|
-
return
|
|
609
|
-
status: staleData.status ?? 200,
|
|
610
|
-
headers: staleData.headers
|
|
611
|
-
});
|
|
635
|
+
return buildCachedFetchResponse(staleData, input);
|
|
612
636
|
}
|
|
613
637
|
} catch (cacheErr) {
|
|
614
638
|
console.error("[vinext] fetch cache read error:", cacheErr);
|
|
@@ -627,7 +651,7 @@ function createPatchedFetch() {
|
|
|
627
651
|
data: {
|
|
628
652
|
headers,
|
|
629
653
|
body,
|
|
630
|
-
url:
|
|
654
|
+
url: response.url,
|
|
631
655
|
status: cloned.status
|
|
632
656
|
},
|
|
633
657
|
tags,
|
|
@@ -700,6 +724,7 @@ async function runWithFetchCache(fn) {
|
|
|
700
724
|
currentRequestTags: [],
|
|
701
725
|
currentFetchSoftTags: [],
|
|
702
726
|
currentFetchCacheMode: null,
|
|
727
|
+
currentForceDynamicFetchDefault: false,
|
|
703
728
|
dynamicFetchUrls: /* @__PURE__ */ new Set(),
|
|
704
729
|
isFetchDedupeActive: true,
|
|
705
730
|
currentFetchDedupeEntries: /* @__PURE__ */ new Map()
|
|
@@ -738,4 +763,4 @@ function getOriginalFetch() {
|
|
|
738
763
|
return originalFetch;
|
|
739
764
|
}
|
|
740
765
|
//#endregion
|
|
741
|
-
export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, withFetchCache };
|
|
766
|
+
export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
|
|
@@ -17,7 +17,12 @@ function scrollToHashTarget(hash) {
|
|
|
17
17
|
idElement.scrollIntoView({ behavior: "auto" });
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
document.getElementsByName(fragment)[0]
|
|
20
|
+
const namedElement = document.getElementsByName(fragment)[0];
|
|
21
|
+
if (namedElement) {
|
|
22
|
+
namedElement.scrollIntoView({ behavior: "auto" });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
window.scrollTo(0, 0);
|
|
21
26
|
}
|
|
22
27
|
function scrollToHashTargetOnNextFrame(hash) {
|
|
23
28
|
requestAnimationFrame(() => {
|
package/dist/shims/headers.js
CHANGED
|
@@ -3,7 +3,8 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
|
|
|
3
3
|
import { MIDDLEWARE_SET_COOKIE_HEADER } from "../server/headers.js";
|
|
4
4
|
import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
|
|
5
5
|
import { serializeSetCookie, validateCookieAttributeValue, validateCookieName } from "./internal/cookie-serialize.js";
|
|
6
|
-
import {
|
|
6
|
+
import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
|
|
7
|
+
import { createPprFallbackShellSuspensePromise } from "./ppr-fallback-shell.js";
|
|
7
8
|
//#region src/shims/headers.ts
|
|
8
9
|
/**
|
|
9
10
|
* next/headers shim
|
|
@@ -81,7 +82,7 @@ function setCookieNameValue(setCookie) {
|
|
|
81
82
|
function rebuildCookiesFromHeader(ctx, cookieHeader) {
|
|
82
83
|
ctx.cookies.clear();
|
|
83
84
|
if (cookieHeader === null) return;
|
|
84
|
-
const nextCookies =
|
|
85
|
+
const nextCookies = parseEdgeRequestCookieHeader(cookieHeader);
|
|
85
86
|
for (const [name, value] of nextCookies) ctx.cookies.set(name, value);
|
|
86
87
|
}
|
|
87
88
|
function mergeMiddlewareSetCookies(ctx, rawHeader) {
|
|
@@ -414,6 +415,26 @@ function _decorateRejectedRequestApiPromise(error) {
|
|
|
414
415
|
throw normalizedError;
|
|
415
416
|
} }));
|
|
416
417
|
}
|
|
418
|
+
function _decorateSuspendingRequestApiPromise(promise) {
|
|
419
|
+
return new Proxy(promise, {
|
|
420
|
+
get(promiseTarget, prop) {
|
|
421
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
422
|
+
const value = Reflect.get(promiseTarget, prop, promiseTarget);
|
|
423
|
+
return typeof value === "function" ? value.bind(promiseTarget) : value;
|
|
424
|
+
}
|
|
425
|
+
throw promise;
|
|
426
|
+
},
|
|
427
|
+
getOwnPropertyDescriptor() {
|
|
428
|
+
throw promise;
|
|
429
|
+
},
|
|
430
|
+
has() {
|
|
431
|
+
throw promise;
|
|
432
|
+
},
|
|
433
|
+
ownKeys() {
|
|
434
|
+
throw promise;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
417
438
|
function _sealHeaders(headers) {
|
|
418
439
|
return new Proxy(headers, { get(target, prop) {
|
|
419
440
|
if (typeof prop === "string" && _HEADERS_MUTATING_METHODS.has(prop)) throw new ReadonlyHeadersError();
|
|
@@ -485,7 +506,7 @@ function headersContextFromRequest(request, options) {
|
|
|
485
506
|
let _cookies = null;
|
|
486
507
|
function getCookies() {
|
|
487
508
|
if (_cookies) return _cookies;
|
|
488
|
-
_cookies =
|
|
509
|
+
_cookies = parseEdgeRequestCookieHeader(headersProxy.get("cookie") || "");
|
|
489
510
|
return _cookies;
|
|
490
511
|
}
|
|
491
512
|
return {
|
|
@@ -512,6 +533,8 @@ function headers() {
|
|
|
512
533
|
if (!state.headersContext) return _decorateRejectedRequestApiPromise(/* @__PURE__ */ new Error("headers() can only be called from a Server Component, Route Handler, or Server Action. Make sure you're not calling it from a Client Component."));
|
|
513
534
|
if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
|
|
514
535
|
markDynamicUsage();
|
|
536
|
+
const fallbackShellPromise = createPprFallbackShellSuspensePromise("`headers()`");
|
|
537
|
+
if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
|
|
515
538
|
return _getOrCreateDecoratedRequestApiPromise(_decoratedHeadersPromises, _getReadonlyHeaders(state.headersContext));
|
|
516
539
|
}
|
|
517
540
|
/**
|
|
@@ -529,6 +552,8 @@ function cookies() {
|
|
|
529
552
|
if (!state.headersContext) return _decorateRejectedRequestApiPromise(/* @__PURE__ */ new Error("cookies() can only be called from a Server Component, Route Handler, or Server Action."));
|
|
530
553
|
if (state.headersContext.accessError) return _decorateRejectedRequestApiPromise(state.headersContext.accessError);
|
|
531
554
|
markDynamicUsage();
|
|
555
|
+
const fallbackShellPromise = createPprFallbackShellSuspensePromise("`cookies()`");
|
|
556
|
+
if (fallbackShellPromise) return _decorateSuspendingRequestApiPromise(fallbackShellPromise);
|
|
532
557
|
return _getOrCreateDecoratedRequestApiPromise(_decoratedCookiesPromises, _areCookiesMutableInCurrentPhase() ? _getMutableCookies(state.headersContext) : _getReadonlyCookies(state.headersContext));
|
|
533
558
|
}
|
|
534
559
|
/** Accumulated Set-Cookie headers from cookies().set() / .delete() calls */
|
|
@@ -572,7 +597,7 @@ function ensureContextDraftModeSecret(ctx) {
|
|
|
572
597
|
function isDraftModeRequest(request, draftModeSecret) {
|
|
573
598
|
const cookieHeader = request.headers.get("cookie");
|
|
574
599
|
if (!cookieHeader) return false;
|
|
575
|
-
return
|
|
600
|
+
return parseEdgeRequestCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
|
|
576
601
|
}
|
|
577
602
|
function draftModeCookieAttributes() {
|
|
578
603
|
if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return "Path=/; HttpOnly; SameSite=Lax";
|
|
@@ -38,6 +38,33 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
38
38
|
*/
|
|
39
39
|
const _g = globalThis;
|
|
40
40
|
/**
|
|
41
|
+
* No-op AsyncLocalStorage used when the runtime does not provide a usable
|
|
42
|
+
* `AsyncLocalStorage` constructor.
|
|
43
|
+
*
|
|
44
|
+
* In browser/client bundles `node:async_hooks` can resolve to a stub without a
|
|
45
|
+
* usable constructor (e.g. Vite's `__vite-browser-external`). Constructing such
|
|
46
|
+
* a value with `new` throws `TypeError: AsyncLocalStorage is not a constructor`
|
|
47
|
+
* at module-eval time, crashing every client-reachable shim that calls
|
|
48
|
+
* `getOrCreateAls` on import (request-context, headers, cache, …).
|
|
49
|
+
*
|
|
50
|
+
* Mirrors Next.js' `FakeAsyncLocalStorage` (and this repo's
|
|
51
|
+
* `async-hooks-stub.ts` client virtual module): `getStore()` returns
|
|
52
|
+
* `undefined` so shims fall back to their non-ALS code path, and the mutating
|
|
53
|
+
* methods are best-effort no-ops that still invoke the callback.
|
|
54
|
+
* See: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/async-local-storage.ts
|
|
55
|
+
*/
|
|
56
|
+
var NoopAsyncLocalStorage = class {
|
|
57
|
+
getStore() {}
|
|
58
|
+
run(_store, fn, ...args) {
|
|
59
|
+
return fn(...args);
|
|
60
|
+
}
|
|
61
|
+
exit(fn, ...args) {
|
|
62
|
+
return fn(...args);
|
|
63
|
+
}
|
|
64
|
+
enterWith(_store) {}
|
|
65
|
+
disable() {}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
41
68
|
* Get (or lazily create) the AsyncLocalStorage registered on `globalThis`
|
|
42
69
|
* under `Symbol.for(key)`. Multiple callers — including callers in different
|
|
43
70
|
* module instances — that pass the same `key` receive the same ALS instance.
|
|
@@ -47,7 +74,7 @@ const _g = globalThis;
|
|
|
47
74
|
*/
|
|
48
75
|
function getOrCreateAls(key) {
|
|
49
76
|
const sym = Symbol.for(key);
|
|
50
|
-
return _g[sym] ??= new AsyncLocalStorage();
|
|
77
|
+
return _g[sym] ??= typeof AsyncLocalStorage === "function" ? new AsyncLocalStorage() : new NoopAsyncLocalStorage();
|
|
51
78
|
}
|
|
52
79
|
//#endregion
|
|
53
80
|
export { getOrCreateAls };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { removeTrailingSlash, stripBasePath } from "../../utils/base-path.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getLocalePathPrefix } from "../../utils/domain-locale.js";
|
|
3
|
+
import { resolveHybridClientRouteOwner } from "./hybrid-client-route-owner.js";
|
|
3
4
|
//#region src/shims/internal/app-route-detection.ts
|
|
4
|
-
const appRouteTrieCache = createRouteTrieCache();
|
|
5
5
|
const _COMPONENTS_KEY = Symbol.for("vinext.pagesRouter.components");
|
|
6
6
|
/**
|
|
7
7
|
* Get-or-create the Pages Router `components` map. Returns the same object
|
|
@@ -32,20 +32,11 @@ function resolveSameOriginPathname(href, basePath) {
|
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
34
|
if (url.origin !== window.location.origin) return null;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* absent (Pages-Router-only build), the URL is external, or no route matches.
|
|
41
|
-
*/
|
|
42
|
-
function matchesAppRoute(href, basePath) {
|
|
43
|
-
if (typeof window === "undefined") return false;
|
|
44
|
-
const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
|
|
45
|
-
if (!routes || routes.length === 0) return false;
|
|
46
|
-
const pathname = resolveSameOriginPathname(href, basePath);
|
|
47
|
-
if (pathname === null) return false;
|
|
48
|
-
return matchRouteWithTrie(pathname, routes, appRouteTrieCache) !== null;
|
|
35
|
+
const pathname = stripBasePath(url.pathname, basePath);
|
|
36
|
+
const locale = getLocalePathPrefix(pathname, window.__VINEXT_LOCALES__);
|
|
37
|
+
if (!locale) return pathname;
|
|
38
|
+
const localePrefixLength = locale.length + 1;
|
|
39
|
+
return pathname.length === localePrefixLength ? "/" : pathname.slice(localePrefixLength);
|
|
49
40
|
}
|
|
50
41
|
/**
|
|
51
42
|
* Record `components[pathname] = { __appRouter: true }` on the shared
|
|
@@ -61,7 +52,7 @@ function matchesAppRoute(href, basePath) {
|
|
|
61
52
|
*/
|
|
62
53
|
function markAppRouteDetectedOnPrefetch(href, basePath) {
|
|
63
54
|
if (typeof window === "undefined") return;
|
|
64
|
-
if (
|
|
55
|
+
if (resolveHybridClientRouteOwner(href, basePath) !== "app") return;
|
|
65
56
|
const rawPathname = resolveSameOriginPathname(href, basePath);
|
|
66
57
|
if (rawPathname === null) return;
|
|
67
58
|
const pathname = removeTrailingSlash(rawPathname);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { NextRewrite } from "../../config/next-config.js";
|
|
2
|
+
import { VinextLinkPrefetchRoute, VinextPagesLinkPrefetchRoute } from "../../client/vinext-next-data.js";
|
|
3
|
+
|
|
4
|
+
//#region src/shims/internal/hybrid-client-route-owner.d.ts
|
|
5
|
+
type HybridClientOwner = "app" | "document" | "pages";
|
|
6
|
+
declare global {
|
|
7
|
+
interface Window {
|
|
8
|
+
__VINEXT_LINK_PREFETCH_ROUTES__?: VinextLinkPrefetchRoute[];
|
|
9
|
+
__VINEXT_PAGES_LINK_PREFETCH_ROUTES__?: VinextPagesLinkPrefetchRoute[];
|
|
10
|
+
__VINEXT_CLIENT_REWRITES__?: {
|
|
11
|
+
afterFiles: NextRewrite[];
|
|
12
|
+
beforeFiles: NextRewrite[];
|
|
13
|
+
fallback: NextRewrite[];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Decide which router should own a soft-navigated URL. Returns:
|
|
19
|
+
* - "app" → the App Router runtime handles the navigation (RSC fetch).
|
|
20
|
+
* - "pages" → Pages owns the URL; the caller must hard-navigate instead.
|
|
21
|
+
* - null → no router matched (preserves the existing 404 path).
|
|
22
|
+
*
|
|
23
|
+
* `basePath` must match what the page uses (typically `process.env.__NEXT_ROUTER_BASEPATH`).
|
|
24
|
+
*
|
|
25
|
+
* The lookup uses the App and Pages manifests on `window` so the same
|
|
26
|
+
* matcher trie produces the same result the server will see when the
|
|
27
|
+
* request lands.
|
|
28
|
+
*/
|
|
29
|
+
declare function resolveHybridClientRouteOwner(href: string, basePath: string): HybridClientOwner | null;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { HybridClientOwner, resolveHybridClientRouteOwner };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { compareHybridRoutePatterns } from "../../routing/utils.js";
|
|
2
|
+
import { stripBasePath } from "../../utils/base-path.js";
|
|
3
|
+
import { createRouteTrieCache, matchRouteWithTrie } from "../../routing/route-matching.js";
|
|
4
|
+
import { isExternalUrl, matchRewrite, parseCookies } from "../../config/config-matchers.js";
|
|
5
|
+
import { getLocalePathPrefix } from "../../utils/domain-locale.js";
|
|
6
|
+
import { mergeRewriteQuery } from "../../utils/query.js";
|
|
7
|
+
//#region src/shims/internal/hybrid-client-route-owner.ts
|
|
8
|
+
/**
|
|
9
|
+
* Client-side resolver that decides whether a URL should be soft-navigated
|
|
10
|
+
* (App Router / RSC) or hard-navigated (Pages Router / document). Delegates
|
|
11
|
+
* the owner decision to `compareHybridRoutePatterns` in `routing/utils.ts`
|
|
12
|
+
* so the server and the client reach the same answer for the same
|
|
13
|
+
* (pages pattern, app pattern) pair.
|
|
14
|
+
*
|
|
15
|
+
* Lives in `shims/internal/` because both `link.tsx` and the App Router
|
|
16
|
+
* browser entry import it without pulling in the server route graph.
|
|
17
|
+
*
|
|
18
|
+
* The App + Pages route manifests are emitted once per page load by the
|
|
19
|
+
* Vite plugin onto the matching `__VINEXT_*_PREFETCH_ROUTES__` window
|
|
20
|
+
* globals (see `entries/app-browser-entry.ts` and
|
|
21
|
+
* `entries/pages-client-entry.ts`). Hybrid builds expose both globals; a
|
|
22
|
+
* single-router build only sets its own.
|
|
23
|
+
*/
|
|
24
|
+
function resolveClientRewrite(href, basePath, rewrites, continueAfterMatch = false) {
|
|
25
|
+
const initialUrl = new URL(href, window.location.href);
|
|
26
|
+
const basePathState = {
|
|
27
|
+
basePath,
|
|
28
|
+
hadBasePath: basePath ? initialUrl.pathname === basePath || initialUrl.pathname.startsWith(`${basePath}/`) : true
|
|
29
|
+
};
|
|
30
|
+
let currentHref = href;
|
|
31
|
+
let matched = false;
|
|
32
|
+
for (const rewrite of rewrites) {
|
|
33
|
+
const pathname = resolveSameOriginPathname(currentHref, basePath);
|
|
34
|
+
if (pathname === null) return null;
|
|
35
|
+
const url = new URL(currentHref, window.location.href);
|
|
36
|
+
const headers = new Headers({ "user-agent": globalThis.navigator?.userAgent ?? "" });
|
|
37
|
+
const context = {
|
|
38
|
+
cookies: parseCookies(globalThis.document?.cookie ?? ""),
|
|
39
|
+
headers,
|
|
40
|
+
host: url.hostname,
|
|
41
|
+
query: url.searchParams
|
|
42
|
+
};
|
|
43
|
+
const rewritten = matchRewrite(pathname, [rewrite], context, basePathState);
|
|
44
|
+
if (rewritten === null) continue;
|
|
45
|
+
if (isExternalUrl(rewritten)) return { kind: "document" };
|
|
46
|
+
currentHref = mergeRewriteQuery(currentHref, rewritten);
|
|
47
|
+
matched = true;
|
|
48
|
+
if (!continueAfterMatch) break;
|
|
49
|
+
}
|
|
50
|
+
return matched ? {
|
|
51
|
+
href: currentHref,
|
|
52
|
+
kind: "rewrite"
|
|
53
|
+
} : null;
|
|
54
|
+
}
|
|
55
|
+
const appRouteTrieCache = createRouteTrieCache();
|
|
56
|
+
const pagesRouteTrieCache = createRouteTrieCache();
|
|
57
|
+
/**
|
|
58
|
+
* Build a `/`-joined pattern from a manifest's `patternParts`. Mirrors the
|
|
59
|
+
* server-side route-graph shape (`{ pattern: string }`) so the
|
|
60
|
+
* `compareHybridRoutePatterns` segment-rank comparator can score both Pages
|
|
61
|
+
* and App patterns. The
|
|
62
|
+
* `patternParts` array never includes an empty string for the static `/`
|
|
63
|
+
* route (the App catch-all handles the bare path), so the simple join is
|
|
64
|
+
* safe for everything the route trie actually matches.
|
|
65
|
+
*/
|
|
66
|
+
function patternFromParts(parts) {
|
|
67
|
+
return "/" + parts.join("/");
|
|
68
|
+
}
|
|
69
|
+
function resolveSameOriginPathname(href, basePath) {
|
|
70
|
+
if (typeof window === "undefined") return null;
|
|
71
|
+
let url;
|
|
72
|
+
try {
|
|
73
|
+
url = new URL(href, window.location.href);
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (url.origin !== window.location.origin) return null;
|
|
78
|
+
const pathname = stripBasePath(url.pathname, basePath);
|
|
79
|
+
const locale = getLocalePathPrefix(pathname, window.__VINEXT_LOCALES__);
|
|
80
|
+
if (!locale) return pathname;
|
|
81
|
+
const localePrefixLength = locale.length + 1;
|
|
82
|
+
return pathname.length === localePrefixLength ? "/" : pathname.slice(localePrefixLength);
|
|
83
|
+
}
|
|
84
|
+
function matchAppRoute(href, basePath, routes) {
|
|
85
|
+
const pathname = resolveSameOriginPathname(href, basePath);
|
|
86
|
+
if (pathname === null) return null;
|
|
87
|
+
return matchRouteWithTrie(pathname, routes, appRouteTrieCache)?.route ?? null;
|
|
88
|
+
}
|
|
89
|
+
function matchPagesRoute(href, basePath, routes) {
|
|
90
|
+
const pathname = resolveSameOriginPathname(href, basePath);
|
|
91
|
+
if (pathname === null) return null;
|
|
92
|
+
return matchRouteWithTrie(pathname, routes, pagesRouteTrieCache)?.route ?? null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Decide which router should own a soft-navigated URL. Returns:
|
|
96
|
+
* - "app" → the App Router runtime handles the navigation (RSC fetch).
|
|
97
|
+
* - "pages" → Pages owns the URL; the caller must hard-navigate instead.
|
|
98
|
+
* - null → no router matched (preserves the existing 404 path).
|
|
99
|
+
*
|
|
100
|
+
* `basePath` must match what the page uses (typically `process.env.__NEXT_ROUTER_BASEPATH`).
|
|
101
|
+
*
|
|
102
|
+
* The lookup uses the App and Pages manifests on `window` so the same
|
|
103
|
+
* matcher trie produces the same result the server will see when the
|
|
104
|
+
* request lands.
|
|
105
|
+
*/
|
|
106
|
+
function resolveHybridClientRouteOwner(href, basePath) {
|
|
107
|
+
if (typeof window === "undefined") return null;
|
|
108
|
+
const appRoutes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
|
|
109
|
+
const pagesRoutes = window.__VINEXT_PAGES_LINK_PREFETCH_ROUTES__;
|
|
110
|
+
const rewrites = window.__VINEXT_CLIENT_REWRITES__;
|
|
111
|
+
if (rewrites) {
|
|
112
|
+
const beforeFilesRewrite = resolveClientRewrite(href, basePath, rewrites.beforeFiles, true);
|
|
113
|
+
if (beforeFilesRewrite?.kind === "document") return "document";
|
|
114
|
+
if (beforeFilesRewrite?.kind === "rewrite") href = beforeFilesRewrite.href;
|
|
115
|
+
}
|
|
116
|
+
let appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
|
|
117
|
+
let pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
|
|
118
|
+
if (rewrites && (appMatch === null || appMatch.isDynamic) && (pagesMatch === null || pagesMatch.isDynamic)) for (const rewrite of rewrites.afterFiles) {
|
|
119
|
+
const afterFilesRewrite = resolveClientRewrite(href, basePath, [rewrite]);
|
|
120
|
+
if (afterFilesRewrite?.kind === "document") return "document";
|
|
121
|
+
if (afterFilesRewrite?.kind !== "rewrite") continue;
|
|
122
|
+
href = afterFilesRewrite.href;
|
|
123
|
+
appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
|
|
124
|
+
pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
|
|
125
|
+
if (appMatch || pagesMatch) break;
|
|
126
|
+
}
|
|
127
|
+
if (rewrites && appMatch === null && pagesMatch === null) for (const rewrite of rewrites.fallback) {
|
|
128
|
+
const fallbackRewrite = resolveClientRewrite(href, basePath, [rewrite]);
|
|
129
|
+
if (fallbackRewrite?.kind === "document") return "document";
|
|
130
|
+
if (fallbackRewrite?.kind !== "rewrite") continue;
|
|
131
|
+
href = fallbackRewrite.href;
|
|
132
|
+
appMatch = appRoutes ? matchAppRoute(href, basePath, appRoutes) : null;
|
|
133
|
+
pagesMatch = pagesRoutes ? matchPagesRoute(href, basePath, pagesRoutes) : null;
|
|
134
|
+
if (appMatch || pagesMatch) break;
|
|
135
|
+
}
|
|
136
|
+
if (appMatch === null && pagesMatch === null) return null;
|
|
137
|
+
if (pagesMatch === null) return appMatch.documentOnly ? "document" : "app";
|
|
138
|
+
if (appMatch === null) return pagesMatch.documentOnly ? "document" : "pages";
|
|
139
|
+
const owner = compareHybridRoutePatterns(patternFromParts(pagesMatch.patternParts), pagesMatch.isDynamic, patternFromParts(appMatch.patternParts), appMatch.isDynamic);
|
|
140
|
+
return (owner === "app" ? appMatch : pagesMatch).documentOnly ? "document" : owner;
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { resolveHybridClientRouteOwner };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/shims/internal/navigation-untracked.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Internal navigation-untracked pathname hook.
|
|
4
|
+
*
|
|
5
|
+
* Used by `unstable_catchError` error boundaries to avoid subscribing to
|
|
6
|
+
* pathname changes. This is NOT part of the public `next/navigation` API.
|
|
7
|
+
*
|
|
8
|
+
* Ported from Next.js:
|
|
9
|
+
* https://github.com/vercel/next.js/blob/v16.2.6/packages/next/src/client/components/navigation-untracked.ts
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Returns the current pathname without registering it as a tracked render
|
|
13
|
+
* dependency. Unlike `usePathname()`, this does not use `useSyncExternalStore`
|
|
14
|
+
* and therefore does not cause the component to re-render on navigation.
|
|
15
|
+
*
|
|
16
|
+
* Server: returns the pathname from context, or `"/"` when no navigation context
|
|
17
|
+
* is available (the client will hydrate with the real value). The `"/"` fallback
|
|
18
|
+
* deliberately matches vinext's `usePathname()` behavior rather than Next.js's
|
|
19
|
+
* null context default. Returns `null` only when the render is a missing-params
|
|
20
|
+
* shell — vinext does not yet implement fallback-route-param detection, so this
|
|
21
|
+
* path is not currently reachable.
|
|
22
|
+
*
|
|
23
|
+
* Client: prefers the render snapshot **only during an active navigation**
|
|
24
|
+
* transition (`navigationSnapshotActiveCount > 0`) so the hook returns the
|
|
25
|
+
* pending URL, not the stale committed one. After commit, falls back to the
|
|
26
|
+
* cached pathname so user `pushState`/`replaceState` calls are immediately
|
|
27
|
+
* reflected.
|
|
28
|
+
*
|
|
29
|
+
* Used by `unstable_catchError` error boundaries to avoid unnecessary re-renders.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
declare function useUntrackedPathname(): string | null;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { useUntrackedPathname };
|