@bleedingdev/modern-js-runtime-extensions 3.8.3-ultramodern.6 → 3.9.0-ultramodern.10

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 (200) hide show
  1. package/dist/cjs/buildIdentity.js +73 -0
  2. package/dist/cjs/contextExtensions.js +74 -0
  3. package/dist/cjs/headRuntime.js +91 -0
  4. package/dist/cjs/helmetContext.js +54 -0
  5. package/dist/cjs/index.js +18 -4
  6. package/dist/cjs/localisedLoaderIdentity.js +51 -0
  7. package/dist/cjs/prefetchPolicy.js +52 -0
  8. package/dist/cjs/reactContext.js +45 -0
  9. package/dist/cjs/request-policy/browser.js +139 -0
  10. package/dist/cjs/request-policy/client.js +234 -0
  11. package/dist/cjs/request-policy/node.js +149 -0
  12. package/dist/cjs/request-policy/policyCore.js +266 -0
  13. package/dist/cjs/request-policy/requestContext.js +137 -0
  14. package/dist/cjs/request-policy/traceparent.js +56 -0
  15. package/dist/cjs/request-policy/transport.js +234 -0
  16. package/dist/cjs/request-policy/types.js +57 -0
  17. package/dist/cjs/routeHydration.js +127 -0
  18. package/dist/cjs/routerPrefetchPolicy.js +153 -0
  19. package/dist/cjs/routerProvider.js +105 -0
  20. package/dist/cjs/routerState.js +204 -0
  21. package/dist/cjs/routerStatePlugin.js +86 -0
  22. package/dist/cjs/routerStateTypes.js +18 -0
  23. package/dist/cjs/rsc-disabled/rscDisabledClientBrowserRuntime.js +69 -0
  24. package/dist/cjs/rsc-disabled/rscDisabledClientEdgeRuntime.js +61 -0
  25. package/dist/cjs/rsc-disabled/rscDisabledClientNodeRuntime.js +65 -0
  26. package/dist/cjs/rsc-disabled/rscDisabledRuntimeError.js +42 -0
  27. package/dist/cjs/rsc-disabled/rscDisabledServerEdgeRuntime.js +93 -0
  28. package/dist/cjs/rsc-disabled/rscDisabledServerNodeRuntime.js +101 -0
  29. package/dist/cjs/runtimeContextProjection.js +112 -0
  30. package/dist/cjs/server-config/bffRuntime.js +18 -0
  31. package/dist/cjs/server-config/index.js +18 -0
  32. package/dist/cjs/server-config/serverTelemetry.js +18 -0
  33. package/dist/cjs/shellStream.js +34 -2
  34. package/dist/cjs/workspaceEvents.js +159 -0
  35. package/dist/esm/buildIdentity.mjs +35 -0
  36. package/dist/esm/contextExtensions.mjs +33 -0
  37. package/dist/esm/headRuntime.mjs +43 -0
  38. package/dist/esm/helmetContext.mjs +13 -0
  39. package/dist/esm/index.mjs +2 -0
  40. package/dist/esm/localisedLoaderIdentity.mjs +13 -0
  41. package/dist/esm/prefetchPolicy.mjs +11 -0
  42. package/dist/esm/reactContext.mjs +7 -0
  43. package/dist/esm/request-policy/browser.mjs +11 -0
  44. package/dist/esm/request-policy/client.mjs +195 -0
  45. package/dist/esm/request-policy/policyCore.mjs +171 -0
  46. package/dist/esm/request-policy/requestContext.mjs +75 -0
  47. package/dist/esm/request-policy/traceparent.mjs +18 -0
  48. package/dist/esm/request-policy/transport.mjs +196 -0
  49. package/dist/esm/request-policy/types.mjs +10 -0
  50. package/dist/esm/routeHydration.mjs +77 -0
  51. package/dist/esm/routerPrefetchPolicy.mjs +115 -0
  52. package/dist/esm/routerProvider.mjs +58 -0
  53. package/dist/esm/routerState.mjs +139 -0
  54. package/dist/esm/routerStatePlugin.mjs +48 -0
  55. package/dist/esm/routerStateTypes.mjs +0 -0
  56. package/dist/esm/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +10 -0
  57. package/dist/esm/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +8 -0
  58. package/dist/esm/rsc-disabled/rscDisabledClientNodeRuntime.mjs +9 -0
  59. package/dist/esm/rsc-disabled/rscDisabledRuntimeError.mjs +4 -0
  60. package/dist/esm/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +16 -0
  61. package/dist/esm/rsc-disabled/rscDisabledServerNodeRuntime.mjs +18 -0
  62. package/dist/esm/runtimeContextProjection.mjs +74 -0
  63. package/dist/esm/server-config/bffRuntime.mjs +0 -0
  64. package/dist/esm/server-config/index.mjs +0 -0
  65. package/dist/esm/server-config/serverTelemetry.mjs +0 -0
  66. package/dist/esm/shellStream.mjs +34 -2
  67. package/dist/esm/workspaceEvents.mjs +66 -0
  68. package/dist/esm-node/buildIdentity.mjs +36 -0
  69. package/dist/esm-node/contextExtensions.mjs +34 -0
  70. package/dist/esm-node/headRuntime.mjs +44 -0
  71. package/dist/esm-node/helmetContext.mjs +14 -0
  72. package/dist/esm-node/index.mjs +2 -0
  73. package/dist/esm-node/localisedLoaderIdentity.mjs +14 -0
  74. package/dist/esm-node/prefetchPolicy.mjs +12 -0
  75. package/dist/esm-node/reactContext.mjs +8 -0
  76. package/dist/esm-node/request-policy/browser.mjs +12 -0
  77. package/dist/esm-node/request-policy/client.mjs +196 -0
  78. package/dist/esm-node/request-policy/node.mjs +22 -0
  79. package/dist/esm-node/request-policy/policyCore.mjs +172 -0
  80. package/dist/esm-node/request-policy/requestContext.mjs +76 -0
  81. package/dist/esm-node/request-policy/traceparent.mjs +19 -0
  82. package/dist/esm-node/request-policy/transport.mjs +197 -0
  83. package/dist/esm-node/request-policy/types.mjs +11 -0
  84. package/dist/esm-node/routeHydration.mjs +78 -0
  85. package/dist/esm-node/routerPrefetchPolicy.mjs +116 -0
  86. package/dist/esm-node/routerProvider.mjs +59 -0
  87. package/dist/esm-node/routerState.mjs +140 -0
  88. package/dist/esm-node/routerStatePlugin.mjs +49 -0
  89. package/dist/esm-node/routerStateTypes.mjs +1 -0
  90. package/dist/esm-node/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +11 -0
  91. package/dist/esm-node/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +9 -0
  92. package/dist/esm-node/rsc-disabled/rscDisabledClientNodeRuntime.mjs +10 -0
  93. package/dist/esm-node/rsc-disabled/rscDisabledRuntimeError.mjs +5 -0
  94. package/dist/esm-node/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +17 -0
  95. package/dist/esm-node/rsc-disabled/rscDisabledServerNodeRuntime.mjs +19 -0
  96. package/dist/esm-node/runtimeContextProjection.mjs +75 -0
  97. package/dist/esm-node/server-config/bffRuntime.mjs +1 -0
  98. package/dist/esm-node/server-config/index.mjs +1 -0
  99. package/dist/esm-node/server-config/serverTelemetry.mjs +1 -0
  100. package/dist/esm-node/shellStream.mjs +34 -2
  101. package/dist/esm-node/workspaceEvents.mjs +67 -0
  102. package/dist/types/buildIdentity.d.ts +37 -0
  103. package/dist/types/contextExtensions.d.ts +34 -0
  104. package/dist/types/headRuntime.d.ts +12 -0
  105. package/dist/types/helmetContext.d.ts +10 -0
  106. package/dist/types/index.d.ts +6 -4
  107. package/dist/types/localisedLoaderIdentity.d.ts +10 -0
  108. package/dist/types/node.d.ts +1 -1
  109. package/dist/types/prefetchPolicy.d.ts +4 -0
  110. package/dist/types/reactContext.d.ts +6 -0
  111. package/dist/types/rendererHead.d.ts +1 -1
  112. package/dist/types/request-policy/browser.d.ts +10 -0
  113. package/dist/types/request-policy/client.d.ts +14 -0
  114. package/dist/types/request-policy/node.d.ts +10 -0
  115. package/dist/types/request-policy/policyCore.d.ts +107 -0
  116. package/dist/types/request-policy/requestContext.d.ts +22 -0
  117. package/dist/types/request-policy/traceparent.d.ts +10 -0
  118. package/dist/types/request-policy/transport.d.ts +12 -0
  119. package/dist/types/request-policy/types.d.ts +144 -0
  120. package/dist/types/routeHydration.d.ts +24 -0
  121. package/dist/types/routerPrefetchPolicy.d.ts +28 -0
  122. package/dist/types/routerProvider.d.ts +55 -0
  123. package/dist/types/routerState.d.ts +18 -0
  124. package/dist/types/routerStatePlugin.d.ts +19 -0
  125. package/dist/types/routerStateTypes.d.ts +40 -0
  126. package/dist/types/rsc-disabled/rscDisabledClientBrowserRuntime.d.ts +9 -0
  127. package/dist/types/rsc-disabled/rscDisabledClientEdgeRuntime.d.ts +7 -0
  128. package/dist/types/rsc-disabled/rscDisabledClientNodeRuntime.d.ts +8 -0
  129. package/dist/types/rsc-disabled/rscDisabledRuntimeError.d.ts +1 -0
  130. package/dist/types/rsc-disabled/rscDisabledServerEdgeRuntime.d.ts +15 -0
  131. package/dist/types/rsc-disabled/rscDisabledServerNodeRuntime.d.ts +17 -0
  132. package/dist/types/runtimeContextProjection.d.ts +30 -0
  133. package/dist/types/server-config/bffRuntime.d.ts +122 -0
  134. package/dist/types/server-config/index.d.ts +2 -0
  135. package/dist/types/server-config/serverTelemetry.d.ts +322 -0
  136. package/dist/types/workspaceEvents.d.ts +62 -0
  137. package/package.json +240 -15
  138. package/rslib.config.mts +17 -2
  139. package/rstest.config.mts +33 -2
  140. package/src/buildIdentity.ts +61 -0
  141. package/src/contextExtensions.ts +81 -0
  142. package/src/headRuntime.tsx +77 -0
  143. package/src/helmetContext.ts +31 -0
  144. package/src/index.ts +2 -0
  145. package/src/localisedLoaderIdentity.ts +30 -0
  146. package/src/prefetchPolicy.ts +33 -0
  147. package/src/reactContext.ts +16 -0
  148. package/src/request-policy/browser.ts +22 -0
  149. package/src/request-policy/client.ts +404 -0
  150. package/src/request-policy/node.ts +41 -0
  151. package/src/request-policy/policyCore.ts +424 -0
  152. package/src/request-policy/requestContext.ts +149 -0
  153. package/src/request-policy/traceparent.ts +43 -0
  154. package/src/request-policy/transport.ts +349 -0
  155. package/src/request-policy/types.ts +229 -0
  156. package/src/routeHydration.ts +208 -0
  157. package/src/routerPrefetchPolicy.ts +195 -0
  158. package/src/routerProvider.ts +160 -0
  159. package/src/routerState.ts +290 -0
  160. package/src/routerStatePlugin.ts +86 -0
  161. package/src/routerStateTypes.ts +46 -0
  162. package/src/rsc-disabled/rscDisabledClientBrowserRuntime.ts +10 -0
  163. package/src/rsc-disabled/rscDisabledClientEdgeRuntime.ts +8 -0
  164. package/src/rsc-disabled/rscDisabledClientNodeRuntime.ts +9 -0
  165. package/src/rsc-disabled/rscDisabledRuntimeError.ts +3 -0
  166. package/src/rsc-disabled/rscDisabledServerEdgeRuntime.ts +16 -0
  167. package/src/rsc-disabled/rscDisabledServerNodeRuntime.ts +18 -0
  168. package/src/runtimeContextProjection.ts +105 -0
  169. package/src/server-config/bffRuntime.ts +136 -0
  170. package/src/server-config/index.ts +2 -0
  171. package/src/server-config/serverTelemetry.ts +337 -0
  172. package/src/shellStream.ts +55 -25
  173. package/src/workspaceEvents.ts +324 -0
  174. package/tests/buildIdentity.test.ts +51 -0
  175. package/tests/contextExtensions.test.ts +27 -0
  176. package/tests/headRuntime.test.tsx +229 -0
  177. package/tests/rendererHead.test.ts +1 -113
  178. package/tests/request-policy/browser-policy.test.ts +108 -0
  179. package/tests/request-policy/client-isolation.test.ts +109 -0
  180. package/tests/request-policy/node-policy.test.ts +447 -0
  181. package/tests/request-policy/policyCore.test.ts +129 -0
  182. package/tests/request-policy/requestContext.test.ts +66 -0
  183. package/tests/request-policy/requestFactory.outbound-contract.test.ts +290 -0
  184. package/tests/request-policy/traceparent.test.ts +52 -0
  185. package/tests/request-policy/transport-retry.test.ts +367 -0
  186. package/tests/routeHydration.test.ts +180 -0
  187. package/tests/routerPrefetchPolicy.test.ts +102 -0
  188. package/tests/routerProvider.test.ts +29 -0
  189. package/tests/routerState.test.ts +78 -0
  190. package/tests/routerStatePlugin.test.ts +63 -0
  191. package/tests/runtimeContextProjection.test.ts +83 -0
  192. package/tests/safeFailure.test.ts +10 -28
  193. package/tests/shellStream.test.ts +37 -0
  194. package/tests/workspaceEvents.test.ts +221 -0
  195. package/dist/cjs/rscHtmlStream.js +0 -128
  196. package/dist/esm/rscHtmlStream.mjs +0 -86
  197. package/dist/esm-node/rscHtmlStream.mjs +0 -87
  198. package/dist/types/rscHtmlStream.d.ts +0 -4
  199. package/src/rscHtmlStream.ts +0 -142
  200. package/tests/rscHtmlStream.test.ts +0 -153
