vinext 1.0.0-beta.2 → 1.0.0-beta.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.
Files changed (126) hide show
  1. package/README.md +6 -9
  2. package/dist/build/client-build-config.js +7 -1
  3. package/dist/check.js +4 -0
  4. package/dist/config/config-matchers.js +4 -1
  5. package/dist/config/next-config.d.ts +12 -3
  6. package/dist/config/next-config.js +4 -0
  7. package/dist/entries/app-browser-entry.d.ts +4 -10
  8. package/dist/entries/app-browser-entry.js +20 -4
  9. package/dist/entries/app-rsc-entry.js +3 -0
  10. package/dist/entries/app-rsc-manifest.js +19 -0
  11. package/dist/entries/pages-client-entry.js +0 -1
  12. package/dist/entries/pages-server-entry.js +10 -3
  13. package/dist/index.js +112 -43
  14. package/dist/init-cloudflare.d.ts +3 -1
  15. package/dist/init-cloudflare.js +59 -5
  16. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  17. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  18. package/dist/plugins/import-meta-url.js +17 -6
  19. package/dist/plugins/require-context.js +20 -15
  20. package/dist/plugins/transform-cache.d.ts +19 -0
  21. package/dist/plugins/transform-cache.js +36 -0
  22. package/dist/routing/app-route-graph.d.ts +14 -6
  23. package/dist/routing/app-route-graph.js +106 -16
  24. package/dist/server/api-handler.d.ts +2 -0
  25. package/dist/server/api-handler.js +3 -3
  26. package/dist/server/app-browser-entry.js +103 -31
  27. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  28. package/dist/server/app-browser-navigation-controller.js +1 -1
  29. package/dist/server/app-page-cache-finalizer.js +1 -1
  30. package/dist/server/app-page-cache.d.ts +1 -1
  31. package/dist/server/app-page-cache.js +16 -2
  32. package/dist/server/app-page-dispatch.d.ts +8 -0
  33. package/dist/server/app-page-dispatch.js +31 -6
  34. package/dist/server/app-page-element-builder.d.ts +2 -0
  35. package/dist/server/app-page-element-builder.js +33 -7
  36. package/dist/server/app-page-head.d.ts +3 -3
  37. package/dist/server/app-page-head.js +58 -13
  38. package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
  39. package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
  40. package/dist/server/app-page-probe.d.ts +4 -0
  41. package/dist/server/app-page-probe.js +6 -2
  42. package/dist/server/app-page-request.d.ts +3 -0
  43. package/dist/server/app-page-request.js +1 -1
  44. package/dist/server/app-page-response.js +1 -1
  45. package/dist/server/app-page-route-wiring.d.ts +7 -0
  46. package/dist/server/app-page-route-wiring.js +211 -49
  47. package/dist/server/app-pages-bridge.d.ts +1 -1
  48. package/dist/server/app-pages-bridge.js +2 -1
  49. package/dist/server/app-route-handler-cache.js +4 -0
  50. package/dist/server/app-route-handler-dispatch.js +9 -3
  51. package/dist/server/app-route-handler-response.js +1 -1
  52. package/dist/server/app-route-module-loader.d.ts +6 -0
  53. package/dist/server/app-route-module-loader.js +3 -0
  54. package/dist/server/app-router-entry.js +6 -3
  55. package/dist/server/app-rsc-errors.js +10 -0
  56. package/dist/server/app-rsc-handler.js +21 -9
  57. package/dist/server/app-rsc-route-matching.d.ts +9 -0
  58. package/dist/server/app-rsc-route-matching.js +6 -0
  59. package/dist/server/app-ssr-entry.js +4 -4
  60. package/dist/server/cache-control.d.ts +2 -2
  61. package/dist/server/cache-control.js +2 -1
  62. package/dist/server/dev-server.d.ts +3 -1
  63. package/dist/server/dev-server.js +145 -312
  64. package/dist/server/headers.d.ts +2 -2
  65. package/dist/server/headers.js +4 -3
  66. package/dist/server/isr-cache.d.ts +10 -33
  67. package/dist/server/isr-cache.js +33 -43
  68. package/dist/server/isr-decision.d.ts +2 -2
  69. package/dist/server/pages-api-route.d.ts +2 -0
  70. package/dist/server/pages-api-route.js +4 -1
  71. package/dist/server/pages-dev-hydration.js +0 -1
  72. package/dist/server/pages-get-initial-props.d.ts +1 -1
  73. package/dist/server/pages-get-initial-props.js +1 -4
  74. package/dist/server/pages-i18n.js +64 -16
  75. package/dist/server/pages-node-compat.d.ts +2 -0
  76. package/dist/server/pages-node-compat.js +7 -3
  77. package/dist/server/pages-page-data.d.ts +61 -9
  78. package/dist/server/pages-page-data.js +334 -74
  79. package/dist/server/pages-page-handler.d.ts +5 -1
  80. package/dist/server/pages-page-handler.js +115 -19
  81. package/dist/server/pages-page-response.d.ts +5 -3
  82. package/dist/server/pages-page-response.js +23 -26
  83. package/dist/server/pages-request-pipeline.d.ts +7 -0
  84. package/dist/server/pages-request-pipeline.js +5 -1
  85. package/dist/server/pages-revalidate.d.ts +1 -1
  86. package/dist/server/pages-revalidate.js +54 -8
  87. package/dist/server/pages-router-entry.d.ts +1 -0
  88. package/dist/server/pages-router-entry.js +10 -4
  89. package/dist/server/prod-server.d.ts +2 -1
  90. package/dist/server/prod-server.js +37 -13
  91. package/dist/server/revalidation-host.d.ts +11 -0
  92. package/dist/server/revalidation-host.js +19 -0
  93. package/dist/server/worker-revalidation-context.d.ts +13 -0
  94. package/dist/server/worker-revalidation-context.js +29 -0
  95. package/dist/shims/cache-handler.d.ts +1 -1
  96. package/dist/shims/cache-handler.js +10 -7
  97. package/dist/shims/cache-runtime.d.ts +6 -0
  98. package/dist/shims/cache-runtime.js +4 -1
  99. package/dist/shims/cache.js +1 -1
  100. package/dist/shims/error.js +1 -1
  101. package/dist/shims/fetch-cache.js +1 -1
  102. package/dist/shims/font-google-base.js +17 -8
  103. package/dist/shims/font-local.js +41 -10
  104. package/dist/shims/headers.d.ts +10 -13
  105. package/dist/shims/headers.js +85 -36
  106. package/dist/shims/internal/cookie-serialize.d.ts +10 -9
  107. package/dist/shims/internal/cookie-serialize.js +9 -8
  108. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  109. package/dist/shims/internal/interpolate-as.js +27 -2
  110. package/dist/shims/link.js +18 -6
  111. package/dist/shims/metadata.d.ts +7 -17
  112. package/dist/shims/metadata.js +74 -24
  113. package/dist/shims/navigation.js +1 -1
  114. package/dist/shims/request-context.d.ts +4 -1
  115. package/dist/shims/router.js +18 -7
  116. package/dist/shims/script.js +1 -1
  117. package/dist/shims/server.d.ts +7 -6
  118. package/dist/shims/server.js +156 -57
  119. package/dist/shims/unified-request-context.d.ts +21 -2
  120. package/dist/shims/unified-request-context.js +82 -1
  121. package/dist/utils/cache-control-metadata.d.ts +2 -1
  122. package/dist/utils/cache-control-metadata.js +5 -1
  123. package/dist/utils/html-limited-bots.js +1 -1
  124. package/dist/utils/protocol-headers.d.ts +7 -1
  125. package/dist/utils/protocol-headers.js +7 -1
  126. package/package.json +1 -1
