@bleedingdev/modern-js-renderer-solid 0.0.0-stage → 3.9.3-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/esm/actions.js +282 -0
- package/dist/esm/application-router.js +30 -0
- package/dist/esm/client.js +49 -0
- package/dist/esm/entry-application.js +60 -0
- package/dist/esm/entry-client.js +24 -0
- package/dist/esm/federation-context.js +25 -0
- package/dist/esm/federation-ssr.js +92 -0
- package/dist/esm/federation.js +87 -0
- package/dist/esm/i18n/I18nProvider.js +33 -0
- package/dist/esm/i18n/LocalizedLink.js +52 -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 +151 -0
- package/dist/esm/route-data-error.js +108 -0
- package/dist/esm/router-binding/Asset.js +202 -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 +124 -0
- package/dist/esm/router-binding/PROVENANCE.json +94 -0
- package/dist/esm/router-binding/RouterProvider.js +52 -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 +109 -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 +168 -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 +387 -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 +223 -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 +14 -0
- package/dist/esm/router-binding/routerContext.js +3 -0
- package/dist/esm/router-binding/routerOptions.js +0 -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 +8 -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 +25 -0
- package/dist/esm/router-binding/useParams.js +11 -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 +11 -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 +30 -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 +24 -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 +92 -0
- package/dist/esm-node/federation.js +87 -0
- package/dist/esm-node/i18n/I18nProvider.js +42 -0
- package/dist/esm-node/i18n/LocalizedLink.js +88 -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 +236 -0
- package/dist/esm-node/plugin/index.js +70 -0
- package/dist/esm-node/plugin/profile.js +51 -0
- package/dist/esm-node/route-completion.js +161 -0
- package/dist/esm-node/route-data-error.js +108 -0
- package/dist/esm-node/router-binding/Asset.js +172 -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 +88 -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 +109 -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 +168 -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 +223 -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 +14 -0
- package/dist/esm-node/router-binding/routerContext.js +3 -0
- package/dist/esm-node/router-binding/routerOptions.js +1 -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 +8 -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 +25 -0
- package/dist/esm-node/router-binding/useParams.js +11 -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 +11 -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 +19 -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 +15 -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 +11 -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 +46 -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 +49 -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/routerOptions.d.ts +6 -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 +130 -4
- package/src/actions.tsx +441 -0
- package/src/application-router.tsx +47 -0
- package/src/client.ts +106 -0
- package/src/entry-application.tsx +73 -0
- package/src/entry-client.tsx +49 -0
- package/src/entry-server.tsx +85 -0
- package/src/federation-context.ts +47 -0
- package/src/federation-ssr.ts +136 -0
- package/src/federation.tsx +197 -0
- package/src/i18n/I18nProvider.tsx +54 -0
- package/src/i18n/LocalizedLink.tsx +83 -0
- package/src/i18n/context.ts +13 -0
- package/src/i18n/index.ts +31 -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 +271 -0
- package/src/plugin/index.ts +69 -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 +226 -0
- package/src/route-data-error.ts +175 -0
- package/src/router-binding/Asset.tsx +284 -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 +128 -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 +177 -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 +292 -0
- package/src/router-binding/history.ts +9 -0
- package/src/router-binding/index.tsx +315 -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 +400 -0
- package/src/router-binding/renderRouteNotFound.tsx +53 -0
- package/src/router-binding/route.tsx +665 -0
- package/src/router-binding/router.ts +123 -0
- package/src/router-binding/routerContext.tsx +6 -0
- package/src/router-binding/routerOptions.ts +26 -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 +51 -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 +45 -0
- package/src/router-binding/useParams.tsx +70 -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 +70 -0
- package/src/router-binding/utils.ts +59 -0
- package/src/router.ts +376 -0
- package/src/server.ts +645 -0
- package/README.md +0 -3
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { DataProtocolError } from '@modern-js/renderer-core/data';
|
|
2
|
+
import type { RequestSession } from '@modern-js/renderer-core/session';
|
|
3
|
+
import {
|
|
4
|
+
getHydrationWriter,
|
|
5
|
+
getRequestEvent,
|
|
6
|
+
takeHydrationValue,
|
|
7
|
+
} from '@solidjs/web';
|
|
8
|
+
import type { AnyRouteMatch, AnyRouter } from '@tanstack/router-core';
|
|
9
|
+
import * as Solid from 'solid-js';
|
|
10
|
+
import { restoreRouteDataError } from '../route-data-error';
|
|
11
|
+
import {
|
|
12
|
+
type PublicSnapshotOwner,
|
|
13
|
+
prepareHydratedLoaderData,
|
|
14
|
+
preparePublicContextData,
|
|
15
|
+
preparePublicLoaderData,
|
|
16
|
+
preparePublicMatchError,
|
|
17
|
+
preparePublishedRouteContext,
|
|
18
|
+
} from './publicMatchData';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Match-state transfer over Solid's hydration registry — the bare pairing's
|
|
22
|
+
* native SSR channel (no `__TSR_SSR__` script injection, no router-owned
|
|
23
|
+
* stream protocol). Entries are content-addressed (`tsr:<matchId>`; match
|
|
24
|
+
* ids are deterministic route-id + interpolated params, so both sides
|
|
25
|
+
* derive the same key from the same URL), the identical mechanism
|
|
26
|
+
* solid-query v6 ships query payloads through (`sq:<queryHash>`).
|
|
27
|
+
*
|
|
28
|
+
* Server half: while the render's serialization context is live, the
|
|
29
|
+
* provider writes each settled match's transferable state. Client half: the
|
|
30
|
+
* hydration-claiming boot — matching is synchronous, so the provider primes
|
|
31
|
+
* match state from the registry and commits before rendering, without
|
|
32
|
+
* running loaders or resolving route chunks up front. Route components
|
|
33
|
+
* resolve at the read point under the boundaries the server actually
|
|
34
|
+
* rendered (Solid `lazy` semantics), and staleness rules own any
|
|
35
|
+
* post-hydration refetching.
|
|
36
|
+
*
|
|
37
|
+
* Both halves no-op under TanStack Start: `router.serverSsr` marks the
|
|
38
|
+
* Start contract (`attachRouterServerSsrUtils` / `dehydrate` / `hydrate`),
|
|
39
|
+
* which owns transfer there — and a Start-hydrated router reaches the
|
|
40
|
+
* client boot with matches already committed, which skips it.
|
|
41
|
+
*/
|
|
42
|
+
export const MATCH_KEY_PREFIX = 'tsr:';
|
|
43
|
+
|
|
44
|
+
/** The slice of a match that transfers; mirrors the single-flight match
|
|
45
|
+
* shape (`createSolidStartFlightMatch`) — state, not identity: the client
|
|
46
|
+
* re-derives identity by matching, then merges this in. */
|
|
47
|
+
interface TransferredMatch {
|
|
48
|
+
status: AnyRouteMatch['status'];
|
|
49
|
+
updatedAt: number;
|
|
50
|
+
loaderData?: unknown;
|
|
51
|
+
error?: unknown;
|
|
52
|
+
notFound?: true;
|
|
53
|
+
ssr?: AnyRouteMatch['ssr'];
|
|
54
|
+
beforeLoadContext?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const preparedTransfers = new WeakMap<
|
|
58
|
+
RequestSession,
|
|
59
|
+
WeakMap<AnyRouter, Map<string, TransferredMatch>>
|
|
60
|
+
>();
|
|
61
|
+
const publicRouteDataOwners = new WeakMap<
|
|
62
|
+
object,
|
|
63
|
+
{
|
|
64
|
+
owner: WeakRef<PublicSnapshotOwner>;
|
|
65
|
+
privateContexts: Array<WeakRef<object>>;
|
|
66
|
+
}
|
|
67
|
+
>();
|
|
68
|
+
|
|
69
|
+
/** Bind the managed public-data scope before native router construction claims hydration. */
|
|
70
|
+
export function registerPublicRouteDataOwner(
|
|
71
|
+
routeTree: object,
|
|
72
|
+
owner: PublicSnapshotOwner,
|
|
73
|
+
privateContexts: readonly object[] = [],
|
|
74
|
+
): void {
|
|
75
|
+
publicRouteDataOwners.set(routeTree, {
|
|
76
|
+
owner: new WeakRef(owner),
|
|
77
|
+
privateContexts: privateContexts.map(value => new WeakRef(value)),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Managed match transfer uses the immutable public-data contract, not custom adapters. */
|
|
82
|
+
export function assertNativeSerializationOptions(options: object): void {
|
|
83
|
+
if ('serializationAdapters' in options) {
|
|
84
|
+
const error = new DataProtocolError(
|
|
85
|
+
'Solid serializationAdapters are unsupported by the immutable public-data profile; return public records, arrays and scalars instead',
|
|
86
|
+
);
|
|
87
|
+
const owner: RequestSession | undefined = getRequestEvent()?.locals.session;
|
|
88
|
+
owner?.fail(error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Framework SSR accepts only routers that passed its public-data factory boundary. */
|
|
94
|
+
export function requireManagedPublicRouter(router: AnyRouter): void {
|
|
95
|
+
assertNativeSerializationOptions(router.options);
|
|
96
|
+
const owner: RequestSession | undefined = getRequestEvent()?.locals.session;
|
|
97
|
+
if (
|
|
98
|
+
!owner ||
|
|
99
|
+
publicRouteDataOwners.get(router.options.routeTree)?.owner.deref()
|
|
100
|
+
)
|
|
101
|
+
return;
|
|
102
|
+
const error = new DataProtocolError(
|
|
103
|
+
'Custom native Solid routers are unsupported by UltraModern SSR. Use the managed filesystem route tree and application router public-data boundary.',
|
|
104
|
+
);
|
|
105
|
+
owner.fail(error);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Project composed public context before every native match-store publication. */
|
|
110
|
+
export function installPublicContextPublication(router: AnyRouter): void {
|
|
111
|
+
const scope = publicRouteDataOwners.get(router.options.routeTree);
|
|
112
|
+
const owner = scope?.owner.deref();
|
|
113
|
+
if (!scope || !owner) return;
|
|
114
|
+
const publish = router.stores.setMatches;
|
|
115
|
+
router.stores.setMatches = matches => {
|
|
116
|
+
try {
|
|
117
|
+
const privateContexts = scope.privateContexts.flatMap(reference => {
|
|
118
|
+
const value = reference.deref();
|
|
119
|
+
return value ? [value] : [];
|
|
120
|
+
});
|
|
121
|
+
preparePublishedMatches(matches, owner, privateContexts);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
owner.fail(error);
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
publish(matches);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function preparePublishedMatches(
|
|
131
|
+
matches: readonly AnyRouteMatch[],
|
|
132
|
+
owner: PublicSnapshotOwner,
|
|
133
|
+
privateContexts: readonly unknown[],
|
|
134
|
+
): void {
|
|
135
|
+
// Check the complete offered chain before native publication updates IDs.
|
|
136
|
+
for (const match of matches)
|
|
137
|
+
preparePublicContextData(match.context, owner, privateContexts);
|
|
138
|
+
for (const match of matches)
|
|
139
|
+
preparePublishedRouteContext(match.context, owner, privateContexts);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function prepareEntries(
|
|
143
|
+
router: AnyRouter,
|
|
144
|
+
owner?: RequestSession,
|
|
145
|
+
privateContexts: readonly unknown[] = [],
|
|
146
|
+
): Map<string, TransferredMatch> {
|
|
147
|
+
const entries = new Map<string, TransferredMatch>();
|
|
148
|
+
const matches = router.stores.matches.get();
|
|
149
|
+
const contexts = privateContexts;
|
|
150
|
+
for (const match of matches) {
|
|
151
|
+
if (match.status === 'pending') continue;
|
|
152
|
+
const entry: TransferredMatch = {
|
|
153
|
+
status: match.status,
|
|
154
|
+
updatedAt: match.updatedAt,
|
|
155
|
+
};
|
|
156
|
+
if (match.loaderData !== undefined)
|
|
157
|
+
entry.loaderData = preparePublicLoaderData(
|
|
158
|
+
match.loaderData,
|
|
159
|
+
owner,
|
|
160
|
+
contexts,
|
|
161
|
+
);
|
|
162
|
+
if (match.error !== undefined)
|
|
163
|
+
entry.error = preparePublicMatchError(match.error, owner, contexts);
|
|
164
|
+
const beforeLoadContext = nativeContextField(match, '__beforeLoadContext');
|
|
165
|
+
if (beforeLoadContext !== undefined)
|
|
166
|
+
entry.beforeLoadContext = preparePublicContextData(
|
|
167
|
+
beforeLoadContext,
|
|
168
|
+
owner,
|
|
169
|
+
contexts,
|
|
170
|
+
) as Record<string, unknown>;
|
|
171
|
+
if (match._notFound) entry.notFound = true;
|
|
172
|
+
if (match.ssr !== undefined) entry.ssr = match.ssr;
|
|
173
|
+
entries.set(match.id, entry);
|
|
174
|
+
}
|
|
175
|
+
return entries;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Validate and capture native settled match state before a response is committed. */
|
|
179
|
+
export function prepareRouterMatchTransfer(
|
|
180
|
+
router: AnyRouter,
|
|
181
|
+
owner: RequestSession,
|
|
182
|
+
privateContexts: readonly unknown[] = [],
|
|
183
|
+
): void {
|
|
184
|
+
try {
|
|
185
|
+
const entries = prepareEntries(router, owner, privateContexts);
|
|
186
|
+
let routers = preparedTransfers.get(owner);
|
|
187
|
+
if (!routers) {
|
|
188
|
+
routers = new WeakMap();
|
|
189
|
+
preparedTransfers.set(owner, routers);
|
|
190
|
+
}
|
|
191
|
+
routers.set(router, entries);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
owner.fail(error);
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function serializeMatchTransfer(router: AnyRouter): void {
|
|
199
|
+
requireManagedPublicRouter(router);
|
|
200
|
+
if (router.serverSsr) return;
|
|
201
|
+
const writer = getHydrationWriter();
|
|
202
|
+
if (!writer || !Solid.isHydratable()) return;
|
|
203
|
+
|
|
204
|
+
const owner: RequestSession | undefined = getRequestEvent()?.locals.session;
|
|
205
|
+
const entries =
|
|
206
|
+
(owner && preparedTransfers.get(owner)?.get(router)) ??
|
|
207
|
+
prepareEntries(router, owner);
|
|
208
|
+
for (const [id, entry] of entries) {
|
|
209
|
+
// Pending matches are skipped, not deferred: this core has no per-match
|
|
210
|
+
// settle promise to hand seroval, so promise-valued entries (streaming
|
|
211
|
+
// SSR, loaders landing after first flush) need a dispatch-time hook —
|
|
212
|
+
// the next increment. A missing entry makes the client boot fall
|
|
213
|
+
// through to today's behavior rather than half-prime.
|
|
214
|
+
writer.write(MATCH_KEY_PREFIX + id, entry);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* The hydration-claiming boot. Returns true when every synchronously
|
|
220
|
+
* matched route found its registry entry and the matches were committed;
|
|
221
|
+
* false falls back to the caller's existing behavior (no entries — a
|
|
222
|
+
* non-registry server, `noHydrate`, or a pending match the server skipped).
|
|
223
|
+
*
|
|
224
|
+
* Entries arrive as inline scripts that execute at document parse, so they
|
|
225
|
+
* are readable through Solid's keyed value channel before client rendering.
|
|
226
|
+
* The boot commits before hydration; store writes inside the claim would
|
|
227
|
+
* change the owner tree being claimed.
|
|
228
|
+
*/
|
|
229
|
+
export function primeRouterFromRegistry(router: AnyRouter): boolean {
|
|
230
|
+
if (router.stores.matches.get().length > 0) return false;
|
|
231
|
+
const registry = (
|
|
232
|
+
globalThis as unknown as { _$HY?: { r: Record<string, unknown> } }
|
|
233
|
+
)._$HY?.r;
|
|
234
|
+
if (!registry) return false;
|
|
235
|
+
// A page with no match entries (SPA, or Start's own channel) skips before
|
|
236
|
+
// paying for a match pass.
|
|
237
|
+
let hasMatchEntries = false;
|
|
238
|
+
for (const key in registry) {
|
|
239
|
+
if (key.startsWith(MATCH_KEY_PREFIX)) {
|
|
240
|
+
hasMatchEntries = true;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (!hasMatchEntries) return false;
|
|
245
|
+
|
|
246
|
+
const matches = router.matchRoutes(router.latestLocation);
|
|
247
|
+
if (matches.length === 0) return false;
|
|
248
|
+
|
|
249
|
+
const entries: Array<TransferredMatch> = [];
|
|
250
|
+
let complete = true;
|
|
251
|
+
for (const match of matches) {
|
|
252
|
+
const key = MATCH_KEY_PREFIX + match.id;
|
|
253
|
+
const transferred = takeHydrationValue<TransferredMatch>(key);
|
|
254
|
+
if (transferred?.status !== 'resolved') {
|
|
255
|
+
complete = false;
|
|
256
|
+
if (transferred?.status === 'pending')
|
|
257
|
+
void Promise.prototype.then.call(
|
|
258
|
+
transferred.promise,
|
|
259
|
+
undefined,
|
|
260
|
+
() => {},
|
|
261
|
+
);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const entry = transferred.value;
|
|
265
|
+
if (!entry || typeof entry.status !== 'string') {
|
|
266
|
+
complete = false;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
entries.push(entry);
|
|
270
|
+
}
|
|
271
|
+
if (!complete) return false;
|
|
272
|
+
|
|
273
|
+
const primed: Array<AnyRouteMatch> = [];
|
|
274
|
+
const scope = publicRouteDataOwners.get(router.options.routeTree);
|
|
275
|
+
const owner = scope?.owner.deref();
|
|
276
|
+
const privateContexts =
|
|
277
|
+
scope?.privateContexts.flatMap(reference => {
|
|
278
|
+
const value = reference.deref();
|
|
279
|
+
return value ? [value] : [];
|
|
280
|
+
}) ?? [];
|
|
281
|
+
try {
|
|
282
|
+
for (const [index, match] of matches.entries()) {
|
|
283
|
+
const entry = entries[index]!;
|
|
284
|
+
const beforeLoadContext = preparePublicContextData(
|
|
285
|
+
entry.beforeLoadContext,
|
|
286
|
+
owner,
|
|
287
|
+
privateContexts,
|
|
288
|
+
) as Record<string, unknown> | undefined;
|
|
289
|
+
const checked: TransferredMatch = {
|
|
290
|
+
...entry,
|
|
291
|
+
loaderData: prepareHydratedLoaderData(
|
|
292
|
+
entry.loaderData,
|
|
293
|
+
owner,
|
|
294
|
+
privateContexts,
|
|
295
|
+
),
|
|
296
|
+
...(beforeLoadContext !== undefined ? { beforeLoadContext } : {}),
|
|
297
|
+
error: preparePublicContextData(entry.error, owner, privateContexts),
|
|
298
|
+
};
|
|
299
|
+
entries[index] = checked;
|
|
300
|
+
primed.push(applyTransferredMatch(match, checked));
|
|
301
|
+
}
|
|
302
|
+
for (const [index, next] of primed.entries()) {
|
|
303
|
+
const match = matches[index]!;
|
|
304
|
+
const route = router.routesById[match.routeId]!;
|
|
305
|
+
const parentContext =
|
|
306
|
+
primed[index - 1]?.context ?? router.options.context ?? {};
|
|
307
|
+
// This is the native core29 hydration context phase: reconstruct client
|
|
308
|
+
// route context, then inherit the explicit checked server beforeLoad value.
|
|
309
|
+
const routeContext =
|
|
310
|
+
route.options.context?.({
|
|
311
|
+
deps: match.loaderDeps,
|
|
312
|
+
params: match.params,
|
|
313
|
+
context: parentContext,
|
|
314
|
+
location: router.latestLocation,
|
|
315
|
+
navigate: (options: Parameters<typeof router.navigate>[0]) =>
|
|
316
|
+
router.navigate({
|
|
317
|
+
...options,
|
|
318
|
+
_fromLocation: router.latestLocation,
|
|
319
|
+
}),
|
|
320
|
+
buildLocation: router.buildLocation,
|
|
321
|
+
cause: match.cause,
|
|
322
|
+
abortController: match.abortController,
|
|
323
|
+
preload: false,
|
|
324
|
+
matches: primed,
|
|
325
|
+
routeId: route.id,
|
|
326
|
+
}) || undefined;
|
|
327
|
+
Object.defineProperty(next, '_ctx', {
|
|
328
|
+
value: routeContext,
|
|
329
|
+
configurable: true,
|
|
330
|
+
writable: true,
|
|
331
|
+
enumerable: true,
|
|
332
|
+
});
|
|
333
|
+
next.context = {
|
|
334
|
+
...parentContext,
|
|
335
|
+
...routeContext,
|
|
336
|
+
...entries[index]!.beforeLoadContext,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (owner) preparePublishedMatches(primed, owner, privateContexts);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
owner?.fail(error);
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Commit the way the single-flight client publishes hydrated matches.
|
|
346
|
+
router._committed = primed;
|
|
347
|
+
router.batch(() => {
|
|
348
|
+
router.stores.setMatches(primed);
|
|
349
|
+
router.stores.status.set('idle');
|
|
350
|
+
router.stores.resolvedLocation.set(router.stores.location.get());
|
|
351
|
+
});
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function applyTransferredMatch(
|
|
356
|
+
match: AnyRouteMatch,
|
|
357
|
+
entry: TransferredMatch,
|
|
358
|
+
): AnyRouteMatch {
|
|
359
|
+
const next = {
|
|
360
|
+
...match,
|
|
361
|
+
status: entry.status,
|
|
362
|
+
updatedAt: entry.updatedAt,
|
|
363
|
+
error: isRouteDataErrorSnapshot(entry.error)
|
|
364
|
+
? Object.freeze(restoreRouteDataError(entry.error))
|
|
365
|
+
: entry.error,
|
|
366
|
+
invalid: false,
|
|
367
|
+
isFetching: false,
|
|
368
|
+
preload: false,
|
|
369
|
+
_notFound: entry.notFound,
|
|
370
|
+
__beforeLoadContext: entry.beforeLoadContext,
|
|
371
|
+
} as AnyRouteMatch;
|
|
372
|
+
if ('loaderData' in entry) next.loaderData = entry.loaderData;
|
|
373
|
+
if ('ssr' in entry) {
|
|
374
|
+
if (entry.ssr === undefined) delete next.ssr;
|
|
375
|
+
else next.ssr = entry.ssr;
|
|
376
|
+
}
|
|
377
|
+
return next;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function isRouteDataErrorSnapshot(value: unknown): boolean {
|
|
381
|
+
return (
|
|
382
|
+
!!value &&
|
|
383
|
+
typeof value === 'object' &&
|
|
384
|
+
Object.getOwnPropertyDescriptor(value, 'kind')?.value ===
|
|
385
|
+
'ultramodern-route-data-error'
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Core strips these native hydration fields from its public declarations. */
|
|
390
|
+
function nativeContextField(
|
|
391
|
+
match: AnyRouteMatch,
|
|
392
|
+
key: '_ctx' | '__beforeLoadContext',
|
|
393
|
+
): unknown {
|
|
394
|
+
const descriptor = Object.getOwnPropertyDescriptor(match, key);
|
|
395
|
+
if (descriptor?.get || descriptor?.set)
|
|
396
|
+
throw new DataProtocolError(
|
|
397
|
+
'Native route context must not contain accessor fields',
|
|
398
|
+
);
|
|
399
|
+
return descriptor?.value;
|
|
400
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { JSX } from '@solidjs/web';
|
|
2
|
+
import type { AnyRoute, AnyRouter } from '@tanstack/router-core';
|
|
3
|
+
import { renderInNonRouteComponentContext } from './nonRouteComponentContext';
|
|
4
|
+
import { DefaultGlobalNotFound } from './not-found';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Renders a not found component for a route when no matching route is found.
|
|
8
|
+
*
|
|
9
|
+
* @param router - The router instance containing the route configuration
|
|
10
|
+
* @param route - The route that triggered the not found state
|
|
11
|
+
* @param data - Additional data to pass to the not found component
|
|
12
|
+
* @returns The rendered not found component or a default fallback component
|
|
13
|
+
*/
|
|
14
|
+
export function renderRouteNotFound(
|
|
15
|
+
router: AnyRouter,
|
|
16
|
+
route: AnyRoute,
|
|
17
|
+
data: any,
|
|
18
|
+
): JSX.Element {
|
|
19
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
20
|
+
if (!route.options.notFoundComponent) {
|
|
21
|
+
if (router.options.defaultNotFoundComponent) {
|
|
22
|
+
const DefaultNotFoundComponent =
|
|
23
|
+
router.options.defaultNotFoundComponent;
|
|
24
|
+
return renderInNonRouteComponentContext(
|
|
25
|
+
() => <DefaultNotFoundComponent {...data} />,
|
|
26
|
+
'notFoundComponent',
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.warn(
|
|
31
|
+
`Warning: A notFoundError was encountered on the route with ID "${route.id}", but a notFoundComponent option was not configured, nor was a router level defaultNotFoundComponent configured. Consider configuring at least one of these to avoid TanStack Router's overly generic defaultNotFoundComponent (<p>Not Found</p>)`,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return <DefaultGlobalNotFound />;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const NotFoundComponent = route.options.notFoundComponent;
|
|
38
|
+
return renderInNonRouteComponentContext(
|
|
39
|
+
() => <NotFoundComponent {...data} />,
|
|
40
|
+
'notFoundComponent',
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!route.options.notFoundComponent) {
|
|
45
|
+
if (router.options.defaultNotFoundComponent) {
|
|
46
|
+
return <router.options.defaultNotFoundComponent {...data} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return <DefaultGlobalNotFound />;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return <route.options.notFoundComponent {...data} />;
|
|
53
|
+
}
|