@@ -0,0 +1,290 @@
1
+ // @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
2
+ import { createRuntimeContextExtension } from './contextExtensions';
3
+ import type {
4
+ InternalRouterRuntimeState,
5
+ InternalRouterServerSnapshot,
6
+ RouterRouteMatchSnapshot,
7
+ RouterServerPrepareResult,
8
+ } from './routerStateTypes';
9
+
10
+ export type {
11
+ BuiltInRouterFramework,
12
+ InternalRouterRuntimeState,
13
+ InternalRouterServerSnapshot,
14
+ RouterFramework,
15
+ RouterLifecyclePhase,
16
+ RouterRouteMatchSnapshot,
17
+ RouterServerPrepareResult,
18
+ } from './routerStateTypes';
19
+
20
+ /**
21
+ * Router runtime state is shared by every router provider (react-router,
22
+ * @modern-js/plugin-tanstack, ...) and consumed by the SSR pipeline. It lives
23
+ * in the runtime-context extension slot instead of ad-hoc fields on
24
+ * `TInternalRuntimeContext`.
25
+ */
26
+ const routerRuntimeStateExtension =
27
+ createRuntimeContextExtension<InternalRouterRuntimeState>(
28
+ '@modern-js/runtime:router-runtime-state',
29
+ );
30
+
31
+ /**
32
+ * The server snapshot is tracked separately: a later
33
+ * `applyRouterRuntimeState` call without a snapshot must not clear a
34
+ * previously captured one.
35
+ */
36
+ const routerServerSnapshotExtension =
37
+ createRuntimeContextExtension<InternalRouterServerSnapshot>(
38
+ '@modern-js/runtime:router-server-snapshot',
39
+ );
40
+
41
+ export function getRouterRuntimeState(
42
+ runtimeContext: object,
43
+ ): InternalRouterRuntimeState | undefined {
44
+ return routerRuntimeStateExtension.get(runtimeContext);
45
+ }
46
+
47
+ export function getRouterServerSnapshot(
48
+ runtimeContext: object,
49
+ ): InternalRouterServerSnapshot | undefined {
50
+ return routerServerSnapshotExtension.get(runtimeContext);
51
+ }
52
+
53
+ type RouterSnapshotLike = Partial<InternalRouterServerSnapshot>;
54
+
55
+ function toHydrationScripts(state: {
56
+ hydrationScript?: string;
57
+ hydrationScripts?: string[];
58
+ }) {
59
+ if (state.hydrationScripts?.length) {
60
+ return state.hydrationScripts;
61
+ }
62
+
63
+ return state.hydrationScript ? [state.hydrationScript] : undefined;
64
+ }
65
+
66
+ function getMatchedRouteIdsFromMatches(matches?: RouterRouteMatchSnapshot[]) {
67
+ const routeIds = matches
68
+ ?.map(match => match.assetRouteId ?? match.routeId)
69
+ .filter((routeId): routeId is string => typeof routeId === 'string');
70
+
71
+ return routeIds?.length ? routeIds : undefined;
72
+ }
73
+
74
+ export function createRouterServerSnapshot(
75
+ state: RouterSnapshotLike,
76
+ ): InternalRouterServerSnapshot {
77
+ const hydrationScripts = toHydrationScripts(state);
78
+ const matchedRouteIds =
79
+ state.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
80
+
81
+ return {
82
+ ...state,
83
+ ...(hydrationScripts?.length
84
+ ? {
85
+ hydrationScript: state.hydrationScript ?? hydrationScripts[0],
86
+ hydrationScripts,
87
+ }
88
+ : {}),
89
+ ...(matchedRouteIds ? { matchedRouteIds } : {}),
90
+ };
91
+ }
92
+
93
+ export function createRouterRuntimeState(
94
+ state: InternalRouterRuntimeState,
95
+ ): InternalRouterRuntimeState {
96
+ const hasSnapshotState =
97
+ Boolean(state.serverSnapshot) ||
98
+ Boolean(state.hydrationScript) ||
99
+ Boolean(state.hydrationScripts?.length) ||
100
+ Boolean(state.matchedRouteIds?.length) ||
101
+ Boolean(state.matches?.length);
102
+ const serverSnapshot = state.serverSnapshot
103
+ ? createRouterServerSnapshot({
104
+ ...state.serverSnapshot,
105
+ framework: state.serverSnapshot.framework ?? state.framework,
106
+ basename: state.serverSnapshot.basename ?? state.basename,
107
+ hydrationScript:
108
+ state.serverSnapshot.hydrationScript ?? state.hydrationScript,
109
+ hydrationScripts:
110
+ state.serverSnapshot.hydrationScripts ?? state.hydrationScripts,
111
+ matchedRouteIds:
112
+ state.serverSnapshot.matchedRouteIds ?? state.matchedRouteIds,
113
+ matches: state.serverSnapshot.matches ?? state.matches,
114
+ })
115
+ : hasSnapshotState
116
+ ? createRouterServerSnapshot({
117
+ framework: state.framework,
118
+ basename: state.basename,
119
+ hydrationScript: state.hydrationScript,
120
+ hydrationScripts: state.hydrationScripts,
121
+ matchedRouteIds: state.matchedRouteIds,
122
+ matches: state.matches,
123
+ })
124
+ : undefined;
125
+ const hydrationScripts = toHydrationScripts({
126
+ hydrationScript: state.hydrationScript ?? serverSnapshot?.hydrationScript,
127
+ hydrationScripts:
128
+ state.hydrationScripts ?? serverSnapshot?.hydrationScripts,
129
+ });
130
+ const matchedRouteIds =
131
+ state.matchedRouteIds ??
132
+ serverSnapshot?.matchedRouteIds ??
133
+ getMatchedRouteIdsFromMatches(state.matches);
134
+
135
+ return {
136
+ ...state,
137
+ ...(hydrationScripts?.length
138
+ ? {
139
+ hydrationScript: state.hydrationScript ?? hydrationScripts[0],
140
+ hydrationScripts,
141
+ }
142
+ : {}),
143
+ ...(matchedRouteIds ? { matchedRouteIds } : {}),
144
+ ...(serverSnapshot ? { serverSnapshot } : {}),
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Listeners per runtime context, so a consumer can react to the slot being
150
+ * filled in. A router provider publishes its instance during render - TanStack
151
+ * installs it when `RouterWrapper` renders - which is after anything that
152
+ * wraps the app has already evaluated. Without a notification those wrappers
153
+ * would hold a routerless view of the app for the rest of the session.
154
+ *
155
+ * Keyed weakly: the runtime context outlives neither the app nor this map.
156
+ */
157
+ const routerRuntimeStateListeners = new WeakMap<object, Set<() => void>>();
158
+
159
+ /**
160
+ * Observe the router runtime-state slot for the given runtime context.
161
+ * Returns an unsubscribe function; safe to call for a context that never
162
+ * receives a router.
163
+ */
164
+ export function subscribeRouterRuntimeState(
165
+ runtimeContext: object,
166
+ listener: () => void,
167
+ ): () => void {
168
+ if (!runtimeContext || typeof runtimeContext !== 'object') {
169
+ return () => undefined;
170
+ }
171
+ let listeners = routerRuntimeStateListeners.get(runtimeContext);
172
+ if (!listeners) {
173
+ listeners = new Set();
174
+ routerRuntimeStateListeners.set(runtimeContext, listeners);
175
+ }
176
+ listeners.add(listener);
177
+ return () => {
178
+ listeners?.delete(listener);
179
+ };
180
+ }
181
+
182
+ /** Contexts with a notification already scheduled, so a burst coalesces. */
183
+ const pendingRouterRuntimeStateNotifications = new WeakSet<object>();
184
+
185
+ function notifyRouterRuntimeState(runtimeContext: object) {
186
+ const listeners = routerRuntimeStateListeners.get(runtimeContext);
187
+ if (!listeners?.size) {
188
+ return;
189
+ }
190
+ if (pendingRouterRuntimeStateNotifications.has(runtimeContext)) {
191
+ return;
192
+ }
193
+ pendingRouterRuntimeStateNotifications.add(runtimeContext);
194
+ // Deferred deliberately. A router provider publishes its instance from
195
+ // inside its own render - `RouterWrapper` does - so calling observers
196
+ // synchronously would schedule an update on a component that is rendering,
197
+ // which React reports as "Cannot update a component while rendering a
198
+ // different component". Delivering after the current render lands keeps the
199
+ // notification correct and silent.
200
+ const deliver = () => {
201
+ pendingRouterRuntimeStateNotifications.delete(runtimeContext);
202
+ const current = routerRuntimeStateListeners.get(runtimeContext);
203
+ if (!current?.size) {
204
+ return;
205
+ }
206
+ for (const listener of [...current]) {
207
+ try {
208
+ listener();
209
+ } catch {
210
+ // One bad observer must not stop the router from being published.
211
+ }
212
+ }
213
+ };
214
+ if (typeof queueMicrotask === 'function') {
215
+ queueMicrotask(deliver);
216
+ } else {
217
+ setTimeout(deliver, 0);
218
+ }
219
+ }
220
+
221
+ export function applyRouterRuntimeState<Context extends object>(
222
+ runtimeContext: Context,
223
+ state: InternalRouterRuntimeState,
224
+ ) {
225
+ const previous = routerRuntimeStateExtension.get(runtimeContext);
226
+ const normalized = createRouterRuntimeState(state);
227
+ routerRuntimeStateExtension.set(runtimeContext, normalized);
228
+ if (normalized.serverSnapshot) {
229
+ routerServerSnapshotExtension.set(
230
+ runtimeContext,
231
+ normalized.serverSnapshot,
232
+ );
233
+ }
234
+ // Only a change of identity is worth a re-render; `RouterWrapper` reapplies
235
+ // the same instance on every render of the app.
236
+ if (
237
+ previous?.instance !== normalized.instance ||
238
+ previous?.framework !== normalized.framework
239
+ ) {
240
+ notifyRouterRuntimeState(runtimeContext);
241
+ }
242
+
243
+ return runtimeContext;
244
+ }
245
+
246
+ export function applyRouterServerPrepareResult<Context extends object>(
247
+ runtimeContext: Context,
248
+ result: RouterServerPrepareResult,
249
+ ) {
250
+ const state = createRouterRuntimeState({
251
+ ...result.state,
252
+ cleanup: result.cleanup ?? result.state.cleanup,
253
+ serverSnapshot: result.snapshot ?? result.state.serverSnapshot,
254
+ });
255
+ applyRouterRuntimeState(runtimeContext, state);
256
+ return runtimeContext;
257
+ }
258
+
259
+ export function getRouterHydrationScripts(runtimeContext: object) {
260
+ const serverSnapshot = getRouterServerSnapshot(runtimeContext);
261
+ const runtimeState = getRouterRuntimeState(runtimeContext);
262
+ return (
263
+ serverSnapshot?.hydrationScripts ??
264
+ toHydrationScripts({
265
+ hydrationScript: serverSnapshot?.hydrationScript,
266
+ }) ??
267
+ runtimeState?.hydrationScripts ??
268
+ toHydrationScripts({
269
+ hydrationScript: runtimeState?.hydrationScript,
270
+ }) ??
271
+ []
272
+ );
273
+ }
274
+
275
+ export function getRouterMatchedRouteIds(runtimeContext: object) {
276
+ const serverSnapshot = getRouterServerSnapshot(runtimeContext);
277
+ const runtimeState = getRouterRuntimeState(runtimeContext);
278
+ return (
279
+ serverSnapshot?.matchedRouteIds ??
280
+ getMatchedRouteIdsFromMatches(serverSnapshot?.matches) ??
281
+ runtimeState?.matchedRouteIds ??
282
+ getMatchedRouteIdsFromMatches(runtimeState?.matches)
283
+ );
284
+ }
285
+
286
+ export async function cleanupRouterRuntimeState(runtimeContext: object) {
287
+ try {
288
+ await getRouterRuntimeState(runtimeContext)?.cleanup?.();
289
+ } catch {}
290
+ }
@@ -0,0 +1,86 @@
1
+ import { createRouterPrefetchPolicy } from './routerPrefetchPolicy';
2
+ import {
3
+ applyRouterRuntimeState,
4
+ createRouterServerSnapshot,
5
+ } from './routerState';
6
+
7
+ type ReactRouterServerContext = {
8
+ statusCode: number;
9
+ errors?: Record<string, unknown> | null;
10
+ loaderData: Record<string, unknown>;
11
+ matches: { route: { id?: string } }[];
12
+ };
13
+
14
+ type RouterLifecycleEvent = {
15
+ framework: string;
16
+ phase: string;
17
+ runtimeContext: object;
18
+ basename?: string;
19
+ router?: unknown;
20
+ };
21
+
22
+ /** Install fork policy through lifecycle hooks supplied by the native owner. */
23
+ export function createRouterStatePlugin<Hooks extends Record<string, unknown>>({
24
+ registryHooks,
25
+ }: {
26
+ registryHooks: Hooks;
27
+ }) {
28
+ return {
29
+ name: '@modern-js/router-runtime-policy',
30
+ registryHooks,
31
+ setup(api: {
32
+ onBeforeRender: (callback: (context: object) => void) => unknown;
33
+ onAfterCreateRouter: (
34
+ callback: (event: RouterLifecycleEvent) => void,
35
+ ) => unknown;
36
+ }) {
37
+ api.onBeforeRender(context => {
38
+ const runtimeContext = context as {
39
+ linkPrefetchPolicy?: ReturnType<typeof createRouterPrefetchPolicy>;
40
+ };
41
+ runtimeContext.linkPrefetchPolicy ??= createRouterPrefetchPolicy();
42
+ });
43
+ api.onAfterCreateRouter(event => {
44
+ if (event.framework !== 'react-router') {
45
+ return;
46
+ }
47
+ if (event.phase === 'ssr-prepare') {
48
+ const { routerContext } = event.runtimeContext as {
49
+ routerContext?: ReactRouterServerContext;
50
+ };
51
+ if (!routerContext) {
52
+ return;
53
+ }
54
+ const serverSnapshot = createRouterServerSnapshot({
55
+ framework: event.framework,
56
+ basename: event.basename,
57
+ statusCode: routerContext.statusCode,
58
+ errors: routerContext.errors ?? undefined,
59
+ routerData: {
60
+ loaderData: routerContext.loaderData,
61
+ errors: routerContext.errors ?? undefined,
62
+ },
63
+ matches: routerContext.matches.flatMap(match =>
64
+ typeof match.route.id === 'string'
65
+ ? [{ routeId: match.route.id }]
66
+ : [],
67
+ ),
68
+ });
69
+ applyRouterRuntimeState(event.runtimeContext, {
70
+ framework: event.framework,
71
+ basename: event.basename,
72
+ instance: event.router,
73
+ matchedRouteIds: serverSnapshot.matchedRouteIds,
74
+ serverSnapshot,
75
+ });
76
+ } else if (event.phase === 'client-create') {
77
+ applyRouterRuntimeState(event.runtimeContext, {
78
+ framework: event.framework,
79
+ basename: event.basename,
80
+ instance: event.router,
81
+ });
82
+ }
83
+ });
84
+ },
85
+ };
86
+ }
@@ -0,0 +1,46 @@
1
+ export type BuiltInRouterFramework = 'react-router' | 'tanstack';
2
+
3
+ export type RouterFramework = BuiltInRouterFramework | (string & {});
4
+
5
+ export interface RouterRouteMatchSnapshot {
6
+ routeId: string;
7
+ assetRouteId?: string;
8
+ pathname?: string;
9
+ params?: Record<string, string>;
10
+ }
11
+
12
+ export interface InternalRouterServerSnapshot {
13
+ framework?: RouterFramework;
14
+ basename?: string;
15
+ statusCode?: number;
16
+ errors?: Record<string, unknown>;
17
+ routerData?: {
18
+ loaderData?: Record<string, unknown>;
19
+ errors?: Record<string, unknown>;
20
+ };
21
+ hydrationScript?: string;
22
+ hydrationScripts?: string[];
23
+ matchedRouteIds?: string[];
24
+ matches?: RouterRouteMatchSnapshot[];
25
+ }
26
+
27
+ export interface InternalRouterRuntimeState {
28
+ framework: RouterFramework;
29
+ basename?: string;
30
+ instance?: unknown;
31
+ hydrationScript?: string;
32
+ hydrationScripts?: string[];
33
+ matchedRouteIds?: string[];
34
+ matches?: RouterRouteMatchSnapshot[];
35
+ serverSnapshot?: InternalRouterServerSnapshot;
36
+ cleanup?: () => void | Promise<void>;
37
+ }
38
+
39
+ export interface RouterServerPrepareResult {
40
+ state: InternalRouterRuntimeState;
41
+ snapshot?: InternalRouterServerSnapshot;
42
+ redirect?: Response;
43
+ cleanup?: () => void | Promise<void>;
44
+ }
45
+
46
+ export type RouterLifecyclePhase = 'ssr-prepare' | 'client-create' | 'hydrate';
@@ -0,0 +1,10 @@
1
+ import { disabledRscRuntime } from './rscDisabledRuntimeError';
2
+
3
+ export const createFromFetch = disabledRscRuntime;
4
+ export const createFromReadableStream = disabledRscRuntime;
5
+ export const createServerReference = disabledRscRuntime;
6
+ export const createTemporaryReferenceSet = disabledRscRuntime;
7
+ export const encodeReply = disabledRscRuntime;
8
+ export const registerServerReference = disabledRscRuntime;
9
+ export const setFindSourceMapURLCallback = disabledRscRuntime;
10
+ export const setServerCallback = disabledRscRuntime;
@@ -0,0 +1,8 @@
1
+ import { disabledRscRuntime } from './rscDisabledRuntimeError';
2
+
3
+ export const createFromFetch = disabledRscRuntime;
4
+ export const createFromReadableStream = disabledRscRuntime;
5
+ export const createServerReference = disabledRscRuntime;
6
+ export const createTemporaryReferenceSet = disabledRscRuntime;
7
+ export const encodeReply = disabledRscRuntime;
8
+ export const registerServerReference = disabledRscRuntime;
@@ -0,0 +1,9 @@
1
+ import { disabledRscRuntime } from './rscDisabledRuntimeError';
2
+
3
+ export const createFromFetch = disabledRscRuntime;
4
+ export const createFromNodeStream = disabledRscRuntime;
5
+ export const createFromReadableStream = disabledRscRuntime;
6
+ export const createServerReference = disabledRscRuntime;
7
+ export const createTemporaryReferenceSet = disabledRscRuntime;
8
+ export const encodeReply = disabledRscRuntime;
9
+ export const registerServerReference = disabledRscRuntime;
@@ -0,0 +1,3 @@
1
+ export function disabledRscRuntime(): never {
2
+ throw new Error('React Server Components are disabled for this build.');
3
+ }
@@ -0,0 +1,16 @@
1
+ import { disabledRscRuntime } from './rscDisabledRuntimeError';
2
+
3
+ export const createServerEntry = disabledRscRuntime;
4
+ export const createTemporaryReferenceSet = disabledRscRuntime;
5
+ export const decodeAction = disabledRscRuntime;
6
+ export const decodeFormState = disabledRscRuntime;
7
+ export const decodeReply = disabledRscRuntime;
8
+ export const decodeReplyFromAsyncIterable = disabledRscRuntime;
9
+ export const decryptServerActionBoundArgs = disabledRscRuntime;
10
+ export const encryptServerActionBoundArgs = disabledRscRuntime;
11
+ export const ensureServerActions = disabledRscRuntime;
12
+ export const loadServerAction = disabledRscRuntime;
13
+ export const registerClientReference = disabledRscRuntime;
14
+ export const registerServerReference = disabledRscRuntime;
15
+ export const renderToReadableStream = disabledRscRuntime;
16
+ export const setServerActionBoundArgsEncryption = disabledRscRuntime;
@@ -0,0 +1,18 @@
1
+ import { disabledRscRuntime } from './rscDisabledRuntimeError';
2
+
3
+ export const createServerEntry = disabledRscRuntime;
4
+ export const createTemporaryReferenceSet = disabledRscRuntime;
5
+ export const decodeAction = disabledRscRuntime;
6
+ export const decodeFormState = disabledRscRuntime;
7
+ export const decodeReply = disabledRscRuntime;
8
+ export const decodeReplyFromAsyncIterable = disabledRscRuntime;
9
+ export const decodeReplyFromBusboy = disabledRscRuntime;
10
+ export const decryptServerActionBoundArgs = disabledRscRuntime;
11
+ export const encryptServerActionBoundArgs = disabledRscRuntime;
12
+ export const ensureServerActions = disabledRscRuntime;
13
+ export const loadServerAction = disabledRscRuntime;
14
+ export const registerClientReference = disabledRscRuntime;
15
+ export const registerServerReference = disabledRscRuntime;
16
+ export const renderToPipeableStream = disabledRscRuntime;
17
+ export const renderToReadableStream = disabledRscRuntime;
18
+ export const setServerActionBoundArgsEncryption = disabledRscRuntime;
@@ -0,0 +1,105 @@
1
+ import { stripRuntimeContextExtensions } from './contextExtensions';
2
+
3
+ // Only the transport fields consumed by this projection are required. This
4
+ // policy module does not depend on the native runtime or plugin API types.
5
+ interface ProjectionContext {
6
+ isBrowser?: boolean;
7
+ ssrContext?: {
8
+ request: {
9
+ url?: unknown;
10
+ userAgent?: unknown;
11
+ cookie?: unknown;
12
+ pathname?: unknown;
13
+ query?: object;
14
+ params?: object;
15
+ headers?: object;
16
+ host?: unknown;
17
+ referer?: unknown;
18
+ };
19
+ response: { locals?: unknown };
20
+ };
21
+ }
22
+
23
+ function createRscSafeRequestContext(
24
+ ssrContext: ProjectionContext['ssrContext'],
25
+ ) {
26
+ const requestContext = {
27
+ request: {
28
+ params: {},
29
+ pathname: '',
30
+ query: {},
31
+ headers: {},
32
+ host: '',
33
+ url: '',
34
+ },
35
+ response: {
36
+ setHeader() {},
37
+ status() {},
38
+ locals: {} as unknown,
39
+ },
40
+ };
41
+ Object.defineProperty(requestContext.response, 'setHeader', {
42
+ enumerable: false,
43
+ });
44
+ Object.defineProperty(requestContext.response, 'status', {
45
+ enumerable: false,
46
+ });
47
+
48
+ if (ssrContext === undefined) {
49
+ return requestContext;
50
+ }
51
+
52
+ const { request, response } = ssrContext;
53
+ return {
54
+ request: {
55
+ url: request.url,
56
+ userAgent: request.userAgent,
57
+ cookie: request.cookie,
58
+ pathname: request.pathname,
59
+ query: { ...request.query },
60
+ params: { ...request.params },
61
+ headers: { ...request.headers },
62
+ host: request.host,
63
+ referer: request.referer,
64
+ },
65
+ response: Object.assign(requestContext.response, {
66
+ locals: response.locals ?? {},
67
+ }),
68
+ };
69
+ }
70
+
71
+ export function projectRuntimeContext<
72
+ InternalContext extends ProjectionContext,
73
+ PublicContext extends ProjectionContext,
74
+ >(
75
+ projection: {
76
+ internalContext: InternalContext;
77
+ publicContext: PublicContext;
78
+ },
79
+ options: { context: InternalContext; isRsc: boolean },
80
+ ) {
81
+ let internalContext = projection.internalContext;
82
+ let publicContext = { ...projection.publicContext };
83
+ // Enumerable symbol slots deliberately survive internal SSR copies. Remove
84
+ // them only from the public projection, never from the original request.
85
+ stripRuntimeContextExtensions(publicContext);
86
+
87
+ if (options.isRsc && options.context.isBrowser === false) {
88
+ const requestContext = createRscSafeRequestContext(
89
+ options.context.ssrContext,
90
+ );
91
+ internalContext = {
92
+ ...internalContext,
93
+ context: requestContext,
94
+ requestContext,
95
+ };
96
+ delete internalContext.ssrContext;
97
+ publicContext = {
98
+ ...publicContext,
99
+ context: requestContext,
100
+ requestContext,
101
+ };
102
+ }
103
+
104
+ return { internalContext, publicContext };
105
+ }