@@ -108,6 +108,60 @@ function createAppPageErrorEntries(route) {
108
108
  }];
109
109
  });
110
110
  }
111
+ function createAppPageLoadingEntries(route) {
112
+ return (route.loadings ?? []).flatMap((loadingModule, index) => {
113
+ if (!loadingModule) return [];
114
+ const treePosition = route.loadingTreePositions?.[index];
115
+ if (treePosition === void 0) return [];
116
+ return [{
117
+ loadingModule,
118
+ treePosition
119
+ }];
120
+ });
121
+ }
122
+ function getPrefetchLoadingEntry(route) {
123
+ let firstEntry = null;
124
+ for (const [index, loadingModule] of (route.loadings ?? []).entries()) {
125
+ if (!getDefaultExport(loadingModule)) continue;
126
+ const treePosition = route.loadingTreePositions?.[index];
127
+ if (treePosition === void 0) continue;
128
+ if (firstEntry === null || treePosition < firstEntry.treePosition) firstEntry = {
129
+ loadingModule,
130
+ treePosition
131
+ };
132
+ }
133
+ if (firstEntry) return firstEntry;
134
+ return getDefaultExport(route.loading) ? {
135
+ loadingModule: route.loading,
136
+ treePosition: route.routeSegments?.length ?? 0
137
+ } : null;
138
+ }
139
+ function createAppPageSlotLoadingEntries(slot, override) {
140
+ const entries = [];
141
+ const slotLoadingModules = (slot.loadings?.length ?? 0) > 0 ? slot.loadings : slot.loading ? [slot.loading] : [];
142
+ const slotLoadingTreePositions = (slot.loadingTreePositions?.length ?? 0) > 0 ? slot.loadingTreePositions : [0];
143
+ for (const [index, loadingModule] of slotLoadingModules.entries()) {
144
+ const treePosition = slotLoadingTreePositions[index];
145
+ if (!getDefaultExport(loadingModule) || treePosition === void 0) continue;
146
+ if (override && treePosition !== 0) continue;
147
+ entries.push({
148
+ loadingModule,
149
+ treePosition
150
+ });
151
+ }
152
+ for (const [index, loadingModule] of (override?.loadingModules ?? []).entries()) {
153
+ const treePosition = override?.loadingTreePositions?.[index];
154
+ if (!getDefaultExport(loadingModule) || treePosition === void 0) continue;
155
+ entries.push({
156
+ loadingModule,
157
+ treePosition
158
+ });
159
+ }
160
+ return entries;
161
+ }
162
+ function getFirstLoadingEntry(entries) {
163
+ return entries.reduce((first, entry) => first === null || entry.treePosition < first.treePosition ? entry : first, null);
164
+ }
111
165
  function createAppPageParallelSlotEntries(layoutIndex, layoutEntries, route, getEffectiveSlotParams, resolveSlotOverride) {
112
166
  const parallelSlots = {};
113
167
  for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {
@@ -223,13 +277,26 @@ function buildAppPageElements(options) {
223
277
  const streamingMetadataOutletId = options.streamingMetadataOutlet ? `__vinext_streaming_metadata_outlet:${routeId}` : null;
224
278
  const layoutEntries = createAppPageLayoutEntries(options.route);
225
279
  const templateEntries = createAppPageTemplateEntries(options.route);
280
+ const loadingEntries = createAppPageLoadingEntries(options.route);
226
281
  const errorEntries = createAppPageErrorEntries(options.route);
282
+ const findNearestAncestorLoadingEntry = (treePosition) => {
283
+ for (let index = loadingEntries.length - 1; index >= 0; index--) if (loadingEntries[index].treePosition < treePosition) return loadingEntries[index];
284
+ };
285
+ const findNearestLoadingEntryAtOrAbove = (treePosition) => {
286
+ let nearest;
287
+ for (const entry of loadingEntries) if (entry.treePosition <= treePosition && (!nearest || entry.treePosition > nearest.treePosition)) nearest = entry;
288
+ return nearest;
289
+ };
290
+ const isPrefetchLoadingShell = renderMode === APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
291
+ const prefetchLoadingEntry = isPrefetchLoadingShell ? getPrefetchLoadingEntry(options.route) : null;
227
292
  const metadataPlacement = options.metadataPlacement ?? "head";
228
293
  const layoutEntriesByTreePosition = /* @__PURE__ */ new Map();
229
294
  const templateEntriesByTreePosition = /* @__PURE__ */ new Map();
295
+ const loadingEntriesByTreePosition = /* @__PURE__ */ new Map();
230
296
  const errorEntriesByTreePosition = /* @__PURE__ */ new Map();
231
297
  for (const layoutEntry of layoutEntries) layoutEntriesByTreePosition.set(layoutEntry.treePosition, layoutEntry);
232
298
  for (const templateEntry of templateEntries) templateEntriesByTreePosition.set(templateEntry.treePosition, templateEntry);
299
+ for (const loadingEntry of loadingEntries) loadingEntriesByTreePosition.set(loadingEntry.treePosition, loadingEntry);
233
300
  for (const errorEntry of errorEntries) errorEntriesByTreePosition.set(errorEntry.treePosition, errorEntry);
234
301
  const layoutIndicesByTreePosition = /* @__PURE__ */ new Map();
235
302
  for (let index = 0; index < layoutEntries.length; index++) layoutIndicesByTreePosition.set(layoutEntries[index].treePosition, index);
@@ -249,6 +316,7 @@ function buildAppPageElements(options) {
249
316
  const orderedTreePositions = Array.from(/* @__PURE__ */ new Set([
250
317
  ...layoutEntries.map((entry) => entry.treePosition),
251
318
  ...templateEntries.map((entry) => entry.treePosition),
319
+ ...loadingEntries.map((entry) => entry.treePosition),
252
320
  ...errorEntries.map((entry) => entry.treePosition)
253
321
  ])).sort((left, right) => left - right);
254
322
  const resolveSlotOverride = (slotKey, slotName) => {
@@ -256,6 +324,11 @@ function buildAppPageElements(options) {
256
324
  if (overrideByKey) return overrideByKey;
257
325
  if (slotKey === slotName || (slotNameCounts.get(slotName) ?? 0) === 1) return options.slotOverrides?.[slotName];
258
326
  };
327
+ const prefetchSlotLoadingEntries = isPrefetchLoadingShell ? Object.entries(options.route.slots ?? {}).flatMap(([slotKey, slot]) => {
328
+ return getFirstLoadingEntry(createAppPageSlotLoadingEntries(slot, resolveSlotOverride(slotKey, slot.name) ?? null)) ? [{ ownerTreePosition: slot.ownerTreePosition ?? 0 }] : [];
329
+ }) : [];
330
+ const prefetchCutoffTreePosition = isPrefetchLoadingShell ? prefetchLoadingEntry?.treePosition ?? prefetchSlotLoadingEntries.reduce((deepest, entry) => Math.max(deepest, entry.ownerTreePosition), 0) : null;
331
+ const includesPrefetchTreePosition = (treePosition) => prefetchCutoffTreePosition === null || treePosition <= prefetchCutoffTreePosition;
259
332
  const elements = { ...AppElementsWire.createMetadataEntries({
260
333
  interception: renderIdentity?.interception ?? options.interception ?? null,
261
334
  interceptionContext,
@@ -278,6 +351,7 @@ function buildAppPageElements(options) {
278
351
  if (options.streamingMetadataOutlet && streamingMetadataOutletId) elements[streamingMetadataOutletId] = /* @__PURE__ */ jsx(AppPageMetadataOutlet, { metadata: options.streamingMetadataOutlet });
279
352
  const getEffectiveSlotParams = (slotKey, slotName) => resolveSlotOverride(slotKey, slotName)?.params ?? options.matchedParams;
280
353
  for (const treePosition of orderedTreePositions) {
354
+ if (isPrefetchLoadingShell && !includesPrefetchTreePosition(treePosition)) continue;
281
355
  const layoutIndex = layoutIndicesByTreePosition.get(treePosition);
282
356
  if (layoutIndex !== void 0) {
283
357
  const layoutEntry = layoutEntries[layoutIndex];
@@ -298,19 +372,31 @@ function buildAppPageElements(options) {
298
372
  pageDependencies.push(templateDependency);
299
373
  }
300
374
  const routeLoadingComponent = getDefaultExport(options.route.loading);
301
- const isPrefetchLoadingShell = renderMode === APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
302
- if (isPrefetchLoadingShell && routeLoadingComponent !== null) elements[APP_PREFETCH_LOADING_SHELL_MARKER_KEY] = "LoadingBoundary";
375
+ const prefetchLoadingComponent = getDefaultExport(prefetchLoadingEntry?.loadingModule);
376
+ if (isPrefetchLoadingShell && (prefetchLoadingComponent !== null || prefetchSlotLoadingEntries.length > 0)) elements[APP_PREFETCH_LOADING_SHELL_MARKER_KEY] = "LoadingBoundary";
303
377
  elements[pageElementId] = isPrefetchLoadingShell ? null : renderAfterAppDependencies(options.element, pageDependencies);
304
378
  for (const templateEntry of templateEntries) {
379
+ if (isPrefetchLoadingShell && !includesPrefetchTreePosition(templateEntry.treePosition)) continue;
305
380
  const templateComponent = getDefaultExport(templateEntry.templateModule);
306
381
  if (!templateComponent) continue;
307
382
  const TemplateComponent = templateComponent;
308
383
  const templateDependency = templateDependenciesById.get(templateEntry.id);
309
- const templateElement = templateDependency ? renderWithAppDependencyBarrier(/* @__PURE__ */ jsx(TemplateComponent, { children: /* @__PURE__ */ jsx(Children$1, {}) }), templateDependency) : /* @__PURE__ */ jsx(TemplateComponent, { children: /* @__PURE__ */ jsx(Children$1, {}) });
384
+ let templateElement = templateDependency ? renderWithAppDependencyBarrier(/* @__PURE__ */ jsx(TemplateComponent, { children: /* @__PURE__ */ jsx(Children$1, {}) }), templateDependency) : /* @__PURE__ */ jsx(TemplateComponent, { children: /* @__PURE__ */ jsx(Children$1, {}) });
385
+ const ancestorLoadingEntry = findNearestAncestorLoadingEntry(templateEntry.treePosition);
386
+ const ancestorLoadingComponent = getDefaultExport(ancestorLoadingEntry?.loadingModule);
387
+ if (ancestorLoadingComponent && ancestorLoadingEntry) {
388
+ const AncestorLoadingComponent = ancestorLoadingComponent;
389
+ const loadingResetKey = resolveAppPageSegmentStateKey(routeSegments, ancestorLoadingEntry.treePosition, options.matchedParams);
390
+ templateElement = /* @__PURE__ */ jsx(Suspense, {
391
+ fallback: /* @__PURE__ */ jsx(AncestorLoadingComponent, {}),
392
+ children: templateElement
393
+ }, loadingResetKey || routeResetKey);
394
+ }
310
395
  elements[templateEntry.id] = renderAfterAppDependencies(templateElement, templateDependenciesBeforeById.get(templateEntry.id) ?? []);
311
396
  }
312
397
  for (let index = 0; index < layoutEntries.length; index++) {
313
398
  const layoutEntry = layoutEntries[index];
399
+ if (isPrefetchLoadingShell && !includesPrefetchTreePosition(layoutEntry.treePosition)) continue;
314
400
  const layoutComponent = getDefaultExport(layoutEntry.layoutModule);
315
401
  if (!layoutComponent) continue;
316
402
  const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, layoutEntry.treePosition, options.matchedParams);
@@ -329,79 +415,146 @@ function buildAppPageElements(options) {
329
415
  }
330
416
  const LayoutComponent = layoutComponent;
331
417
  const layoutDependency = layoutDependenciesByIndex.get(index);
332
- const layoutElement = layoutDependency ? renderWithAppDependencyBarrier(/* @__PURE__ */ jsx(LayoutComponent, {
418
+ let layoutElement = layoutDependency ? renderWithAppDependencyBarrier(/* @__PURE__ */ jsx(LayoutComponent, {
333
419
  ...layoutProps,
334
420
  children: /* @__PURE__ */ jsx(Children$1, {})
335
421
  }), layoutDependency) : /* @__PURE__ */ jsx(LayoutComponent, {
336
422
  ...layoutProps,
337
423
  children: /* @__PURE__ */ jsx(Children$1, {})
338
424
  });
425
+ const ancestorLoadingEntry = findNearestAncestorLoadingEntry(layoutEntry.treePosition);
426
+ const ancestorLoadingComponent = getDefaultExport(ancestorLoadingEntry?.loadingModule);
427
+ if (ancestorLoadingComponent && ancestorLoadingEntry) {
428
+ const AncestorLoadingComponent = ancestorLoadingComponent;
429
+ const loadingResetKey = resolveAppPageSegmentStateKey(routeSegments, ancestorLoadingEntry.treePosition, options.matchedParams);
430
+ layoutElement = /* @__PURE__ */ jsx(Suspense, {
431
+ fallback: /* @__PURE__ */ jsx(AncestorLoadingComponent, {}),
432
+ children: layoutElement
433
+ }, loadingResetKey || routeResetKey);
434
+ }
339
435
  elements[layoutEntry.id] = renderAfterAppDependencies(layoutElement, layoutDependenciesBefore[index] ?? []);
340
436
  }
341
437
  for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {
342
438
  const slotName = slot.name;
343
439
  const targetIndex = slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1;
440
+ const targetTreePosition = layoutEntries[targetIndex]?.treePosition ?? 0;
441
+ const ownerTreePosition = slot.ownerTreePosition ?? targetTreePosition;
442
+ const isOwnedAtRoutePrefetchCutoff = isPrefetchLoadingShell && prefetchLoadingEntry !== null && ownerTreePosition === prefetchLoadingEntry.treePosition;
443
+ if (isPrefetchLoadingShell && (prefetchLoadingEntry ? ownerTreePosition > prefetchLoadingEntry.treePosition : !includesPrefetchTreePosition(targetTreePosition))) continue;
344
444
  const slotId = resolveAppPageSlotId(slot, layoutEntries[targetIndex]?.treePath ?? "/");
345
445
  const slotOverride = resolveSlotOverride(slotKey, slotName);
346
446
  const slotParams = getEffectiveSlotParams(slotKey, slotName);
347
447
  const slotRouteSegments = slotOverride?.routeSegments ?? slot.routeSegments ?? [];
348
448
  const slotOwnerParams = resolveAppPageSegmentParams(options.route.routeSegments, layoutEntries[targetIndex]?.treePosition ?? 0, options.matchedParams);
349
449
  const slotResetKey = resolveAppPageRouteStateKey(slotRouteSegments, slotParams);
450
+ const hasSlotTreeOverride = slotOverride?.pageModule != null || slotOverride?.layoutModules !== void 0;
451
+ const slotLoadingEntries = createAppPageSlotLoadingEntries(slot, hasSlotTreeOverride ? slotOverride ?? null : null);
452
+ const prefetchSlotLoadingEntry = isOwnedAtRoutePrefetchCutoff ? prefetchLoadingEntry : isPrefetchLoadingShell ? getFirstLoadingEntry(slotLoadingEntries) : null;
453
+ if (isPrefetchLoadingShell && prefetchSlotLoadingEntry === null) continue;
350
454
  const overrideOrPageComponent = getDefaultExport(slotOverride?.pageModule) ?? getDefaultExport(slot.page);
351
455
  const defaultComponent = getDefaultExport(slot.default);
352
456
  if (!overrideOrPageComponent && defaultComponent && options.isRscRequest && options.mountedSlotIds?.has(slotId)) continue;
353
457
  const slotComponent = overrideOrPageComponent ?? defaultComponent;
354
- if (!slotComponent) {
458
+ if (!slotComponent && !isOwnedAtRoutePrefetchCutoff) {
355
459
  elements[slotId] = AppElementsWire.unmatchedSlotValue;
356
460
  continue;
357
461
  }
358
- const slotProps = { params: options.makeThenableParams(slotParams) };
359
- if (options.searchParams !== void 0) slotProps.searchParams = options.searchParams;
360
- if (slotOverride?.props) Object.assign(slotProps, slotOverride.props);
361
- let slotElement = options.createPageElement ? options.createPageElement(slotComponent, slotProps) : (() => {
362
- return /* @__PURE__ */ jsx(slotComponent, { ...slotProps });
363
- })();
364
- const hasSlotTreeOverride = slotOverride?.pageModule != null || slotOverride?.layoutModules !== void 0;
365
- const interceptLayouts = slotOverride?.layoutModules ?? [];
366
- for (let layoutIndex = interceptLayouts.length - 1; layoutIndex >= 0; layoutIndex--) {
367
- const interceptLayoutComponent = getDefaultExport(interceptLayouts[layoutIndex]);
368
- if (!interceptLayoutComponent) continue;
369
- const InterceptLayoutComponent = interceptLayoutComponent;
370
- const interceptLayoutParams = resolveSlotLayoutParams(slotOverride?.branchSegments ?? slotRouteSegments, slotOverride?.layoutSegments?.[layoutIndex]?.length ?? slotRouteSegments.length, slotParams);
371
- slotElement = /* @__PURE__ */ jsx(InterceptLayoutComponent, {
372
- params: options.makeThenableParams(interceptLayoutParams),
373
- children: slotElement
462
+ let slotElement;
463
+ if (prefetchSlotLoadingEntry) slotElement = /* @__PURE__ */ jsx(getDefaultExport(prefetchSlotLoadingEntry.loadingModule), {});
464
+ else {
465
+ const slotProps = { params: options.makeThenableParams(slotParams) };
466
+ if (options.searchParams !== void 0) slotProps.searchParams = options.searchParams;
467
+ if (slotOverride?.props) Object.assign(slotProps, slotOverride.props);
468
+ slotElement = options.createPageElement ? options.createPageElement(slotComponent, slotProps) : (() => {
469
+ return /* @__PURE__ */ jsx(slotComponent, { ...slotProps });
470
+ })();
471
+ }
472
+ const branchSegments = slotOverride?.branchSegments ?? slotRouteSegments;
473
+ const branchLayouts = /* @__PURE__ */ new Map();
474
+ const addBranchLayout = (treePosition, entry) => {
475
+ const entries = branchLayouts.get(treePosition) ?? [];
476
+ entries.push(entry);
477
+ branchLayouts.set(treePosition, entries);
478
+ };
479
+ if (hasSlotTreeOverride) for (const [layoutIndex, layoutModule] of (slotOverride?.layoutModules ?? []).entries()) {
480
+ const component = getDefaultExport(layoutModule);
481
+ if (!component) continue;
482
+ const treePosition = slotOverride?.layoutSegments?.[layoutIndex]?.length ?? branchSegments.length;
483
+ addBranchLayout(treePosition, {
484
+ component,
485
+ params: resolveSlotLayoutParams(branchSegments, treePosition, slotParams)
374
486
  });
375
487
  }
376
- if (!hasSlotTreeOverride) for (let layoutIndex = (slot.configLayouts?.length ?? 0) - 1; layoutIndex >= 0; layoutIndex--) {
377
- const nestedLayoutComponent = getDefaultExport(slot.configLayouts?.[layoutIndex]);
378
- if (!nestedLayoutComponent) continue;
379
- const NestedLayoutComponent = nestedLayoutComponent;
380
- const nestedLayoutParams = resolveSlotLayoutParams(slotRouteSegments, slot.configLayoutTreePositions?.[layoutIndex] ?? 0, slotParams);
381
- slotElement = /* @__PURE__ */ jsx(NestedLayoutComponent, {
382
- params: options.makeThenableParams({
488
+ else for (const [layoutIndex, layoutModule] of (slot.configLayouts ?? []).entries()) {
489
+ const component = getDefaultExport(layoutModule);
490
+ if (!component) continue;
491
+ const treePosition = slot.configLayoutTreePositions?.[layoutIndex] ?? 0;
492
+ addBranchLayout(treePosition, {
493
+ component,
494
+ params: {
383
495
  ...slotOwnerParams,
384
- ...nestedLayoutParams
385
- }),
386
- children: slotElement
496
+ ...resolveSlotLayoutParams(slotRouteSegments, treePosition, slotParams)
497
+ }
387
498
  });
388
499
  }
389
500
  const slotLayoutComponent = overrideOrPageComponent ? getDefaultExport(slot.layout) : null;
390
- if (slotLayoutComponent) slotElement = /* @__PURE__ */ jsx(slotLayoutComponent, {
391
- params: options.makeThenableParams(slotOwnerParams),
392
- children: slotElement
393
- });
394
- const slotLoadingComponent = getDefaultExport(slot.loading);
395
- if (slotLoadingComponent) slotElement = /* @__PURE__ */ jsx(Suspense, {
396
- fallback: /* @__PURE__ */ jsx(slotLoadingComponent, {}),
397
- children: slotElement
398
- }, slotResetKey);
501
+ if (slotLayoutComponent) {
502
+ const rootEntries = branchLayouts.get(0) ?? [];
503
+ branchLayouts.set(0, [{
504
+ component: slotLayoutComponent,
505
+ params: slotOwnerParams
506
+ }, ...rootEntries]);
507
+ }
508
+ const branchLoadings = /* @__PURE__ */ new Map();
509
+ for (const entry of slotLoadingEntries) {
510
+ const component = getDefaultExport(entry.loadingModule);
511
+ if (!component) continue;
512
+ const components = branchLoadings.get(entry.treePosition) ?? [];
513
+ components.push(component);
514
+ branchLoadings.set(entry.treePosition, components);
515
+ }
399
516
  const slotErrorComponent = getErrorBoundaryExport(slot.error);
400
- if (slotErrorComponent) slotElement = /* @__PURE__ */ jsx(ErrorBoundary, {
401
- resetKey: slotResetKey,
402
- fallback: slotErrorComponent,
403
- children: slotElement
404
- });
517
+ const branchTreePositions = Array.from(/* @__PURE__ */ new Set([
518
+ ...branchLayouts.keys(),
519
+ ...branchLoadings.keys(),
520
+ ...slotErrorComponent ? [0] : []
521
+ ])).filter((treePosition) => !prefetchSlotLoadingEntry || !isOwnedAtRoutePrefetchCutoff && treePosition <= prefetchSlotLoadingEntry.treePosition).sort((left, right) => left - right);
522
+ for (let index = branchTreePositions.length - 1; index >= 0; index--) {
523
+ const treePosition = branchTreePositions[index];
524
+ const loadingComponents = prefetchSlotLoadingEntry ? [] : branchLoadings.get(treePosition) ?? [];
525
+ for (let loadingIndex = loadingComponents.length - 1; loadingIndex >= 0; loadingIndex--) {
526
+ const LoadingComponent = loadingComponents[loadingIndex];
527
+ const loadingResetKey = resolveAppPageSegmentStateKey(branchSegments, treePosition, slotParams);
528
+ slotElement = /* @__PURE__ */ jsx(Suspense, {
529
+ fallback: /* @__PURE__ */ jsx(LoadingComponent, {}),
530
+ children: slotElement
531
+ }, loadingResetKey || slotResetKey);
532
+ }
533
+ if (treePosition === 0 && slotErrorComponent) slotElement = /* @__PURE__ */ jsx(ErrorBoundary, {
534
+ resetKey: slotResetKey,
535
+ fallback: slotErrorComponent,
536
+ children: slotElement
537
+ });
538
+ const layoutEntriesAtPosition = branchLayouts.get(treePosition) ?? [];
539
+ for (let layoutIndex = layoutEntriesAtPosition.length - 1; layoutIndex >= 0; layoutIndex--) {
540
+ const layoutEntry = layoutEntriesAtPosition[layoutIndex];
541
+ const LayoutComponent = layoutEntry.component;
542
+ slotElement = /* @__PURE__ */ jsx(LayoutComponent, {
543
+ params: options.makeThenableParams(layoutEntry.params),
544
+ children: slotElement
545
+ });
546
+ }
547
+ }
548
+ const ownerLoadingEntry = isPrefetchLoadingShell ? void 0 : findNearestLoadingEntryAtOrAbove(ownerTreePosition);
549
+ const ownerLoadingComponent = getDefaultExport(ownerLoadingEntry?.loadingModule);
550
+ if (ownerLoadingComponent && ownerLoadingEntry) {
551
+ const OwnerLoadingComponent = ownerLoadingComponent;
552
+ const ownerResetKey = resolveAppPageSegmentStateKey(routeSegments, ownerLoadingEntry.treePosition, options.matchedParams);
553
+ slotElement = /* @__PURE__ */ jsx(Suspense, {
554
+ fallback: /* @__PURE__ */ jsx(OwnerLoadingComponent, {}),
555
+ children: slotElement
556
+ }, ownerResetKey || slotResetKey);
557
+ }
405
558
  elements[slotId] = renderAfterAppDependencies(slotElement, targetIndex >= 0 ? slotDependenciesByLayoutIndex[targetIndex] ?? [] : []);
406
559
  }
407
560
  let routeChildren = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(LayoutSegmentProvider, {
@@ -409,8 +562,8 @@ function buildAppPageElements(options) {
409
562
  segmentMap: { children: [APP_PAGE_SEGMENT_KEY] },
410
563
  children: /* @__PURE__ */ jsx(Slot, { id: pageElementId })
411
564
  }), createAppPageStreamingMetadataOutlet(streamingMetadataOutletId, options.streamingMetadataOutletSuspended)] });
412
- if (isPrefetchLoadingShell) if (routeLoadingComponent === null) routeChildren = null;
413
- else routeChildren = /* @__PURE__ */ jsx(routeLoadingComponent, {});
565
+ if (isPrefetchLoadingShell) if (prefetchLoadingComponent === null) routeChildren = null;
566
+ else routeChildren = /* @__PURE__ */ jsx(prefetchLoadingComponent, {});
414
567
  else {
415
568
  routeChildren = /* @__PURE__ */ jsx(RedirectBoundary, { children: routeChildren });
416
569
  if (routeLoadingComponent) routeChildren = /* @__PURE__ */ jsx(Suspense, {
@@ -444,13 +597,22 @@ function buildAppPageElements(options) {
444
597
  fallback: pageErrorComponent,
445
598
  children: routeChildren
446
599
  });
447
- for (let index = orderedTreePositions.length - 1; index >= 0; index--) {
448
- const treePosition = orderedTreePositions[index];
600
+ const renderedTreePositions = isPrefetchLoadingShell ? orderedTreePositions.filter(includesPrefetchTreePosition) : orderedTreePositions;
601
+ for (let index = renderedTreePositions.length - 1; index >= 0; index--) {
602
+ const treePosition = renderedTreePositions[index];
449
603
  const segmentResetKey = resolveAppPageSegmentStateKey(routeSegments, treePosition, options.matchedParams);
450
604
  let segmentChildren = routeChildren;
451
605
  const layoutEntry = layoutEntriesByTreePosition.get(treePosition);
452
606
  const templateEntry = templateEntriesByTreePosition.get(treePosition);
607
+ const loadingEntry = loadingEntriesByTreePosition.get(treePosition);
453
608
  const errorEntry = errorEntriesByTreePosition.get(treePosition);
609
+ if (!isPrefetchLoadingShell && treePosition < routeSegments.length) {
610
+ const segmentLoadingComponent = getDefaultExport(loadingEntry?.loadingModule);
611
+ if (segmentLoadingComponent) segmentChildren = /* @__PURE__ */ jsx(Suspense, {
612
+ fallback: /* @__PURE__ */ jsx(segmentLoadingComponent, {}),
613
+ children: segmentChildren
614
+ }, segmentResetKey || routeResetKey);
615
+ }
454
616
  if (layoutEntry) {
455
617
  const layoutNotFoundComponent = getDefaultExport(layoutEntry.notFoundModule);
456
618
  if (layoutNotFoundComponent) segmentChildren = /* @__PURE__ */ jsx(NotFoundBoundary, {
@@ -2,7 +2,7 @@ import { AppMiddlewareContext } from "./app-middleware.js";
2
2
 
3
3
  //#region src/server/app-pages-bridge.d.ts
4
4
  type PagesEntry = {
5
- handleApiRoute?: (request: Request, url: string) => Promise<Response> | Response;
5
+ handleApiRoute?: (request: Request, url: string, ctx?: unknown, trustedRevalidateOrigin?: string) => Promise<Response> | Response;
6
6
  matchApiRoute?: (url: string, request: Request) => PagesRouteMatch | null;
7
7
  matchPageRoute?: (url: string, request: Request) => PagesRouteMatch | null;
8
8
  renderPage?: (request: Request, url: string, query: Record<string, unknown>, parsedUrl: unknown, middlewareRequestHeaders?: Headers | null, options?: {
@@ -1,3 +1,4 @@
1
+ import { getRequestExecutionContext } from "../shims/request-context.js";
1
2
  import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
2
3
  import { pagesRouteHasPriorityOverAppRoute } from "./hybrid-route-priority.js";
3
4
  //#region src/server/app-pages-bridge.ts
@@ -26,7 +27,7 @@ async function renderPagesFallback(options, dependencies) {
26
27
  if (appRouteMatch !== null) {
27
28
  if (apiMatch === null || !pagesRouteHasPriorityOverAppRoute(apiMatch.route, appRouteMatch.route)) return null;
28
29
  }
29
- const pagesApiResponse = await pagesEntry.handleApiRoute(pagesRequest, pagesUrl);
30
+ const pagesApiResponse = await pagesEntry.handleApiRoute(pagesRequest, pagesUrl, void 0, getRequestExecutionContext()?.trustedRevalidateOrigin ?? new URL(pagesRequest.url).origin);
30
31
  const draftCookie = getDraftModeCookieHeader();
31
32
  return applyDraftModeCookie(applyRouteHandlerMiddlewareContext(pagesApiResponse, middlewareContext), draftCookie);
32
33
  }
@@ -12,6 +12,10 @@ async function readAppRouteHandlerCacheResponse(options) {
12
12
  try {
13
13
  const cached = await options.isrGet(routeKey);
14
14
  const cachedValue = getCachedAppRouteValue(cached);
15
+ if (cached?.isExpired) {
16
+ options.isrDebug?.("MISS (expired route)", options.cleanPathname);
17
+ return null;
18
+ }
15
19
  if (cachedValue && !cached?.isStale) {
16
20
  options.isrDebug?.("HIT (route)", options.cleanPathname);
17
21
  options.clearRequestContext();
@@ -1,4 +1,4 @@
1
- import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
1
+ import { closeAfterResponse, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
3
  import { reportRequestError } from "./instrumentation.js";
4
4
  import { consumeDynamicUsage, getActiveDraftModeState, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, setHeadersAccessPhase } from "../shims/headers.js";
@@ -23,7 +23,7 @@ function buildRouteHandlerPageCacheTags(pathname, extraTags, routeSegments) {
23
23
  return buildPageCacheTags(pathname, extraTags, routeSegments, "route");
24
24
  }
25
25
  async function runInRouteHandlerRevalidationContext(options, renderFn) {
26
- await runWithRequestContext(createRequestContext({
26
+ const requestContext = createRequestContext({
27
27
  headersContext: createStaticGenerationHeadersContext({
28
28
  draftModeEnabled: false,
29
29
  draftModeSecret: options.draftModeSecret,
@@ -33,7 +33,8 @@ async function runInRouteHandlerRevalidationContext(options, renderFn) {
33
33
  }),
34
34
  executionContext: getRequestExecutionContext(),
35
35
  unstableCacheRevalidation: "foreground"
36
- }), async () => {
36
+ });
37
+ const revalidation = runWithRequestContext(requestContext, async () => {
37
38
  ensureFetchPatch();
38
39
  setCurrentFetchSoftTags(buildRouteHandlerPageCacheTags(options.cleanPathname, [], options.routeSegments));
39
40
  setCurrentFetchCacheMode(options.fetchCacheMode);
@@ -44,6 +45,11 @@ async function runInRouteHandlerRevalidationContext(options, renderFn) {
44
45
  await _drainPendingRevalidations();
45
46
  }
46
47
  });
48
+ try {
49
+ await revalidation;
50
+ } finally {
51
+ await closeAfterResponse(requestContext);
52
+ }
47
53
  }
48
54
  async function dispatchAppRouteHandler(options) {
49
55
  const { route } = options;
@@ -1,9 +1,9 @@
1
1
  import "../utils/protocol-headers.js";
2
2
  import "./headers.js";
3
3
  import { processMiddlewareHeaders } from "./request-pipeline.js";
4
- import { setCacheStateHeaders } from "./cache-headers.js";
5
4
  import { applyCdnResponseHeaders } from "./cache-control.js";
6
5
  import { buildAppRouteMissIsrCacheControl, decideIsr } from "./isr-decision.js";
6
+ import { setCacheStateHeaders } from "./cache-headers.js";
7
7
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
8
8
  import { getSetCookieName } from "./cookie-utils.js";
9
9
  //#region src/server/app-route-handler-response.ts
@@ -28,6 +28,8 @@ type LazyModuleLoaderArray = readonly (LazyModuleThunk | null | undefined)[];
28
28
  type LazyLoadableIntercept = {
29
29
  interceptLayouts?: readonly unknown[] | null;
30
30
  __loadInterceptLayouts?: LazyModuleLoaderArray | null;
31
+ interceptLoadings?: readonly unknown[] | null;
32
+ __loadInterceptLoadings?: LazyModuleLoaderArray | null;
31
33
  __loadState?: {
32
34
  interceptLayoutsLoading: Promise<readonly unknown[]> | null;
33
35
  };
@@ -38,6 +40,7 @@ type LazyLoadableSlot = {
38
40
  layout?: unknown;
39
41
  configLayouts?: readonly unknown[];
40
42
  loading?: unknown;
43
+ loadings?: readonly unknown[];
41
44
  error?: unknown;
42
45
  notFound?: unknown;
43
46
  __loadPage?: LazyModuleThunk | null;
@@ -45,6 +48,7 @@ type LazyLoadableSlot = {
45
48
  __loadLayout?: LazyModuleThunk | null;
46
49
  __loadConfigLayouts?: LazyModuleLoaderArray | null;
47
50
  __loadLoading?: LazyModuleThunk | null;
51
+ __loadLoadings?: LazyModuleLoaderArray | null;
48
52
  __loadError?: LazyModuleThunk | null;
49
53
  __loadNotFound?: LazyModuleThunk | null; /** Hydrated only after an intercept matches, not with the slot's base modules. */
50
54
  intercepts?: LazyLoadableIntercept[];
@@ -54,6 +58,7 @@ type LazyLoadableRoute = {
54
58
  routeHandler?: unknown;
55
59
  layouts?: unknown[];
56
60
  templates?: unknown[];
61
+ loadings?: unknown[];
57
62
  errors?: unknown[];
58
63
  errorPaths?: unknown[];
59
64
  notFounds?: unknown[];
@@ -70,6 +75,7 @@ type LazyLoadableRoute = {
70
75
  __loadRouteHandler?: LazyModuleThunk | null;
71
76
  __loadLayouts?: LazyModuleLoaderArray | null;
72
77
  __loadTemplates?: LazyModuleLoaderArray | null;
78
+ __loadLoadings?: LazyModuleLoaderArray | null;
73
79
  __loadErrors?: LazyModuleLoaderArray | null;
74
80
  __loadErrorPaths?: LazyModuleLoaderArray | null;
75
81
  __loadNotFounds?: LazyModuleLoaderArray | null;
@@ -20,6 +20,7 @@ function loadAppInterceptLayouts(intercept) {
20
20
  if (loadState?.interceptLayoutsLoading) return loadState.interceptLayoutsLoading;
21
21
  const loads = [];
22
22
  pushArrayLoads(loads, intercept.interceptLayouts, intercept.__loadInterceptLayouts);
23
+ pushArrayLoads(loads, intercept.interceptLoadings, intercept.__loadInterceptLoadings);
23
24
  if (loads.length === 0) return Promise.resolve(intercept.interceptLayouts ?? []);
24
25
  const loading = Promise.all(loads).then(() => {
25
26
  if (loadState) loadState.interceptLayoutsLoading = null;
@@ -52,6 +53,7 @@ function ensureAppRouteModulesLoaded(route) {
52
53
  pushFieldLoad(loads, route, "unauthorized", route.__loadUnauthorized);
53
54
  pushArrayLoads(loads, route.layouts, route.__loadLayouts);
54
55
  pushArrayLoads(loads, route.templates, route.__loadTemplates);
56
+ pushArrayLoads(loads, route.loadings, route.__loadLoadings);
55
57
  pushArrayLoads(loads, route.errors, route.__loadErrors);
56
58
  pushArrayLoads(loads, route.errorPaths, route.__loadErrorPaths);
57
59
  pushArrayLoads(loads, route.notFounds, route.__loadNotFounds);
@@ -63,6 +65,7 @@ function ensureAppRouteModulesLoaded(route) {
63
65
  pushFieldLoad(loads, slot, "layout", slot.__loadLayout);
64
66
  pushArrayLoads(loads, slot.configLayouts, slot.__loadConfigLayouts);
65
67
  pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
68
+ pushArrayLoads(loads, slot.loadings, slot.__loadLoadings);
66
69
  pushFieldLoad(loads, slot, "error", slot.__loadError);
67
70
  pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
68
71
  }
@@ -1,6 +1,6 @@
1
1
  import "./server-globals.js";
2
2
  import { runWithExecutionContext } from "../shims/request-context.js";
3
- import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "../utils/protocol-headers.js";
3
+ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
4
4
  import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
5
5
  import { isOpenRedirectShaped } from "./open-redirect.js";
6
6
  import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
@@ -8,6 +8,7 @@ import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js"
8
8
  import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
9
9
  import { finalizeMissingStaticAssetResponse, resolveStaticAssetSignal } from "./worker-utils.js";
10
10
  import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
11
+ import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
11
12
  import rscHandler, { __assetPrefix, __basePath, __imageAllowedWidths, __imageConfig } from "virtual:vinext-rsc-entry";
12
13
  import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
13
14
  import { registerConfiguredImageOptimizer } from "virtual:vinext-image-adapters";
@@ -17,7 +18,8 @@ const __workerAssetPathPrefix = assetPrefixPathname(typeof __assetPrefix === "st
17
18
  var app_router_entry_default = { async fetch(request, env, ctx) {
18
19
  return handleRequest(request, env, ctx);
19
20
  } };
20
- async function handleRequest(request, env, ctx) {
21
+ async function handleRequest(request, env, platformCtx) {
22
+ const ctx = platformCtx?.trustedRevalidateOrigin ? platformCtx : createWorkerRevalidationContext(platformCtx, (internalRequest, internalCtx) => handleRequest(internalRequest, env, internalCtx));
21
23
  registerConfiguredCacheAdapters(env);
22
24
  registerConfiguredImageOptimizer(env);
23
25
  const url = new URL(request.url);
@@ -34,7 +36,8 @@ async function handleRequest(request, env, ctx) {
34
36
  const missingBuildAsset = isNextStaticPath(url.pathname, __workerBasePath, __workerAssetPathPrefix);
35
37
  {
36
38
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);
37
- const filteredHeaders = filterInternalHeaders(request.headers);
39
+ const filteredHeaders = ctx.isInternalPagesRevalidation ? new Headers(request.headers) : filterInternalHeaders(request.headers);
40
+ filteredHeaders.delete(VINEXT_REVALIDATE_HOST_HEADER);
38
41
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
39
42
  if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
40
43
  request = cloneRequestWithHeaders(request, filteredHeaders);
@@ -7,6 +7,11 @@ function hasDigest(error) {
7
7
  }
8
8
  const BAILOUT_TO_CSR_DIGEST = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
9
9
  const DYNAMIC_SERVER_USAGE_DIGEST = "DYNAMIC_SERVER_USAGE";
10
+ function isAbortError(error) {
11
+ if (!error || typeof error !== "object") return false;
12
+ const name = Reflect.get(error, "name");
13
+ return name === "AbortError" || name === "ResponseAborted";
14
+ }
10
15
  /**
11
16
  * vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
12
17
  * string only when the error is a genuine control-flow signal — a redirect,
@@ -52,6 +57,7 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
52
57
  function createRscOnErrorHandler(options) {
53
58
  return (error) => {
54
59
  const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;
60
+ if (isAbortError(error)) return;
55
61
  const wellKnownDigest = getDigestForWellKnownError(error);
56
62
  if (wellKnownDigest !== void 0) return wellKnownDigest;
57
63
  if (nodeEnv !== "production" && error instanceof Error && error.message.includes("Only plain objects, and a few built-ins, can be passed to Client Components")) {
@@ -62,6 +68,10 @@ function createRscOnErrorHandler(options) {
62
68
  const reportableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
63
69
  options.reportRequestError(reportableError instanceof Error ? reportableError : new Error(getThrownValueMessage(reportableError)), options.requestInfo, options.errorContext);
64
70
  }
71
+ if (nodeEnv !== "production" && error && !hasDigest(error)) {
72
+ const loggableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
73
+ console.error("[vinext] Server render error:", loggableError);
74
+ }
65
75
  if (hasDigest(error)) return String(error.digest);
66
76
  if (error) {
67
77
  const digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));