@bleedingdev/modern-js-runtime-extensions 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21

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 (251) 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/localisedUrls/config.js +49 -0
  8. package/dist/cjs/localisedUrls/index.js +95 -0
  9. package/dist/cjs/localisedUrls/normalise.js +87 -0
  10. package/dist/cjs/localisedUrls/pathname.js +68 -0
  11. package/dist/cjs/localisedUrls/patterns.js +214 -0
  12. package/dist/cjs/localisedUrls/redirect.js +100 -0
  13. package/dist/cjs/localisedUrls/resolve.js +78 -0
  14. package/dist/cjs/localisedUrls/routeIdentity.js +92 -0
  15. package/dist/cjs/localisedUrls/routes.js +217 -0
  16. package/dist/cjs/localisedUrls/types.js +18 -0
  17. package/dist/cjs/prefetchPolicy.js +52 -0
  18. package/dist/cjs/rendererHead.js +18 -5
  19. package/dist/cjs/request-policy/browser.js +139 -0
  20. package/dist/cjs/request-policy/client.js +234 -0
  21. package/dist/cjs/request-policy/node.js +149 -0
  22. package/dist/cjs/request-policy/policyCore.js +266 -0
  23. package/dist/cjs/request-policy/requestContext.js +137 -0
  24. package/dist/cjs/request-policy/traceparent.js +56 -0
  25. package/dist/cjs/request-policy/transport.js +234 -0
  26. package/dist/cjs/request-policy/types.js +57 -0
  27. package/dist/cjs/routeHydration.js +127 -0
  28. package/dist/cjs/routerPrefetchPolicy.js +153 -0
  29. package/dist/cjs/routerProvider.js +105 -0
  30. package/dist/cjs/routerState.js +175 -0
  31. package/dist/cjs/routerStatePlugin.js +113 -0
  32. package/dist/cjs/routerStateTypes.js +18 -0
  33. package/dist/cjs/rsc-disabled/rscDisabledClientBrowserRuntime.js +69 -0
  34. package/dist/cjs/rsc-disabled/rscDisabledClientEdgeRuntime.js +61 -0
  35. package/dist/cjs/rsc-disabled/rscDisabledClientNodeRuntime.js +65 -0
  36. package/dist/cjs/rsc-disabled/rscDisabledRuntimeError.js +42 -0
  37. package/dist/cjs/rsc-disabled/rscDisabledServerEdgeRuntime.js +93 -0
  38. package/dist/cjs/rsc-disabled/rscDisabledServerNodeRuntime.js +101 -0
  39. package/dist/cjs/runtimeContextProjection.js +112 -0
  40. package/dist/cjs/server-config/bffRuntime.js +18 -0
  41. package/dist/cjs/server-config/index.js +18 -0
  42. package/dist/cjs/server-config/serverTelemetry.js +18 -0
  43. package/dist/cjs/shellStream.js +34 -2
  44. package/dist/cjs/workspaceEvents.js +159 -0
  45. package/dist/esm/buildIdentity.mjs +35 -0
  46. package/dist/esm/contextExtensions.mjs +33 -0
  47. package/dist/esm/headRuntime.mjs +43 -0
  48. package/dist/esm/helmetContext.mjs +13 -0
  49. package/dist/esm/index.mjs +2 -0
  50. package/dist/esm/localisedLoaderIdentity.mjs +13 -0
  51. package/dist/esm/localisedUrls/config.mjs +11 -0
  52. package/dist/esm/localisedUrls/index.mjs +8 -0
  53. package/dist/esm/localisedUrls/normalise.mjs +37 -0
  54. package/dist/esm/localisedUrls/pathname.mjs +24 -0
  55. package/dist/esm/localisedUrls/patterns.mjs +152 -0
  56. package/dist/esm/localisedUrls/redirect.mjs +53 -0
  57. package/dist/esm/localisedUrls/resolve.mjs +37 -0
  58. package/dist/esm/localisedUrls/routeIdentity.mjs +54 -0
  59. package/dist/esm/localisedUrls/routes.mjs +176 -0
  60. package/dist/esm/localisedUrls/types.mjs +0 -0
  61. package/dist/esm/prefetchPolicy.mjs +11 -0
  62. package/dist/esm/rendererHead.mjs +14 -5
  63. package/dist/esm/request-policy/browser.mjs +11 -0
  64. package/dist/esm/request-policy/client.mjs +195 -0
  65. package/dist/esm/request-policy/policyCore.mjs +171 -0
  66. package/dist/esm/request-policy/requestContext.mjs +75 -0
  67. package/dist/esm/request-policy/traceparent.mjs +18 -0
  68. package/dist/esm/request-policy/transport.mjs +196 -0
  69. package/dist/esm/request-policy/types.mjs +10 -0
  70. package/dist/esm/routeHydration.mjs +77 -0
  71. package/dist/esm/routerPrefetchPolicy.mjs +115 -0
  72. package/dist/esm/routerProvider.mjs +58 -0
  73. package/dist/esm/routerState.mjs +113 -0
  74. package/dist/esm/routerStatePlugin.mjs +75 -0
  75. package/dist/esm/routerStateTypes.mjs +0 -0
  76. package/dist/esm/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +10 -0
  77. package/dist/esm/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +8 -0
  78. package/dist/esm/rsc-disabled/rscDisabledClientNodeRuntime.mjs +9 -0
  79. package/dist/esm/rsc-disabled/rscDisabledRuntimeError.mjs +4 -0
  80. package/dist/esm/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +16 -0
  81. package/dist/esm/rsc-disabled/rscDisabledServerNodeRuntime.mjs +18 -0
  82. package/dist/esm/runtimeContextProjection.mjs +74 -0
  83. package/dist/esm/server-config/bffRuntime.mjs +0 -0
  84. package/dist/esm/server-config/index.mjs +0 -0
  85. package/dist/esm/server-config/serverTelemetry.mjs +0 -0
  86. package/dist/esm/shellStream.mjs +34 -2
  87. package/dist/esm/workspaceEvents.mjs +66 -0
  88. package/dist/esm-node/buildIdentity.mjs +36 -0
  89. package/dist/esm-node/contextExtensions.mjs +34 -0
  90. package/dist/esm-node/headRuntime.mjs +44 -0
  91. package/dist/esm-node/helmetContext.mjs +14 -0
  92. package/dist/esm-node/index.mjs +2 -0
  93. package/dist/esm-node/localisedLoaderIdentity.mjs +14 -0
  94. package/dist/esm-node/localisedUrls/config.mjs +12 -0
  95. package/dist/esm-node/localisedUrls/index.mjs +9 -0
  96. package/dist/esm-node/localisedUrls/normalise.mjs +38 -0
  97. package/dist/esm-node/localisedUrls/pathname.mjs +25 -0
  98. package/dist/esm-node/localisedUrls/patterns.mjs +153 -0
  99. package/dist/esm-node/localisedUrls/redirect.mjs +54 -0
  100. package/dist/esm-node/localisedUrls/resolve.mjs +38 -0
  101. package/dist/esm-node/localisedUrls/routeIdentity.mjs +55 -0
  102. package/dist/esm-node/localisedUrls/routes.mjs +177 -0
  103. package/dist/esm-node/localisedUrls/types.mjs +1 -0
  104. package/dist/esm-node/prefetchPolicy.mjs +12 -0
  105. package/dist/esm-node/rendererHead.mjs +14 -5
  106. package/dist/esm-node/request-policy/browser.mjs +12 -0
  107. package/dist/esm-node/request-policy/client.mjs +196 -0
  108. package/dist/esm-node/request-policy/node.mjs +22 -0
  109. package/dist/esm-node/request-policy/policyCore.mjs +172 -0
  110. package/dist/esm-node/request-policy/requestContext.mjs +76 -0
  111. package/dist/esm-node/request-policy/traceparent.mjs +19 -0
  112. package/dist/esm-node/request-policy/transport.mjs +197 -0
  113. package/dist/esm-node/request-policy/types.mjs +11 -0
  114. package/dist/esm-node/routeHydration.mjs +78 -0
  115. package/dist/esm-node/routerPrefetchPolicy.mjs +116 -0
  116. package/dist/esm-node/routerProvider.mjs +59 -0
  117. package/dist/esm-node/routerState.mjs +114 -0
  118. package/dist/esm-node/routerStatePlugin.mjs +76 -0
  119. package/dist/esm-node/routerStateTypes.mjs +1 -0
  120. package/dist/esm-node/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +11 -0
  121. package/dist/esm-node/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +9 -0
  122. package/dist/esm-node/rsc-disabled/rscDisabledClientNodeRuntime.mjs +10 -0
  123. package/dist/esm-node/rsc-disabled/rscDisabledRuntimeError.mjs +5 -0
  124. package/dist/esm-node/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +17 -0
  125. package/dist/esm-node/rsc-disabled/rscDisabledServerNodeRuntime.mjs +19 -0
  126. package/dist/esm-node/runtimeContextProjection.mjs +75 -0
  127. package/dist/esm-node/server-config/bffRuntime.mjs +1 -0
  128. package/dist/esm-node/server-config/index.mjs +1 -0
  129. package/dist/esm-node/server-config/serverTelemetry.mjs +1 -0
  130. package/dist/esm-node/shellStream.mjs +34 -2
  131. package/dist/esm-node/workspaceEvents.mjs +67 -0
  132. package/dist/types/buildIdentity.d.ts +37 -0
  133. package/dist/types/contextExtensions.d.ts +34 -0
  134. package/dist/types/headRuntime.d.ts +12 -0
  135. package/dist/types/helmetCompat.d.ts +1 -1
  136. package/dist/types/helmetContext.d.ts +10 -0
  137. package/dist/types/index.d.ts +2 -0
  138. package/dist/types/localisedLoaderIdentity.d.ts +10 -0
  139. package/dist/types/localisedUrls/config.d.ts +9 -0
  140. package/dist/types/localisedUrls/index.d.ts +10 -0
  141. package/dist/types/localisedUrls/normalise.d.ts +10 -0
  142. package/dist/types/localisedUrls/pathname.d.ts +4 -0
  143. package/dist/types/localisedUrls/patterns.d.ts +11 -0
  144. package/dist/types/localisedUrls/redirect.d.ts +19 -0
  145. package/dist/types/localisedUrls/resolve.d.ts +7 -0
  146. package/dist/types/localisedUrls/routeIdentity.d.ts +22 -0
  147. package/dist/types/localisedUrls/routes.d.ts +3 -0
  148. package/dist/types/localisedUrls/types.d.ts +14 -0
  149. package/dist/types/prefetchPolicy.d.ts +4 -0
  150. package/dist/types/rendererHead.d.ts +5 -3
  151. package/dist/types/request-policy/browser.d.ts +10 -0
  152. package/dist/types/request-policy/client.d.ts +14 -0
  153. package/dist/types/request-policy/node.d.ts +10 -0
  154. package/dist/types/request-policy/policyCore.d.ts +107 -0
  155. package/dist/types/request-policy/requestContext.d.ts +22 -0
  156. package/dist/types/request-policy/traceparent.d.ts +10 -0
  157. package/dist/types/request-policy/transport.d.ts +12 -0
  158. package/dist/types/request-policy/types.d.ts +144 -0
  159. package/dist/types/routeHydration.d.ts +24 -0
  160. package/dist/types/routerPrefetchPolicy.d.ts +28 -0
  161. package/dist/types/routerProvider.d.ts +55 -0
  162. package/dist/types/routerState.d.ts +17 -0
  163. package/dist/types/routerStatePlugin.d.ts +19 -0
  164. package/dist/types/routerStateTypes.d.ts +70 -0
  165. package/dist/types/rsc-disabled/rscDisabledClientBrowserRuntime.d.ts +9 -0
  166. package/dist/types/rsc-disabled/rscDisabledClientEdgeRuntime.d.ts +7 -0
  167. package/dist/types/rsc-disabled/rscDisabledClientNodeRuntime.d.ts +8 -0
  168. package/dist/types/rsc-disabled/rscDisabledRuntimeError.d.ts +1 -0
  169. package/dist/types/rsc-disabled/rscDisabledServerEdgeRuntime.d.ts +15 -0
  170. package/dist/types/rsc-disabled/rscDisabledServerNodeRuntime.d.ts +17 -0
  171. package/dist/types/runtimeContextProjection.d.ts +30 -0
  172. package/dist/types/server-config/bffRuntime.d.ts +122 -0
  173. package/dist/types/server-config/index.d.ts +2 -0
  174. package/dist/types/server-config/serverTelemetry.d.ts +322 -0
  175. package/dist/types/workspaceEvents.d.ts +62 -0
  176. package/package.json +240 -15
  177. package/rslib.config.mts +17 -2
  178. package/rstest.config.mts +33 -2
  179. package/src/buildIdentity.ts +61 -0
  180. package/src/contextExtensions.ts +81 -0
  181. package/src/headRuntime.tsx +77 -0
  182. package/src/helmetCompat.ts +1 -1
  183. package/src/helmetContext.ts +31 -0
  184. package/src/index.ts +2 -0
  185. package/src/localisedLoaderIdentity.ts +30 -0
  186. package/src/localisedUrls/config.ts +18 -0
  187. package/src/localisedUrls/index.ts +25 -0
  188. package/src/localisedUrls/normalise.ts +62 -0
  189. package/src/localisedUrls/pathname.ts +60 -0
  190. package/src/localisedUrls/patterns.ts +283 -0
  191. package/src/localisedUrls/redirect.ts +107 -0
  192. package/src/localisedUrls/resolve.ts +106 -0
  193. package/src/localisedUrls/routeIdentity.ts +83 -0
  194. package/src/localisedUrls/routes.ts +451 -0
  195. package/src/localisedUrls/types.ts +18 -0
  196. package/src/prefetchPolicy.ts +33 -0
  197. package/src/rendererHead.ts +25 -8
  198. package/src/request-policy/browser.ts +22 -0
  199. package/src/request-policy/client.ts +404 -0
  200. package/src/request-policy/node.ts +41 -0
  201. package/src/request-policy/policyCore.ts +424 -0
  202. package/src/request-policy/requestContext.ts +149 -0
  203. package/src/request-policy/traceparent.ts +43 -0
  204. package/src/request-policy/transport.ts +349 -0
  205. package/src/request-policy/types.ts +229 -0
  206. package/src/routeHydration.ts +208 -0
  207. package/src/routerPrefetchPolicy.ts +195 -0
  208. package/src/routerProvider.ts +160 -0
  209. package/src/routerState.ts +220 -0
  210. package/src/routerStatePlugin.ts +125 -0
  211. package/src/routerStateTypes.ts +76 -0
  212. package/src/rsc-disabled/rscDisabledClientBrowserRuntime.ts +10 -0
  213. package/src/rsc-disabled/rscDisabledClientEdgeRuntime.ts +8 -0
  214. package/src/rsc-disabled/rscDisabledClientNodeRuntime.ts +9 -0
  215. package/src/rsc-disabled/rscDisabledRuntimeError.ts +3 -0
  216. package/src/rsc-disabled/rscDisabledServerEdgeRuntime.ts +16 -0
  217. package/src/rsc-disabled/rscDisabledServerNodeRuntime.ts +18 -0
  218. package/src/runtimeContextProjection.ts +105 -0
  219. package/src/server-config/bffRuntime.ts +136 -0
  220. package/src/server-config/index.ts +2 -0
  221. package/src/server-config/serverTelemetry.ts +337 -0
  222. package/src/shellStream.ts +55 -25
  223. package/src/workspaceEvents.ts +324 -0
  224. package/tests/buildIdentity.test.ts +51 -0
  225. package/tests/contextExtensions.test.ts +27 -0
  226. package/tests/headRuntime.test.tsx +229 -0
  227. package/tests/localisedUrls.test.ts +560 -0
  228. package/tests/rendererHead.test.ts +52 -121
  229. package/tests/request-policy/browser-policy.test.ts +108 -0
  230. package/tests/request-policy/client-isolation.test.ts +109 -0
  231. package/tests/request-policy/node-policy.test.ts +447 -0
  232. package/tests/request-policy/policyCore.test.ts +129 -0
  233. package/tests/request-policy/requestContext.test.ts +66 -0
  234. package/tests/request-policy/requestFactory.outbound-contract.test.ts +290 -0
  235. package/tests/request-policy/traceparent.test.ts +52 -0
  236. package/tests/request-policy/transport-retry.test.ts +367 -0
  237. package/tests/routeHydration.test.ts +180 -0
  238. package/tests/routerPrefetchPolicy.test.ts +102 -0
  239. package/tests/routerProvider.test.ts +29 -0
  240. package/tests/routerState.test.ts +77 -0
  241. package/tests/routerStatePlugin.test.ts +63 -0
  242. package/tests/runtimeContextProjection.test.ts +83 -0
  243. package/tests/safeFailure.test.ts +10 -28
  244. package/tests/shellStream.test.ts +39 -2
  245. package/tests/workspaceEvents.test.ts +221 -0
  246. package/dist/cjs/rscHtmlStream.js +0 -128
  247. package/dist/esm/rscHtmlStream.mjs +0 -86
  248. package/dist/esm-node/rscHtmlStream.mjs +0 -87
  249. package/dist/types/rscHtmlStream.d.ts +0 -4
  250. package/src/rscHtmlStream.ts +0 -142
  251. package/tests/rscHtmlStream.test.ts +0 -153
