@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
package/rslib.config.mts CHANGED
@@ -1,4 +1,19 @@
1
- import { rslibConfig } from '@modern-js/rslib';
1
+ import { RSLIB_CODE_ENTRY_GLOB, rslibConfig } from '@modern-js/rslib';
2
2
  import { defineConfig } from '@rslib/core';
3
3
 
4
- export default defineConfig(rslibConfig);
4
+ export default defineConfig({
5
+ ...rslibConfig,
6
+ lib: rslibConfig.lib.map(lib =>
7
+ lib.id === 'esm-web'
8
+ ? {
9
+ ...lib,
10
+ source: {
11
+ ...lib.source,
12
+ entry: {
13
+ index: [RSLIB_CODE_ENTRY_GLOB, '!./src/request-policy/node.ts'],
14
+ },
15
+ },
16
+ }
17
+ : lib,
18
+ ),
19
+ });
package/rstest.config.mts CHANGED
@@ -1,7 +1,38 @@
1
+ import type { ProjectConfig } from '@rstest/core';
1
2
  import { withTestPreset } from '@scripts/rstest-config';
2
3
 
3
- export default withTestPreset({
4
+ const commonConfig: ProjectConfig = {
4
5
  root: __dirname,
5
- testEnvironment: 'node',
6
6
  globals: true,
7
+ setupFiles: ['@scripts/rstest-config/setup.ts'],
8
+ tools: {
9
+ swc: {
10
+ jsc: {
11
+ transform: {
12
+ react: {
13
+ runtime: 'automatic',
14
+ },
15
+ },
16
+ },
17
+ },
18
+ },
19
+ };
20
+
21
+ const browserPolicyProject = withTestPreset({
22
+ name: 'runtime-extensions-request-policy-browser',
23
+ testEnvironment: 'happy-dom',
24
+ extends: commonConfig,
25
+ include: ['tests/request-policy/browser-policy.test.ts'],
7
26
  });
27
+
28
+ export default {
29
+ projects: [
30
+ withTestPreset({
31
+ name: 'runtime-extensions-node',
32
+ exclude: ['tests/request-policy/browser-policy.test.ts'],
33
+ testEnvironment: 'node',
34
+ extends: commonConfig,
35
+ }),
36
+ browserPolicyProject,
37
+ ],
38
+ };
@@ -0,0 +1,61 @@
1
+ interface BuildIdentity {
2
+ readonly build: string;
3
+ readonly buildMarker: string;
4
+ readonly sourceRevision: string;
5
+ }
6
+
7
+ interface BuildArtifact {
8
+ readonly deliveryUnit: BuildIdentity;
9
+ readonly surfaces: {
10
+ readonly api: BuildIdentity;
11
+ readonly ui: BuildIdentity;
12
+ };
13
+ }
14
+
15
+ interface BuildIdentityReaders {
16
+ readonly buildMarker: () => string;
17
+ readonly sourceRevision: () => string;
18
+ }
19
+
20
+ function readBuildValue(read: () => string, fallback: string): string {
21
+ try {
22
+ return read();
23
+ } catch (error) {
24
+ // An uncompiled generated module has no injected constants. Check the
25
+ // error tag across realms, since source validators may evaluate in a VM.
26
+ if (
27
+ error !== null &&
28
+ typeof error === 'object' &&
29
+ 'name' in error &&
30
+ error.name === 'ReferenceError'
31
+ ) {
32
+ return fallback;
33
+ }
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ /** Read compiler constants in the caller, even when this package is external. */
39
+ export function resolveUltramodernBuildArtifact<Artifact extends BuildArtifact>(
40
+ artifact: Artifact,
41
+ readers?: BuildIdentityReaders,
42
+ ) {
43
+ const buildMarker = readers
44
+ ? readBuildValue(readers.buildMarker, artifact.deliveryUnit.buildMarker)
45
+ : artifact.deliveryUnit.buildMarker;
46
+ const sourceRevision = readers
47
+ ? readBuildValue(
48
+ readers.sourceRevision,
49
+ artifact.deliveryUnit.sourceRevision,
50
+ )
51
+ : artifact.deliveryUnit.sourceRevision;
52
+ const identity = { build: buildMarker, buildMarker, sourceRevision };
53
+ return {
54
+ ...artifact,
55
+ deliveryUnit: { ...artifact.deliveryUnit, ...identity },
56
+ surfaces: {
57
+ api: { ...artifact.surfaces.api, ...identity },
58
+ ui: { ...artifact.surfaces.ui, ...identity },
59
+ },
60
+ };
61
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Fork-owned runtime-context extension mechanism.
3
+ *
4
+ * Plugins must not add ad-hoc fields to `TRuntimeContext` /
5
+ * `TInternalRuntimeContext`. Instead they store state in a single internal
6
+ * slot (a `Map` keyed by symbol) attached to the context object under a
7
+ * symbol property, so nothing leaks into string-key enumeration
8
+ * (`Object.keys`, `JSON.stringify`). Object spreads preserve the slot.
9
+ *
10
+ * `Symbol.for` is used for both the slot and the extension keys so that the
11
+ * mechanism stays coherent even if this module is instantiated twice
12
+ * (e.g. esm/cjs interop in test runners).
13
+ */
14
+
15
+ const EXTENSIONS_SLOT: unique symbol = Symbol.for(
16
+ '@modern-js/runtime:context-extensions',
17
+ );
18
+
19
+ type ExtensionStore = Map<symbol, unknown>;
20
+
21
+ type ExtensibleContext = {
22
+ [EXTENSIONS_SLOT]?: ExtensionStore;
23
+ };
24
+
25
+ export interface RuntimeContextExtension<T> {
26
+ /** Stable identity of this extension. */
27
+ readonly key: symbol;
28
+ get(context: object): T | undefined;
29
+ set(context: object, value: T): void;
30
+ remove(context: object): void;
31
+ }
32
+
33
+ function getStore(context: object): ExtensionStore | undefined {
34
+ return (context as ExtensibleContext)[EXTENSIONS_SLOT];
35
+ }
36
+
37
+ function ensureStore(context: object): ExtensionStore {
38
+ const target = context as ExtensibleContext;
39
+ const store = target[EXTENSIONS_SLOT] ?? new Map();
40
+ Object.defineProperty(target, EXTENSIONS_SLOT, {
41
+ configurable: true,
42
+ enumerable: true,
43
+ value: store,
44
+ });
45
+ return store;
46
+ }
47
+
48
+ /**
49
+ * Removes the extension slot from a context object.
50
+ *
51
+ * The symbol slot crosses object spreads while remaining absent from string-key
52
+ * enumeration and JSON. Callers can still explicitly clear the original context.
53
+ */
54
+ export function stripRuntimeContextExtensions(context: object): void {
55
+ delete (context as ExtensibleContext)[EXTENSIONS_SLOT];
56
+ }
57
+
58
+ /**
59
+ * Creates a typed accessor pair over the shared extension slot.
60
+ *
61
+ * The `id` must be globally unique (it is interned via `Symbol.for`); use a
62
+ * package-prefixed name such as `@modern-js/plugin-tanstack:router-state`.
63
+ */
64
+ export function createRuntimeContextExtension<T>(
65
+ id: string,
66
+ ): RuntimeContextExtension<T> {
67
+ const key = Symbol.for(`@modern-js/runtime:context-extension:${id}`);
68
+
69
+ return {
70
+ key,
71
+ get(context: object): T | undefined {
72
+ return getStore(context)?.get(key) as T | undefined;
73
+ },
74
+ set(context: object, value: T): void {
75
+ ensureStore(context).set(key, value);
76
+ },
77
+ remove(context: object): void {
78
+ getStore(context)?.delete(key);
79
+ },
80
+ };
81
+ }
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import {
3
+ Helmet as AsyncHelmet,
4
+ type HelmetProps,
5
+ HelmetProvider,
6
+ type HelmetServerState,
7
+ } from 'react-helmet-async';
8
+ import type { HelmetContextSlot } from './helmetContext';
9
+ import * as runtimeHead from './rendererHead';
10
+
11
+ export interface HeadRenderContext {
12
+ runtimeContext: object;
13
+ helmetContext: HelmetContextSlot;
14
+ }
15
+
16
+ // Keep one adapter per plugin setup. Its component/provider identity is stable;
17
+ // each HTML render supplies its own original context and captured helmet slot.
18
+ export function createHeadRuntime() {
19
+ const HeadContext = React.createContext<HeadRenderContext | undefined>(
20
+ undefined,
21
+ );
22
+
23
+ const collectServerHelmet = (
24
+ { runtimeContext, helmetContext }: HeadRenderContext,
25
+ props: React.PropsWithChildren<HelmetProps>,
26
+ ) => {
27
+ const createRecord = () => runtimeHead.createHelmetRecord(React, props);
28
+ const deriveState = (records: runtimeHead.HelmetCompatRecord[]) =>
29
+ runtimeHead.deriveHelmetServerState(React, records) as HelmetServerState;
30
+ const marker = runtimeHead.collectHeadState(
31
+ runtimeContext,
32
+ createRecord,
33
+ deriveState,
34
+ helmetContext,
35
+ );
36
+ if (marker !== undefined) return marker;
37
+ helmetContext.helmet = runtimeHead.collectImmediateHelmetState(
38
+ React,
39
+ helmetContext,
40
+ createRecord(),
41
+ ) as HelmetServerState;
42
+ };
43
+
44
+ const Head = (props: React.PropsWithChildren<HelmetProps>) => {
45
+ const state = React.useContext(HeadContext);
46
+ if (state !== undefined) {
47
+ return runtimeHead.renderHeadMarker(
48
+ React,
49
+ collectServerHelmet(state, props),
50
+ );
51
+ }
52
+ return React.createElement(AsyncHelmet, props);
53
+ };
54
+
55
+ const ClientRoot = ({ children }: { children: React.ReactNode }) => {
56
+ const state = React.useContext(HeadContext);
57
+ return state === undefined ? (
58
+ <HelmetProvider>{children}</HelmetProvider>
59
+ ) : (
60
+ children
61
+ );
62
+ };
63
+
64
+ return {
65
+ Head,
66
+ wrapServerRoot(root: React.ReactNode, state: HeadRenderContext) {
67
+ return (
68
+ <HeadContext.Provider value={state}>
69
+ <HelmetProvider context={state.helmetContext}>{root}</HelmetProvider>
70
+ </HeadContext.Provider>
71
+ );
72
+ },
73
+ wrapClientRoot(root: React.ReactNode) {
74
+ return <ClientRoot>{root}</ClientRoot>;
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Fork-owned helmet state, stored via the runtime-context extension slot
3
+ * instead of an ad-hoc `_helmetContext` field on `TInternalRuntimeContext`.
4
+ */
5
+ import type { HelmetServerState } from 'react-helmet-async';
6
+ import { createRuntimeContextExtension } from './contextExtensions';
7
+
8
+ export interface HelmetContextSlot {
9
+ helmet?: HelmetServerState | null;
10
+ }
11
+
12
+ const helmetContextExtension = createRuntimeContextExtension<HelmetContextSlot>(
13
+ '@modern-js/runtime:helmet-context',
14
+ );
15
+
16
+ export function getHelmetContext(
17
+ context: object,
18
+ ): HelmetContextSlot | undefined {
19
+ return helmetContextExtension.get(context);
20
+ }
21
+
22
+ export function ensureHelmetContext(context: object): HelmetContextSlot {
23
+ const existing = helmetContextExtension.get(context);
24
+ if (existing !== undefined) {
25
+ return existing;
26
+ }
27
+
28
+ const created: HelmetContextSlot = {};
29
+ helmetContextExtension.set(context, created);
30
+ return created;
31
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './html';
2
2
  export * from './navigationWarmup';
3
+ export * from './prefetchPolicy';
3
4
  export * from './rendererHead';
5
+ export * from './routeHydration';
4
6
  export * from './shellStream';
@@ -0,0 +1,30 @@
1
+ interface RouteNode {
2
+ id?: string;
3
+ children?: RouteNode[];
4
+ modernLocalisedRoute?: { id?: string };
5
+ }
6
+
7
+ /** Map a source loader ID only to its own alias already matched by the router. */
8
+ export function resolveLocalisedLoaderRouteId(
9
+ routes: RouteNode[],
10
+ requestedId: string,
11
+ matchedIds: (string | undefined)[] = [],
12
+ ): string {
13
+ if (matchedIds.includes(requestedId)) return requestedId;
14
+ const matched = new Set(matchedIds);
15
+ const visit = (nodes: RouteNode[]): string | undefined => {
16
+ for (const route of nodes) {
17
+ if (
18
+ route.id &&
19
+ matched.has(route.id) &&
20
+ route.modernLocalisedRoute?.id === requestedId
21
+ ) {
22
+ return route.id;
23
+ }
24
+ const child = route.children && visit(route.children);
25
+ if (child) return child;
26
+ }
27
+ return undefined;
28
+ };
29
+ return visit(routes) ?? requestedId;
30
+ }
@@ -0,0 +1,33 @@
1
+ type PrefetchBehavior = 'intent' | 'render' | 'viewport' | 'none';
2
+
3
+ export function resolvePreloadFromPrefetch(
4
+ prefetch: PrefetchBehavior | undefined,
5
+ preload: unknown,
6
+ ) {
7
+ if (typeof preload !== 'undefined') {
8
+ return preload;
9
+ }
10
+
11
+ if (prefetch === 'none') {
12
+ return false;
13
+ }
14
+
15
+ if (
16
+ prefetch === 'intent' ||
17
+ prefetch === 'render' ||
18
+ prefetch === 'viewport'
19
+ ) {
20
+ return prefetch;
21
+ }
22
+
23
+ return 'viewport';
24
+ }
25
+
26
+ // React Router supplies its render default before calling this adapter.
27
+ export function normalizePreloadBehavior(
28
+ preload: PrefetchBehavior | false | undefined,
29
+ prefetch: PrefetchBehavior,
30
+ ): PrefetchBehavior {
31
+ const resolved = resolvePreloadFromPrefetch(prefetch, preload);
32
+ return resolved === false ? 'none' : (resolved as PrefetchBehavior);
33
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Federation can bundle a runtime subpath separately from its shared root.
3
+ * Share React context identity across those copies, leaving request values to
4
+ * React's providers. Public and internal contexts retain separate identities.
5
+ */
6
+ export function getRuntimeReactContext<T>(
7
+ kind: 'public' | 'internal',
8
+ create: () => T,
9
+ ): T {
10
+ const key = Symbol.for(`@modern-js/runtime:react-context:v1:${kind}`);
11
+ const contexts = globalThis as typeof globalThis & {
12
+ [key: symbol]: unknown;
13
+ };
14
+ contexts[key] ??= create();
15
+ return contexts[key] as T;
16
+ }
@@ -0,0 +1,22 @@
1
+ import { createClient as createNativeClient } from '@modern-js/create-request/client';
2
+ import { createPolicyClient } from './client';
3
+
4
+ /** Create a browser producer client with its own configuration and policy. */
5
+ export const createClient = () =>
6
+ createPolicyClient(createNativeClient(), {
7
+ target: 'browser',
8
+ resolveSourceOrigin: () =>
9
+ typeof window !== 'undefined' ? window.location.origin : undefined,
10
+ });
11
+
12
+ export const { configure, createRequest, createUploader } = createClient();
13
+
14
+ export {
15
+ CrossOriginEnvelopePolicyError,
16
+ IdentityBindingViolationError,
17
+ OperationContractViolationError,
18
+ ProducerClientNotInitializedError,
19
+ ProducerDomainNotConfiguredError,
20
+ } from './policyCore';
21
+ export * from './requestContext';
22
+ export * from './types';