vinext 0.0.47 → 0.0.48

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 (263) hide show
  1. package/README.md +1 -1
  2. package/dist/build/layout-classification.js +3 -1
  3. package/dist/build/layout-classification.js.map +1 -1
  4. package/dist/build/prerender.js +10 -10
  5. package/dist/build/prerender.js.map +1 -1
  6. package/dist/build/report.d.ts +8 -4
  7. package/dist/build/report.js +17 -7
  8. package/dist/build/report.js.map +1 -1
  9. package/dist/build/run-prerender.d.ts +5 -0
  10. package/dist/build/run-prerender.js +4 -1
  11. package/dist/build/run-prerender.js.map +1 -1
  12. package/dist/build/server-manifest.js +2 -7
  13. package/dist/build/server-manifest.js.map +1 -1
  14. package/dist/build/standalone.js +3 -5
  15. package/dist/build/standalone.js.map +1 -1
  16. package/dist/check.js +45 -29
  17. package/dist/check.js.map +1 -1
  18. package/dist/cli-args.d.ts +3 -1
  19. package/dist/cli-args.js +18 -1
  20. package/dist/cli-args.js.map +1 -1
  21. package/dist/cli.js +9 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config/config-matchers.js +46 -37
  24. package/dist/config/config-matchers.js.map +1 -1
  25. package/dist/deploy.d.ts +18 -2
  26. package/dist/deploy.js +47 -4
  27. package/dist/deploy.js.map +1 -1
  28. package/dist/entries/app-rsc-entry.js +11 -9
  29. package/dist/entries/app-rsc-entry.js.map +1 -1
  30. package/dist/entries/app-rsc-manifest.js +4 -1
  31. package/dist/entries/app-rsc-manifest.js.map +1 -1
  32. package/dist/entries/pages-client-entry.js +3 -2
  33. package/dist/entries/pages-client-entry.js.map +1 -1
  34. package/dist/entries/pages-server-entry.js +14 -59
  35. package/dist/entries/pages-server-entry.js.map +1 -1
  36. package/dist/entries/runtime-entry-module.d.ts +12 -3
  37. package/dist/entries/runtime-entry-module.js +15 -4
  38. package/dist/entries/runtime-entry-module.js.map +1 -1
  39. package/dist/index.js +12 -7
  40. package/dist/index.js.map +1 -1
  41. package/dist/plugins/og-assets.js +15 -16
  42. package/dist/plugins/og-assets.js.map +1 -1
  43. package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
  44. package/dist/plugins/rsc-client-shim-excludes.js +10 -1
  45. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  46. package/dist/routing/app-route-graph.d.ts +90 -4
  47. package/dist/routing/app-route-graph.js +210 -7
  48. package/dist/routing/app-route-graph.js.map +1 -1
  49. package/dist/routing/app-router.d.ts +15 -3
  50. package/dist/routing/app-router.js +20 -23
  51. package/dist/routing/app-router.js.map +1 -1
  52. package/dist/routing/file-matcher.d.ts +3 -1
  53. package/dist/routing/file-matcher.js +6 -1
  54. package/dist/routing/file-matcher.js.map +1 -1
  55. package/dist/routing/pages-router.js +10 -19
  56. package/dist/routing/pages-router.js.map +1 -1
  57. package/dist/routing/route-matching.d.ts +28 -0
  58. package/dist/routing/route-matching.js +44 -0
  59. package/dist/routing/route-matching.js.map +1 -0
  60. package/dist/routing/route-pattern.js +4 -1
  61. package/dist/routing/route-pattern.js.map +1 -1
  62. package/dist/routing/route-trie.d.ts +8 -0
  63. package/dist/routing/route-trie.js +12 -1
  64. package/dist/routing/route-trie.js.map +1 -1
  65. package/dist/routing/route-validation.js +3 -4
  66. package/dist/routing/route-validation.js.map +1 -1
  67. package/dist/routing/utils.d.ts +8 -1
  68. package/dist/routing/utils.js +25 -2
  69. package/dist/routing/utils.js.map +1 -1
  70. package/dist/server/app-browser-entry.js +66 -49
  71. package/dist/server/app-browser-entry.js.map +1 -1
  72. package/dist/server/app-browser-navigation-controller.d.ts +7 -5
  73. package/dist/server/app-browser-navigation-controller.js +43 -35
  74. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  75. package/dist/server/app-browser-state.d.ts +33 -15
  76. package/dist/server/app-browser-state.js +52 -59
  77. package/dist/server/app-browser-state.js.map +1 -1
  78. package/dist/server/app-browser-visible-commit.d.ts +68 -0
  79. package/dist/server/app-browser-visible-commit.js +182 -0
  80. package/dist/server/app-browser-visible-commit.js.map +1 -0
  81. package/dist/server/app-client-reference-preloader.d.ts +15 -0
  82. package/dist/server/app-client-reference-preloader.js +46 -0
  83. package/dist/server/app-client-reference-preloader.js.map +1 -0
  84. package/dist/server/app-elements-wire.d.ts +130 -0
  85. package/dist/server/app-elements-wire.js +205 -0
  86. package/dist/server/app-elements-wire.js.map +1 -0
  87. package/dist/server/app-elements.d.ts +2 -84
  88. package/dist/server/app-elements.js +3 -102
  89. package/dist/server/app-elements.js.map +1 -1
  90. package/dist/server/app-fallback-renderer.d.ts +1 -1
  91. package/dist/server/app-middleware.d.ts +2 -1
  92. package/dist/server/app-middleware.js +34 -11
  93. package/dist/server/app-middleware.js.map +1 -1
  94. package/dist/server/app-page-boundary-render.d.ts +1 -1
  95. package/dist/server/app-page-boundary-render.js +8 -5
  96. package/dist/server/app-page-boundary-render.js.map +1 -1
  97. package/dist/server/app-page-boundary.js +2 -1
  98. package/dist/server/app-page-boundary.js.map +1 -1
  99. package/dist/server/app-page-cache.d.ts +1 -0
  100. package/dist/server/app-page-cache.js +8 -13
  101. package/dist/server/app-page-cache.js.map +1 -1
  102. package/dist/server/app-page-dispatch.d.ts +2 -1
  103. package/dist/server/app-page-dispatch.js +18 -10
  104. package/dist/server/app-page-dispatch.js.map +1 -1
  105. package/dist/server/app-page-element-builder.d.ts +1 -1
  106. package/dist/server/app-page-element-builder.js +8 -5
  107. package/dist/server/app-page-element-builder.js.map +1 -1
  108. package/dist/server/app-page-execution.d.ts +23 -5
  109. package/dist/server/app-page-execution.js +39 -24
  110. package/dist/server/app-page-execution.js.map +1 -1
  111. package/dist/server/app-page-head.js +2 -1
  112. package/dist/server/app-page-head.js.map +1 -1
  113. package/dist/server/app-page-method.js +2 -5
  114. package/dist/server/app-page-method.js.map +1 -1
  115. package/dist/server/app-page-probe.d.ts +1 -1
  116. package/dist/server/app-page-probe.js +5 -1
  117. package/dist/server/app-page-probe.js.map +1 -1
  118. package/dist/server/app-page-render.d.ts +1 -1
  119. package/dist/server/app-page-render.js +38 -3
  120. package/dist/server/app-page-render.js.map +1 -1
  121. package/dist/server/app-page-request.d.ts +0 -1
  122. package/dist/server/app-page-request.js +7 -10
  123. package/dist/server/app-page-request.js.map +1 -1
  124. package/dist/server/app-page-response.js +3 -2
  125. package/dist/server/app-page-response.js.map +1 -1
  126. package/dist/server/app-page-route-wiring.d.ts +5 -2
  127. package/dist/server/app-page-route-wiring.js +15 -12
  128. package/dist/server/app-page-route-wiring.js.map +1 -1
  129. package/dist/server/app-page-stream.d.ts +7 -0
  130. package/dist/server/app-page-stream.js +9 -2
  131. package/dist/server/app-page-stream.js.map +1 -1
  132. package/dist/server/app-prerender-endpoints.js +3 -2
  133. package/dist/server/app-prerender-endpoints.js.map +1 -1
  134. package/dist/server/app-route-handler-cache.js +2 -1
  135. package/dist/server/app-route-handler-cache.js.map +1 -1
  136. package/dist/server/app-route-handler-dispatch.js +6 -5
  137. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  138. package/dist/server/app-route-handler-policy.js +13 -13
  139. package/dist/server/app-route-handler-policy.js.map +1 -1
  140. package/dist/server/app-route-handler-response.js +2 -1
  141. package/dist/server/app-route-handler-response.js.map +1 -1
  142. package/dist/server/app-route-handler-runtime.d.ts +9 -1
  143. package/dist/server/app-route-handler-runtime.js +11 -1
  144. package/dist/server/app-route-handler-runtime.js.map +1 -1
  145. package/dist/server/app-router-entry.js +9 -4
  146. package/dist/server/app-router-entry.js.map +1 -1
  147. package/dist/server/app-rsc-cache-busting.d.ts +34 -0
  148. package/dist/server/app-rsc-cache-busting.js +137 -0
  149. package/dist/server/app-rsc-cache-busting.js.map +1 -0
  150. package/dist/server/app-rsc-handler.js +22 -11
  151. package/dist/server/app-rsc-handler.js.map +1 -1
  152. package/dist/server/app-rsc-request-normalization.d.ts +4 -2
  153. package/dist/server/app-rsc-request-normalization.js +10 -6
  154. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  155. package/dist/server/app-rsc-response-finalizer.js +1 -1
  156. package/dist/server/app-rsc-route-matching.js +8 -4
  157. package/dist/server/app-rsc-route-matching.js.map +1 -1
  158. package/dist/server/app-segment-config.js +4 -0
  159. package/dist/server/app-segment-config.js.map +1 -1
  160. package/dist/server/app-server-action-execution.js +43 -51
  161. package/dist/server/app-server-action-execution.js.map +1 -1
  162. package/dist/server/app-ssr-entry.js +21 -20
  163. package/dist/server/app-ssr-entry.js.map +1 -1
  164. package/dist/server/artifact-compatibility.d.ts +44 -0
  165. package/dist/server/artifact-compatibility.js +82 -0
  166. package/dist/server/artifact-compatibility.js.map +1 -0
  167. package/dist/server/cache-proof.d.ts +200 -0
  168. package/dist/server/cache-proof.js +342 -0
  169. package/dist/server/cache-proof.js.map +1 -0
  170. package/dist/server/dev-origin-check.js +8 -4
  171. package/dist/server/dev-origin-check.js.map +1 -1
  172. package/dist/server/dev-server.js +1 -6
  173. package/dist/server/dev-server.js.map +1 -1
  174. package/dist/server/http-error-responses.d.ts +67 -0
  175. package/dist/server/http-error-responses.js +77 -0
  176. package/dist/server/http-error-responses.js.map +1 -0
  177. package/dist/server/image-optimization.js +2 -1
  178. package/dist/server/image-optimization.js.map +1 -1
  179. package/dist/server/metadata-route-response.js +6 -5
  180. package/dist/server/metadata-route-response.js.map +1 -1
  181. package/dist/server/metadata-routes.d.ts +1 -0
  182. package/dist/server/metadata-routes.js +6 -0
  183. package/dist/server/metadata-routes.js.map +1 -1
  184. package/dist/server/middleware-matcher.js +2 -2
  185. package/dist/server/middleware-matcher.js.map +1 -1
  186. package/dist/server/middleware-response-headers.js +21 -0
  187. package/dist/server/middleware-response-headers.js.map +1 -1
  188. package/dist/server/middleware-runtime.js +3 -3
  189. package/dist/server/middleware-runtime.js.map +1 -1
  190. package/dist/server/navigation-trace.d.ts +33 -0
  191. package/dist/server/navigation-trace.js +35 -0
  192. package/dist/server/navigation-trace.js.map +1 -0
  193. package/dist/server/next-error-digest.d.ts +44 -0
  194. package/dist/server/next-error-digest.js +40 -0
  195. package/dist/server/next-error-digest.js.map +1 -0
  196. package/dist/server/pages-api-route.js +2 -1
  197. package/dist/server/pages-api-route.js.map +1 -1
  198. package/dist/server/pages-node-compat.js +4 -16
  199. package/dist/server/pages-node-compat.js.map +1 -1
  200. package/dist/server/pages-page-response.d.ts +2 -8
  201. package/dist/server/pages-page-response.js +44 -14
  202. package/dist/server/pages-page-response.js.map +1 -1
  203. package/dist/server/prod-server.d.ts +6 -0
  204. package/dist/server/prod-server.js +28 -21
  205. package/dist/server/prod-server.js.map +1 -1
  206. package/dist/server/request-pipeline.d.ts +42 -1
  207. package/dist/server/request-pipeline.js +97 -17
  208. package/dist/server/request-pipeline.js.map +1 -1
  209. package/dist/shims/cache-runtime.d.ts +2 -2
  210. package/dist/shims/cache-runtime.js +3 -6
  211. package/dist/shims/cache-runtime.js.map +1 -1
  212. package/dist/shims/cache.js +3 -5
  213. package/dist/shims/cache.js.map +1 -1
  214. package/dist/shims/fetch-cache.js +2 -3
  215. package/dist/shims/fetch-cache.js.map +1 -1
  216. package/dist/shims/head-state.js +2 -3
  217. package/dist/shims/head-state.js.map +1 -1
  218. package/dist/shims/headers.js +4 -44
  219. package/dist/shims/headers.js.map +1 -1
  220. package/dist/shims/i18n-state.js +2 -3
  221. package/dist/shims/i18n-state.js.map +1 -1
  222. package/dist/shims/internal/als-registry.d.ts +15 -0
  223. package/dist/shims/internal/als-registry.js +55 -0
  224. package/dist/shims/internal/als-registry.js.map +1 -0
  225. package/dist/shims/internal/cookie-serialize.d.ts +46 -0
  226. package/dist/shims/internal/cookie-serialize.js +51 -0
  227. package/dist/shims/internal/cookie-serialize.js.map +1 -0
  228. package/dist/shims/link.js +31 -26
  229. package/dist/shims/link.js.map +1 -1
  230. package/dist/shims/metadata.d.ts +26 -1
  231. package/dist/shims/metadata.js +94 -4
  232. package/dist/shims/metadata.js.map +1 -1
  233. package/dist/shims/navigation-state.js +2 -3
  234. package/dist/shims/navigation-state.js.map +1 -1
  235. package/dist/shims/navigation.d.ts +2 -7
  236. package/dist/shims/navigation.js +44 -36
  237. package/dist/shims/navigation.js.map +1 -1
  238. package/dist/shims/request-context.js +2 -4
  239. package/dist/shims/request-context.js.map +1 -1
  240. package/dist/shims/router-state.js +2 -3
  241. package/dist/shims/router-state.js.map +1 -1
  242. package/dist/shims/router.js +2 -2
  243. package/dist/shims/router.js.map +1 -1
  244. package/dist/shims/server.js +5 -30
  245. package/dist/shims/server.js.map +1 -1
  246. package/dist/shims/slot.d.ts +1 -1
  247. package/dist/shims/slot.js +5 -4
  248. package/dist/shims/slot.js.map +1 -1
  249. package/dist/shims/thenable-params.d.ts +5 -2
  250. package/dist/shims/thenable-params.js +26 -6
  251. package/dist/shims/thenable-params.js.map +1 -1
  252. package/dist/shims/unified-request-context.js +2 -14
  253. package/dist/shims/unified-request-context.js.map +1 -1
  254. package/dist/utils/base-path.d.ts +7 -1
  255. package/dist/utils/base-path.js +12 -1
  256. package/dist/utils/base-path.js.map +1 -1
  257. package/dist/utils/safe-json-file.d.ts +18 -0
  258. package/dist/utils/safe-json-file.js +25 -0
  259. package/dist/utils/safe-json-file.js.map +1 -0
  260. package/dist/utils/text-stream.d.ts +29 -0
  261. package/dist/utils/text-stream.js +66 -0
  262. package/dist/utils/text-stream.js.map +1 -0
  263. package/package.json +5 -5
