@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/cjs/cli/index.js +47 -27
  2. package/dist/cjs/cli/routeSplitting.js +0 -32
  3. package/dist/cjs/cli/tanstackTypes.js +34 -199
  4. package/dist/cjs/runtime/hooks.js +11 -14
  5. package/dist/cjs/runtime/index.js +107 -319
  6. package/dist/cjs/runtime/lifecycle.js +12 -86
  7. package/dist/cjs/runtime/loaderBridge.js +173 -0
  8. package/dist/cjs/runtime/plugin.js +6 -30
  9. package/dist/cjs/runtime/plugin.node.js +7 -29
  10. package/dist/cjs/runtime/pluginCore.js +55 -0
  11. package/dist/cjs/runtime/register.js +56 -0
  12. package/dist/cjs/runtime/routeTree.js +10 -207
  13. package/dist/cjs/runtime/{DefaultNotFound.js → router.js} +5 -15
  14. package/dist/cjs/runtime/rsc/payloadRouter.js +35 -1
  15. package/dist/cjs/runtime/state.js +45 -0
  16. package/dist/cjs/runtime/utils.js +0 -5
  17. package/dist/esm/cli/index.mjs +52 -26
  18. package/dist/esm/cli/routeSplitting.mjs +1 -30
  19. package/dist/esm/cli/tanstackTypes.mjs +32 -194
  20. package/dist/esm/runtime/hooks.mjs +1 -8
  21. package/dist/esm/runtime/index.mjs +4 -2
  22. package/dist/esm/runtime/lifecycle.mjs +1 -82
  23. package/dist/esm/runtime/loaderBridge.mjs +114 -0
  24. package/dist/esm/runtime/plugin.mjs +8 -32
  25. package/dist/esm/runtime/plugin.node.mjs +10 -32
  26. package/dist/esm/runtime/pluginCore.mjs +14 -0
  27. package/dist/esm/runtime/register.mjs +18 -0
  28. package/dist/esm/runtime/routeTree.mjs +4 -198
  29. package/dist/esm/runtime/router.mjs +2 -0
  30. package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
  31. package/dist/esm/runtime/state.mjs +7 -0
  32. package/dist/esm/runtime/utils.mjs +0 -5
  33. package/dist/esm-node/cli/index.mjs +52 -26
  34. package/dist/esm-node/cli/routeSplitting.mjs +1 -30
  35. package/dist/esm-node/cli/tanstackTypes.mjs +32 -194
  36. package/dist/esm-node/runtime/hooks.mjs +1 -8
  37. package/dist/esm-node/runtime/index.mjs +4 -2
  38. package/dist/esm-node/runtime/lifecycle.mjs +1 -82
  39. package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
  40. package/dist/esm-node/runtime/plugin.mjs +8 -32
  41. package/dist/esm-node/runtime/plugin.node.mjs +10 -32
  42. package/dist/esm-node/runtime/pluginCore.mjs +15 -0
  43. package/dist/esm-node/runtime/register.mjs +19 -0
  44. package/dist/esm-node/runtime/routeTree.mjs +4 -198
  45. package/dist/esm-node/runtime/router.mjs +3 -0
  46. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
  47. package/dist/esm-node/runtime/state.mjs +8 -0
  48. package/dist/esm-node/runtime/utils.mjs +0 -5
  49. package/dist/types/cli/index.d.ts +9 -2
  50. package/dist/types/cli/routeSplitting.d.ts +6 -15
  51. package/dist/types/cli/tanstackTypes.d.ts +13 -2
  52. package/dist/types/runtime/hooks.d.ts +8 -18
  53. package/dist/types/runtime/index.d.ts +6 -4
  54. package/dist/types/runtime/lifecycle.d.ts +7 -22
  55. package/dist/types/runtime/loaderBridge.d.ts +48 -0
  56. package/dist/types/runtime/plugin.d.ts +1 -14
  57. package/dist/types/runtime/plugin.node.d.ts +1 -14
  58. package/dist/types/runtime/pluginCore.d.ts +21 -0
  59. package/dist/types/runtime/register.d.ts +9 -0
  60. package/dist/types/runtime/routeTree.d.ts +0 -2
  61. package/dist/types/runtime/router.d.ts +14 -0
  62. package/dist/types/runtime/state.d.ts +16 -0
  63. package/dist/types/runtime/types.d.ts +7 -53
  64. package/package.json +30 -28
  65. package/rstest.config.mts +6 -0
  66. package/src/cli/index.ts +111 -29
  67. package/src/cli/routeSplitting.ts +6 -44
  68. package/src/cli/tanstackTypes.ts +78 -214
  69. package/src/runtime/hooks.ts +10 -27
  70. package/src/runtime/index.tsx +12 -107
  71. package/src/runtime/lifecycle.ts +16 -151
  72. package/src/runtime/loaderBridge.ts +257 -0
  73. package/src/runtime/plugin.node.tsx +14 -77
  74. package/src/runtime/plugin.tsx +12 -72
  75. package/src/runtime/pluginCore.ts +48 -0
  76. package/src/runtime/register.ts +58 -0
  77. package/src/runtime/routeTree.ts +8 -370
  78. package/src/runtime/router.ts +15 -0
  79. package/src/runtime/rsc/payloadRouter.ts +45 -2
  80. package/src/runtime/state.ts +29 -0
  81. package/src/runtime/types.ts +20 -67
  82. package/src/runtime/utils.tsx +3 -6
  83. package/tests/router/cli.test.ts +297 -31
  84. package/tests/router/hooks.test.ts +26 -0
  85. package/tests/router/loaderBridge.test.ts +211 -0
  86. package/tests/router/packageSurface.test.ts +24 -0
  87. package/tests/router/register.test.ts +46 -0
  88. package/tests/router/routeTree.test.ts +65 -180
  89. package/tests/router/rsc.test.tsx +70 -0
  90. package/tests/router/tanstackTypes.test.ts +164 -6
  91. package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
  92. package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
  93. package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
  94. package/src/runtime/DefaultNotFound.tsx +0 -15
