vinext 1.0.1 → 1.1.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.
- package/README.md +72 -1
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/prerender-paths.js +3 -78
- package/dist/build/prerender.js +33 -8
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +3 -1
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -43
- package/dist/index.d.ts +4 -1
- package/dist/index.js +59 -30
- package/dist/plugins/cache-flight-codec.d.ts +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.js +17 -7
- package/dist/server/app-browser-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +93 -10
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +5 -0
- package/dist/server/app-page-cache.js +27 -7
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +47 -30
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +2 -2
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +1 -2
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +55 -33
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +4 -4
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-router-entry.js +3 -3
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +212 -96
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +6 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +6 -4
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +2 -2
- package/dist/server/app-worker-stages.js +3 -3
- package/dist/server/cacheability-request.js +9 -5
- package/dist/server/config-headers.js +2 -0
- package/dist/server/dev-server.js +12 -2
- package/dist/server/headers.d.ts +14 -0
- package/dist/server/headers.js +15 -1
- package/dist/server/image-optimization.d.ts +16 -0
- package/dist/server/image-optimization.js +26 -6
- package/dist/server/isr-cache.js +2 -2
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-response-headers.js +2 -0
- package/dist/server/multi-stage.d.ts +8 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- package/dist/server/pages-page-handler.js +21 -4
- package/dist/server/pages-request-stage-entry.js +8 -4
- package/dist/server/prod-server.d.ts +8 -7
- package/dist/server/prod-server.js +153 -69
- package/dist/server/request-pipeline.d.ts +20 -8
- package/dist/server/request-pipeline.js +21 -7
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- package/dist/server/seed-cache.js +10 -7
- package/dist/server/socket-error-backstop.d.ts +14 -0
- package/dist/server/socket-error-backstop.js +27 -4
- package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +2 -40
- package/dist/shims/cache-callable-runtime.js +50 -168
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +6 -19
- package/dist/shims/cache-runtime.js +165 -225
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +5 -4
- package/dist/shims/cacheability-classification.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- package/dist/shims/fetch-cache.d.ts +6 -0
- package/dist/shims/fetch-cache.js +19 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -1
- package/dist/shims/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +14 -4
- package/dist/shims/request-context.d.ts +9 -0
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -1
- package/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
|
|
3
|
-
import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
3
|
+
import { claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
4
4
|
import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
|
|
5
5
|
import { resolveActiveRoutePaths } from "./app-history-state.js";
|
|
6
6
|
import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
|
|
@@ -76,10 +76,15 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
76
76
|
let activeNavigationId = 0;
|
|
77
77
|
let pendingUserNavigationId = null;
|
|
78
78
|
let pendingUserNavigationLane = null;
|
|
79
|
+
let committingNavigationRenderId = null;
|
|
80
|
+
let pendingUserNavigationCommitStarted = false;
|
|
79
81
|
let latestHmrUpdateId = 0;
|
|
80
82
|
const pendingNavigationCommits = /* @__PURE__ */ new Map();
|
|
81
83
|
const pendingNavigationFailureTargets = /* @__PURE__ */ new Map();
|
|
82
84
|
const pendingNavigationPrePaintEffects = /* @__PURE__ */ new Map();
|
|
85
|
+
const snapshotRenderIds = /* @__PURE__ */ new Set();
|
|
86
|
+
let pendingUserNavigationShellHref = null;
|
|
87
|
+
let retiredNavigationUrl = null;
|
|
83
88
|
let setBrowserRouterState = null;
|
|
84
89
|
let browserRouterStateRef = null;
|
|
85
90
|
let activePendingBrowserRouterState = null;
|
|
@@ -113,6 +118,9 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
113
118
|
activeNavigationId += 1;
|
|
114
119
|
pendingUserNavigationId = activeNavigationId;
|
|
115
120
|
pendingUserNavigationLane = null;
|
|
121
|
+
pendingUserNavigationCommitStarted = false;
|
|
122
|
+
pendingUserNavigationShellHref = null;
|
|
123
|
+
retiredNavigationUrl = null;
|
|
116
124
|
return activeNavigationId;
|
|
117
125
|
}
|
|
118
126
|
function getActiveNavigationId() {
|
|
@@ -159,9 +167,63 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
159
167
|
if (isCurrentNavigation(navId)) {
|
|
160
168
|
pendingUserNavigationId = null;
|
|
161
169
|
pendingUserNavigationLane = null;
|
|
170
|
+
pendingUserNavigationShellHref = null;
|
|
171
|
+
retiredNavigationUrl = null;
|
|
162
172
|
clearPendingPathname(navId);
|
|
163
173
|
}
|
|
164
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Discard the user navigation that has not committed yet, keeping
|
|
177
|
+
* `visibleState` (the committed tree) on screen. Next.js does the same when
|
|
178
|
+
* a raw history.pushState/replaceState dispatches ACTION_RESTORE: the
|
|
179
|
+
* pending action is marked discarded and the restore commits the current
|
|
180
|
+
* tree in a transition, which replaces the navigation's suspended one.
|
|
181
|
+
* Returns whether a navigation was discarded.
|
|
182
|
+
*/
|
|
183
|
+
function discardPendingNavigation(visibleState) {
|
|
184
|
+
if (pendingUserNavigationId === null || pendingUserNavigationCommitStarted) return false;
|
|
185
|
+
if (pendingUserNavigationShellHref !== null) {
|
|
186
|
+
retiredNavigationUrl = {
|
|
187
|
+
navigationId: pendingUserNavigationId,
|
|
188
|
+
href: pendingUserNavigationShellHref
|
|
189
|
+
};
|
|
190
|
+
for (const renderId of pendingNavigationPrePaintEffects.keys()) releaseRenderSnapshot(renderId);
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
activeNavigationId += 1;
|
|
194
|
+
pendingUserNavigationId = null;
|
|
195
|
+
pendingUserNavigationLane = null;
|
|
196
|
+
clearAppRouterScrollIntent();
|
|
197
|
+
for (const renderId of pendingNavigationPrePaintEffects.keys()) {
|
|
198
|
+
pendingNavigationPrePaintEffects.delete(renderId);
|
|
199
|
+
releaseRenderSnapshot(renderId);
|
|
200
|
+
}
|
|
201
|
+
clearCommittedNavigationFailureTargets(nextNavigationRenderId);
|
|
202
|
+
settleNavigationCommits(nextNavigationRenderId, false);
|
|
203
|
+
if (visibleState && setBrowserRouterState) {
|
|
204
|
+
const setter = setBrowserRouterState;
|
|
205
|
+
startTransition(() => {
|
|
206
|
+
setter(visibleState);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Run the URL update of a navigation render React is committing right now.
|
|
213
|
+
* It normally runs in NavigationCommitSignal's layout effect, after the
|
|
214
|
+
* route's own layout effects. Next.js writes the URL in an insertion effect
|
|
215
|
+
* instead, so a raw history write from a destination layout effect lands on
|
|
216
|
+
* top of the destination entry. Called before such a write to keep that order.
|
|
217
|
+
*/
|
|
218
|
+
function flushCommittingNavigationUrl() {
|
|
219
|
+
if (committingNavigationRenderId !== null) drainPrePaintEffects(committingNavigationRenderId);
|
|
220
|
+
}
|
|
221
|
+
function releaseRenderSnapshot(renderId) {
|
|
222
|
+
if (snapshotRenderIds.delete(renderId)) commitClientNavigationStateImpl(void 0, { releaseSnapshot: true });
|
|
223
|
+
}
|
|
224
|
+
function isRetiredNavigationUrl(navId, targetHref) {
|
|
225
|
+
return retiredNavigationUrl !== null && retiredNavigationUrl.navigationId === navId && retiredNavigationUrl.href === normalizeBrowserHref(targetHref);
|
|
226
|
+
}
|
|
165
227
|
function queuePrePaintNavigationEffect(renderId, effect) {
|
|
166
228
|
if (!effect) return;
|
|
167
229
|
pendingNavigationPrePaintEffects.set(renderId, effect);
|
|
@@ -182,7 +244,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
182
244
|
if (id > upToRenderId) continue;
|
|
183
245
|
pendingNavigationPrePaintEffects.delete(id);
|
|
184
246
|
if (id === upToRenderId) effect();
|
|
185
|
-
else
|
|
247
|
+
else releaseRenderSnapshot(id);
|
|
186
248
|
}
|
|
187
249
|
}
|
|
188
250
|
/**
|
|
@@ -199,7 +261,17 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
199
261
|
pendingCommit.resolve(didCommit);
|
|
200
262
|
}
|
|
201
263
|
}
|
|
264
|
+
/** Runs when React starts committing a render, before any layout effect. */
|
|
265
|
+
function beginNavigationRenderCommit(renderId) {
|
|
266
|
+
committingNavigationRenderId = renderId;
|
|
267
|
+
const committingCommit = pendingNavigationCommits.get(renderId);
|
|
268
|
+
const committingOperation = committingCommit?.committedState?.activeOperation;
|
|
269
|
+
if (committingCommit && committingOperation?.navigationCommitKind === "detached" && committingOperation.navigationId === pendingUserNavigationId) pendingUserNavigationShellHref = normalizeBrowserHref(committingCommit.targetHref);
|
|
270
|
+
else pendingUserNavigationCommitStarted = true;
|
|
271
|
+
clearCommittedNavigationFailureTargets(renderId);
|
|
272
|
+
}
|
|
202
273
|
function commitNavigationRender(renderId) {
|
|
274
|
+
committingNavigationRenderId = null;
|
|
203
275
|
drainPrePaintEffects(renderId);
|
|
204
276
|
settleNavigationCommits(renderId, true);
|
|
205
277
|
}
|
|
@@ -239,7 +311,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
239
311
|
}
|
|
240
312
|
function NavigationCommitSignal({ renderId, children }) {
|
|
241
313
|
useInsertionEffect(() => {
|
|
242
|
-
|
|
314
|
+
beginNavigationRenderCommit(renderId);
|
|
243
315
|
}, [renderId]);
|
|
244
316
|
useLayoutEffect(() => {
|
|
245
317
|
commitNavigationRender(renderId);
|
|
@@ -371,10 +443,10 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
371
443
|
pendingNavigationCommits.set(renderId, {
|
|
372
444
|
committedState: null,
|
|
373
445
|
onCommittedState: options.onCommittedState,
|
|
374
|
-
resolve
|
|
446
|
+
resolve,
|
|
447
|
+
targetHref: options.targetHref
|
|
375
448
|
});
|
|
376
449
|
});
|
|
377
|
-
let snapshotActivated = false;
|
|
378
450
|
try {
|
|
379
451
|
const pendingOptions = {
|
|
380
452
|
currentState: options.navigationInitiationState,
|
|
@@ -425,7 +497,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
425
497
|
const approvedCommit = approval.approvedCommit;
|
|
426
498
|
if (approvedCommit === null) throw new Error("[vinext] Commit decision did not approve a visible commit");
|
|
427
499
|
const approvedVisibleState = applyApprovedVisibleCommit(getBrowserRouterState(), approvedCommit);
|
|
428
|
-
|
|
500
|
+
const commitEffect = options.createNavigationCommitEffect({
|
|
429
501
|
activeRoutePaths: resolveActiveRoutePaths(approvedVisibleState.slotBindings),
|
|
430
502
|
bfcacheIds: approvedVisibleState.bfcacheIds,
|
|
431
503
|
href: options.targetHref,
|
|
@@ -434,10 +506,18 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
434
506
|
params: options.params,
|
|
435
507
|
previousNextUrl: approvedCommit.previousNextUrl,
|
|
436
508
|
targetHistoryIndex: options.targetHistoryIndex
|
|
437
|
-
})
|
|
509
|
+
});
|
|
510
|
+
queuePrePaintNavigationEffect(renderId, () => {
|
|
511
|
+
commitEffect({
|
|
512
|
+
keepCurrentUrl: isRetiredNavigationUrl(options.navId, options.targetHref),
|
|
513
|
+
releaseSnapshot: snapshotRenderIds.delete(renderId)
|
|
514
|
+
});
|
|
515
|
+
});
|
|
438
516
|
claimAppRouterScrollIntentForCommit(options.scrollIntent, renderId);
|
|
439
|
-
|
|
440
|
-
|
|
517
|
+
if (!isRetiredNavigationUrl(options.navId, options.targetHref)) {
|
|
518
|
+
activateNavigationSnapshot();
|
|
519
|
+
snapshotRenderIds.add(renderId);
|
|
520
|
+
}
|
|
441
521
|
dispatchApprovedVisibleCommit(renderId, approvedCommit, options.pendingRouterState, shouldForceSynchronousCommit(options) ? "synchronous" : options.visibleCommitMode ?? "transition");
|
|
442
522
|
if (options.navigationResponseCompletion) options.navigationResponseCompletion.then(() => {
|
|
443
523
|
if (!isCurrentNavigation(options.navId) || !hasBrowserRouterState()) return;
|
|
@@ -451,7 +531,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
451
531
|
pendingNavigationFailureTargets.delete(renderId);
|
|
452
532
|
pendingNavigationPrePaintEffects.delete(renderId);
|
|
453
533
|
pendingNavigationCommits.delete(renderId);
|
|
454
|
-
if (
|
|
534
|
+
if (snapshotRenderIds.delete(renderId)) commitClientNavigationStateImpl(options.navId);
|
|
455
535
|
settlePendingBrowserRouterState(options.pendingRouterState);
|
|
456
536
|
resolveCommitted?.(false);
|
|
457
537
|
throw error;
|
|
@@ -530,11 +610,14 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
530
610
|
attachBrowserRouterState,
|
|
531
611
|
beginPendingBrowserRouterState,
|
|
532
612
|
finalizeNavigation,
|
|
613
|
+
discardPendingNavigation,
|
|
614
|
+
flushCommittingNavigationUrl,
|
|
533
615
|
restoreHistorySnapshotVisibleState,
|
|
534
616
|
renderNavigationPayload,
|
|
535
617
|
commitSameUrlNavigatePayload,
|
|
536
618
|
hmrReplaceTree,
|
|
537
619
|
drainPrePaintEffects,
|
|
620
|
+
beginNavigationRenderCommit,
|
|
538
621
|
commitNavigationRender,
|
|
539
622
|
clearCommittedNavigationFailureTargets,
|
|
540
623
|
NavigationCommitSignal
|
|
@@ -96,6 +96,8 @@ type AppFallbackRenderer<TModule extends AppPageModule = AppPageModule> = {
|
|
|
96
96
|
boundaryComponent?: AppPageComponent | null;
|
|
97
97
|
boundaryModule?: TModule | null;
|
|
98
98
|
intercept?: AppPageInterceptOptions<TModule> | null;
|
|
99
|
+
/** The document may be stored, so it must not carry the request's query. */
|
|
100
|
+
isCacheCandidate?: boolean;
|
|
99
101
|
layouts?: readonly (TModule | null | undefined)[] | null;
|
|
100
102
|
matchedParams?: AppPageParams;
|
|
101
103
|
}, scriptNonce: string | undefined, middlewareContext: AppPageMiddlewareContext, callContext?: AppFallbackRendererCallContext) => Promise<Response | null>;
|
|
@@ -86,6 +86,7 @@ function createAppFallbackRenderer(options) {
|
|
|
86
86
|
getNavigationContext,
|
|
87
87
|
globalErrorModule: effectiveGlobalErrorModule,
|
|
88
88
|
intercept: opts?.intercept ?? null,
|
|
89
|
+
isCacheCandidate: opts?.isCacheCandidate,
|
|
89
90
|
isEdgeRuntime: callContext?.isEdgeRuntime,
|
|
90
91
|
isRscRequest,
|
|
91
92
|
layoutModules: useGlobalNotFound ? [] : opts?.layouts ?? null,
|
|
@@ -29,6 +29,8 @@ export declare class HistoryStateSnapshotCache<TState> {
|
|
|
29
29
|
historyIndex: number | null;
|
|
30
30
|
state: TState;
|
|
31
31
|
}): void;
|
|
32
|
+
/** Point every entry that remembered `previous` at `next` instead. */
|
|
33
|
+
replaceState(previous: TState, next: TState): void;
|
|
32
34
|
resolveRestore(options: {
|
|
33
35
|
currentBfcacheVersion: number;
|
|
34
36
|
guarded: boolean;
|
|
@@ -51,6 +53,7 @@ export declare class RestorableClientStateController<TState> {
|
|
|
51
53
|
historyIndex: number | null;
|
|
52
54
|
state: TState;
|
|
53
55
|
}): void;
|
|
56
|
+
replaceHistoryStateSnapshots(previous: TState, next: TState): void;
|
|
54
57
|
resolveHistoryStateSnapshotRestore(historyState: unknown): HistoryStateSnapshotRestoreDecision<TState>;
|
|
55
58
|
}
|
|
56
59
|
export declare function createHistoryStateWithPreviousNextUrl(state: unknown, previousNextUrl: string | null): HistoryStateRecord | null;
|
|
@@ -31,6 +31,10 @@ var HistoryStateSnapshotCache = class {
|
|
|
31
31
|
const oldestIndex = this.#snapshots.keys().next().value;
|
|
32
32
|
if (typeof oldestIndex === "number") this.#snapshots.delete(oldestIndex);
|
|
33
33
|
}
|
|
34
|
+
/** Point every entry that remembered `previous` at `next` instead. */
|
|
35
|
+
replaceState(previous, next) {
|
|
36
|
+
for (const snapshot of this.#snapshots.values()) if (snapshot.state === previous) snapshot.state = next;
|
|
37
|
+
}
|
|
34
38
|
resolveRestore(options) {
|
|
35
39
|
const targetHistoryIndex = readHistoryStateTraversalIndex(options.historyState);
|
|
36
40
|
if (targetHistoryIndex === null) return {
|
|
@@ -111,6 +115,9 @@ var RestorableClientStateController = class {
|
|
|
111
115
|
state: options.state
|
|
112
116
|
});
|
|
113
117
|
}
|
|
118
|
+
replaceHistoryStateSnapshots(previous, next) {
|
|
119
|
+
this.#snapshots.replaceState(previous, next);
|
|
120
|
+
}
|
|
114
121
|
resolveHistoryStateSnapshotRestore(historyState) {
|
|
115
122
|
return this.#snapshots.resolveRestore({
|
|
116
123
|
currentBfcacheVersion: this.#currentBfcacheVersion,
|
|
@@ -49,7 +49,8 @@ function requestWithMiddlewareRequestHeaders(request, middlewareHeaders) {
|
|
|
49
49
|
const init = {
|
|
50
50
|
method: request.method,
|
|
51
51
|
headers: nextHeaders,
|
|
52
|
-
body: request.body
|
|
52
|
+
body: request.body,
|
|
53
|
+
signal: request.signal
|
|
53
54
|
};
|
|
54
55
|
if (request.body) Object.defineProperty(init, "duplex", {
|
|
55
56
|
value: "half",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isUnknownRecord } from "../utils/record.js";
|
|
2
2
|
import { buildParams, decodeMatchedParams, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
3
3
|
import { stripBasePath } from "../utils/base-path.js";
|
|
4
|
+
import { extractRawRoutePatternParams, matchRoutePattern } from "../routing/route-pattern.js";
|
|
4
5
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
6
|
import "./app-elements.js";
|
|
6
|
-
import { extractRawRoutePatternParams, matchRoutePattern } from "../routing/route-pattern.js";
|
|
7
7
|
import { createNestedBfcacheSlotSegmentId, deriveBfcacheSegmentIdentity, isNestedBfcacheSlotSegmentId } from "./bfcache-identity.js";
|
|
8
8
|
import { stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
|
|
9
9
|
import { canonicalizeAppPageParams, resolveAppPagePatternStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
@@ -49,6 +49,11 @@ type AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageM
|
|
|
49
49
|
getFontStyles: () => string[];
|
|
50
50
|
getNavigationContext: () => NavigationContext | null;
|
|
51
51
|
globalErrorModule?: TModule | null;
|
|
52
|
+
/**
|
|
53
|
+
* The document may be stored under a query-free key, so its SSR
|
|
54
|
+
* `useSearchParams()` waits as a cache candidate's does.
|
|
55
|
+
*/
|
|
56
|
+
isCacheCandidate?: boolean;
|
|
52
57
|
isEdgeRuntime?: boolean;
|
|
53
58
|
isRscRequest: boolean;
|
|
54
59
|
loadSsrHandler: () => Promise<AppPageSsrHandler>;
|
|
@@ -6,19 +6,20 @@ import "./app-elements.js";
|
|
|
6
6
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
7
7
|
import { ErrorBoundary, GlobalErrorBoundary, SerializedErrorBoundary } from "../shims/error-boundary.js";
|
|
8
8
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
9
|
+
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
9
10
|
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
10
11
|
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
11
12
|
import { stripRscSuffix } from "./app-rsc-cache-busting.js";
|
|
12
13
|
import { buildRscRedirectFlightStream } from "./app-rsc-redirect-flight.js";
|
|
13
14
|
import { bufferAppPageBinaryStream, buildAppPageSpecialErrorResponse, resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
14
|
-
import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
|
|
15
15
|
import { createAppPageLayoutEntries, createAppPageSourcePage } from "./app-page-route-wiring.js";
|
|
16
|
+
import { createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
16
17
|
import { buildClientHookErrorMessage } from "../shims/client-hook-error.js";
|
|
18
|
+
import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
|
|
17
19
|
import { resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
|
|
18
20
|
import "./app-rsc-route-matching.js";
|
|
19
21
|
import { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryModule, wrapAppPageBoundaryElement } from "./app-page-boundary.js";
|
|
20
22
|
import { resolveSlotParamOverrides } from "./app-page-element-builder.js";
|
|
21
|
-
import { createAppPageFontData, createAppPageRscErrorTracker, createAppPageSsrErrorHandler, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
22
23
|
import { Fragment, createElement } from "react";
|
|
23
24
|
//#region src/server/app-page-boundary-render.ts
|
|
24
25
|
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
@@ -56,10 +57,10 @@ function wrapRenderedBoundaryElement(options) {
|
|
|
56
57
|
});
|
|
57
58
|
},
|
|
58
59
|
renderLayout(LayoutComponent, children, asyncParams) {
|
|
59
|
-
return createElement(LayoutComponent, {
|
|
60
|
+
return createElement(LayoutComponent, withUseCacheLayoutMarker(LayoutComponent, {
|
|
60
61
|
children,
|
|
61
62
|
params: asyncParams
|
|
62
|
-
});
|
|
63
|
+
}));
|
|
63
64
|
},
|
|
64
65
|
renderLayoutSegmentProvider(segmentMap, children) {
|
|
65
66
|
return createElement(LayoutSegmentProvider, { segmentMap }, children);
|
|
@@ -153,6 +154,7 @@ async function renderAppPageBoundaryElementResponse(options) {
|
|
|
153
154
|
clearRequestContext: options.clearRequestContext,
|
|
154
155
|
fontData,
|
|
155
156
|
fontLinkHeader: options.buildFontLinkHeader(fontData.preloads),
|
|
157
|
+
isCacheCandidate: options.isCacheCandidate,
|
|
156
158
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
157
159
|
middlewareHeaders: options.middlewareContext.headers,
|
|
158
160
|
navigationContext: options.getNavigationContext() ?? {
|
|
@@ -2,6 +2,7 @@ import { RenderObservation } from "./cache-proof.js";
|
|
|
2
2
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
3
3
|
import { AppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
4
4
|
import { AppPageCacheSetter } from "./isr-cache.js";
|
|
5
|
+
import { AppPageRscRenderStatus } from "./app-page-rsc-render-status.js";
|
|
5
6
|
//#region src/server/app-page-cache-finalizer.d.ts
|
|
6
7
|
type AppPageDebugLogger = (event: string, detail: string) => void;
|
|
7
8
|
type AppPageRscCacheKeyBuilder = (pathname: string, mountedSlotsHeader?: string | null, renderMode?: AppRscRenderMode, interceptionContext?: string | null, interceptionId?: string | null) => string;
|
|
@@ -26,6 +27,8 @@ type FinalizeAppPageCacheabilityEvaluationOptions = {
|
|
|
26
27
|
* cacheable even when a cacheLife resolves during the render.
|
|
27
28
|
*/
|
|
28
29
|
isStaticEligible: boolean;
|
|
30
|
+
/** An RSC render's status, from its document's shell. */
|
|
31
|
+
resolveRscRenderStatus?: () => Promise<AppPageRscRenderStatus>;
|
|
29
32
|
revalidateSeconds: number | null;
|
|
30
33
|
};
|
|
31
34
|
type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
@@ -53,6 +56,12 @@ type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
|
53
56
|
isStaticEligible: boolean;
|
|
54
57
|
revalidateSeconds: number | null;
|
|
55
58
|
linkHeader: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* The status and headers stored with both entries, for a render that ended
|
|
61
|
+
* in a special error: 404/403/401, or 307/308 with its `location`.
|
|
62
|
+
*/
|
|
63
|
+
status?: number;
|
|
64
|
+
headers?: Record<string, string>;
|
|
56
65
|
waitUntil?: (promise: Promise<void>) => void;
|
|
57
66
|
};
|
|
58
67
|
type ScheduleAppPageRscCacheWriteOptions = {
|
|
@@ -73,6 +82,8 @@ type ScheduleAppPageRscCacheWriteOptions = {
|
|
|
73
82
|
mountedSlotsHeader?: string | null;
|
|
74
83
|
omitPendingDynamicCacheState?: boolean;
|
|
75
84
|
renderMode?: AppRscRenderMode;
|
|
85
|
+
/** The render's status, from its document's shell. Without it the render is a 200. */
|
|
86
|
+
resolveRscRenderStatus?: () => Promise<AppPageRscRenderStatus>;
|
|
76
87
|
preserveClientResponseHeaders?: boolean;
|
|
77
88
|
expireSeconds?: number;
|
|
78
89
|
isStaticEligible: boolean;
|
|
@@ -10,6 +10,7 @@ import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
|
10
10
|
import { markFrameworkLinkHeaders } from "./app-response-header-provenance.js";
|
|
11
11
|
import { hasQueryInvariantRenderProof } from "./cache-proof.js";
|
|
12
12
|
import { createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
13
|
+
import { resolveAppPageRscResponseStatus } from "./app-page-rsc-render-status.js";
|
|
13
14
|
//#region src/server/app-page-cache-finalizer.ts
|
|
14
15
|
function applyPendingDynamicCdnHeaders(headers, tags, options = {}) {
|
|
15
16
|
const cacheable = headers.get("Cache-Control") ?? "";
|
|
@@ -50,6 +51,22 @@ function resolveAppPageCacheControl(options) {
|
|
|
50
51
|
function appPageCacheControlHeader(cacheControl) {
|
|
51
52
|
return cacheControl.revalidate === Infinity ? STATIC_CACHE_CONTROL : buildRevalidateCacheControl(cacheControl.revalidate, cacheControl.expire);
|
|
52
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* The completed response replaces a streamed 200 with the status Next.js sends
|
|
56
|
+
* for the render's special error, and stores that.
|
|
57
|
+
*/
|
|
58
|
+
function applyRscRenderStatus(outcome, renderStatus) {
|
|
59
|
+
if (renderStatus.kind === "page") return outcome;
|
|
60
|
+
if (renderStatus.kind === "unstorable") return {
|
|
61
|
+
cacheable: false,
|
|
62
|
+
reason: "render ended in a special error Next.js doesn't store"
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
...outcome,
|
|
66
|
+
status: resolveAppPageRscResponseStatus(renderStatus.status),
|
|
67
|
+
...renderStatus.headers ? { headers: renderStatus.headers } : {}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
53
70
|
function finalizeEvaluatedAppPageResponse(response, options) {
|
|
54
71
|
if (!isRouteCacheabilityEvaluation()) return null;
|
|
55
72
|
const complete = deferRouteCacheability();
|
|
@@ -90,6 +107,14 @@ function finalizeEvaluatedAppPageResponse(response, options) {
|
|
|
90
107
|
reason: "render did not produce a cache policy"
|
|
91
108
|
};
|
|
92
109
|
}
|
|
110
|
+
if (outcome.cacheable && options.resolveRscRenderStatus) {
|
|
111
|
+
const cacheableOutcome = outcome;
|
|
112
|
+
options.resolveRscRenderStatus().then((renderStatus) => complete(applyRscRenderStatus(cacheableOutcome, renderStatus)), () => complete({
|
|
113
|
+
cacheable: false,
|
|
114
|
+
reason: "render status could not be resolved"
|
|
115
|
+
}));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
93
118
|
complete(outcome);
|
|
94
119
|
};
|
|
95
120
|
if (!response.body) {
|
|
@@ -131,15 +156,15 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
131
156
|
markFrameworkLinkHeaders(clientResponse.headers, options.linkHeader);
|
|
132
157
|
return clientResponse;
|
|
133
158
|
}
|
|
134
|
-
|
|
135
|
-
const [streamForClient, streamForCache] = response.body.tee();
|
|
159
|
+
const [streamForClient, streamForCache] = response.body ? response.body.tee() : [null, null];
|
|
136
160
|
const htmlKey = options.isrHtmlKey(options.cleanPathname);
|
|
137
161
|
const rscKey = options.isrRscKey(options.cleanPathname, null, void 0, options.interceptionContext, options.interceptionId);
|
|
138
162
|
const clientHeaders = new Headers(response.headers);
|
|
139
163
|
if (options.preserveClientResponseHeaders !== true) applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
|
|
140
164
|
const cachePromise = (async () => {
|
|
141
165
|
try {
|
|
142
|
-
let cachedHtml = await readStreamAsText(streamForCache);
|
|
166
|
+
let cachedHtml = streamForCache ? await readStreamAsText(streamForCache) : "";
|
|
167
|
+
const rscData = options.capturedRscDataPromise ? await options.capturedRscDataPromise : void 0;
|
|
143
168
|
if (options.capturedDynamicUsageBeforeContextCleanup?.() === true || options.consumeDynamicUsage()) {
|
|
144
169
|
options.isrDebug?.("HTML cache write skipped (dynamic usage during render)", htmlKey);
|
|
145
170
|
return;
|
|
@@ -168,18 +193,22 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
|
|
|
168
193
|
state: observationState
|
|
169
194
|
});
|
|
170
195
|
const linkHeader = options.linkHeader;
|
|
196
|
+
const status = options.status ?? 200;
|
|
171
197
|
if (!hasQueryInvariantRenderProof(htmlRenderObservation) || !hasQueryInvariantRenderProof(rscRenderObservation)) {
|
|
172
198
|
options.isrDebug?.("HTML cache write skipped (searchParams not proven unread)", htmlKey);
|
|
173
199
|
return;
|
|
174
200
|
}
|
|
175
|
-
const writes = [options.isrSet(htmlKey, buildAppPageCacheValue(cachedHtml, void 0,
|
|
201
|
+
const writes = [options.isrSet(htmlKey, buildAppPageCacheValue(cachedHtml, void 0, status, htmlRenderObservation, linkHeader ? {
|
|
202
|
+
...options.headers,
|
|
203
|
+
link: linkHeader
|
|
204
|
+
} : options.headers), {
|
|
176
205
|
cacheControl,
|
|
177
206
|
tags: pageTags
|
|
178
207
|
})];
|
|
179
|
-
if (
|
|
208
|
+
if (rscData) writes.push(options.isrSet(rscKey, buildAppPageCacheValue("", rscData, status, rscRenderObservation, options.headers), {
|
|
180
209
|
cacheControl,
|
|
181
210
|
tags: pageTags
|
|
182
|
-
}))
|
|
211
|
+
}));
|
|
183
212
|
await Promise.all(writes);
|
|
184
213
|
options.isrDebug?.("HTML cache written", htmlKey);
|
|
185
214
|
} catch (cacheError) {
|
|
@@ -243,7 +272,12 @@ function scheduleAppPageRscCacheWrite(options) {
|
|
|
243
272
|
options.isrDebug?.("RSC cache write skipped (searchParams not proven unread)", rscKey);
|
|
244
273
|
return;
|
|
245
274
|
}
|
|
246
|
-
await options.
|
|
275
|
+
const renderStatus = await options.resolveRscRenderStatus?.() ?? { kind: "page" };
|
|
276
|
+
if (renderStatus.kind === "unstorable") {
|
|
277
|
+
options.isrDebug?.("RSC cache write skipped (unstorable special error)", rscKey);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
await options.isrSet(rscKey, renderStatus.kind === "special-error" ? buildAppPageCacheValue("", rscData, renderStatus.status, rscRenderObservation, renderStatus.headers) : buildAppPageCacheValue("", rscData, 200, rscRenderObservation), {
|
|
247
281
|
cacheControl,
|
|
248
282
|
tags: pageTags
|
|
249
283
|
});
|
|
@@ -24,11 +24,18 @@ export type RenderAppPageCacheArtifactsOptions = {
|
|
|
24
24
|
getNavigationContext: () => NavigationContext | null;
|
|
25
25
|
loadSsrHandler: () => Promise<AppPageSsrHandler>;
|
|
26
26
|
mountedSlotsHeader?: string | null;
|
|
27
|
+
/** Start mirroring Flight into Next.js's `self.__next_f` once this returns true. */
|
|
28
|
+
mirrorNextFlight?: () => boolean;
|
|
27
29
|
navigationParams: Record<string, unknown>;
|
|
28
30
|
isCapturedRscError?: (error: unknown) => boolean;
|
|
29
31
|
onError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
|
|
30
32
|
onSsrError?: (error: unknown) => unknown;
|
|
31
33
|
reactMaxHeadersLength?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Render the document of a special error that rejected the shell, or return
|
|
36
|
+
* null to fail the render with it.
|
|
37
|
+
*/
|
|
38
|
+
renderShellSpecialError?: (error: unknown) => Promise<AppPageCacheSpecialErrorDocument | null>;
|
|
32
39
|
renderToReadableStream: (element: AppPageRenderableElement, options: {
|
|
33
40
|
onError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
|
|
34
41
|
}) => ReadableStream<Uint8Array>;
|
|
@@ -37,13 +44,24 @@ export type RenderAppPageCacheArtifactsOptions = {
|
|
|
37
44
|
waitForAllReady?: boolean;
|
|
38
45
|
isForceStatic?: boolean;
|
|
39
46
|
};
|
|
47
|
+
type AppPageCacheSpecialErrorDocument = {
|
|
48
|
+
/** Response headers stored with the entries, such as a redirect's `location`. */
|
|
49
|
+
headers?: Record<string, string>;
|
|
50
|
+
html: string;
|
|
51
|
+
/** The renderer's own `Link` header, without middleware's. */
|
|
52
|
+
linkHeader?: string;
|
|
53
|
+
status: number;
|
|
54
|
+
};
|
|
40
55
|
export type RenderAppPageCacheArtifactsResult = {
|
|
41
56
|
cacheControl?: CacheControlMetadata;
|
|
57
|
+
headers?: Record<string, string>;
|
|
42
58
|
html: string;
|
|
43
59
|
htmlRenderObservation: ReturnType<typeof createAppPageRenderObservation>;
|
|
44
60
|
linkHeader?: string;
|
|
45
61
|
rscData?: ArrayBuffer;
|
|
46
62
|
rscRenderObservation?: ReturnType<typeof createAppPageRenderObservation>;
|
|
63
|
+
/** The status of a render whose shell ended in a special error. */
|
|
64
|
+
status?: number;
|
|
47
65
|
tags: string[];
|
|
48
66
|
/** The render used a dynamic API, so its output must not be stored. */
|
|
49
67
|
usedDynamicApi: boolean;
|
|
@@ -26,34 +26,49 @@ async function renderAppPageCacheArtifactsImpl(options, renderSpan) {
|
|
|
26
26
|
const rscCapture = teeAppPageRscStreamForCapture(rscStream, options.captureRscData);
|
|
27
27
|
const capturedRscDataRef = { value: null };
|
|
28
28
|
const fontPreloads = options.getFontPreloads();
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
29
|
+
const ssrHandler = await options.loadSsrHandler();
|
|
30
|
+
let htmlResult = null;
|
|
31
|
+
let specialErrorDocument = null;
|
|
32
|
+
try {
|
|
33
|
+
htmlResult = await ssrHandler.handleSsr(rscCapture.ssrStream, options.getNavigationContext(), {
|
|
34
|
+
links: options.getFontLinks(),
|
|
35
|
+
styles: options.getFontStyles(),
|
|
36
|
+
preloads: fontPreloads
|
|
37
|
+
}, {
|
|
38
|
+
basePath: options.basePath,
|
|
39
|
+
clientTraceMetadata: options.clientTraceMetadata,
|
|
40
|
+
reactMaxHeadersLength: options.reactMaxHeadersLength,
|
|
41
|
+
rootParams: options.rootParams,
|
|
42
|
+
waitForAllReady: options.waitForAllReady,
|
|
43
|
+
mirrorNextFlight: options.mirrorNextFlight,
|
|
44
|
+
isStaticGeneration: true,
|
|
45
|
+
isForceStatic: options.isForceStatic,
|
|
46
|
+
onSsrError: options.onSsrError && options.isCapturedRscError ? createAppPageSsrErrorHandler((error) => {
|
|
47
|
+
recordAppPageRenderError(renderSpan, error);
|
|
48
|
+
return options.onSsrError?.(error);
|
|
49
|
+
}, options.isCapturedRscError) : options.onSsrError ? (error) => {
|
|
50
|
+
recordAppPageRenderError(renderSpan, error);
|
|
51
|
+
return options.onSsrError?.(error);
|
|
52
|
+
} : void 0,
|
|
53
|
+
...rscCapture.sideStream ? {
|
|
54
|
+
sideStream: rscCapture.sideStream,
|
|
55
|
+
capturedRscDataRef
|
|
56
|
+
} : {}
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (!options.renderShellSpecialError) throw error;
|
|
60
|
+
await capturedRscDataRef.value?.catch(() => {});
|
|
61
|
+
specialErrorDocument = await options.renderShellSpecialError(error);
|
|
62
|
+
if (!specialErrorDocument) throw error;
|
|
63
|
+
}
|
|
64
|
+
let html = specialErrorDocument?.html ?? "";
|
|
65
|
+
let linkHeader = specialErrorDocument?.linkHeader;
|
|
66
|
+
if (htmlResult) {
|
|
67
|
+
const htmlStream = isAppSsrRenderResult(htmlResult) ? htmlResult.htmlStream : htmlResult;
|
|
68
|
+
const reactLinkHeader = isAppSsrRenderResult(htmlResult) ? htmlResult.linkHeader : void 0;
|
|
69
|
+
linkHeader = buildAppPageLinkHeader(reactLinkHeader, buildAppPageFontLinkHeader(fontPreloads), options.reactMaxHeadersLength);
|
|
70
|
+
html = await readStreamAsText(htmlStream);
|
|
71
|
+
}
|
|
57
72
|
let rscData;
|
|
58
73
|
if (options.captureRscData) {
|
|
59
74
|
const capturedPromise = capturedRscDataRef.value;
|
|
@@ -65,24 +80,29 @@ async function renderAppPageCacheArtifactsImpl(options, renderSpan) {
|
|
|
65
80
|
const observationState = consumeAppPageRenderObservationState();
|
|
66
81
|
consumeInvalidDynamicUsageError();
|
|
67
82
|
const usedDynamicApi = consumeDynamicUsage() || isRenderDynamicLatched();
|
|
83
|
+
const htmlRenderObservation = createAppPageRenderObservation({
|
|
84
|
+
boundaryOutcome: { kind: "success" },
|
|
85
|
+
cacheability: "public",
|
|
86
|
+
cacheTags: tags,
|
|
87
|
+
cleanPathname: options.cleanPathname,
|
|
88
|
+
completeness: "complete",
|
|
89
|
+
output: createAppPageHtmlOutputScope({
|
|
90
|
+
element: options.element,
|
|
91
|
+
renderEpoch: null,
|
|
92
|
+
rootBoundaryId: null,
|
|
93
|
+
routePattern: options.route.pattern
|
|
94
|
+
}),
|
|
95
|
+
params: options.navigationParams,
|
|
96
|
+
state: observationState
|
|
97
|
+
});
|
|
68
98
|
const result = {
|
|
69
99
|
html,
|
|
70
|
-
htmlRenderObservation
|
|
71
|
-
boundaryOutcome: { kind: "success" },
|
|
72
|
-
cacheability: "public",
|
|
73
|
-
cacheTags: tags,
|
|
74
|
-
cleanPathname: options.cleanPathname,
|
|
75
|
-
completeness: "complete",
|
|
76
|
-
output: createAppPageHtmlOutputScope({
|
|
77
|
-
element: options.element,
|
|
78
|
-
renderEpoch: null,
|
|
79
|
-
rootBoundaryId: null,
|
|
80
|
-
routePattern: options.route.pattern
|
|
81
|
-
}),
|
|
82
|
-
params: options.navigationParams,
|
|
83
|
-
state: observationState
|
|
84
|
-
}),
|
|
100
|
+
htmlRenderObservation,
|
|
85
101
|
...linkHeader ? { linkHeader } : {},
|
|
102
|
+
...specialErrorDocument ? {
|
|
103
|
+
headers: specialErrorDocument.headers,
|
|
104
|
+
status: specialErrorDocument.status
|
|
105
|
+
} : {},
|
|
86
106
|
tags,
|
|
87
107
|
usedDynamicApi,
|
|
88
108
|
cacheControl: typeof cacheLife?.revalidate === "number" ? {
|