@@ -0,0 +1,205 @@
1
+ import { createArtifactCompatibilityEnvelope, parseArtifactCompatibilityEnvelope } from "./artifact-compatibility.js";
2
+ import { isValidElement } from "react";
3
+ //#region src/server/app-elements-wire.ts
4
+ const APP_INTERCEPTION_SEPARATOR = "\0";
5
+ const APP_ARTIFACT_COMPATIBILITY_KEY = "__artifactCompatibility";
6
+ const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
7
+ const APP_LAYOUT_FLAGS_KEY = "__layoutFlags";
8
+ const APP_ROUTE_KEY = "__route";
9
+ const APP_ROOT_LAYOUT_KEY = "__rootLayout";
10
+ const APP_UNMATCHED_SLOT_WIRE_VALUE = "__VINEXT_UNMATCHED_SLOT__";
11
+ const UNMATCHED_SLOT = Symbol.for("vinext.unmatchedSlot");
12
+ function appendInterceptionContext(identity, interceptionContext) {
13
+ return interceptionContext === null ? identity : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;
14
+ }
15
+ function createAppPayloadRouteId(routePath, interceptionContext) {
16
+ return appendInterceptionContext(`route:${routePath}`, interceptionContext);
17
+ }
18
+ function createAppPayloadPageId(routePath, interceptionContext) {
19
+ return appendInterceptionContext(`page:${routePath}`, interceptionContext);
20
+ }
21
+ function createAppPayloadLayoutId(treePath) {
22
+ return `layout:${treePath}`;
23
+ }
24
+ function createAppPayloadTemplateId(treePath) {
25
+ return `template:${treePath}`;
26
+ }
27
+ function createAppPayloadSlotId(slotName, treePath) {
28
+ return `slot:${slotName}:${treePath}`;
29
+ }
30
+ function createAppPayloadCacheKey(rscUrl, interceptionContext) {
31
+ return appendInterceptionContext(rscUrl, interceptionContext);
32
+ }
33
+ function parsePathWithInterception(input) {
34
+ const separatorIndex = input.indexOf(APP_INTERCEPTION_SEPARATOR);
35
+ const path = separatorIndex === -1 ? input : input.slice(0, separatorIndex);
36
+ if (!path.startsWith("/")) return null;
37
+ return {
38
+ interceptionContext: separatorIndex === -1 ? null : input.slice(separatorIndex + 1),
39
+ path
40
+ };
41
+ }
42
+ /**
43
+ * AppElements tree paths are absolute route-tree paths on the wire.
44
+ * Bare segment names are not valid layout/template/slot tree identities.
45
+ */
46
+ function parseTreePath(input) {
47
+ return input.startsWith("/") ? input : null;
48
+ }
49
+ function parseAppElementsWireElementKey(key) {
50
+ if (key.startsWith("route:")) {
51
+ const parsed = parsePathWithInterception(key.slice(6));
52
+ if (!parsed) return null;
53
+ return {
54
+ interceptionContext: parsed.interceptionContext,
55
+ kind: "route",
56
+ path: parsed.path
57
+ };
58
+ }
59
+ if (key.startsWith("page:")) {
60
+ const parsed = parsePathWithInterception(key.slice(5));
61
+ if (!parsed) return null;
62
+ return {
63
+ interceptionContext: parsed.interceptionContext,
64
+ kind: "page",
65
+ path: parsed.path
66
+ };
67
+ }
68
+ if (key.startsWith("layout:")) {
69
+ const treePath = parseTreePath(key.slice(7));
70
+ return treePath ? {
71
+ kind: "layout",
72
+ treePath
73
+ } : null;
74
+ }
75
+ if (key.startsWith("template:")) {
76
+ const treePath = parseTreePath(key.slice(9));
77
+ return treePath ? {
78
+ kind: "template",
79
+ treePath
80
+ } : null;
81
+ }
82
+ if (key.startsWith("slot:")) {
83
+ const body = key.slice(5);
84
+ const separatorIndex = body.indexOf(":");
85
+ if (separatorIndex <= 0) return null;
86
+ const name = body.slice(0, separatorIndex);
87
+ const treePath = parseTreePath(body.slice(separatorIndex + 1));
88
+ return treePath ? {
89
+ kind: "slot",
90
+ name,
91
+ treePath
92
+ } : null;
93
+ }
94
+ return null;
95
+ }
96
+ function isAppElementsWireSlotId(key) {
97
+ if (!key.startsWith("slot:")) return false;
98
+ const body = key.slice(5);
99
+ const separatorIndex = body.indexOf(":");
100
+ return separatorIndex > 0 && body.charCodeAt(separatorIndex + 1) === 47;
101
+ }
102
+ function createAppElementsWireMetadataEntries(input) {
103
+ return {
104
+ [APP_ROUTE_KEY]: input.routeId,
105
+ [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,
106
+ [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath
107
+ };
108
+ }
109
+ function normalizeAppElements(elements) {
110
+ let needsNormalization = false;
111
+ for (const [key, value] of Object.entries(elements)) if (isAppElementsWireSlotId(key) && value === "__VINEXT_UNMATCHED_SLOT__") {
112
+ needsNormalization = true;
113
+ break;
114
+ }
115
+ if (!needsNormalization) return elements;
116
+ const normalized = {};
117
+ for (const [key, value] of Object.entries(elements)) normalized[key] = isAppElementsWireSlotId(key) && value === "__VINEXT_UNMATCHED_SLOT__" ? UNMATCHED_SLOT : value;
118
+ return normalized;
119
+ }
120
+ function isLayoutFlagsRecord(value) {
121
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
122
+ for (const v of Object.values(value)) if (v !== "s" && v !== "d") return false;
123
+ return true;
124
+ }
125
+ function parseLayoutFlags(value) {
126
+ if (isLayoutFlagsRecord(value)) return value;
127
+ return {};
128
+ }
129
+ /**
130
+ * Type predicate for a plain (non-null, non-array) record of app payload values.
131
+ * Used to distinguish the App Router payload object from bare React elements at
132
+ * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because
133
+ * the outgoing payload carries heterogeneous values (ReactNodes for the rendered
134
+ * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates
135
+ * to React's canonical `isValidElement` so we don't depend on React's internal
136
+ * `$$typeof` marker scheme.
137
+ */
138
+ function isAppElementsRecord(value) {
139
+ if (typeof value !== "object" || value === null) return false;
140
+ if (Array.isArray(value)) return false;
141
+ if (isValidElement(value)) return false;
142
+ return true;
143
+ }
144
+ function withLayoutFlags(elements, layoutFlags) {
145
+ return {
146
+ ...elements,
147
+ [APP_LAYOUT_FLAGS_KEY]: layoutFlags
148
+ };
149
+ }
150
+ function buildOutgoingAppPayload(input) {
151
+ if (!isAppElementsRecord(input.element)) return input.element;
152
+ return {
153
+ ...input.element,
154
+ [APP_LAYOUT_FLAGS_KEY]: input.layoutFlags,
155
+ [APP_ARTIFACT_COMPATIBILITY_KEY]: input.artifactCompatibility ?? createArtifactCompatibilityEnvelope()
156
+ };
157
+ }
158
+ function readArtifactCompatibilityMetadata(value) {
159
+ if (value === void 0) return createArtifactCompatibilityEnvelope();
160
+ return parseArtifactCompatibilityEnvelope(value) ?? createArtifactCompatibilityEnvelope();
161
+ }
162
+ function readAppElementsMetadata(elements) {
163
+ const routeId = elements[APP_ROUTE_KEY];
164
+ if (typeof routeId !== "string") throw new Error("[vinext] Missing __route string in App Router payload");
165
+ const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];
166
+ if (interceptionContext !== void 0 && interceptionContext !== null && typeof interceptionContext !== "string") throw new Error("[vinext] Invalid __interceptionContext in App Router payload");
167
+ const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];
168
+ if (rootLayoutTreePath === void 0) throw new Error("[vinext] Missing __rootLayout key in App Router payload");
169
+ if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== "string") throw new Error("[vinext] Invalid __rootLayout in App Router payload: expected string or null");
170
+ const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);
171
+ return {
172
+ artifactCompatibility: readArtifactCompatibilityMetadata(elements[APP_ARTIFACT_COMPATIBILITY_KEY]),
173
+ interceptionContext: interceptionContext ?? null,
174
+ layoutFlags,
175
+ routeId,
176
+ rootLayoutTreePath
177
+ };
178
+ }
179
+ const AppElementsWire = {
180
+ keys: {
181
+ artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,
182
+ interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,
183
+ layoutFlags: APP_LAYOUT_FLAGS_KEY,
184
+ rootLayout: APP_ROOT_LAYOUT_KEY,
185
+ route: APP_ROUTE_KEY
186
+ },
187
+ unmatchedSlotValue: APP_UNMATCHED_SLOT_WIRE_VALUE,
188
+ createMetadataEntries: createAppElementsWireMetadataEntries,
189
+ decode: normalizeAppElements,
190
+ encodeCacheKey: createAppPayloadCacheKey,
191
+ encodeLayoutId: createAppPayloadLayoutId,
192
+ encodeOutgoingPayload: buildOutgoingAppPayload,
193
+ encodePageId: createAppPayloadPageId,
194
+ encodeRouteId: createAppPayloadRouteId,
195
+ encodeSlotId: createAppPayloadSlotId,
196
+ encodeTemplateId: createAppPayloadTemplateId,
197
+ isSlotId: isAppElementsWireSlotId,
198
+ parseElementKey: parseAppElementsWireElementKey,
199
+ readMetadata: readAppElementsMetadata,
200
+ withLayoutFlags
201
+ };
202
+ //#endregion
203
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags };
204
+
205
+ //# sourceMappingURL=app-elements-wire.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-elements-wire.js","names":[],"sources":["../../src/server/app-elements-wire.ts"],"sourcesContent":["import { isValidElement, type ReactNode } from \"react\";\nimport {\n createArtifactCompatibilityEnvelope,\n parseArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEnvelope,\n} from \"./artifact-compatibility.js\";\n\nconst APP_INTERCEPTION_SEPARATOR = \"\\0\";\n\nexport const APP_ARTIFACT_COMPATIBILITY_KEY = \"__artifactCompatibility\";\nexport const APP_INTERCEPTION_CONTEXT_KEY = \"__interceptionContext\";\nexport const APP_LAYOUT_FLAGS_KEY = \"__layoutFlags\";\nexport const APP_ROUTE_KEY = \"__route\";\nexport const APP_ROOT_LAYOUT_KEY = \"__rootLayout\";\nexport const APP_UNMATCHED_SLOT_WIRE_VALUE = \"__VINEXT_UNMATCHED_SLOT__\";\n\nexport const UNMATCHED_SLOT = Symbol.for(\"vinext.unmatchedSlot\");\n\nexport type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null;\ntype AppWireElementValue = ReactNode | string | null;\n\nexport type AppElements = Readonly<Record<string, AppElementValue>>;\nexport type AppWireElements = Readonly<Record<string, AppWireElementValue>>;\n\n/**\n * Per-layout static/dynamic flags. `\"s\"` = static (skippable on next nav);\n * `\"d\"` = dynamic (must always render).\n *\n * Lifecycle (partial — later PRs extend this):\n *\n * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns\n * LayoutFlags for every layout in the route at render time.\n *\n * 2. ATTACH — AppElementsWire.encodeOutgoingPayload writes `__layoutFlags`\n * into the outgoing App Router payload record.\n *\n * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.\n *\n * 4. PARSE — AppElementsWire.readMetadata extracts layoutFlags from the\n * wire payload on the client side.\n */\nexport type LayoutFlags = Readonly<Record<string, \"s\" | \"d\">>;\n\ntype AppElementsMetadata = {\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n interceptionContext: string | null;\n layoutFlags: LayoutFlags;\n routeId: string;\n rootLayoutTreePath: string | null;\n};\n\ntype AppElementsWireElementKey =\n | { kind: \"layout\"; treePath: string }\n | { interceptionContext: string | null; kind: \"page\"; path: string }\n | { interceptionContext: string | null; kind: \"route\"; path: string }\n | { kind: \"slot\"; name: string; treePath: string }\n | { kind: \"template\"; treePath: string };\n\ntype AppElementsWireMetadataInput = {\n interceptionContext: string | null;\n routeId: string;\n rootLayoutTreePath: string | null;\n};\n\ntype AppElementsWireMetadataEntries = Readonly<{\n [APP_ROUTE_KEY]: string;\n [APP_INTERCEPTION_CONTEXT_KEY]: string | null;\n [APP_ROOT_LAYOUT_KEY]: string | null;\n}>;\n\n/**\n * The outgoing wire payload shape. Includes ReactNode values for the\n * rendered tree plus metadata values like LayoutFlags attached under\n * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements\n * which only carry render-time values.\n */\nexport type AppOutgoingElements = Readonly<\n Record<string, ReactNode | LayoutFlags | ArtifactCompatibilityEnvelope>\n>;\n\ntype AppElementsWireKeys = {\n readonly artifactCompatibility: typeof APP_ARTIFACT_COMPATIBILITY_KEY;\n readonly interceptionContext: typeof APP_INTERCEPTION_CONTEXT_KEY;\n readonly layoutFlags: typeof APP_LAYOUT_FLAGS_KEY;\n readonly rootLayout: typeof APP_ROOT_LAYOUT_KEY;\n readonly route: typeof APP_ROUTE_KEY;\n};\n\ntype AppElementsWireCodec = {\n readonly keys: AppElementsWireKeys;\n readonly unmatchedSlotValue: typeof APP_UNMATCHED_SLOT_WIRE_VALUE;\n createMetadataEntries(input: AppElementsWireMetadataInput): AppElementsWireMetadataEntries;\n decode(elements: AppWireElements): AppElements;\n encodeCacheKey(rscUrl: string, interceptionContext: string | null): string;\n encodeLayoutId(treePath: string): string;\n encodeOutgoingPayload(input: {\n element: ReactNode | Readonly<Record<string, ReactNode>>;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n }): ReactNode | AppOutgoingElements;\n encodePageId(routePath: string, interceptionContext: string | null): string;\n encodeRouteId(routePath: string, interceptionContext: string | null): string;\n encodeSlotId(slotName: string, treePath: string): string;\n encodeTemplateId(treePath: string): string;\n isSlotId(key: string): boolean;\n parseElementKey(key: string): AppElementsWireElementKey | null;\n readMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;\n withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n ): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags };\n};\n\nfunction appendInterceptionContext(identity: string, interceptionContext: string | null): string {\n return interceptionContext === null\n ? identity\n : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;\n}\n\nfunction createAppPayloadRouteId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`route:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadPageId(routePath: string, interceptionContext: string | null): string {\n return appendInterceptionContext(`page:${routePath}`, interceptionContext);\n}\n\nfunction createAppPayloadLayoutId(treePath: string): string {\n return `layout:${treePath}`;\n}\n\nfunction createAppPayloadTemplateId(treePath: string): string {\n return `template:${treePath}`;\n}\n\nfunction createAppPayloadSlotId(slotName: string, treePath: string): string {\n return `slot:${slotName}:${treePath}`;\n}\n\nfunction createAppPayloadCacheKey(rscUrl: string, interceptionContext: string | null): string {\n return appendInterceptionContext(rscUrl, interceptionContext);\n}\n\nfunction parsePathWithInterception(input: string): {\n interceptionContext: string | null;\n path: string;\n} | null {\n const separatorIndex = input.indexOf(APP_INTERCEPTION_SEPARATOR);\n const path = separatorIndex === -1 ? input : input.slice(0, separatorIndex);\n if (!path.startsWith(\"/\")) return null;\n\n return {\n interceptionContext: separatorIndex === -1 ? null : input.slice(separatorIndex + 1),\n path,\n };\n}\n\n/**\n * AppElements tree paths are absolute route-tree paths on the wire.\n * Bare segment names are not valid layout/template/slot tree identities.\n */\nfunction parseTreePath(input: string): string | null {\n return input.startsWith(\"/\") ? input : null;\n}\n\nfunction parseAppElementsWireElementKey(key: string): AppElementsWireElementKey | null {\n if (key.startsWith(\"route:\")) {\n const parsed = parsePathWithInterception(key.slice(\"route:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"route\", path: parsed.path };\n }\n\n if (key.startsWith(\"page:\")) {\n const parsed = parsePathWithInterception(key.slice(\"page:\".length));\n if (!parsed) return null;\n return { interceptionContext: parsed.interceptionContext, kind: \"page\", path: parsed.path };\n }\n\n if (key.startsWith(\"layout:\")) {\n const treePath = parseTreePath(key.slice(\"layout:\".length));\n return treePath ? { kind: \"layout\", treePath } : null;\n }\n\n if (key.startsWith(\"template:\")) {\n const treePath = parseTreePath(key.slice(\"template:\".length));\n return treePath ? { kind: \"template\", treePath } : null;\n }\n\n if (key.startsWith(\"slot:\")) {\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n if (separatorIndex <= 0) return null;\n const name = body.slice(0, separatorIndex);\n const treePath = parseTreePath(body.slice(separatorIndex + 1));\n return treePath ? { kind: \"slot\", name, treePath } : null;\n }\n\n return null;\n}\n\nfunction isAppElementsWireSlotId(key: string): boolean {\n if (!key.startsWith(\"slot:\")) return false;\n const body = key.slice(\"slot:\".length);\n const separatorIndex = body.indexOf(\":\");\n return separatorIndex > 0 && body.charCodeAt(separatorIndex + 1) === 0x2f;\n}\n\nfunction createAppElementsWireMetadataEntries(\n input: AppElementsWireMetadataInput,\n): AppElementsWireMetadataEntries {\n return {\n [APP_ROUTE_KEY]: input.routeId,\n [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,\n [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath,\n };\n}\n\nexport function normalizeAppElements(elements: AppWireElements): AppElements {\n let needsNormalization = false;\n for (const [key, value] of Object.entries(elements)) {\n if (isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE) {\n needsNormalization = true;\n break;\n }\n }\n\n if (!needsNormalization) {\n return elements;\n }\n\n const normalized: Record<string, AppElementValue> = {};\n for (const [key, value] of Object.entries(elements)) {\n normalized[key] =\n isAppElementsWireSlotId(key) && value === APP_UNMATCHED_SLOT_WIRE_VALUE\n ? UNMATCHED_SLOT\n : value;\n }\n\n return normalized;\n}\n\nfunction isLayoutFlagsRecord(value: unknown): value is LayoutFlags {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n for (const v of Object.values(value)) {\n if (v !== \"s\" && v !== \"d\") return false;\n }\n return true;\n}\n\nfunction parseLayoutFlags(value: unknown): LayoutFlags {\n if (isLayoutFlagsRecord(value)) return value;\n return {};\n}\n\n/**\n * Type predicate for a plain (non-null, non-array) record of app payload values.\n * Used to distinguish the App Router payload object from bare React elements at\n * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because\n * the outgoing payload carries heterogeneous values (ReactNodes for the rendered\n * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates\n * to React's canonical `isValidElement` so we don't depend on React's internal\n * `$$typeof` marker scheme.\n */\nexport function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) return false;\n if (Array.isArray(value)) return false;\n if (isValidElement(value)) return false;\n return true;\n}\n\nexport function withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags } {\n return { ...elements, [APP_LAYOUT_FLAGS_KEY]: layoutFlags };\n}\n\nexport function buildOutgoingAppPayload(input: {\n element: ReactNode | Readonly<Record<string, ReactNode>>;\n artifactCompatibility?: ArtifactCompatibilityEnvelope;\n layoutFlags: LayoutFlags;\n}): ReactNode | AppOutgoingElements {\n if (!isAppElementsRecord(input.element)) {\n return input.element;\n }\n return {\n ...input.element,\n [APP_LAYOUT_FLAGS_KEY]: input.layoutFlags,\n [APP_ARTIFACT_COMPATIBILITY_KEY]:\n input.artifactCompatibility ?? createArtifactCompatibilityEnvelope(),\n };\n}\n\nfunction readArtifactCompatibilityMetadata(value: unknown): ArtifactCompatibilityEnvelope {\n if (value === undefined) return createArtifactCompatibilityEnvelope();\n\n const artifactCompatibility = parseArtifactCompatibilityEnvelope(value);\n // TODO(#726-COMPAT-04): hard-fail malformed compatibility metadata once\n // cache/skip consumers depend on this proof. During Wave01 the field is\n // emitted as scaffolding, so bad or future-version values degrade like\n // missing __layoutFlags instead of crashing render paths that do not read it.\n return artifactCompatibility ?? createArtifactCompatibilityEnvelope();\n}\n\nexport function readAppElementsMetadata(\n elements: Readonly<Record<string, unknown>>,\n): AppElementsMetadata {\n const routeId = elements[APP_ROUTE_KEY];\n if (typeof routeId !== \"string\") {\n throw new Error(\"[vinext] Missing __route string in App Router payload\");\n }\n\n const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];\n if (\n interceptionContext !== undefined &&\n interceptionContext !== null &&\n typeof interceptionContext !== \"string\"\n ) {\n throw new Error(\"[vinext] Invalid __interceptionContext in App Router payload\");\n }\n\n const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];\n if (rootLayoutTreePath === undefined) {\n throw new Error(\"[vinext] Missing __rootLayout key in App Router payload\");\n }\n if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== \"string\") {\n throw new Error(\"[vinext] Invalid __rootLayout in App Router payload: expected string or null\");\n }\n\n const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);\n const artifactCompatibility = readArtifactCompatibilityMetadata(\n elements[APP_ARTIFACT_COMPATIBILITY_KEY],\n );\n\n return {\n artifactCompatibility,\n interceptionContext: interceptionContext ?? null,\n layoutFlags,\n routeId,\n rootLayoutTreePath,\n };\n}\n\nexport const AppElementsWire: AppElementsWireCodec = {\n // WIRE follow-ups use these stable key names when moving payload readers and writers\n // behind the codec boundary.\n keys: {\n artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,\n interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,\n layoutFlags: APP_LAYOUT_FLAGS_KEY,\n rootLayout: APP_ROOT_LAYOUT_KEY,\n route: APP_ROUTE_KEY,\n },\n unmatchedSlotValue: APP_UNMATCHED_SLOT_WIRE_VALUE,\n createMetadataEntries: createAppElementsWireMetadataEntries,\n decode: normalizeAppElements,\n encodeCacheKey: createAppPayloadCacheKey,\n encodeLayoutId: createAppPayloadLayoutId,\n encodeOutgoingPayload: buildOutgoingAppPayload,\n encodePageId: createAppPayloadPageId,\n encodeRouteId: createAppPayloadRouteId,\n encodeSlotId: createAppPayloadSlotId,\n encodeTemplateId: createAppPayloadTemplateId,\n isSlotId: isAppElementsWireSlotId,\n parseElementKey: parseAppElementsWireElementKey,\n readMetadata: readAppElementsMetadata,\n withLayoutFlags,\n};\n"],"mappings":"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"}
@@ -1,91 +1,9 @@
1
- import { ReactNode } from "react";
1
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsWire, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
2
2
 