@@ -0,0 +1,220 @@
1
+ // @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
2
+ import { createRuntimeContextExtension } from './contextExtensions';
3
+ import type {
4
+ InternalRouterRuntimeState,
5
+ InternalRouterServerSnapshot,
6
+ RouterServerPrepareResult,
7
+ } from './routerStateTypes';
8
+
9
+ export type {
10
+ BuiltInRouterFramework,
11
+ InternalRouterRuntimeState,
12
+ InternalRouterServerSnapshot,
13
+ RouterFramework,
14
+ RouterLifecyclePhase,
15
+ RouterLinkTarget,
16
+ RouterNavigationCapability,
17
+ RouterNavigationSnapshot,
18
+ RouterRouteMatchSnapshot,
19
+ RouterServerPrepareResult,
20
+ } from './routerStateTypes';
21
+
22
+ /**
23
+ * Router runtime state is shared by every router provider (react-router,
24
+ * @modern-js/plugin-tanstack, ...) and consumed by the SSR pipeline. It lives
25
+ * in the runtime-context extension slot instead of ad-hoc fields on
26
+ * `TInternalRuntimeContext`.
27
+ */
28
+ const routerRuntimeStateExtension =
29
+ createRuntimeContextExtension<InternalRouterRuntimeState>(
30
+ '@modern-js/runtime:router-runtime-state',
31
+ );
32
+
33
+ /**
34
+ * The server snapshot is tracked separately: a later
35
+ * `applyRouterRuntimeState` call without a snapshot must not clear a
36
+ * previously captured one.
37
+ */
38
+ const routerServerSnapshotExtension =
39
+ createRuntimeContextExtension<InternalRouterServerSnapshot>(
40
+ '@modern-js/runtime:router-server-snapshot',
41
+ );
42
+
43
+ export function getRouterRuntimeState(
44
+ runtimeContext: object,
45
+ ): InternalRouterRuntimeState | undefined {
46
+ return routerRuntimeStateExtension.get(runtimeContext);
47
+ }
48
+
49
+ export function getRouterServerSnapshot(
50
+ runtimeContext: object,
51
+ ): InternalRouterServerSnapshot | undefined {
52
+ return routerServerSnapshotExtension.get(runtimeContext);
53
+ }
54
+
55
+ /** Capture prepared metadata once; live router updates cannot rewrite it. */
56
+ export function createRouterServerSnapshot(
57
+ snapshot: InternalRouterServerSnapshot,
58
+ ): InternalRouterServerSnapshot {
59
+ const matches = snapshot.matches?.map(match =>
60
+ Object.freeze({
61
+ ...match,
62
+ ...(match.params ? { params: Object.freeze({ ...match.params }) } : {}),
63
+ }),
64
+ );
65
+ const matchedRouteIds =
66
+ snapshot.matchedRouteIds ??
67
+ matches?.map(match => match.assetRouteId ?? match.routeId);
68
+ return Object.freeze({
69
+ ...snapshot,
70
+ ...(snapshot.hydrationScripts
71
+ ? { hydrationScripts: Object.freeze([...snapshot.hydrationScripts]) }
72
+ : {}),
73
+ ...(matchedRouteIds
74
+ ? { matchedRouteIds: Object.freeze([...matchedRouteIds]) }
75
+ : {}),
76
+ ...(matches ? { matches: Object.freeze(matches) } : {}),
77
+ ...(snapshot.errors
78
+ ? { errors: Object.freeze({ ...snapshot.errors }) }
79
+ : {}),
80
+ ...(snapshot.routerData
81
+ ? {
82
+ routerData: Object.freeze({
83
+ ...snapshot.routerData,
84
+ ...(snapshot.routerData.loaderData
85
+ ? {
86
+ loaderData: Object.freeze({
87
+ ...snapshot.routerData.loaderData,
88
+ }),
89
+ }
90
+ : {}),
91
+ ...(snapshot.routerData.errors
92
+ ? { errors: Object.freeze({ ...snapshot.routerData.errors }) }
93
+ : {}),
94
+ }),
95
+ }
96
+ : {}),
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Listeners per runtime context, so a consumer can react to the slot being
102
+ * filled in. A router provider publishes its instance during render - TanStack
103
+ * installs it when `RouterWrapper` renders - which is after anything that
104
+ * wraps the app has already evaluated. Without a notification those wrappers
105
+ * would hold a routerless view of the app for the rest of the session.
106
+ *
107
+ * Keyed weakly: the runtime context outlives neither the app nor this map.
108
+ */
109
+ const routerRuntimeStateListeners = new WeakMap<object, Set<() => void>>();
110
+
111
+ /**
112
+ * Observe the router runtime-state slot for the given runtime context.
113
+ * Returns an unsubscribe function; safe to call for a context that never
114
+ * receives a router.
115
+ */
116
+ export function subscribeRouterRuntimeState(
117
+ runtimeContext: object,
118
+ listener: () => void,
119
+ ): () => void {
120
+ if (!runtimeContext || typeof runtimeContext !== 'object') {
121
+ return () => undefined;
122
+ }
123
+ let listeners = routerRuntimeStateListeners.get(runtimeContext);
124
+ if (!listeners) {
125
+ listeners = new Set();
126
+ routerRuntimeStateListeners.set(runtimeContext, listeners);
127
+ }
128
+ listeners.add(listener);
129
+ return () => {
130
+ listeners?.delete(listener);
131
+ };
132
+ }
133
+
134
+ /** Contexts with a notification already scheduled, so a burst coalesces. */
135
+ const pendingRouterRuntimeStateNotifications = new WeakSet<object>();
136
+
137
+ function notifyRouterRuntimeState(runtimeContext: object) {
138
+ const listeners = routerRuntimeStateListeners.get(runtimeContext);
139
+ if (!listeners?.size) {
140
+ return;
141
+ }
142
+ if (pendingRouterRuntimeStateNotifications.has(runtimeContext)) {
143
+ return;
144
+ }
145
+ pendingRouterRuntimeStateNotifications.add(runtimeContext);
146
+ // Deferred deliberately. A router provider publishes its instance from
147
+ // inside its own render - `RouterWrapper` does - so calling observers
148
+ // synchronously would schedule an update on a component that is rendering,
149
+ // which React reports as "Cannot update a component while rendering a
150
+ // different component". Delivering after the current render lands keeps the
151
+ // notification correct and silent.
152
+ const deliver = () => {
153
+ pendingRouterRuntimeStateNotifications.delete(runtimeContext);
154
+ const current = routerRuntimeStateListeners.get(runtimeContext);
155
+ if (!current?.size) {
156
+ return;
157
+ }
158
+ for (const listener of [...current]) {
159
+ try {
160
+ listener();
161
+ } catch {
162
+ // One bad observer must not stop the router from being published.
163
+ }
164
+ }
165
+ };
166
+ if (typeof queueMicrotask === 'function') {
167
+ queueMicrotask(deliver);
168
+ } else {
169
+ setTimeout(deliver, 0);
170
+ }
171
+ }
172
+
173
+ export function applyRouterRuntimeState<Context extends object>(
174
+ runtimeContext: Context,
175
+ state: InternalRouterRuntimeState,
176
+ ) {
177
+ const previous = routerRuntimeStateExtension.get(runtimeContext);
178
+ routerRuntimeStateExtension.set(runtimeContext, state);
179
+ // Only a change of identity is worth a re-render; `RouterWrapper` reapplies
180
+ // the same instance on every render of the app.
181
+ if (
182
+ previous?.instance !== state.instance ||
183
+ previous?.framework !== state.framework ||
184
+ previous?.navigation !== state.navigation
185
+ ) {
186
+ notifyRouterRuntimeState(runtimeContext);
187
+ }
188
+
189
+ return runtimeContext;
190
+ }
191
+
192
+ export function applyRouterServerPrepareResult<Context extends object>(
193
+ runtimeContext: Context,
194
+ result: RouterServerPrepareResult,
195
+ ) {
196
+ if (result.snapshot) {
197
+ routerServerSnapshotExtension.set(
198
+ runtimeContext,
199
+ createRouterServerSnapshot(result.snapshot),
200
+ );
201
+ }
202
+ return applyRouterRuntimeState(runtimeContext, {
203
+ ...result.state,
204
+ cleanup: result.cleanup ?? result.state.cleanup,
205
+ });
206
+ }
207
+
208
+ export function getRouterHydrationScripts(runtimeContext: object) {
209
+ return getRouterServerSnapshot(runtimeContext)?.hydrationScripts ?? [];
210
+ }
211
+
212
+ export function getRouterMatchedRouteIds(runtimeContext: object) {
213
+ return getRouterServerSnapshot(runtimeContext)?.matchedRouteIds;
214
+ }
215
+
216
+ export async function cleanupRouterRuntimeState(runtimeContext: object) {
217
+ try {
218
+ await getRouterRuntimeState(runtimeContext)?.cleanup?.();
219
+ } catch {}
220
+ }
@@ -0,0 +1,125 @@
1
+ import type { createMemoryRouter } from '@modern-js/runtime-utils/router';
2
+ import { createRouterPrefetchPolicy } from './routerPrefetchPolicy';
3
+ import {
4
+ applyRouterRuntimeState,
5
+ applyRouterServerPrepareResult,
6
+ } from './routerState';
7
+ import type {
8
+ RouterNavigationCapability,
9
+ RouterNavigationSnapshot,
10
+ } from './routerStateTypes';
11
+
12
+ type ReactRouterServerContext = {
13
+ statusCode: number;
14
+ errors?: Record<string, unknown> | null;
15
+ loaderData: Record<string, unknown>;
16
+ matches: { route: { id?: string } }[];
17
+ };
18
+
19
+ type RouterLifecycleEvent = {
20
+ framework: string;
21
+ phase: string;
22
+ runtimeContext: object;
23
+ basename?: string;
24
+ router?: unknown;
25
+ };
26
+
27
+ function createReactRouterNavigation(
28
+ router: ReturnType<typeof createMemoryRouter>,
29
+ Link: RouterNavigationCapability['Link'],
30
+ ): RouterNavigationCapability {
31
+ let state: typeof router.state | undefined;
32
+ let snapshot: RouterNavigationSnapshot;
33
+ return {
34
+ Link,
35
+ getSnapshot() {
36
+ if (state !== router.state) {
37
+ state = router.state;
38
+ snapshot = {
39
+ location: state.location,
40
+ params: Object.assign(
41
+ {},
42
+ ...state.matches.map(match => match.params),
43
+ ),
44
+ };
45
+ }
46
+ return snapshot;
47
+ },
48
+ subscribe: listener => router.subscribe(listener),
49
+ navigate: (href, options) => router.navigate(href, options),
50
+ };
51
+ }
52
+
53
+ /** Install fork policy through lifecycle hooks supplied by the native owner. */
54
+ export function createRouterStatePlugin<Hooks extends Record<string, unknown>>({
55
+ registryHooks,
56
+ }: {
57
+ registryHooks: Hooks;
58
+ }) {
59
+ return {
60
+ name: '@modern-js/router-runtime-policy',
61
+ registryHooks,
62
+ setup(api: {
63
+ onBeforeRender: (callback: (context: object) => void) => unknown;
64
+ onAfterCreateRouter: (
65
+ callback: (event: RouterLifecycleEvent) => void,
66
+ ) => unknown;
67
+ }) {
68
+ api.onBeforeRender(context => {
69
+ const runtimeContext = context as {
70
+ linkPrefetchPolicy?: ReturnType<typeof createRouterPrefetchPolicy>;
71
+ };
72
+ runtimeContext.linkPrefetchPolicy ??= createRouterPrefetchPolicy();
73
+ });
74
+ api.onAfterCreateRouter(event => {
75
+ if (event.framework !== 'react-router') {
76
+ return;
77
+ }
78
+ if (event.phase === 'ssr-prepare') {
79
+ const { routerContext } = event.runtimeContext as {
80
+ routerContext?: ReactRouterServerContext;
81
+ };
82
+ if (!routerContext) {
83
+ return;
84
+ }
85
+ const snapshot = {
86
+ framework: event.framework,
87
+ basename: event.basename,
88
+ statusCode: routerContext.statusCode,
89
+ errors: routerContext.errors ?? undefined,
90
+ routerData: {
91
+ loaderData: routerContext.loaderData,
92
+ errors: routerContext.errors ?? undefined,
93
+ },
94
+ matches: routerContext.matches.flatMap(match =>
95
+ typeof match.route.id === 'string'
96
+ ? [{ routeId: match.route.id }]
97
+ : [],
98
+ ),
99
+ };
100
+ applyRouterServerPrepareResult(event.runtimeContext, {
101
+ snapshot,
102
+ state: {
103
+ framework: event.framework,
104
+ basename: event.basename,
105
+ instance: event.router,
106
+ },
107
+ });
108
+ } else if (event.phase === 'client-create') {
109
+ const router = event.router as ReturnType<typeof createMemoryRouter>;
110
+ const { router: api } = event.runtimeContext as {
111
+ router?: { Link?: RouterNavigationCapability['Link'] };
112
+ };
113
+ applyRouterRuntimeState(event.runtimeContext, {
114
+ framework: event.framework,
115
+ basename: event.basename,
116
+ instance: router,
117
+ ...(api?.Link
118
+ ? { navigation: createReactRouterNavigation(router, api.Link) }
119
+ : {}),
120
+ });
121
+ }
122
+ });
123
+ },
124
+ };
125
+ }
@@ -0,0 +1,76 @@
1
+ import type React from 'react';
2
+
3
+ export type BuiltInRouterFramework = 'react-router' | 'tanstack';
4
+
5
+ export type RouterFramework = BuiltInRouterFramework | (string & {});
6
+
7
+ export interface RouterRouteMatchSnapshot {
8
+ routeId: string;
9
+ assetRouteId?: string;
10
+ pathname?: string;
11
+ params?: Record<string, string>;
12
+ }
13
+
14
+ export interface InternalRouterServerSnapshot {
15
+ readonly framework?: RouterFramework;
16
+ readonly basename?: string;
17
+ readonly statusCode?: number;
18
+ readonly errors?: Record<string, unknown>;
19
+ readonly routerData?: {
20
+ readonly loaderData?: Record<string, unknown>;
21
+ readonly errors?: Record<string, unknown>;
22
+ };
23
+ readonly hydrationScripts?: readonly string[];
24
+ readonly matchedRouteIds?: readonly string[];
25
+ readonly matches?: readonly RouterRouteMatchSnapshot[];
26
+ }
27
+
28
+ export interface InternalRouterRuntimeState {
29
+ framework: RouterFramework;
30
+ basename?: string;
31
+ instance?: unknown;
32
+ navigation?: RouterNavigationCapability;
33
+ cleanup?: () => void | Promise<void>;
34
+ }
35
+
36
+ export interface RouterServerPrepareResult {
37
+ state: InternalRouterRuntimeState;
38
+ snapshot?: InternalRouterServerSnapshot;
39
+ cleanup?: () => void | Promise<void>;
40
+ }
41
+
42
+ export type RouterLifecyclePhase = 'ssr-prepare' | 'client-create' | 'hydrate';
43
+
44
+ /** Provider-owned browser navigation. Consumers never inspect router internals. */
45
+ export interface RouterNavigationSnapshot {
46
+ location: { pathname: string; search: string; hash: string };
47
+ params: Record<string, string>;
48
+ }
49
+
50
+ export interface RouterLinkTarget {
51
+ pathname: string;
52
+ href: string;
53
+ search?: Record<string, unknown>;
54
+ hash?: string;
55
+ hashScrollIntoView?: boolean | ScrollIntoViewOptions;
56
+ prefetch?: 'intent' | 'render' | 'viewport' | 'none';
57
+ preload?: unknown;
58
+ }
59
+
60
+ export interface RouterNavigationCapability {
61
+ getSnapshot: () => RouterNavigationSnapshot;
62
+ subscribe: (listener: () => void) => () => void;
63
+ navigate: (
64
+ href: string,
65
+ options?: { replace?: boolean; state?: unknown },
66
+ ) => void | Promise<void>;
67
+ Link: React.ComponentType<{
68
+ to: string;
69
+ children?: React.ReactNode;
70
+ [key: string]: unknown;
71
+ }>;
72
+ createLinkProps?: (target: RouterLinkTarget) => {
73
+ to: string;
74
+ [key: string]: unknown;
75
+ };
76
+ }
@@ -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
+ }