@bleedingdev/modern-js-renderer-solid 0.0.0-bootstrap → 3.9.3-ultramodern.1
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/esm/actions.js +283 -0
- package/dist/esm/application-router.js +25 -0
- package/dist/esm/client.js +49 -0
- package/dist/esm/entry-application.js +60 -0
- package/dist/esm/entry-client.js +23 -0
- package/dist/esm/federation-context.js +25 -0
- package/dist/esm/federation-ssr.js +84 -0
- package/dist/esm/federation.js +83 -0
- package/dist/esm/i18n/I18nProvider.js +33 -0
- package/dist/esm/i18n/LocalizedLink.js +74 -0
- package/dist/esm/i18n/context.js +3 -0
- package/dist/esm/i18n/index.js +8 -0
- package/dist/esm/i18n/languageSync.js +50 -0
- package/dist/esm/i18n/types.js +0 -0
- package/dist/esm/i18n/useI18n.js +74 -0
- package/dist/esm/index.js +58 -0
- package/dist/esm/manifest.js +150 -0
- package/dist/esm/route-completion.js +150 -0
- package/dist/esm/route-data-error.js +108 -0
- package/dist/esm/router-binding/Asset.js +201 -0
- package/dist/esm/router-binding/CatchBoundary.js +94 -0
- package/dist/esm/router-binding/ClientOnly.js +26 -0
- package/dist/esm/router-binding/HeadContent.js +8 -0
- package/dist/esm/router-binding/LICENSE +21 -0
- package/dist/esm/router-binding/Match.js +319 -0
- package/dist/esm/router-binding/Matches.js +117 -0
- package/dist/esm/router-binding/PROVENANCE.json +94 -0
- package/dist/esm/router-binding/RouterProvider.js +51 -0
- package/dist/esm/router-binding/SafeFragment.js +5 -0
- package/dist/esm/router-binding/ScriptOnce.js +15 -0
- package/dist/esm/router-binding/Scripts.js +30 -0
- package/dist/esm/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm/router-binding/Transitioner.js +103 -0
- package/dist/esm/router-binding/awaited.js +48 -0
- package/dist/esm/router-binding/fileRoute.js +83 -0
- package/dist/esm/router-binding/flightData.js +23 -0
- package/dist/esm/router-binding/headContentUtils.js +162 -0
- package/dist/esm/router-binding/history.js +0 -0
- package/dist/esm/router-binding/index.js +35 -0
- package/dist/esm/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm/router-binding/link.js +389 -0
- package/dist/esm/router-binding/matchContext.js +7 -0
- package/dist/esm/router-binding/nonRouteComponentContext.js +13 -0
- package/dist/esm/router-binding/not-found.js +35 -0
- package/dist/esm/router-binding/publicMatchData.js +447 -0
- package/dist/esm/router-binding/registryTransfer.js +210 -0
- package/dist/esm/router-binding/renderRouteNotFound.js +23 -0
- package/dist/esm/router-binding/route.js +143 -0
- package/dist/esm/router-binding/router.js +13 -0
- package/dist/esm/router-binding/routerContext.js +3 -0
- package/dist/esm/router-binding/routerStores.js +50 -0
- package/dist/esm/router-binding/scroll-restoration.js +13 -0
- package/dist/esm/router-binding/typePrimitives.js +0 -0
- package/dist/esm/router-binding/useBlocker.js +152 -0
- package/dist/esm/router-binding/useCanGoBack.js +7 -0
- package/dist/esm/router-binding/useLoaderData.js +9 -0
- package/dist/esm/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm/router-binding/useLocation.js +14 -0
- package/dist/esm/router-binding/useMatch.js +28 -0
- package/dist/esm/router-binding/useNavigate.js +19 -0
- package/dist/esm/router-binding/useParams.js +13 -0
- package/dist/esm/router-binding/useRouteContext.js +8 -0
- package/dist/esm/router-binding/useRouter.js +10 -0
- package/dist/esm/router-binding/useRouterState.js +19 -0
- package/dist/esm/router-binding/useSearch.js +13 -0
- package/dist/esm/router-binding/utils.js +23 -0
- package/dist/esm/router.js +187 -0
- package/dist/esm-node/actions.js +263 -0
- package/dist/esm-node/application-router.js +25 -0
- package/dist/esm-node/client.js +49 -0
- package/dist/esm-node/entry-application.js +110 -0
- package/dist/esm-node/entry-client.js +23 -0
- package/dist/esm-node/entry-server.js +47 -0
- package/dist/esm-node/federation-context.js +25 -0
- package/dist/esm-node/federation-ssr.js +84 -0
- package/dist/esm-node/federation.js +83 -0
- package/dist/esm-node/i18n/I18nProvider.js +42 -0
- package/dist/esm-node/i18n/LocalizedLink.js +142 -0
- package/dist/esm-node/i18n/context.js +3 -0
- package/dist/esm-node/i18n/index.js +8 -0
- package/dist/esm-node/i18n/languageSync.js +50 -0
- package/dist/esm-node/i18n/types.js +1 -0
- package/dist/esm-node/i18n/useI18n.js +74 -0
- package/dist/esm-node/index.js +58 -0
- package/dist/esm-node/manifest.js +150 -0
- package/dist/esm-node/native-promise-serialization.js +113 -0
- package/dist/esm-node/plugin/compiler.js +209 -0
- package/dist/esm-node/plugin/create.js +235 -0
- package/dist/esm-node/plugin/index.js +73 -0
- package/dist/esm-node/plugin/profile.js +52 -0
- package/dist/esm-node/route-completion.js +160 -0
- package/dist/esm-node/route-data-error.js +108 -0
- package/dist/esm-node/router-binding/Asset.js +171 -0
- package/dist/esm-node/router-binding/CatchBoundary.js +136 -0
- package/dist/esm-node/router-binding/ClientOnly.js +46 -0
- package/dist/esm-node/router-binding/HeadContent.js +8 -0
- package/dist/esm-node/router-binding/LICENSE +21 -0
- package/dist/esm-node/router-binding/Match.js +660 -0
- package/dist/esm-node/router-binding/Matches.js +161 -0
- package/dist/esm-node/router-binding/PROVENANCE.json +94 -0
- package/dist/esm-node/router-binding/RouterProvider.js +87 -0
- package/dist/esm-node/router-binding/SafeFragment.js +5 -0
- package/dist/esm-node/router-binding/ScriptOnce.js +16 -0
- package/dist/esm-node/router-binding/Scripts.js +49 -0
- package/dist/esm-node/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm-node/router-binding/Transitioner.js +103 -0
- package/dist/esm-node/router-binding/awaited.js +75 -0
- package/dist/esm-node/router-binding/fileRoute.js +83 -0
- package/dist/esm-node/router-binding/flightData.js +23 -0
- package/dist/esm-node/router-binding/headContentUtils.js +162 -0
- package/dist/esm-node/router-binding/history.js +1 -0
- package/dist/esm-node/router-binding/index.js +35 -0
- package/dist/esm-node/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm-node/router-binding/link.js +399 -0
- package/dist/esm-node/router-binding/matchContext.js +7 -0
- package/dist/esm-node/router-binding/nonRouteComponentContext.js +22 -0
- package/dist/esm-node/router-binding/not-found.js +49 -0
- package/dist/esm-node/router-binding/publicMatchData.js +447 -0
- package/dist/esm-node/router-binding/registryTransfer.js +210 -0
- package/dist/esm-node/router-binding/renderRouteNotFound.js +22 -0
- package/dist/esm-node/router-binding/route.js +162 -0
- package/dist/esm-node/router-binding/router.js +13 -0
- package/dist/esm-node/router-binding/routerContext.js +3 -0
- package/dist/esm-node/router-binding/routerStores.js +50 -0
- package/dist/esm-node/router-binding/scroll-restoration.js +12 -0
- package/dist/esm-node/router-binding/typePrimitives.js +1 -0
- package/dist/esm-node/router-binding/useBlocker.js +152 -0
- package/dist/esm-node/router-binding/useCanGoBack.js +7 -0
- package/dist/esm-node/router-binding/useLoaderData.js +9 -0
- package/dist/esm-node/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm-node/router-binding/useLocation.js +14 -0
- package/dist/esm-node/router-binding/useMatch.js +28 -0
- package/dist/esm-node/router-binding/useNavigate.js +19 -0
- package/dist/esm-node/router-binding/useParams.js +13 -0
- package/dist/esm-node/router-binding/useRouteContext.js +8 -0
- package/dist/esm-node/router-binding/useRouter.js +10 -0
- package/dist/esm-node/router-binding/useRouterState.js +19 -0
- package/dist/esm-node/router-binding/useSearch.js +13 -0
- package/dist/esm-node/router-binding/utils.js +23 -0
- package/dist/esm-node/router.js +187 -0
- package/dist/esm-node/server.js +396 -0
- package/dist/types/actions.d.ts +45 -0
- package/dist/types/application-router.d.ts +5 -0
- package/dist/types/client.d.ts +23 -0
- package/dist/types/entry-application.d.ts +10 -0
- package/dist/types/entry-client.d.ts +5 -0
- package/dist/types/entry-server.d.ts +5 -0
- package/dist/types/federation-context.d.ts +16 -0
- package/dist/types/federation-ssr.d.ts +21 -0
- package/dist/types/federation.d.ts +30 -0
- package/dist/types/i18n/I18nProvider.d.ts +21 -0
- package/dist/types/i18n/LocalizedLink.d.ts +43 -0
- package/dist/types/i18n/context.d.ts +11 -0
- package/dist/types/i18n/index.d.ts +9 -0
- package/dist/types/i18n/languageSync.d.ts +31 -0
- package/dist/types/i18n/types.d.ts +33 -0
- package/dist/types/i18n/useI18n.d.ts +24 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/manifest.d.ts +55 -0
- package/dist/types/native-promise-serialization.d.ts +9 -0
- package/dist/types/plugin/compiler.d.ts +6 -0
- package/dist/types/plugin/create.d.ts +21 -0
- package/dist/types/plugin/index.d.ts +3 -0
- package/dist/types/plugin/lazy-modules.d.cts +15 -0
- package/dist/types/plugin/preserve-import-loader.d.cts +3 -0
- package/dist/types/plugin/profile.d.ts +2 -0
- package/dist/types/plugin/solid-loader.d.cts +2 -0
- package/dist/types/plugin/svg-component-template.d.cts +6 -0
- package/dist/types/route-completion.d.ts +21 -0
- package/dist/types/route-data-error.d.ts +17 -0
- package/dist/types/router-binding/Asset.d.ts +3 -0
- package/dist/types/router-binding/CatchBoundary.d.ts +13 -0
- package/dist/types/router-binding/ClientOnly.d.ts +31 -0
- package/dist/types/router-binding/HeadContent.d.ts +13 -0
- package/dist/types/router-binding/Match.d.ts +6 -0
- package/dist/types/router-binding/Matches.d.ts +26 -0
- package/dist/types/router-binding/RouterProvider.d.ts +10 -0
- package/dist/types/router-binding/SafeFragment.d.ts +2 -0
- package/dist/types/router-binding/ScriptOnce.d.ts +6 -0
- package/dist/types/router-binding/Scripts.d.ts +2 -0
- package/dist/types/router-binding/ScrollRestoration.d.ts +14 -0
- package/dist/types/router-binding/Transitioner.d.ts +2 -0
- package/dist/types/router-binding/awaited.d.ts +11 -0
- package/dist/types/router-binding/fileRoute.d.ts +54 -0
- package/dist/types/router-binding/flightData.d.ts +38 -0
- package/dist/types/router-binding/headContentUtils.d.ts +15 -0
- package/dist/types/router-binding/history.d.ts +8 -0
- package/dist/types/router-binding/index.d.ts +45 -0
- package/dist/types/router-binding/lazyRouteComponent.d.ts +2 -0
- package/dist/types/router-binding/link.d.ts +43 -0
- package/dist/types/router-binding/matchContext.d.ts +7 -0
- package/dist/types/router-binding/nonRouteComponentContext.d.ts +5 -0
- package/dist/types/router-binding/not-found.d.ts +11 -0
- package/dist/types/router-binding/publicMatchData.d.ts +19 -0
- package/dist/types/router-binding/registryTransfer.d.ts +47 -0
- package/dist/types/router-binding/renderRouteNotFound.d.ts +11 -0
- package/dist/types/router-binding/route.d.ts +105 -0
- package/dist/types/router-binding/router.d.ts +70 -0
- package/dist/types/router-binding/routerContext.d.ts +3 -0
- package/dist/types/router-binding/routerStores.d.ts +2 -0
- package/dist/types/router-binding/scroll-restoration.d.ts +2 -0
- package/dist/types/router-binding/typePrimitives.d.ts +10 -0
- package/dist/types/router-binding/useBlocker.d.ts +70 -0
- package/dist/types/router-binding/useCanGoBack.d.ts +2 -0
- package/dist/types/router-binding/useLoaderData.d.ts +8 -0
- package/dist/types/router-binding/useLoaderDeps.d.ts +8 -0
- package/dist/types/router-binding/useLocation.d.ts +7 -0
- package/dist/types/router-binding/useMatch.d.ts +10 -0
- package/dist/types/router-binding/useNavigate.d.ts +5 -0
- package/dist/types/router-binding/useParams.d.ts +9 -0
- package/dist/types/router-binding/useRouteContext.d.ts +4 -0
- package/dist/types/router-binding/useRouter.d.ts +4 -0
- package/dist/types/router-binding/useRouterState.d.ts +8 -0
- package/dist/types/router-binding/useSearch.d.ts +9 -0
- package/dist/types/router-binding/utils.d.ts +25 -0
- package/dist/types/router.d.ts +31 -0
- package/dist/types/server.d.ts +47 -0
- package/package.json +118 -4
- package/src/actions.tsx +437 -0
- package/src/application-router.tsx +41 -0
- package/src/client.ts +106 -0
- package/src/entry-application.tsx +73 -0
- package/src/entry-client.tsx +48 -0
- package/src/entry-server.tsx +85 -0
- package/src/federation-context.ts +47 -0
- package/src/federation-ssr.ts +117 -0
- package/src/federation.tsx +193 -0
- package/src/i18n/I18nProvider.tsx +54 -0
- package/src/i18n/LocalizedLink.tsx +122 -0
- package/src/i18n/context.ts +13 -0
- package/src/i18n/index.ts +35 -0
- package/src/i18n/languageSync.ts +113 -0
- package/src/i18n/types.ts +35 -0
- package/src/i18n/useI18n.ts +121 -0
- package/src/index.ts +41 -0
- package/src/manifest.ts +337 -0
- package/src/native-promise-serialization.ts +167 -0
- package/src/plugin/compiler.ts +320 -0
- package/src/plugin/create.ts +270 -0
- package/src/plugin/index.ts +72 -0
- package/src/plugin/lazy-modules.cjs +146 -0
- package/src/plugin/preserve-import-loader.cjs +46 -0
- package/src/plugin/profile.ts +42 -0
- package/src/plugin/solid-loader.cjs +83 -0
- package/src/plugin/svg-component-template.cjs +19 -0
- package/src/route-completion.tsx +222 -0
- package/src/route-data-error.ts +175 -0
- package/src/router-binding/Asset.tsx +283 -0
- package/src/router-binding/CatchBoundary.tsx +130 -0
- package/src/router-binding/ClientOnly.tsx +76 -0
- package/src/router-binding/HeadContent.tsx +23 -0
- package/src/router-binding/LICENSE +21 -0
- package/src/router-binding/Match.tsx +397 -0
- package/src/router-binding/Matches.tsx +242 -0
- package/src/router-binding/PROVENANCE.json +94 -0
- package/src/router-binding/RouterProvider.tsx +129 -0
- package/src/router-binding/SafeFragment.tsx +5 -0
- package/src/router-binding/ScriptOnce.tsx +23 -0
- package/src/router-binding/Scripts.tsx +44 -0
- package/src/router-binding/ScrollRestoration.tsx +49 -0
- package/src/router-binding/Transitioner.tsx +172 -0
- package/src/router-binding/awaited.tsx +71 -0
- package/src/router-binding/fileRoute.ts +268 -0
- package/src/router-binding/flightData.ts +90 -0
- package/src/router-binding/headContentUtils.tsx +290 -0
- package/src/router-binding/history.ts +9 -0
- package/src/router-binding/index.tsx +318 -0
- package/src/router-binding/lazyRouteComponent.tsx +70 -0
- package/src/router-binding/link.tsx +865 -0
- package/src/router-binding/matchContext.tsx +15 -0
- package/src/router-binding/nonRouteComponentContext.tsx +23 -0
- package/src/router-binding/not-found.tsx +65 -0
- package/src/router-binding/publicMatchData.ts +674 -0
- package/src/router-binding/registryTransfer.ts +383 -0
- package/src/router-binding/renderRouteNotFound.tsx +53 -0
- package/src/router-binding/route.tsx +665 -0
- package/src/router-binding/router.ts +121 -0
- package/src/router-binding/routerContext.tsx +6 -0
- package/src/router-binding/routerStores.ts +85 -0
- package/src/router-binding/scroll-restoration.tsx +15 -0
- package/src/router-binding/typePrimitives.ts +74 -0
- package/src/router-binding/useBlocker.tsx +359 -0
- package/src/router-binding/useCanGoBack.ts +9 -0
- package/src/router-binding/useLoaderData.tsx +50 -0
- package/src/router-binding/useLoaderDeps.tsx +46 -0
- package/src/router-binding/useLocation.tsx +43 -0
- package/src/router-binding/useMatch.tsx +111 -0
- package/src/router-binding/useNavigate.tsx +43 -0
- package/src/router-binding/useParams.tsx +72 -0
- package/src/router-binding/useRouteContext.ts +30 -0
- package/src/router-binding/useRouter.tsx +17 -0
- package/src/router-binding/useRouterState.tsx +50 -0
- package/src/router-binding/useSearch.tsx +72 -0
- package/src/router-binding/utils.ts +59 -0
- package/src/router.ts +376 -0
- package/src/server.ts +645 -0
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertPublicData,
|
|
3
|
+
DataProtocolError,
|
|
4
|
+
parsePublicData,
|
|
5
|
+
serializePublicData,
|
|
6
|
+
} from '@modern-js/renderer-core/data';
|
|
7
|
+
import { RouteDataError } from '@modern-js/renderer-core/router';
|
|
8
|
+
import type { RequestSession } from '@modern-js/renderer-core/session';
|
|
9
|
+
import { getRequestEvent } from '@solidjs/web';
|
|
10
|
+
import type { RouteDataErrorSnapshot } from '../route-data-error';
|
|
11
|
+
import { projectRouteDataError } from '../route-data-error';
|
|
12
|
+
|
|
13
|
+
export type PublicSnapshotOwner = Pick<RequestSession, 'fail' | 'signal'>;
|
|
14
|
+
interface DeferredObservation {
|
|
15
|
+
scopes: Array<WeakSet<object>>;
|
|
16
|
+
projection: Promise<unknown>;
|
|
17
|
+
}
|
|
18
|
+
const observed = new WeakMap<
|
|
19
|
+
PublicSnapshotOwner,
|
|
20
|
+
WeakMap<Promise<unknown>, DeferredObservation>
|
|
21
|
+
>();
|
|
22
|
+
const snapshots = new WeakMap<
|
|
23
|
+
PublicSnapshotOwner,
|
|
24
|
+
WeakMap<object, { snapshot: unknown; deferred: Promise<unknown>[] }>
|
|
25
|
+
>();
|
|
26
|
+
const projectedPromises = new WeakSet<Promise<unknown>>();
|
|
27
|
+
|
|
28
|
+
function requestFailureOwner(
|
|
29
|
+
explicit?: PublicSnapshotOwner,
|
|
30
|
+
): PublicSnapshotOwner | undefined {
|
|
31
|
+
return explicit ?? getRequestEvent()?.locals.session;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Keep known private request identities out of an otherwise plain public graph. */
|
|
35
|
+
function privateReferences(
|
|
36
|
+
owner: PublicSnapshotOwner | undefined,
|
|
37
|
+
contexts: readonly unknown[],
|
|
38
|
+
): WeakSet<object> {
|
|
39
|
+
const references = new WeakSet<object>();
|
|
40
|
+
const event = getRequestEvent();
|
|
41
|
+
const identity = owner && 'identity' in owner ? owner.identity : undefined;
|
|
42
|
+
let count = 0;
|
|
43
|
+
const visit = (value: unknown, depth: number): void => {
|
|
44
|
+
if (
|
|
45
|
+
!value ||
|
|
46
|
+
(typeof value !== 'object' && typeof value !== 'function') ||
|
|
47
|
+
value === identity
|
|
48
|
+
)
|
|
49
|
+
return;
|
|
50
|
+
if (++count > 20_000 || depth > 100)
|
|
51
|
+
throw new DataProtocolError(
|
|
52
|
+
'Private request context exceeds its size or depth limit',
|
|
53
|
+
);
|
|
54
|
+
if (references.has(value)) return;
|
|
55
|
+
references.add(value);
|
|
56
|
+
const prototype = Object.getPrototypeOf(value);
|
|
57
|
+
if (prototype === Map.prototype) {
|
|
58
|
+
for (const [key, entry] of Map.prototype.entries.call(value)) {
|
|
59
|
+
visit(key, depth + 1);
|
|
60
|
+
visit(entry, depth + 1);
|
|
61
|
+
}
|
|
62
|
+
} else if (prototype === Set.prototype) {
|
|
63
|
+
for (const entry of Set.prototype.values.call(value))
|
|
64
|
+
visit(entry, depth + 1);
|
|
65
|
+
} else if (
|
|
66
|
+
prototype === Object.prototype ||
|
|
67
|
+
prototype === null ||
|
|
68
|
+
prototype === Array.prototype
|
|
69
|
+
) {
|
|
70
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
71
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key)!;
|
|
72
|
+
if (!descriptor.get && !descriptor.set)
|
|
73
|
+
visit(descriptor.value, depth + 1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
if (owner) {
|
|
78
|
+
references.add(owner);
|
|
79
|
+
if ('request' in owner) visit(owner.request, 0);
|
|
80
|
+
if ('platform' in owner) visit(owner.platform, 0);
|
|
81
|
+
}
|
|
82
|
+
if (event) {
|
|
83
|
+
visit(event, 0);
|
|
84
|
+
visit(event.locals, 0);
|
|
85
|
+
}
|
|
86
|
+
for (const context of contexts) visit(context, 0);
|
|
87
|
+
return references;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function rejectPrivateReferences(
|
|
91
|
+
value: unknown,
|
|
92
|
+
references: WeakSet<object>,
|
|
93
|
+
): void {
|
|
94
|
+
const seen = new WeakSet<object>();
|
|
95
|
+
let count = 0;
|
|
96
|
+
const visit = (current: unknown, depth: number): void => {
|
|
97
|
+
if (++count > 20_000 || depth > 100)
|
|
98
|
+
throw new DataProtocolError(
|
|
99
|
+
'Public data exceeds its size or depth limit',
|
|
100
|
+
);
|
|
101
|
+
if (!current || typeof current !== 'object') return;
|
|
102
|
+
if (references.has(current))
|
|
103
|
+
throw new DataProtocolError(
|
|
104
|
+
'Public data must not contain private request references',
|
|
105
|
+
);
|
|
106
|
+
if (seen.has(current)) return;
|
|
107
|
+
seen.add(current);
|
|
108
|
+
const prototype = Object.getPrototypeOf(current);
|
|
109
|
+
if (prototype === Promise.prototype) return;
|
|
110
|
+
for (const key of Reflect.ownKeys(current)) {
|
|
111
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key)!;
|
|
112
|
+
if (!descriptor.get && !descriptor.set)
|
|
113
|
+
visit(descriptor.value, depth + 1);
|
|
114
|
+
}
|
|
115
|
+
if (prototype === Map.prototype) {
|
|
116
|
+
for (const [key, entry] of Map.prototype.entries.call(current)) {
|
|
117
|
+
visit(key, depth + 1);
|
|
118
|
+
visit(entry, depth + 1);
|
|
119
|
+
}
|
|
120
|
+
} else if (prototype === Set.prototype) {
|
|
121
|
+
for (const entry of Set.prototype.values.call(current))
|
|
122
|
+
visit(entry, depth + 1);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
visit(value, 0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function projectDeferred(
|
|
129
|
+
promise: Promise<unknown>,
|
|
130
|
+
session: PublicSnapshotOwner,
|
|
131
|
+
references: WeakSet<object>,
|
|
132
|
+
): Promise<unknown> {
|
|
133
|
+
let promises = observed.get(session);
|
|
134
|
+
if (!promises) {
|
|
135
|
+
promises = new WeakMap();
|
|
136
|
+
observed.set(session, promises);
|
|
137
|
+
}
|
|
138
|
+
const previous = promises.get(promise);
|
|
139
|
+
if (previous) {
|
|
140
|
+
previous.scopes.push(references);
|
|
141
|
+
return previous.projection;
|
|
142
|
+
}
|
|
143
|
+
const scopes = [references];
|
|
144
|
+
const owner = new WeakRef(session);
|
|
145
|
+
const project = (value: unknown): unknown => {
|
|
146
|
+
try {
|
|
147
|
+
for (const scope of scopes) rejectPrivateReferences(value, scope);
|
|
148
|
+
return immutableSnapshot(value, owner.deref());
|
|
149
|
+
} catch (error) {
|
|
150
|
+
owner.deref()?.fail(error);
|
|
151
|
+
throw Object.freeze({
|
|
152
|
+
name: 'DataProtocolError',
|
|
153
|
+
message: 'Invalid public deferred data',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const reject = (reason: unknown): never => {
|
|
158
|
+
let projected: unknown;
|
|
159
|
+
try {
|
|
160
|
+
for (const scope of scopes) rejectPrivateReferences(reason, scope);
|
|
161
|
+
projected =
|
|
162
|
+
reason instanceof Error
|
|
163
|
+
? preparePublicMatchError(reason, owner.deref())
|
|
164
|
+
: immutableSnapshot(reason, owner.deref());
|
|
165
|
+
} catch (error) {
|
|
166
|
+
owner.deref()?.fail(error);
|
|
167
|
+
throw Object.freeze({
|
|
168
|
+
name: 'DataProtocolError',
|
|
169
|
+
message: 'Invalid public deferred error',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
throw projected;
|
|
173
|
+
};
|
|
174
|
+
const projection = Promise.prototype.then.call(
|
|
175
|
+
promise,
|
|
176
|
+
project,
|
|
177
|
+
reject,
|
|
178
|
+
) as Promise<unknown>;
|
|
179
|
+
const observation = { scopes, projection };
|
|
180
|
+
promises.set(promise, observation);
|
|
181
|
+
promises.set(projection, observation);
|
|
182
|
+
projectedPromises.add(projection);
|
|
183
|
+
// RC.13 annotates native Promise handles with s then v. Keep that protocol
|
|
184
|
+
// while preventing metadata from becoming a second unchecked value channel.
|
|
185
|
+
let status: 0 | 1 | 2 | undefined;
|
|
186
|
+
let settledValue: unknown;
|
|
187
|
+
Object.defineProperties(projection, {
|
|
188
|
+
s: {
|
|
189
|
+
get: () => status,
|
|
190
|
+
set: (next: unknown) => {
|
|
191
|
+
if (next === undefined || next === 0 || next === 1 || next === 2) {
|
|
192
|
+
status = next;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const error = new DataProtocolError(
|
|
196
|
+
'Unsupported native immutable route-data Promise state. AsyncIterable values are not supported.',
|
|
197
|
+
);
|
|
198
|
+
owner.deref()?.fail(error);
|
|
199
|
+
throw error;
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
v: {
|
|
203
|
+
get: () => settledValue,
|
|
204
|
+
set: (next: unknown) => {
|
|
205
|
+
try {
|
|
206
|
+
for (const scope of scopes) rejectPrivateReferences(next, scope);
|
|
207
|
+
settledValue =
|
|
208
|
+
status === 2 && next instanceof Error
|
|
209
|
+
? preparePublicMatchError(next, owner.deref())
|
|
210
|
+
: immutableSnapshot(next, owner.deref());
|
|
211
|
+
} catch (error) {
|
|
212
|
+
owner.deref()?.fail(error);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
Object.seal(projection);
|
|
219
|
+
// Native serialization may not have subscribed yet; rejection is still owned.
|
|
220
|
+
void projection.catch(() => {});
|
|
221
|
+
return projection;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Replace only supported top-level Promise slots before the canonical codec. */
|
|
225
|
+
function criticalProjection(
|
|
226
|
+
value: unknown,
|
|
227
|
+
validateNativePromise?: (promise: Promise<unknown>) => void,
|
|
228
|
+
): {
|
|
229
|
+
critical: unknown;
|
|
230
|
+
slots: Array<[string, PropertyDescriptor]>;
|
|
231
|
+
} {
|
|
232
|
+
const seen = new WeakMap<object, object>();
|
|
233
|
+
const slots: Array<[string, PropertyDescriptor]> = [];
|
|
234
|
+
let count = 0;
|
|
235
|
+
const copy = (current: unknown, depth: number): unknown => {
|
|
236
|
+
if (++count > 20_000 || depth > 100)
|
|
237
|
+
throw new DataProtocolError(
|
|
238
|
+
'Public data exceeds its size or depth limit',
|
|
239
|
+
);
|
|
240
|
+
if (!current || typeof current !== 'object') return current;
|
|
241
|
+
const previous = seen.get(current);
|
|
242
|
+
if (previous) return previous;
|
|
243
|
+
const prototype = Object.getPrototypeOf(current);
|
|
244
|
+
for (const key of Reflect.ownKeys(current)) {
|
|
245
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key)!;
|
|
246
|
+
if (typeof key === 'symbol' || descriptor.get || descriptor.set)
|
|
247
|
+
throw new DataProtocolError(
|
|
248
|
+
'Public data must not contain symbols or accessors',
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
let result: object;
|
|
252
|
+
if (prototype === Object.prototype || prototype === null)
|
|
253
|
+
result = Object.create(prototype);
|
|
254
|
+
else if (prototype === Array.prototype && Array.isArray(current))
|
|
255
|
+
result = [];
|
|
256
|
+
else {
|
|
257
|
+
rejectMutableNativeContainer(prototype);
|
|
258
|
+
assertPublicData(current);
|
|
259
|
+
throw new DataProtocolError('Unsupported public data container');
|
|
260
|
+
}
|
|
261
|
+
seen.set(current, result);
|
|
262
|
+
for (const key of Reflect.ownKeys(current)) {
|
|
263
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key)!;
|
|
264
|
+
if (typeof key === 'symbol' || descriptor.get || descriptor.set)
|
|
265
|
+
throw new DataProtocolError(
|
|
266
|
+
'Public data must not contain symbols or accessors',
|
|
267
|
+
);
|
|
268
|
+
if (
|
|
269
|
+
depth === 0 &&
|
|
270
|
+
(prototype === Object.prototype || prototype === null) &&
|
|
271
|
+
descriptor.enumerable &&
|
|
272
|
+
descriptor.value instanceof Promise
|
|
273
|
+
) {
|
|
274
|
+
const promise = descriptor.value as Promise<unknown>;
|
|
275
|
+
if (Object.getPrototypeOf(promise) !== Promise.prototype)
|
|
276
|
+
throw new DataProtocolError(
|
|
277
|
+
'Public data must not contain custom Promise properties or prototypes',
|
|
278
|
+
);
|
|
279
|
+
if (
|
|
280
|
+
!projectedPromises.has(promise) &&
|
|
281
|
+
Reflect.ownKeys(promise).length !== 0
|
|
282
|
+
) {
|
|
283
|
+
if (!validateNativePromise)
|
|
284
|
+
throw new DataProtocolError(
|
|
285
|
+
'Public data must not contain custom Promise properties or prototypes',
|
|
286
|
+
);
|
|
287
|
+
validateNativePromise(promise);
|
|
288
|
+
}
|
|
289
|
+
slots.push([key, descriptor]);
|
|
290
|
+
Object.defineProperty(result, key, { ...descriptor, value: undefined });
|
|
291
|
+
} else
|
|
292
|
+
Object.defineProperty(result, key, {
|
|
293
|
+
...descriptor,
|
|
294
|
+
value: copy(descriptor.value, depth + 1),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return result;
|
|
298
|
+
};
|
|
299
|
+
return { critical: copy(value, 0), slots };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** A stable transfer snapshot; the renderer retains its original values and Promises. */
|
|
303
|
+
export function preparePublicLoaderData(
|
|
304
|
+
value: unknown,
|
|
305
|
+
owner?: PublicSnapshotOwner,
|
|
306
|
+
privateContexts: readonly unknown[] = [],
|
|
307
|
+
): unknown {
|
|
308
|
+
return prepareLoaderData(value, owner, privateContexts);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** Only the native keyed receiver admits Seroval's checked s/v data metadata. */
|
|
312
|
+
export function prepareHydratedLoaderData(
|
|
313
|
+
value: unknown,
|
|
314
|
+
owner?: PublicSnapshotOwner,
|
|
315
|
+
privateContexts: readonly unknown[] = [],
|
|
316
|
+
): unknown {
|
|
317
|
+
return prepareLoaderData(value, owner, privateContexts, true);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function prepareLoaderData(
|
|
321
|
+
value: unknown,
|
|
322
|
+
owner?: PublicSnapshotOwner,
|
|
323
|
+
privateContexts: readonly unknown[] = [],
|
|
324
|
+
hydration = false,
|
|
325
|
+
): unknown {
|
|
326
|
+
const session = requestFailureOwner(owner);
|
|
327
|
+
const references = privateReferences(session, privateContexts);
|
|
328
|
+
rejectPrivateReferences(value, references);
|
|
329
|
+
if (value && typeof value === 'object' && session) {
|
|
330
|
+
const cached = snapshots.get(session)?.get(value);
|
|
331
|
+
if (cached) {
|
|
332
|
+
for (const promise of cached.deferred)
|
|
333
|
+
projectDeferred(promise, session, references);
|
|
334
|
+
return cached.snapshot;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const nativeSettlements = new Map<
|
|
338
|
+
Promise<unknown>,
|
|
339
|
+
{ status: 0 | 1 | 2; hasValue: boolean; value: unknown }
|
|
340
|
+
>();
|
|
341
|
+
const validateNativePromise = hydration
|
|
342
|
+
? (promise: Promise<unknown>): void => {
|
|
343
|
+
const descriptors = Object.getOwnPropertyDescriptors(promise);
|
|
344
|
+
for (const key of Reflect.ownKeys(promise)) {
|
|
345
|
+
const descriptor = Object.getOwnPropertyDescriptor(promise, key)!;
|
|
346
|
+
if ((key !== 's' && key !== 'v') || descriptor.get || descriptor.set)
|
|
347
|
+
throw new DataProtocolError(
|
|
348
|
+
'Native hydrated Promise metadata must contain only s/v data fields',
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
const status = descriptors.s?.value;
|
|
352
|
+
if (status !== 0 && status !== 1 && status !== 2)
|
|
353
|
+
throw new DataProtocolError(
|
|
354
|
+
'Unsupported native hydrated Promise state; AsyncIterable values are not supported',
|
|
355
|
+
);
|
|
356
|
+
if ((status === 1 || status === 2) && !descriptors.v)
|
|
357
|
+
throw new DataProtocolError(
|
|
358
|
+
'Native settled hydrated Promises require a value data field',
|
|
359
|
+
);
|
|
360
|
+
let projected: unknown;
|
|
361
|
+
if (descriptors.v) {
|
|
362
|
+
const settled = descriptors.v.value;
|
|
363
|
+
rejectPrivateReferences(settled, references);
|
|
364
|
+
if (status === 2 && settled instanceof Error)
|
|
365
|
+
projected = preparePublicMatchError(
|
|
366
|
+
settled,
|
|
367
|
+
session,
|
|
368
|
+
privateContexts,
|
|
369
|
+
);
|
|
370
|
+
else projected = immutableSnapshot(settled, session);
|
|
371
|
+
}
|
|
372
|
+
nativeSettlements.set(promise, {
|
|
373
|
+
status,
|
|
374
|
+
hasValue: Boolean(descriptors.v),
|
|
375
|
+
value: projected,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
: undefined;
|
|
379
|
+
const { critical, slots } = criticalProjection(value, validateNativePromise);
|
|
380
|
+
let snapshot = parsePublicData(serializePublicData(critical));
|
|
381
|
+
if (slots.length) {
|
|
382
|
+
if (
|
|
383
|
+
!session ||
|
|
384
|
+
typeof session.fail !== 'function' ||
|
|
385
|
+
!(session.signal instanceof AbortSignal)
|
|
386
|
+
)
|
|
387
|
+
throw new DataProtocolError(
|
|
388
|
+
'Native deferred public data requires its owning request session',
|
|
389
|
+
);
|
|
390
|
+
for (const [key, descriptor] of slots) {
|
|
391
|
+
const projection = projectDeferred(descriptor.value, session, references);
|
|
392
|
+
const settlement = nativeSettlements.get(descriptor.value);
|
|
393
|
+
if (settlement) {
|
|
394
|
+
// Keep an already decoded native slot settled before the client memo
|
|
395
|
+
// reads it. Only our controlled transport receives these annotations.
|
|
396
|
+
Object.getOwnPropertyDescriptor(projection, 's')!.set!.call(
|
|
397
|
+
projection,
|
|
398
|
+
settlement.status,
|
|
399
|
+
);
|
|
400
|
+
if (settlement.hasValue)
|
|
401
|
+
Object.getOwnPropertyDescriptor(projection, 'v')!.set!.call(
|
|
402
|
+
projection,
|
|
403
|
+
settlement.value,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
Object.defineProperty(snapshot, key, {
|
|
407
|
+
...descriptor,
|
|
408
|
+
value: projection,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
snapshot = rememberSnapshot(
|
|
413
|
+
value,
|
|
414
|
+
snapshot,
|
|
415
|
+
session,
|
|
416
|
+
slots.map(([, descriptor]) => descriptor.value),
|
|
417
|
+
);
|
|
418
|
+
return snapshot;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Native beforeLoad context is an explicit pure public return value. */
|
|
422
|
+
export function preparePublicContextData(
|
|
423
|
+
value: unknown,
|
|
424
|
+
owner?: PublicSnapshotOwner,
|
|
425
|
+
privateContexts: readonly unknown[] = [],
|
|
426
|
+
): unknown {
|
|
427
|
+
assertPublicData(value);
|
|
428
|
+
return preparePublicLoaderData(value, owner, privateContexts);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** Preserve the native composed root while replacing authored nested values. */
|
|
432
|
+
export function preparePublishedRouteContext(
|
|
433
|
+
context: Record<string, unknown>,
|
|
434
|
+
owner: PublicSnapshotOwner,
|
|
435
|
+
privateContexts: readonly unknown[] = [],
|
|
436
|
+
): void {
|
|
437
|
+
const snapshot = preparePublicContextData(context, owner, privateContexts);
|
|
438
|
+
if (!snapshot || typeof snapshot !== 'object')
|
|
439
|
+
throw new DataProtocolError(
|
|
440
|
+
'Native public route context must be a plain record',
|
|
441
|
+
);
|
|
442
|
+
const prototype = Object.getPrototypeOf(context);
|
|
443
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
444
|
+
throw new DataProtocolError(
|
|
445
|
+
'Native public route context must be a plain record',
|
|
446
|
+
);
|
|
447
|
+
if (snapshot !== context) {
|
|
448
|
+
for (const key of Reflect.ownKeys(context)) {
|
|
449
|
+
const descriptor = Object.getOwnPropertyDescriptor(context, key)!;
|
|
450
|
+
const checked = Object.getOwnPropertyDescriptor(snapshot, key);
|
|
451
|
+
if (checked && checked.value !== descriptor.value)
|
|
452
|
+
Object.defineProperty(context, key, {
|
|
453
|
+
...descriptor,
|
|
454
|
+
value: checked.value,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
freezeSnapshot(context);
|
|
459
|
+
const record = { snapshot: context, deferred: [] };
|
|
460
|
+
snapshots.get(owner)?.set(context, record);
|
|
461
|
+
snapshots.get(owner)?.set(snapshot, record);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const errorNames = new Map<object, string>([
|
|
465
|
+
[DataProtocolError.prototype, 'DataProtocolError'],
|
|
466
|
+
[Error.prototype, 'Error'],
|
|
467
|
+
[EvalError.prototype, 'EvalError'],
|
|
468
|
+
[RangeError.prototype, 'RangeError'],
|
|
469
|
+
[ReferenceError.prototype, 'ReferenceError'],
|
|
470
|
+
[SyntaxError.prototype, 'SyntaxError'],
|
|
471
|
+
[TypeError.prototype, 'TypeError'],
|
|
472
|
+
[URIError.prototype, 'URIError'],
|
|
473
|
+
]);
|
|
474
|
+
export interface PublicMatchError {
|
|
475
|
+
name: string;
|
|
476
|
+
message: string;
|
|
477
|
+
stack?: string;
|
|
478
|
+
cause?: unknown;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/** Error diagnostics are a fixed public projection, never a raw Error object. */
|
|
482
|
+
export function preparePublicMatchError(
|
|
483
|
+
error: unknown,
|
|
484
|
+
owner?: PublicSnapshotOwner,
|
|
485
|
+
privateContexts: readonly unknown[] = [],
|
|
486
|
+
): PublicMatchError | RouteDataErrorSnapshot | Record<string, unknown> {
|
|
487
|
+
const references = privateReferences(
|
|
488
|
+
requestFailureOwner(owner),
|
|
489
|
+
privateContexts,
|
|
490
|
+
);
|
|
491
|
+
if (
|
|
492
|
+
error &&
|
|
493
|
+
typeof error === 'object' &&
|
|
494
|
+
Object.getPrototypeOf(error) === RouteDataError.prototype
|
|
495
|
+
) {
|
|
496
|
+
const result = projectRouteDataError(
|
|
497
|
+
error,
|
|
498
|
+
process.env.NODE_ENV !== 'development',
|
|
499
|
+
);
|
|
500
|
+
rejectPrivateReferences(result, references);
|
|
501
|
+
return immutableSnapshot(
|
|
502
|
+
result,
|
|
503
|
+
requestFailureOwner(owner),
|
|
504
|
+
) as RouteDataErrorSnapshot;
|
|
505
|
+
}
|
|
506
|
+
const fallback = Object.freeze({
|
|
507
|
+
name: 'Error',
|
|
508
|
+
message: 'Unexpected Server Error',
|
|
509
|
+
});
|
|
510
|
+
if (!error || typeof error !== 'object') return fallback;
|
|
511
|
+
const prototype = Object.getPrototypeOf(error);
|
|
512
|
+
if (
|
|
513
|
+
(prototype === Object.prototype || prototype === null) &&
|
|
514
|
+
Object.getOwnPropertyDescriptor(error, 'isNotFound')?.value === true
|
|
515
|
+
) {
|
|
516
|
+
return preparePublicContextData(error, owner, privateContexts) as Record<
|
|
517
|
+
string,
|
|
518
|
+
unknown
|
|
519
|
+
>;
|
|
520
|
+
}
|
|
521
|
+
const name = errorNames.get(prototype);
|
|
522
|
+
if (!name)
|
|
523
|
+
throw new DataProtocolError(
|
|
524
|
+
'Public match errors require an exact supported error prototype',
|
|
525
|
+
);
|
|
526
|
+
const descriptors = Object.getOwnPropertyDescriptors(error);
|
|
527
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
528
|
+
const descriptor = Object.getOwnPropertyDescriptor(error, key)!;
|
|
529
|
+
if (
|
|
530
|
+
typeof key !== 'string' ||
|
|
531
|
+
!['name', 'message', 'stack', 'cause'].includes(key)
|
|
532
|
+
)
|
|
533
|
+
throw new DataProtocolError(
|
|
534
|
+
'Public errors must not contain undeclared fields',
|
|
535
|
+
);
|
|
536
|
+
// Node's native lazy stack is an accessor. Never read it.
|
|
537
|
+
if (key === 'stack' && (descriptor.get || descriptor.set)) continue;
|
|
538
|
+
if (typeof key === 'symbol' || descriptor.get || descriptor.set)
|
|
539
|
+
throw new DataProtocolError(
|
|
540
|
+
'Public errors must not contain symbols or accessors',
|
|
541
|
+
);
|
|
542
|
+
rejectPrivateReferences(descriptor.value, references);
|
|
543
|
+
assertPublicData(descriptor.value);
|
|
544
|
+
}
|
|
545
|
+
if (
|
|
546
|
+
process.env.NODE_ENV !== 'development' &&
|
|
547
|
+
prototype !== DataProtocolError.prototype
|
|
548
|
+
)
|
|
549
|
+
return fallback;
|
|
550
|
+
const result: PublicMatchError = {
|
|
551
|
+
name:
|
|
552
|
+
typeof descriptors.name?.value === 'string'
|
|
553
|
+
? descriptors.name.value
|
|
554
|
+
: name,
|
|
555
|
+
message:
|
|
556
|
+
typeof descriptors.message?.value === 'string'
|
|
557
|
+
? descriptors.message.value
|
|
558
|
+
: fallback.message,
|
|
559
|
+
};
|
|
560
|
+
if (
|
|
561
|
+
process.env.NODE_ENV === 'development' &&
|
|
562
|
+
typeof descriptors.stack?.value === 'string'
|
|
563
|
+
)
|
|
564
|
+
result.stack = descriptors.stack.value;
|
|
565
|
+
if (descriptors.cause) result.cause = descriptors.cause.value;
|
|
566
|
+
return immutableSnapshot(
|
|
567
|
+
result,
|
|
568
|
+
requestFailureOwner(owner),
|
|
569
|
+
) as PublicMatchError;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function rejectMutableNativeContainer(prototype: object | null): void {
|
|
573
|
+
const names = new Map<object, string>([
|
|
574
|
+
[Date.prototype, 'Date'],
|
|
575
|
+
[RegExp.prototype, 'RegExp'],
|
|
576
|
+
[Map.prototype, 'Map'],
|
|
577
|
+
[Set.prototype, 'Set'],
|
|
578
|
+
]);
|
|
579
|
+
const name = prototype && names.get(prototype);
|
|
580
|
+
if (name)
|
|
581
|
+
throw new DataProtocolError(
|
|
582
|
+
`Unsupported native immutable route-data: ${name}. Use scalar values, plain records or arrays.`,
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Promise transport handles retain Solid's native state annotation protocol. */
|
|
587
|
+
function freezeSnapshot(value: unknown): void {
|
|
588
|
+
const seen = new WeakSet<object>();
|
|
589
|
+
const visit = (current: unknown): void => {
|
|
590
|
+
if (
|
|
591
|
+
!current ||
|
|
592
|
+
typeof current !== 'object' ||
|
|
593
|
+
current instanceof Promise ||
|
|
594
|
+
seen.has(current)
|
|
595
|
+
)
|
|
596
|
+
return;
|
|
597
|
+
seen.add(current);
|
|
598
|
+
rejectMutableNativeContainer(Object.getPrototypeOf(current));
|
|
599
|
+
for (const key of Reflect.ownKeys(current))
|
|
600
|
+
visit(Object.getOwnPropertyDescriptor(current, key)!.value);
|
|
601
|
+
Object.freeze(current);
|
|
602
|
+
};
|
|
603
|
+
visit(value);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function immutableSnapshot(
|
|
607
|
+
value: unknown,
|
|
608
|
+
owner?: PublicSnapshotOwner,
|
|
609
|
+
): unknown {
|
|
610
|
+
assertPublicData(value);
|
|
611
|
+
const { critical } = criticalProjection(value);
|
|
612
|
+
const snapshot = parsePublicData(serializePublicData(critical));
|
|
613
|
+
return rememberSnapshot(value, snapshot, owner);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/** Preserve aliases across loader/context projections in the same public scope. */
|
|
617
|
+
function rememberSnapshot(
|
|
618
|
+
original: unknown,
|
|
619
|
+
snapshot: unknown,
|
|
620
|
+
owner?: PublicSnapshotOwner,
|
|
621
|
+
deferred: Promise<unknown>[] = [],
|
|
622
|
+
): unknown {
|
|
623
|
+
if (!owner || !original || typeof original !== 'object') {
|
|
624
|
+
freezeSnapshot(snapshot);
|
|
625
|
+
return snapshot;
|
|
626
|
+
}
|
|
627
|
+
let values = snapshots.get(owner);
|
|
628
|
+
if (!values) {
|
|
629
|
+
values = new WeakMap();
|
|
630
|
+
snapshots.set(owner, values);
|
|
631
|
+
}
|
|
632
|
+
const aliases = new WeakMap<object, object>();
|
|
633
|
+
const records: Array<[object, object]> = [];
|
|
634
|
+
const reuse = (source: unknown, projected: unknown): unknown => {
|
|
635
|
+
if (
|
|
636
|
+
!source ||
|
|
637
|
+
typeof source !== 'object' ||
|
|
638
|
+
source instanceof Promise ||
|
|
639
|
+
!projected ||
|
|
640
|
+
typeof projected !== 'object'
|
|
641
|
+
)
|
|
642
|
+
return projected;
|
|
643
|
+
const cached = values.get(source);
|
|
644
|
+
if (cached) return cached.snapshot;
|
|
645
|
+
const previous = aliases.get(source);
|
|
646
|
+
if (previous) return previous;
|
|
647
|
+
aliases.set(source, projected);
|
|
648
|
+
records.push([source, projected]);
|
|
649
|
+
for (const key of Reflect.ownKeys(projected)) {
|
|
650
|
+
const sourceDescriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
651
|
+
const descriptor = Object.getOwnPropertyDescriptor(projected, key)!;
|
|
652
|
+
if (!sourceDescriptor || sourceDescriptor.get || sourceDescriptor.set)
|
|
653
|
+
continue;
|
|
654
|
+
const value = reuse(sourceDescriptor.value, descriptor.value);
|
|
655
|
+
if (value !== descriptor.value)
|
|
656
|
+
Object.defineProperty(projected, key, { ...descriptor, value });
|
|
657
|
+
}
|
|
658
|
+
return projected;
|
|
659
|
+
};
|
|
660
|
+
const result = reuse(original, snapshot);
|
|
661
|
+
// Reused aliases may retain an earlier, larger public value than its source.
|
|
662
|
+
const { critical } = criticalProjection(result);
|
|
663
|
+
serializePublicData(critical);
|
|
664
|
+
freezeSnapshot(result);
|
|
665
|
+
for (const [source, projected] of records) {
|
|
666
|
+
const record = {
|
|
667
|
+
snapshot: projected,
|
|
668
|
+
deferred: source === original ? deferred : [],
|
|
669
|
+
};
|
|
670
|
+
values.set(source, record);
|
|
671
|
+
values.set(projected, record);
|
|
672
|
+
}
|
|
673
|
+
return result;
|
|
674
|
+
}
|