3
3
  //#region src/server/app-elements.d.ts
4
- declare const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
5
- declare const APP_LAYOUT_FLAGS_KEY = "__layoutFlags";
6
- declare const APP_ROUTE_KEY = "__route";
7
- declare const APP_ROOT_LAYOUT_KEY = "__rootLayout";
8
- declare const APP_UNMATCHED_SLOT_WIRE_VALUE = "__VINEXT_UNMATCHED_SLOT__";
9
- declare const UNMATCHED_SLOT: unique symbol;
10
- type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null;
11
- type AppWireElementValue = ReactNode | string | null;
12
- type AppElements = Readonly<Record<string, AppElementValue>>;
13
- type AppWireElements = Readonly<Record<string, AppWireElementValue>>;
14
- /**
15
- * Per-layout static/dynamic flags. `"s"` = static (skippable on next nav);
16
- * `"d"` = dynamic (must always render).
17
- *
18
- * Lifecycle (partial — later PRs extend this):
19
- *
20
- * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns
21
- * LayoutFlags for every layout in the route at render time.
22
- *
23
- * 2. ATTACH — withLayoutFlags (this file) writes `__layoutFlags` into the
24
- * outgoing App Router payload record.
25
- *
26
- * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.
27
- *
28
- * 4. PARSE — readAppElementsMetadata (this file) extracts layoutFlags from
29
- * the wire payload on the client side.
30
- */
31
- type LayoutFlags = Readonly<Record<string, "s" | "d">>;
32
- type AppElementsMetadata = {
33
- interceptionContext: string | null;
34
- layoutFlags: LayoutFlags;
35
- routeId: string;
36
- rootLayoutTreePath: string | null;
37
- };
38
4
  declare function getMountedSlotIds(elements: AppElements): string[];