@@ -1,151 +1,16 @@
1
- // @effect-diagnostics strictBooleanExpressions:off
2
- import type { TInternalRuntimeContext } from '@modern-js/runtime/context';
3
- import type { RouteObject } from '@modern-js/runtime-utils/router';
4
- import type {
5
- InternalRouterRuntimeState,
6
- InternalRouterServerSnapshot,
7
- RouterFramework,
8
- RouterRouteMatchSnapshot,
9
- RouterServerPrepareResult,
10
- } from './types';
11
-
12
- export type RouterLifecyclePhase = 'ssr-prepare' | 'client-create' | 'hydrate';
13
-
14
- export type RouterLifecycleContext = {
15
- framework: RouterFramework;
16
- phase: RouterLifecyclePhase;
17
- routes: RouteObject[];
18
- runtimeContext: TInternalRuntimeContext;
19
- basename?: string;
20
- hydrationData?: unknown;
21
- router?: unknown;
22
- matches?: RouterRouteMatchSnapshot[];
23
- cleanup?: () => void | Promise<void>;
24
- serverSnapshot?: InternalRouterServerSnapshot;
25
- };
26
-
27
- type RouterSnapshotLike = Partial<InternalRouterServerSnapshot>;
28
-
29
- function toHydrationScripts(state: {
30
- hydrationScript?: string;
31
- hydrationScripts?: string[];
32
- }) {
33
- if (state.hydrationScripts?.length) {
34
- return state.hydrationScripts;
35
- }
36
-
37
- return state.hydrationScript ? [state.hydrationScript] : undefined;
38
- }
39
-
40
- function getMatchedRouteIdsFromMatches(matches?: RouterRouteMatchSnapshot[]) {
41
- const routeIds = matches
42
- ?.map(match => match.assetRouteId ?? match.routeId)
43
- .filter((routeId): routeId is string => typeof routeId === 'string');
44
-
45
- return routeIds?.length ? routeIds : undefined;
46
- }
47
-
48
- export function createRouterServerSnapshot(
49
- state: RouterSnapshotLike,
50
- ): InternalRouterServerSnapshot {
51
- const hydrationScripts = toHydrationScripts(state);
52
- const matchedRouteIds =
53
- state.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
54
-
55
- return {
56
- ...state,
57
- ...(hydrationScripts?.length
58
- ? {
59
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
60
- hydrationScripts,
61
- }
62
- : {}),
63
- ...(matchedRouteIds ? { matchedRouteIds } : {}),
64
- };
65
- }
66
-
67
- export function createRouterRuntimeState(
68
- state: InternalRouterRuntimeState,
69
- ): InternalRouterRuntimeState {
70
- const hasSnapshotState =
71
- Boolean(state.serverSnapshot) ||
72
- Boolean(state.hydrationScript) ||
73
- Boolean(state.hydrationScripts?.length) ||
74
- Boolean(state.matchedRouteIds?.length) ||
75
- Boolean(state.matches?.length);
76
- const serverSnapshot = state.serverSnapshot
77
- ? createRouterServerSnapshot({
78
- ...state.serverSnapshot,
79
- framework: state.serverSnapshot.framework ?? state.framework,
80
- basename: state.serverSnapshot.basename ?? state.basename,
81
- hydrationScript:
82
- state.serverSnapshot.hydrationScript ?? state.hydrationScript,
83
- hydrationScripts:
84
- state.serverSnapshot.hydrationScripts ?? state.hydrationScripts,
85
- matchedRouteIds:
86
- state.serverSnapshot.matchedRouteIds ?? state.matchedRouteIds,
87
- matches: state.serverSnapshot.matches ?? state.matches,
88
- })
89
- : hasSnapshotState
90
- ? createRouterServerSnapshot({
91
- framework: state.framework,
92
- basename: state.basename,
93
- hydrationScript: state.hydrationScript,
94
- hydrationScripts: state.hydrationScripts,
95
- matchedRouteIds: state.matchedRouteIds,
96
- matches: state.matches,
97
- })
98
- : undefined;
99
- const hydrationScripts = toHydrationScripts({
100
- hydrationScript: state.hydrationScript ?? serverSnapshot?.hydrationScript,
101
- hydrationScripts:
102
- state.hydrationScripts ?? serverSnapshot?.hydrationScripts,
103
- });
104
- const matchedRouteIds =
105
- state.matchedRouteIds ??
106
- serverSnapshot?.matchedRouteIds ??
107
- getMatchedRouteIdsFromMatches(state.matches);
108
-
109
- return {
110
- ...state,
111
- ...(hydrationScripts?.length
112
- ? {
113
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
114
- hydrationScripts,
115
- }
116
- : {}),
117
- ...(matchedRouteIds ? { matchedRouteIds } : {}),
118
- ...(serverSnapshot ? { serverSnapshot } : {}),
119
- };
120
- }
121
-
122
- export function applyRouterRuntimeState(
123
- runtimeContext: TInternalRuntimeContext,
124
- state: InternalRouterRuntimeState,
125
- ) {
126
- const normalized = createRouterRuntimeState(state);
127
- const mutableRuntimeContext = runtimeContext as any;
128
- mutableRuntimeContext.routerFramework = normalized.framework;
129
- mutableRuntimeContext.routerInstance = normalized.instance;
130
- mutableRuntimeContext.routerHydrationScript = normalized.hydrationScript;
131
- mutableRuntimeContext.routerMatchedRouteIds = normalized.matchedRouteIds;
132
- mutableRuntimeContext.routerRuntime = normalized;
133
- if (normalized.serverSnapshot) {
134
- mutableRuntimeContext.routerServerSnapshot = normalized.serverSnapshot;
135
- }
136
-
137
- return runtimeContext;
138
- }
139
-
140
- export function applyRouterServerPrepareResult(
141
- runtimeContext: TInternalRuntimeContext,
142
- result: RouterServerPrepareResult,
143
- ) {
144
- const state = createRouterRuntimeState({
145
- ...result.state,
146
- cleanup: result.cleanup ?? result.state.cleanup,
147
- serverSnapshot: result.snapshot ?? result.state.serverSnapshot,
148
- });
149
- applyRouterRuntimeState(runtimeContext, state);
150
- return runtimeContext;
151
- }
1
+ /**
2
+ * The router runtime state helpers are owned by @modern-js/runtime (the same
3
+ * implementation backs the built-in react-router provider and the SSR
4
+ * pipeline). This module only re-exports them so every router provider
5
+ * writes to the exact same runtime-context extension slot.
6
+ */
7
+ export {
8
+ applyRouterRuntimeState,
9
+ applyRouterServerPrepareResult,
10
+ createRouterRuntimeState,
11
+ createRouterServerSnapshot,
12
+ getRouterRuntimeState,
13
+ getRouterServerSnapshot,
14
+ type RouterLifecycleContext,
15
+ type RouterLifecyclePhase,
16
+ } from '@modern-js/runtime/context';
@@ -0,0 +1,257 @@
1
+ // @effect-diagnostics strictBooleanExpressions:off
2
+ /**
3
+ * Runtime bridge between Modern.js data loaders and TanStack Router.
4
+ *
5
+ * The generated `src/modern-tanstack/<entry>/router.gen.ts` files import these
6
+ * helpers instead of inlining them, so loader/redirect bugfixes ship with the
7
+ * package instead of requiring every app to regenerate its files. The
8
+ * hand-written route-tree builder (`routeTree.ts`) shares the response/redirect
9
+ * helpers for the same reason.
10
+ */
11
+ import { notFound, redirect } from '@tanstack/react-router';
12
+
13
+ /** Router context shape used by the generated TanStack router types. */
14
+ export type ModernRouterContext = {
15
+ request?: Request;
16
+ requestContext?: unknown;
17
+ };
18
+
19
+ export function isResponse(value: unknown): value is Response {
20
+ const record = value as { headers?: unknown; status?: unknown } | null;
21
+ return (
22
+ record != null &&
23
+ typeof record === 'object' &&
24
+ typeof record.status === 'number' &&
25
+ typeof record.headers === 'object'
26
+ );
27
+ }
28
+
29
+ const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
30
+
31
+ export function isRedirectResponse(res: Response): boolean {
32
+ return redirectStatusCodes.has(res.status);
33
+ }
34
+
35
+ /**
36
+ * TanStack redirects are Response objects carrying the original redirect
37
+ * `options`. They must be re-thrown untouched — re-translating them through
38
+ * the Modern Response handling would lose `to`-based (internal) targets.
39
+ */
40
+ export function isTanstackRedirect(value: unknown): boolean {
41
+ return (
42
+ isResponse(value) &&
43
+ typeof (value as { options?: unknown }).options === 'object'
44
+ );
45
+ }
46
+
47
+ export function isAbsoluteUrl(value: string): boolean {
48
+ try {
49
+ void new URL(value);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Re-throw a Modern.js `Location` redirect as a TanStack redirect.
58
+ *
59
+ * Prefers `to` for internal/relative redirects so the basepath rewrite can be
60
+ * applied; absolute (external) URLs go through `href` untouched.
61
+ */
62
+ export function throwTanstackRedirect(location: string): never {
63
+ const target = location || '/';
64
+ if (isAbsoluteUrl(target)) {
65
+ throw redirect({ href: target });
66
+ }
67
+
68
+ throw redirect({ to: target });
69
+ }
70
+
71
+ /**
72
+ * React Router uses `*` for splat params, TanStack Router uses `_splat`.
73
+ * Modern loaders expect the React Router spelling.
74
+ */
75
+ export function mapSplatParamsForModernLoader(
76
+ params: Record<string, string>,
77
+ hasSplat: boolean,
78
+ ): Record<string, string> {
79
+ if (!hasSplat) {
80
+ return params;
81
+ }
82
+
83
+ const { _splat, ...rest } = params as Record<string, string> & {
84
+ _splat?: string;
85
+ };
86
+ if (typeof _splat !== 'undefined') {
87
+ return { ...rest, '*': _splat };
88
+ }
89
+ return rest;
90
+ }
91
+
92
+ /**
93
+ * Static-data factory used by the generated router files: drops empty fields
94
+ * so route static data stays minimal.
95
+ */
96
+ export function createRouteStaticData(opts: {
97
+ modernRouteId?: string;
98
+ modernRouteAction?: unknown;
99
+ modernRouteLoader?: unknown;
100
+ }): {
101
+ modernRouteId?: string;
102
+ modernRouteAction?: unknown;
103
+ modernRouteLoader?: unknown;
104
+ } {
105
+ const staticData: {
106
+ modernRouteId?: string;
107
+ modernRouteAction?: unknown;
108
+ modernRouteLoader?: unknown;
109
+ } = {};
110
+
111
+ if (typeof opts.modernRouteId === 'string' && opts.modernRouteId.length > 0) {
112
+ staticData.modernRouteId = opts.modernRouteId;
113
+ }
114
+
115
+ if (typeof opts.modernRouteLoader !== 'undefined') {
116
+ staticData.modernRouteLoader = opts.modernRouteLoader;
117
+ }
118
+
119
+ if (typeof opts.modernRouteAction !== 'undefined') {
120
+ staticData.modernRouteAction = opts.modernRouteAction;
121
+ }
122
+
123
+ return staticData;
124
+ }
125
+
126
+ type LoaderLikeContext = {
127
+ abortController?: AbortController;
128
+ signal?: AbortSignal;
129
+ context?: ModernRouterContext;
130
+ location?:
131
+ | string
132
+ | {
133
+ publicHref?: string;
134
+ href?: string;
135
+ url?: { href?: string };
136
+ };
137
+ params?: Record<string, string>;
138
+ };
139
+
140
+ function getLoaderSignal(ctx: LoaderLikeContext | undefined): AbortSignal {
141
+ const abortSignal = ctx?.abortController?.signal;
142
+ if (abortSignal instanceof AbortSignal) {
143
+ return abortSignal;
144
+ }
145
+ if (ctx?.signal instanceof AbortSignal) {
146
+ return ctx.signal;
147
+ }
148
+ return new AbortController().signal;
149
+ }
150
+
151
+ function getLoaderHref(ctx: LoaderLikeContext | undefined): string {
152
+ if (typeof ctx?.location === 'string') {
153
+ return ctx.location;
154
+ }
155
+
156
+ const publicHref = ctx?.location?.publicHref;
157
+ if (typeof publicHref === 'string') {
158
+ return publicHref;
159
+ }
160
+
161
+ const href = ctx?.location?.href;
162
+ if (typeof href === 'string') {
163
+ return href;
164
+ }
165
+
166
+ const urlHref = ctx?.location?.url?.href;
167
+ return typeof urlHref === 'string' ? urlHref : '';
168
+ }
169
+
170
+ function getLoaderParams(
171
+ ctx: LoaderLikeContext | undefined,
172
+ ): Record<string, string> {
173
+ return typeof ctx?.params === 'object' && ctx.params !== null
174
+ ? ctx.params
175
+ : {};
176
+ }
177
+
178
+ function handleModernLoaderResult<LoaderResult>(
179
+ result: LoaderResult,
180
+ ): LoaderResult {
181
+ if (isResponse(result)) {
182
+ if (isRedirectResponse(result)) {
183
+ const location = result.headers.get('Location') ?? '/';
184
+ throwTanstackRedirect(location);
185
+ }
186
+ if (result.status === 404) {
187
+ throw notFound();
188
+ }
189
+ }
190
+
191
+ return result;
192
+ }
193
+
194
+ function handleModernLoaderError(err: unknown): never {
195
+ if (isResponse(err)) {
196
+ if (isTanstackRedirect(err)) {
197
+ throw err;
198
+ }
199
+ if (isRedirectResponse(err)) {
200
+ const location = err.headers.get('Location') ?? '/';
201
+ throwTanstackRedirect(location);
202
+ }
203
+ if (err.status === 404) {
204
+ throw notFound();
205
+ }
206
+ }
207
+
208
+ throw err;
209
+ }
210
+
211
+ /**
212
+ * Wrap a Modern.js data loader (`page.data.ts` loader/action style) into a
213
+ * TanStack Router loader: builds a `Request` from the loader context, maps
214
+ * splat params, and translates Response redirects/404s into TanStack
215
+ * `redirect()`/`notFound()`.
216
+ */
217
+ export function modernLoaderToTanstack<TLoader extends (args: any) => any>(
218
+ opts: { hasSplat: boolean },
219
+ modernLoader: TLoader,
220
+ ): (ctx: unknown) => Promise<Awaited<ReturnType<TLoader>>> {
221
+ type LoaderResult = Awaited<ReturnType<TLoader>>;
222
+
223
+ return (rawCtx: unknown): Promise<LoaderResult> => {
224
+ const ctx = rawCtx as LoaderLikeContext | undefined;
225
+ try {
226
+ const signal = getLoaderSignal(ctx);
227
+ const baseRequest: Request | undefined =
228
+ ctx?.context?.request instanceof Request
229
+ ? ctx.context.request
230
+ : undefined;
231
+
232
+ const href = getLoaderHref(ctx);
233
+
234
+ const request =
235
+ baseRequest !== undefined
236
+ ? new Request(baseRequest, { signal })
237
+ : new Request(href, { signal });
238
+
239
+ const params = mapSplatParamsForModernLoader(
240
+ getLoaderParams(ctx),
241
+ opts.hasSplat,
242
+ );
243
+
244
+ return Promise.resolve(
245
+ (modernLoader as (args: unknown) => unknown)({
246
+ request,
247
+ params,
248
+ context: ctx?.context?.requestContext,
249
+ }) as LoaderResult,
250
+ )
251
+ .then((result: LoaderResult) => handleModernLoaderResult(result))
252
+ .catch(handleModernLoaderError);
253
+ } catch (err) {
254
+ handleModernLoaderError(err);
255
+ }
256
+ };
257
+ }
@@ -1,23 +1,17 @@
1
1
  // @effect-diagnostics asyncFunction:off newPromise:off strictBooleanExpressions:off unnecessaryArrowBlock:off
2
2
  /// <reference path="./ssr-shim.d.ts" />
3
3
 
4
- import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
5
- import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
6
4
  import {
7
5
  getGlobalEnableRsc,
8
- getGlobalLayoutApp,
9
- getGlobalRoutes,
10
6
  InternalRuntimeContext,
11
7
  type ServerPayload,
12
8
  type TInternalRuntimeContext,
13
9
  } from '@modern-js/runtime/context';
14
- import { merge } from '@modern-js/runtime-utils/merge';
15
10
  import {
16
11
  createRequestContext,
17
12
  type RequestContext,
18
13
  storage,
19
14
  } from '@modern-js/runtime-utils/node';
20
- import type { RouteObject } from '@modern-js/runtime-utils/router';
21
15
  import { time } from '@modern-js/runtime-utils/time';
22
16
  import { LOADER_REPORTER_NAME } from '@modern-js/utils/universal/constants';
23
17
  import {
@@ -30,21 +24,20 @@ import { attachRouterServerSsrUtils } from '@tanstack/router-core/ssr/server';
30
24
  import type React from 'react';
31
25
  import { useContext } from 'react';
32
26
  import { createModernBasepathRewrite } from './basepathRewrite';
33
- import {
34
- modifyRoutes as modifyRoutesHook,
35
- onAfterCreateRouter as onAfterCreateRouterHook,
36
- onAfterHydrateRouter as onAfterHydrateRouterHook,
37
- onBeforeCreateRouter as onBeforeCreateRouterHook,
38
- onBeforeCreateRoutes as onBeforeCreateRoutesHook,
39
- onBeforeHydrateRouter as onBeforeHydrateRouterHook,
40
- type RouterExtendsHooks,
41
- } from './hooks';
27
+ import { routerProviderRegistryHooks } from './hooks';
42
28
  import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
43
29
  import {
44
30
  applyRouterServerPrepareResult,
45
31
  createRouterServerSnapshot,
32
+ getRouterRuntimeState,
46
33
  type RouterLifecycleContext,
47
34
  } from './lifecycle';
35
+ import {
36
+ getFinalRouteConfig,
37
+ getMergedRouterConfig,
38
+ type TanstackRouterPluginAPI,
39
+ type TanstackRouterRuntimePlugin,
40
+ } from './pluginCore';
48
41
  import {
49
42
  createRouteTreeFromRouteObjects,
50
43
  getModernRouteIdsFromMatches,
@@ -65,25 +58,6 @@ type ModernTanstackRouterContext = {
65
58
  requestContext: RequestContext<Record<string, unknown>>;
66
59
  };
67
60
 
68
- type TanstackRouterRuntimeConfig = {
69
- plugins?: TanstackRouterRuntimePlugin[];
70
- router?: Partial<RouterConfig>;
71
- [key: string]: unknown;
72
- };
73
-
74
- type TanstackRouterRuntimeExtends = Required<
75
- RuntimePluginExtends<TanstackRouterRuntimeConfig, TInternalRuntimeContext>
76
- > & {
77
- extendHooks: RouterExtendsHooks;
78
- };
79
-
80
- type TanstackRouterPluginAPI = RuntimePluginAPI<TanstackRouterRuntimeExtends>;
81
-
82
- type TanstackRouterRuntimePlugin = Plugin<
83
- TanstackRouterPluginAPI,
84
- TInternalRuntimeContext
85
- >;
86
-
87
61
  const setTanstackRscServerPayload = (payload: ServerPayload) => {
88
62
  const storageContext = storage.useContext?.() as
89
63
  | { serverPayload?: ServerPayload }
@@ -300,20 +274,6 @@ function createGetSsrHref(request: Request): string {
300
274
  return `${url.pathname}${url.search}${url.hash}`;
301
275
  }
302
276
 
303
- function stripSyntheticNotFoundRoute(routes: RouteObject[]): RouteObject[] {
304
- return routes
305
- .filter(route => !(route.path === '*' && !route.id && !route.loader))
306
- .map(route => {
307
- if (!route.children?.length) {
308
- return route;
309
- }
310
- return {
311
- ...route,
312
- children: stripSyntheticNotFoundRoute(route.children),
313
- };
314
- });
315
- }
316
-
317
277
  function collectRouterErrors(
318
278
  tanstackRouter: AnyRouter,
319
279
  ): Record<string, unknown> | undefined {
@@ -345,35 +305,18 @@ export const tanstackRouterPlugin = (
345
305
  ): TanstackRouterRuntimePlugin => {
346
306
  const plugin: TanstackRouterRuntimePlugin = {
347
307
  name: '@modern-js/plugin-router-tanstack',
348
- registryHooks: {
349
- modifyRoutes: modifyRoutesHook,
350
- onAfterCreateRouter: onAfterCreateRouterHook,
351
- onAfterHydrateRouter: onAfterHydrateRouterHook,
352
- onBeforeCreateRouter: onBeforeCreateRouterHook,
353
- onBeforeCreateRoutes: onBeforeCreateRoutesHook,
354
- onBeforeHydrateRouter: onBeforeHydrateRouterHook,
355
- },
308
+ registryHooks: routerProviderRegistryHooks,
356
309
  setup: (api: TanstackRouterPluginAPI) => {
357
310
  api.onBeforeRender(async (context, interrupt) => {
358
- const pluginConfig = api.getRuntimeConfig() as {
359
- router?: Partial<RouterConfig>;
360
- };
361
- const mergedConfig = merge(
362
- pluginConfig.router || {},
363
- userConfig,
364
- ) as RouterConfig;
311
+ const mergedConfig = getMergedRouterConfig(api, userConfig);
365
312
  const serializationAdapters = getGlobalEnableRsc()
366
313
  ? (await import('./rsc/server')).getTanstackRscSerializationAdapters()
367
314
  : undefined;
368
315
  const enableRsc = getGlobalEnableRsc();
369
316
 
370
- const { basename = '', routesConfig, createRoutes } = mergedConfig;
317
+ const { basename = '', createRoutes } = mergedConfig;
371
318
 
372
- const finalRouteConfig = {
373
- routes: getGlobalRoutes(),
374
- globalApp: getGlobalLayoutApp(),
375
- ...routesConfig,
376
- };
319
+ const finalRouteConfig = getFinalRouteConfig(mergedConfig);
377
320
 
378
321
  if (!finalRouteConfig.routes && !createRoutes) {
379
322
  return;
@@ -388,12 +331,7 @@ export const tanstackRouterPlugin = (
388
331
  routesConfig: finalRouteConfig,
389
332
  ssrMode: context.ssrContext?.mode,
390
333
  }) || [];
391
- const normalizedRouteObjects = createRoutes
392
- ? routeObjects
393
- : stripSyntheticNotFoundRoute(routeObjects);
394
- const modifiedRouteObjects = hooks.modifyRoutes.call(
395
- normalizedRouteObjects,
396
- );
334
+ const modifiedRouteObjects = hooks.modifyRoutes.call(routeObjects);
397
335
 
398
336
  if (!modifiedRouteObjects.length) {
399
337
  return;
@@ -560,8 +498,7 @@ export const tanstackRouterPlugin = (
560
498
  const context = useContext(
561
499
  InternalRuntimeContext,
562
500
  ) as unknown as TInternalRuntimeContext;
563
- const router =
564
- context.routerInstance ?? context.routerRuntime?.instance;
501
+ const router = getRouterRuntimeState(context)?.instance;
565
502
  if (!router) {
566
503
  return App ? <App {...props} /> : null;
567
504
  }