@bleedingdev/modern-js-runtime-extensions 3.9.0-ultramodern.1 → 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.
- package/dist/cjs/buildIdentity.js +73 -0
- package/dist/cjs/contextExtensions.js +74 -0
- package/dist/cjs/headRuntime.js +91 -0
- package/dist/cjs/helmetContext.js +54 -0
- package/dist/cjs/index.js +18 -4
- package/dist/cjs/localisedLoaderIdentity.js +51 -0
- package/dist/cjs/prefetchPolicy.js +52 -0
- package/dist/cjs/reactContext.js +45 -0
- package/dist/cjs/request-policy/browser.js +139 -0
- package/dist/cjs/request-policy/client.js +234 -0
- package/dist/cjs/request-policy/node.js +149 -0
- package/dist/cjs/request-policy/policyCore.js +266 -0
- package/dist/cjs/request-policy/requestContext.js +137 -0
- package/dist/cjs/request-policy/traceparent.js +56 -0
- package/dist/cjs/request-policy/transport.js +234 -0
- package/dist/cjs/request-policy/types.js +57 -0
- package/dist/cjs/routeHydration.js +127 -0
- package/dist/cjs/routerPrefetchPolicy.js +153 -0
- package/dist/cjs/routerProvider.js +105 -0
- package/dist/cjs/routerState.js +204 -0
- package/dist/cjs/routerStatePlugin.js +86 -0
- package/dist/cjs/routerStateTypes.js +18 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientBrowserRuntime.js +69 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientEdgeRuntime.js +61 -0
- package/dist/cjs/rsc-disabled/rscDisabledClientNodeRuntime.js +65 -0
- package/dist/cjs/rsc-disabled/rscDisabledRuntimeError.js +42 -0
- package/dist/cjs/rsc-disabled/rscDisabledServerEdgeRuntime.js +93 -0
- package/dist/cjs/rsc-disabled/rscDisabledServerNodeRuntime.js +101 -0
- package/dist/cjs/runtimeContextProjection.js +112 -0
- package/dist/cjs/server-config/bffRuntime.js +18 -0
- package/dist/cjs/server-config/index.js +18 -0
- package/dist/cjs/server-config/serverTelemetry.js +18 -0
- package/dist/cjs/shellStream.js +34 -2
- package/dist/cjs/workspaceEvents.js +159 -0
- package/dist/esm/buildIdentity.mjs +35 -0
- package/dist/esm/contextExtensions.mjs +33 -0
- package/dist/esm/headRuntime.mjs +43 -0
- package/dist/esm/helmetContext.mjs +13 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/localisedLoaderIdentity.mjs +13 -0
- package/dist/esm/prefetchPolicy.mjs +11 -0
- package/dist/esm/reactContext.mjs +7 -0
- package/dist/esm/request-policy/browser.mjs +11 -0
- package/dist/esm/request-policy/client.mjs +195 -0
- package/dist/esm/request-policy/policyCore.mjs +171 -0
- package/dist/esm/request-policy/requestContext.mjs +75 -0
- package/dist/esm/request-policy/traceparent.mjs +18 -0
- package/dist/esm/request-policy/transport.mjs +196 -0
- package/dist/esm/request-policy/types.mjs +10 -0
- package/dist/esm/routeHydration.mjs +77 -0
- package/dist/esm/routerPrefetchPolicy.mjs +115 -0
- package/dist/esm/routerProvider.mjs +58 -0
- package/dist/esm/routerState.mjs +139 -0
- package/dist/esm/routerStatePlugin.mjs +48 -0
- package/dist/esm/routerStateTypes.mjs +0 -0
- package/dist/esm/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +10 -0
- package/dist/esm/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +8 -0
- package/dist/esm/rsc-disabled/rscDisabledClientNodeRuntime.mjs +9 -0
- package/dist/esm/rsc-disabled/rscDisabledRuntimeError.mjs +4 -0
- package/dist/esm/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +16 -0
- package/dist/esm/rsc-disabled/rscDisabledServerNodeRuntime.mjs +18 -0
- package/dist/esm/runtimeContextProjection.mjs +74 -0
- package/dist/esm/server-config/bffRuntime.mjs +0 -0
- package/dist/esm/server-config/index.mjs +0 -0
- package/dist/esm/server-config/serverTelemetry.mjs +0 -0
- package/dist/esm/shellStream.mjs +34 -2
- package/dist/esm/workspaceEvents.mjs +66 -0
- package/dist/esm-node/buildIdentity.mjs +36 -0
- package/dist/esm-node/contextExtensions.mjs +34 -0
- package/dist/esm-node/headRuntime.mjs +44 -0
- package/dist/esm-node/helmetContext.mjs +14 -0
- package/dist/esm-node/index.mjs +2 -0
- package/dist/esm-node/localisedLoaderIdentity.mjs +14 -0
- package/dist/esm-node/prefetchPolicy.mjs +12 -0
- package/dist/esm-node/reactContext.mjs +8 -0
- package/dist/esm-node/request-policy/browser.mjs +12 -0
- package/dist/esm-node/request-policy/client.mjs +196 -0
- package/dist/esm-node/request-policy/node.mjs +22 -0
- package/dist/esm-node/request-policy/policyCore.mjs +172 -0
- package/dist/esm-node/request-policy/requestContext.mjs +76 -0
- package/dist/esm-node/request-policy/traceparent.mjs +19 -0
- package/dist/esm-node/request-policy/transport.mjs +197 -0
- package/dist/esm-node/request-policy/types.mjs +11 -0
- package/dist/esm-node/routeHydration.mjs +78 -0
- package/dist/esm-node/routerPrefetchPolicy.mjs +116 -0
- package/dist/esm-node/routerProvider.mjs +59 -0
- package/dist/esm-node/routerState.mjs +140 -0
- package/dist/esm-node/routerStatePlugin.mjs +49 -0
- package/dist/esm-node/routerStateTypes.mjs +1 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientBrowserRuntime.mjs +11 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientEdgeRuntime.mjs +9 -0
- package/dist/esm-node/rsc-disabled/rscDisabledClientNodeRuntime.mjs +10 -0
- package/dist/esm-node/rsc-disabled/rscDisabledRuntimeError.mjs +5 -0
- package/dist/esm-node/rsc-disabled/rscDisabledServerEdgeRuntime.mjs +17 -0
- package/dist/esm-node/rsc-disabled/rscDisabledServerNodeRuntime.mjs +19 -0
- package/dist/esm-node/runtimeContextProjection.mjs +75 -0
- package/dist/esm-node/server-config/bffRuntime.mjs +1 -0
- package/dist/esm-node/server-config/index.mjs +1 -0
- package/dist/esm-node/server-config/serverTelemetry.mjs +1 -0
- package/dist/esm-node/shellStream.mjs +34 -2
- package/dist/esm-node/workspaceEvents.mjs +67 -0
- package/dist/types/buildIdentity.d.ts +37 -0
- package/dist/types/contextExtensions.d.ts +34 -0
- package/dist/types/headRuntime.d.ts +12 -0
- package/dist/types/helmetContext.d.ts +10 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/localisedLoaderIdentity.d.ts +10 -0
- package/dist/types/prefetchPolicy.d.ts +4 -0
- package/dist/types/reactContext.d.ts +6 -0
- package/dist/types/request-policy/browser.d.ts +10 -0
- package/dist/types/request-policy/client.d.ts +14 -0
- package/dist/types/request-policy/node.d.ts +10 -0
- package/dist/types/request-policy/policyCore.d.ts +107 -0
- package/dist/types/request-policy/requestContext.d.ts +22 -0
- package/dist/types/request-policy/traceparent.d.ts +10 -0
- package/dist/types/request-policy/transport.d.ts +12 -0
- package/dist/types/request-policy/types.d.ts +144 -0
- package/dist/types/routeHydration.d.ts +24 -0
- package/dist/types/routerPrefetchPolicy.d.ts +28 -0
- package/dist/types/routerProvider.d.ts +55 -0
- package/dist/types/routerState.d.ts +18 -0
- package/dist/types/routerStatePlugin.d.ts +19 -0
- package/dist/types/routerStateTypes.d.ts +40 -0
- package/dist/types/rsc-disabled/rscDisabledClientBrowserRuntime.d.ts +9 -0
- package/dist/types/rsc-disabled/rscDisabledClientEdgeRuntime.d.ts +7 -0
- package/dist/types/rsc-disabled/rscDisabledClientNodeRuntime.d.ts +8 -0
- package/dist/types/rsc-disabled/rscDisabledRuntimeError.d.ts +1 -0
- package/dist/types/rsc-disabled/rscDisabledServerEdgeRuntime.d.ts +15 -0
- package/dist/types/rsc-disabled/rscDisabledServerNodeRuntime.d.ts +17 -0
- package/dist/types/runtimeContextProjection.d.ts +30 -0
- package/dist/types/server-config/bffRuntime.d.ts +122 -0
- package/dist/types/server-config/index.d.ts +2 -0
- package/dist/types/server-config/serverTelemetry.d.ts +322 -0
- package/dist/types/workspaceEvents.d.ts +62 -0
- package/package.json +239 -14
- package/rslib.config.mts +17 -2
- package/rstest.config.mts +33 -2
- package/src/buildIdentity.ts +61 -0
- package/src/contextExtensions.ts +81 -0
- package/src/headRuntime.tsx +77 -0
- package/src/helmetContext.ts +31 -0
- package/src/index.ts +2 -0
- package/src/localisedLoaderIdentity.ts +30 -0
- package/src/prefetchPolicy.ts +33 -0
- package/src/reactContext.ts +16 -0
- package/src/request-policy/browser.ts +22 -0
- package/src/request-policy/client.ts +404 -0
- package/src/request-policy/node.ts +41 -0
- package/src/request-policy/policyCore.ts +424 -0
- package/src/request-policy/requestContext.ts +149 -0
- package/src/request-policy/traceparent.ts +43 -0
- package/src/request-policy/transport.ts +349 -0
- package/src/request-policy/types.ts +229 -0
- package/src/routeHydration.ts +208 -0
- package/src/routerPrefetchPolicy.ts +195 -0
- package/src/routerProvider.ts +160 -0
- package/src/routerState.ts +290 -0
- package/src/routerStatePlugin.ts +86 -0
- package/src/routerStateTypes.ts +46 -0
- package/src/rsc-disabled/rscDisabledClientBrowserRuntime.ts +10 -0
- package/src/rsc-disabled/rscDisabledClientEdgeRuntime.ts +8 -0
- package/src/rsc-disabled/rscDisabledClientNodeRuntime.ts +9 -0
- package/src/rsc-disabled/rscDisabledRuntimeError.ts +3 -0
- package/src/rsc-disabled/rscDisabledServerEdgeRuntime.ts +16 -0
- package/src/rsc-disabled/rscDisabledServerNodeRuntime.ts +18 -0
- package/src/runtimeContextProjection.ts +105 -0
- package/src/server-config/bffRuntime.ts +136 -0
- package/src/server-config/index.ts +2 -0
- package/src/server-config/serverTelemetry.ts +337 -0
- package/src/shellStream.ts +55 -25
- package/src/workspaceEvents.ts +324 -0
- package/tests/buildIdentity.test.ts +51 -0
- package/tests/contextExtensions.test.ts +27 -0
- package/tests/headRuntime.test.tsx +229 -0
- package/tests/rendererHead.test.ts +1 -113
- package/tests/request-policy/browser-policy.test.ts +108 -0
- package/tests/request-policy/client-isolation.test.ts +109 -0
- package/tests/request-policy/node-policy.test.ts +447 -0
- package/tests/request-policy/policyCore.test.ts +129 -0
- package/tests/request-policy/requestContext.test.ts +66 -0
- package/tests/request-policy/requestFactory.outbound-contract.test.ts +290 -0
- package/tests/request-policy/traceparent.test.ts +52 -0
- package/tests/request-policy/transport-retry.test.ts +367 -0
- package/tests/routeHydration.test.ts +180 -0
- package/tests/routerPrefetchPolicy.test.ts +102 -0
- package/tests/routerProvider.test.ts +29 -0
- package/tests/routerState.test.ts +78 -0
- package/tests/routerStatePlugin.test.ts +63 -0
- package/tests/runtimeContextProjection.test.ts +83 -0
- package/tests/safeFailure.test.ts +10 -28
- package/tests/shellStream.test.ts +37 -0
- package/tests/workspaceEvents.test.ts +221 -0
- package/dist/cjs/rscHtmlStream.js +0 -128
- package/dist/esm/rscHtmlStream.mjs +0 -86
- package/dist/esm-node/rscHtmlStream.mjs +0 -87
- package/dist/types/rscHtmlStream.d.ts +0 -4
- package/src/rscHtmlStream.ts +0 -142
- 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,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
|
+
}
|