39
5
  declare function getMountedSlotIdsHeader(elements: AppElements): string | null;
40
- declare function createAppPayloadRouteId(routePath: string, interceptionContext: string | null): string;
41
- declare function createAppPayloadPageId(routePath: string, interceptionContext: string | null): string;
42
- declare function createAppPayloadCacheKey(rscUrl: string, interceptionContext: string | null): string;
43
6
  declare function resolveVisitedResponseInterceptionContext(requestInterceptionContext: string | null, payloadInterceptionContext: string | null): string | null;
44
- declare function normalizeAppElements(elements: AppWireElements): AppElements;
45
- /**
46
- * Type predicate for a plain (non-null, non-array) record of app payload values.
47
- * Used to distinguish the App Router payload object from bare React elements at
48
- * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because
49
- * the outgoing payload carries heterogeneous values (ReactNodes for the rendered
50
- * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates
51
- * to React's canonical `isValidElement` so we don't depend on React's internal
52
- * `$$typeof` marker scheme.
53
- */
54
- declare function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>>;
55
- /**
56
- * Pure: returns a new record with `__layoutFlags` attached. Owns the write
57
- * boundary for the layout flags key so the write side sits next to
58
- * `readAppElementsMetadata`.
59
- *
60
- * See `LayoutFlags` type docblock in this file for lifecycle.
61
- */
62
- declare function withLayoutFlags<T extends Record<string, unknown>>(elements: T, layoutFlags: LayoutFlags): T & {
63
- [APP_LAYOUT_FLAGS_KEY]: LayoutFlags;
64
- };
65
- /**
66
- * The outgoing wire payload shape. Includes ReactNode values for the
67
- * rendered tree plus metadata values like LayoutFlags attached under
68
- * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements
69
- * which only carry render-time values.
70
- */
71
- type AppOutgoingElements = Readonly<Record<string, ReactNode | LayoutFlags>>;
72
- /**
73
- * Pure: builds the outgoing payload for the wire. Non-record inputs (e.g. a
74
- * bare React element) are returned unchanged. Record inputs get a fresh copy
75
- * with `__layoutFlags` attached. Never mutates `input.element`.
76
- */
77
- declare function buildOutgoingAppPayload(input: {
78
- element: ReactNode | Readonly<Record<string, ReactNode>>;
79
- layoutFlags: LayoutFlags;
80
- }): ReactNode | AppOutgoingElements;
81
- /**
82
- * Parses metadata from the wire payload. Accepts `Record<string, unknown>`
83
- * because the RSC payload carries heterogeneous values (React elements,
84
- * strings, and plain objects like layout flags) under the same record type.
85
- *
86
- * See `LayoutFlags` type docblock in this file for lifecycle.
87
- */
88
- declare function readAppElementsMetadata(elements: Readonly<Record<string, unknown>>): AppElementsMetadata;
89
7
  //#endregion
90
- export { APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, createAppPayloadCacheKey, createAppPayloadPageId, createAppPayloadRouteId, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
8
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, type AppElementValue, type AppElements, AppElementsWire, type AppOutgoingElements, type AppWireElements, type LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
91
9
  //# sourceMappingURL=app-elements.d.ts.map
@@ -1,118 +1,19 @@
1
1
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
2
- import { isValidElement } from "react";
2
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
3
3
  //#region src/server/app-elements.ts
4
- const APP_INTERCEPTION_SEPARATOR = "\0";
5
- const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
6
- const APP_LAYOUT_FLAGS_KEY = "__layoutFlags";
7
- const APP_ROUTE_KEY = "__route";
8
- const APP_ROOT_LAYOUT_KEY = "__rootLayout";
9
- const APP_UNMATCHED_SLOT_WIRE_VALUE = "__VINEXT_UNMATCHED_SLOT__";
10
- const UNMATCHED_SLOT = Symbol.for("vinext.unmatchedSlot");
11
4
  function getMountedSlotIds(elements) {
12
5
  return Object.keys(elements).filter((key) => {
13
6
  const value = elements[key];
14
- return key.startsWith("slot:") && value !== null && value !== void 0 && value !== UNMATCHED_SLOT;
7
+ return AppElementsWire.isSlotId(key) && value !== null && value !== void 0 && value !== UNMATCHED_SLOT;
15
8
  }).sort();
16
9
  }
17
10
  function getMountedSlotIdsHeader(elements) {
18
11
  return normalizeMountedSlotsHeader(getMountedSlotIds(elements).join(" "));
19
12
  }
20
- function appendInterceptionContext(identity, interceptionContext) {
21
- return interceptionContext === null ? identity : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;
22
- }
23
- function createAppPayloadRouteId(routePath, interceptionContext) {
24
- return appendInterceptionContext(`route:${routePath}`, interceptionContext);
25
- }
26
- function createAppPayloadPageId(routePath, interceptionContext) {
27
- return appendInterceptionContext(`page:${routePath}`, interceptionContext);
28
- }
29
- function createAppPayloadCacheKey(rscUrl, interceptionContext) {
30
- return appendInterceptionContext(rscUrl, interceptionContext);
31
- }
32
13
  function resolveVisitedResponseInterceptionContext(requestInterceptionContext, payloadInterceptionContext) {
33
14
  return payloadInterceptionContext ?? requestInterceptionContext;
34
15
  }
35
- function normalizeAppElements(elements) {
36
- let needsNormalization = false;
37
- for (const [key, value] of Object.entries(elements)) if (key.startsWith("slot:") && value === "__VINEXT_UNMATCHED_SLOT__") {
38
- needsNormalization = true;
39
- break;
40
- }
41
- if (!needsNormalization) return elements;
42
- const normalized = {};
43
- for (const [key, value] of Object.entries(elements)) normalized[key] = key.startsWith("slot:") && value === "__VINEXT_UNMATCHED_SLOT__" ? UNMATCHED_SLOT : value;
44
- return normalized;
45
- }
46
- function isLayoutFlagsRecord(value) {
47
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
48
- for (const v of Object.values(value)) if (v !== "s" && v !== "d") return false;
49
- return true;
50
- }
51
- function parseLayoutFlags(value) {
52
- if (isLayoutFlagsRecord(value)) return value;
53
- return {};
54
- }
55
- /**
56
- * Type predicate for a plain (non-null, non-array) record of app payload values.
57
- * Used to distinguish the App Router payload object from bare React elements at
58
- * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because
59
- * the outgoing payload carries heterogeneous values (ReactNodes for the rendered
60
- * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates
61
- * to React's canonical `isValidElement` so we don't depend on React's internal
62
- * `$$typeof` marker scheme.
63
- */
64
- function isAppElementsRecord(value) {
65
- if (typeof value !== "object" || value === null) return false;
66
- if (Array.isArray(value)) return false;
67
- if (isValidElement(value)) return false;
68
- return true;
69
- }
70
- /**
71
- * Pure: returns a new record with `__layoutFlags` attached. Owns the write
72
- * boundary for the layout flags key so the write side sits next to
73
- * `readAppElementsMetadata`.
74
- *
75
- * See `LayoutFlags` type docblock in this file for lifecycle.
76
- */
77
- function withLayoutFlags(elements, layoutFlags) {
78
- return {
79
- ...elements,
80
- [APP_LAYOUT_FLAGS_KEY]: layoutFlags
81
- };
82
- }
83
- /**
84
- * Pure: builds the outgoing payload for the wire. Non-record inputs (e.g. a
85
- * bare React element) are returned unchanged. Record inputs get a fresh copy
86
- * with `__layoutFlags` attached. Never mutates `input.element`.
87
- */
88
- function buildOutgoingAppPayload(input) {
89
- if (!isAppElementsRecord(input.element)) return input.element;
90
- return withLayoutFlags(input.element, input.layoutFlags);
91
- }
92
- /**
93
- * Parses metadata from the wire payload. Accepts `Record<string, unknown>`
94
- * because the RSC payload carries heterogeneous values (React elements,
95
- * strings, and plain objects like layout flags) under the same record type.
96
- *
97
- * See `LayoutFlags` type docblock in this file for lifecycle.
98
- */
99
- function readAppElementsMetadata(elements) {
100
- const routeId = elements[APP_ROUTE_KEY];
101
- if (typeof routeId !== "string") throw new Error("[vinext] Missing __route string in App Router payload");
102
- const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];
103
- if (interceptionContext !== void 0 && interceptionContext !== null && typeof interceptionContext !== "string") throw new Error("[vinext] Invalid __interceptionContext in App Router payload");
104
- const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];
105
- if (rootLayoutTreePath === void 0) throw new Error("[vinext] Missing __rootLayout key in App Router payload");
106
- if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== "string") throw new Error("[vinext] Invalid __rootLayout in App Router payload: expected string or null");
107
- const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);
108
- return {
109
- interceptionContext: interceptionContext ?? null,
110
- layoutFlags,
111
- routeId,
112
- rootLayoutTreePath
113
- };
114
- }
115
16
  //#endregion
116
- export { APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, UNMATCHED_SLOT, buildOutgoingAppPayload, createAppPayloadCacheKey, createAppPayloadPageId, createAppPayloadRouteId, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
17
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_LAYOUT_FLAGS_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
117
18
 
118
19
  //# sourceMappingURL=app-elements.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-elements.js","names":[],"sources":["../../src/server/app-elements.ts"],"sourcesContent":["import { isValidElement, type ReactNode } from \"react\";\nimport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\n\nconst APP_INTERCEPTION_SEPARATOR = \"\\0\";\n\nexport const APP_INTERCEPTION_CONTEXT_KEY = \"__interceptionContext\";\nexport const APP_LAYOUT_FLAGS_KEY = \"__layoutFlags\";\nexport const APP_ROUTE_KEY = \"__route\";\nexport const APP_ROOT_LAYOUT_KEY = \"__rootLayout\";\nexport const APP_UNMATCHED_SLOT_WIRE_VALUE = \"__VINEXT_UNMATCHED_SLOT__\";\n\nexport const UNMATCHED_SLOT = Symbol.for(\"vinext.unmatchedSlot\");\n\nexport type AppElementValue = ReactNode | typeof UNMATCHED_SLOT | string | null;\ntype AppWireElementValue = ReactNode | string | null;\n\nexport type AppElements = Readonly<Record<string, AppElementValue>>;\nexport type AppWireElements = Readonly<Record<string, AppWireElementValue>>;\n\n/**\n * Per-layout static/dynamic flags. `\"s\"` = static (skippable on next nav);\n * `\"d\"` = dynamic (must always render).\n *\n * Lifecycle (partial — later PRs extend this):\n *\n * 1. PROBE — probeAppPageLayouts (server/app-page-execution.ts) returns\n * LayoutFlags for every layout in the route at render time.\n *\n * 2. ATTACH — withLayoutFlags (this file) writes `__layoutFlags` into the\n * outgoing App Router payload record.\n *\n * 3. WIRE — renderToReadableStream serializes the record as RSC row 0.\n *\n * 4. PARSE — readAppElementsMetadata (this file) extracts layoutFlags from\n * the wire payload on the client side.\n */\nexport type LayoutFlags = Readonly<Record<string, \"s\" | \"d\">>;\n\ntype AppElementsMetadata = {\n interceptionContext: string | null;\n layoutFlags: LayoutFlags;\n routeId: string;\n rootLayoutTreePath: string | null;\n};\n\nexport function getMountedSlotIds(elements: AppElements): string[] {\n return Object.keys(elements)\n .filter((key) => {\n const value = elements[key];\n return (\n key.startsWith(\"slot:\") && value !== null && value !== undefined && value !== UNMATCHED_SLOT\n );\n })\n .sort();\n}\n\nexport function getMountedSlotIdsHeader(elements: AppElements): string | null {\n return normalizeMountedSlotsHeader(getMountedSlotIds(elements).join(\" \"));\n}\n\nfunction appendInterceptionContext(identity: string, interceptionContext: string | null): string {\n return interceptionContext === null\n ? identity\n : `${identity}${APP_INTERCEPTION_SEPARATOR}${interceptionContext}`;\n}\n\nexport function createAppPayloadRouteId(\n routePath: string,\n interceptionContext: string | null,\n): string {\n return appendInterceptionContext(`route:${routePath}`, interceptionContext);\n}\n\nexport function createAppPayloadPageId(\n routePath: string,\n interceptionContext: string | null,\n): string {\n return appendInterceptionContext(`page:${routePath}`, interceptionContext);\n}\n\nexport function createAppPayloadCacheKey(\n rscUrl: string,\n interceptionContext: string | null,\n): string {\n return appendInterceptionContext(rscUrl, interceptionContext);\n}\n\nexport function resolveVisitedResponseInterceptionContext(\n requestInterceptionContext: string | null,\n payloadInterceptionContext: string | null,\n): string | null {\n return payloadInterceptionContext ?? requestInterceptionContext;\n}\n\nexport function normalizeAppElements(elements: AppWireElements): AppElements {\n let needsNormalization = false;\n for (const [key, value] of Object.entries(elements)) {\n if (key.startsWith(\"slot:\") && value === APP_UNMATCHED_SLOT_WIRE_VALUE) {\n needsNormalization = true;\n break;\n }\n }\n\n if (!needsNormalization) {\n return elements;\n }\n\n const normalized: Record<string, AppElementValue> = {};\n for (const [key, value] of Object.entries(elements)) {\n normalized[key] =\n key.startsWith(\"slot:\") && value === APP_UNMATCHED_SLOT_WIRE_VALUE ? UNMATCHED_SLOT : value;\n }\n\n return normalized;\n}\n\nfunction isLayoutFlagsRecord(value: unknown): value is LayoutFlags {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n for (const v of Object.values(value)) {\n if (v !== \"s\" && v !== \"d\") return false;\n }\n return true;\n}\n\nfunction parseLayoutFlags(value: unknown): LayoutFlags {\n if (isLayoutFlagsRecord(value)) return value;\n return {};\n}\n\n/**\n * Type predicate for a plain (non-null, non-array) record of app payload values.\n * Used to distinguish the App Router payload object from bare React elements at\n * the render boundary. Narrows to `Readonly<Record<string, unknown>>` because\n * the outgoing payload carries heterogeneous values (ReactNodes for the rendered\n * tree, plus metadata like `__layoutFlags` which is a plain object). Delegates\n * to React's canonical `isValidElement` so we don't depend on React's internal\n * `$$typeof` marker scheme.\n */\nexport function isAppElementsRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null) return false;\n if (Array.isArray(value)) return false;\n if (isValidElement(value)) return false;\n return true;\n}\n\n/**\n * Pure: returns a new record with `__layoutFlags` attached. Owns the write\n * boundary for the layout flags key so the write side sits next to\n * `readAppElementsMetadata`.\n *\n * See `LayoutFlags` type docblock in this file for lifecycle.\n */\nexport function withLayoutFlags<T extends Record<string, unknown>>(\n elements: T,\n layoutFlags: LayoutFlags,\n): T & { [APP_LAYOUT_FLAGS_KEY]: LayoutFlags } {\n return { ...elements, [APP_LAYOUT_FLAGS_KEY]: layoutFlags };\n}\n\n/**\n * The outgoing wire payload shape. Includes ReactNode values for the\n * rendered tree plus metadata values like LayoutFlags attached under\n * known keys (e.g. __layoutFlags). Distinct from AppElements / AppWireElements\n * which only carry render-time values.\n */\nexport type AppOutgoingElements = Readonly<Record<string, ReactNode | LayoutFlags>>;\n\n/**\n * Pure: builds the outgoing payload for the wire. Non-record inputs (e.g. a\n * bare React element) are returned unchanged. Record inputs get a fresh copy\n * with `__layoutFlags` attached. Never mutates `input.element`.\n */\nexport function buildOutgoingAppPayload(input: {\n element: ReactNode | Readonly<Record<string, ReactNode>>;\n layoutFlags: LayoutFlags;\n}): ReactNode | AppOutgoingElements {\n if (!isAppElementsRecord(input.element)) {\n return input.element;\n }\n return withLayoutFlags(input.element, input.layoutFlags);\n}\n\n/**\n * Parses metadata from the wire payload. Accepts `Record<string, unknown>`\n * because the RSC payload carries heterogeneous values (React elements,\n * strings, and plain objects like layout flags) under the same record type.\n *\n * See `LayoutFlags` type docblock in this file for lifecycle.\n */\nexport function readAppElementsMetadata(\n elements: Readonly<Record<string, unknown>>,\n): AppElementsMetadata {\n const routeId = elements[APP_ROUTE_KEY];\n if (typeof routeId !== \"string\") {\n throw new Error(\"[vinext] Missing __route string in App Router payload\");\n }\n\n const interceptionContext = elements[APP_INTERCEPTION_CONTEXT_KEY];\n if (\n interceptionContext !== undefined &&\n interceptionContext !== null &&\n typeof interceptionContext !== \"string\"\n ) {\n throw new Error(\"[vinext] Invalid __interceptionContext in App Router payload\");\n }\n\n const rootLayoutTreePath = elements[APP_ROOT_LAYOUT_KEY];\n if (rootLayoutTreePath === undefined) {\n throw new Error(\"[vinext] Missing __rootLayout key in App Router payload\");\n }\n if (rootLayoutTreePath !== null && typeof rootLayoutTreePath !== \"string\") {\n throw new Error(\"[vinext] Invalid __rootLayout in App Router payload: expected string or null\");\n }\n\n const layoutFlags = parseLayoutFlags(elements[APP_LAYOUT_FLAGS_KEY]);\n\n return {\n interceptionContext: interceptionContext ?? null,\n layoutFlags,\n routeId,\n rootLayoutTreePath,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-elements.js","names":[],"sources":["../../src/server/app-elements.ts"],"sourcesContent":["import { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { AppElementsWire, UNMATCHED_SLOT, type AppElements } from \"./app-elements-wire.js\";\n\nexport {\n AppElementsWire,\n APP_ARTIFACT_COMPATIBILITY_KEY,\n APP_INTERCEPTION_CONTEXT_KEY,\n APP_LAYOUT_FLAGS_KEY,\n APP_ROOT_LAYOUT_KEY,\n APP_ROUTE_KEY,\n APP_UNMATCHED_SLOT_WIRE_VALUE,\n UNMATCHED_SLOT,\n buildOutgoingAppPayload,\n isAppElementsRecord,\n normalizeAppElements,\n readAppElementsMetadata,\n withLayoutFlags,\n type AppElementValue,\n type AppElements,\n type AppOutgoingElements,\n type AppWireElements,\n type LayoutFlags,\n} from \"./app-elements-wire.js\";\n\n// Raw constructor helpers stay private because callers use AppElementsWire codecs.\n\nexport function getMountedSlotIds(elements: AppElements): string[] {\n return Object.keys(elements)\n .filter((key) => {\n const value = elements[key];\n return (\n AppElementsWire.isSlotId(key) &&\n value !== null &&\n value !== undefined &&\n value !== UNMATCHED_SLOT\n );\n })\n .sort();\n}\n\nexport function getMountedSlotIdsHeader(elements: AppElements): string | null {\n return normalizeMountedSlotsHeader(getMountedSlotIds(elements).join(\" \"));\n}\n\nexport function resolveVisitedResponseInterceptionContext(\n requestInterceptionContext: string | null,\n payloadInterceptionContext: string | null,\n): string | null {\n return payloadInterceptionContext ?? requestInterceptionContext;\n}\n"],"mappings":";;;AA0BA,SAAgB,kBAAkB,UAAiC;AACjE,QAAO,OAAO,KAAK,SAAS,CACzB,QAAQ,QAAQ;EACf,MAAM,QAAQ,SAAS;AACvB,SACE,gBAAgB,SAAS,IAAI,IAC7B,UAAU,QACV,UAAU,KAAA,KACV,UAAU;GAEZ,CACD,MAAM;;AAGX,SAAgB,wBAAwB,UAAsC;AAC5E,QAAO,4BAA4B,kBAAkB,SAAS,CAAC,KAAK,IAAI,CAAC;;AAG3E,SAAgB,0CACd,4BACA,4BACe;AACf,QAAO,8BAA8B"}
@@ -1,5 +1,5 @@
1
1
  import { MetadataFileRoute } from "./metadata-routes.js";
2
- import { AppElements } from "./app-elements.js";
2
+ import { AppElements } from "./app-elements-wire.js";
3
3
  import { AppPageParams } from "./app-page-boundary.js";
4
4
  import { AppPageFontPreload } from "./app-page-execution.js";
5
5
  import { AppPageMiddlewareContext } from "./app-page-response.js";
@@ -24,9 +24,10 @@ type ApplyAppMiddlewareResult = {
24
24
  kind: "response";
25
25
  response: Response;
26
26
  };
27
+ declare const FLIGHT_HEADERS: readonly string[];
27
28
  declare function isExternalMiddlewareRewrite(rewriteUrl: string, request: Request): boolean;
28
29
  declare function proxyExternalMiddlewareRewrite(request: Request, rewriteUrl: string, context: AppMiddlewareContext): Promise<Response>;
29
30
  declare function applyAppMiddleware(options: ApplyAppMiddlewareOptions): Promise<ApplyAppMiddlewareResult>;
30
31
  //#endregion
31
- export { AppMiddlewareContext, ApplyAppMiddlewareOptions, ApplyAppMiddlewareResult, applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
32
+ export { AppMiddlewareContext, ApplyAppMiddlewareOptions, ApplyAppMiddlewareResult, FLIGHT_HEADERS, applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
32
33
  //# sourceMappingURL=app-middleware.d.ts.map
@@ -1,14 +1,31 @@
1
1
  import { buildRequestHeadersFromMiddlewareResponse } from "./middleware-request-headers.js";
2
2
  import { isExternalUrl, proxyExternalRequest } from "../config/config-matchers.js";
3
- import { processMiddlewareHeaders } from "./request-pipeline.js";
3
+ import { internalServerErrorResponse } from "./http-error-responses.js";
4
+ import { cloneRequestWithHeaders, processMiddlewareHeaders } from "./request-pipeline.js";
4
5
  import { executeMiddleware } from "./middleware-runtime.js";
5
6
  import { applyMiddlewareRequestHeaders, setHeadersContext } from "../shims/headers.js";
6
7
  import { setNavigationContext } from "../shims/navigation.js";
7
8
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
8
9
  //#region src/server/app-middleware.ts
10
+ const FLIGHT_HEADERS = [
11
+ "rsc",
12
+ "next-router-state-tree",
13
+ "next-router-prefetch",
14
+ "next-hmr-refresh",
15
+ "next-router-segment-prefetch"
16
+ ];
17
+ const FLIGHT_HEADER_SET = new Set(FLIGHT_HEADERS);
9
18
  function isForwardedMiddlewareContext(value) {
10
19
  return !!value && typeof value === "object";
11
20
  }
21
+ function requestWithoutFlightHeaders(request) {
22
+ let hasFlightHeader = false;
23
+ const headers = new Headers();
24
+ for (const [key, value] of request.headers) if (FLIGHT_HEADER_SET.has(key.toLowerCase())) hasFlightHeader = true;
25
+ else headers.append(key, value);
26
+ if (!hasFlightHeader) return request;
27
+ return cloneRequestWithHeaders(request.body ? request.clone() : request, headers);
28
+ }
12
29
  function appendForwardedHeader(headers, value) {
13
30
  if (!Array.isArray(value) || value.length < 2) return;
14
31
  const key = value[0];
@@ -46,10 +63,15 @@ async function proxyExternalMiddlewareRewrite(request, rewriteUrl, context) {
46
63
  setHeadersContext(null);
47
64
  setNavigationContext(null);
48
65
  const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);
49
- if (!context.headers) return proxyResponse;
66
+ const headers = new Headers(proxyResponse.headers);
67
+ processMiddlewareHeaders(headers);
68
+ if (!context.headers) return new Response(proxyResponse.body, {
69
+ status: proxyResponse.status,
70
+ statusText: proxyResponse.statusText,
71
+ headers
72
+ });
50
73
  const middlewareHeaders = new Headers(context.headers);
51
74
  processMiddlewareHeaders(middlewareHeaders);
52
- const headers = new Headers(proxyResponse.headers);
53
75
  mergeMiddlewareResponseHeaders(headers, middlewareHeaders);
54
76
  return new Response(proxyResponse.body, {
55
77
  status: proxyResponse.status,
@@ -81,14 +103,15 @@ function applyForwardedMiddlewareContext(request, context) {
81
103
  }
82
104
  async function applyAppMiddleware(options) {
83
105
  const forwarded = applyForwardedMiddlewareContext(options.request, options.context);
106
+ const middlewareRequest = requestWithoutFlightHeaders(options.request);
84
107
  let cleanPathname = options.cleanPathname;
85
108
  let search = null;
86
109
  if (forwarded.rewriteUrl) try {
87
- if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, options.request)) return {
110
+ if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, middlewareRequest)) return {
88
111
  kind: "response",
89
- response: await proxyExternalMiddlewareRewrite(options.request, forwarded.rewriteUrl, options.context)
112
+ response: await proxyExternalMiddlewareRewrite(middlewareRequest, forwarded.rewriteUrl, options.context)
90
113
  };
91
- const rewriteParsed = new URL(forwarded.rewriteUrl, options.request.url);
114
+ const rewriteParsed = new URL(forwarded.rewriteUrl, middlewareRequest.url);
92
115
  cleanPathname = rewriteParsed.pathname;
93
116
  search = rewriteParsed.search;
94
117
  } catch (e) {
@@ -102,7 +125,7 @@ async function applyAppMiddleware(options) {
102
125
  isProxy: options.isProxy,
103
126
  module: options.module,
104
127
  normalizedPathname: cleanPathname,
105
- request: options.request
128
+ request: middlewareRequest
106
129
  });
107
130
  if (!result.continue) {
108
131
  if (result.redirectUrl) return {
@@ -115,7 +138,7 @@ async function applyAppMiddleware(options) {
115
138
  };
116
139
  return {
117
140
  kind: "response",
118
- response: new Response("Internal Server Error", { status: 500 })
141
+ response: internalServerErrorResponse()
119
142
  };
120
143
  }
121
144
  if (result.responseHeaders) options.context.headers = new Headers(result.responseHeaders);
@@ -123,9 +146,9 @@ async function applyAppMiddleware(options) {
123
146
  if (result.rewriteStatus !== void 0) options.context.status = result.rewriteStatus;
124
147
  if (isExternalUrl(result.rewriteUrl)) return {
125
148
  kind: "response",
126
- response: await proxyExternalMiddlewareRewrite(options.request, result.rewriteUrl, options.context)
149
+ response: await proxyExternalMiddlewareRewrite(middlewareRequest, result.rewriteUrl, options.context)
127
150
  };
128
- const rewriteParsed = new URL(result.rewriteUrl, options.request.url);
151
+ const rewriteParsed = new URL(result.rewriteUrl, middlewareRequest.url);
129
152
  cleanPathname = rewriteParsed.pathname;
130
153
  search = rewriteParsed.search;
131
154
  }
@@ -142,6 +165,6 @@ async function applyAppMiddleware(options) {
142
165
  };
143
166
  }
144
167
  //#endregion
145
- export { applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
168
+ export { FLIGHT_HEADERS, applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
146
169
 
147
170
  //# sourceMappingURL=app-middleware.js.map