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

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 (87) hide show
  1. package/dist/cjs/cli/index.js +47 -9
  2. package/dist/cjs/cli/routeSplitting.js +87 -0
  3. package/dist/cjs/cli/tanstackTypes.js +230 -63
  4. package/dist/cjs/cli.js +12 -8
  5. package/dist/cjs/runtime/DefaultNotFound.js +9 -5
  6. package/dist/cjs/runtime/basepathRewrite.js +12 -8
  7. package/dist/cjs/runtime/dataMutation.js +9 -5
  8. package/dist/cjs/runtime/hooks.js +9 -5
  9. package/dist/cjs/runtime/hydrationBoundary.js +48 -0
  10. package/dist/cjs/runtime/index.js +330 -74
  11. package/dist/cjs/runtime/lifecycle.js +15 -11
  12. package/dist/cjs/runtime/outlet.js +58 -0
  13. package/dist/cjs/runtime/plugin.js +203 -98
  14. package/dist/cjs/runtime/plugin.node.js +38 -16
  15. package/dist/cjs/runtime/plugin.worker.js +53 -0
  16. package/dist/cjs/runtime/prefetchLink.js +10 -6
  17. package/dist/cjs/runtime/routeTree.js +81 -17
  18. package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
  19. package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
  20. package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
  21. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
  22. package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
  23. package/dist/cjs/runtime/rsc/client.js +9 -5
  24. package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
  25. package/dist/cjs/runtime/rsc/index.js +9 -5
  26. package/dist/cjs/runtime/rsc/payloadRouter.js +9 -5
  27. package/dist/cjs/runtime/rsc/server.js +9 -5
  28. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
  29. package/dist/cjs/runtime/rsc/symbols.js +20 -15
  30. package/dist/cjs/runtime/types.js +31 -1
  31. package/dist/cjs/runtime/utils.js +9 -5
  32. package/dist/cjs/runtime.js +9 -5
  33. package/dist/esm/cli/index.mjs +28 -6
  34. package/dist/esm/cli/routeSplitting.mjs +43 -0
  35. package/dist/esm/cli/tanstackTypes.mjs +219 -59
  36. package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
  37. package/dist/esm/runtime/index.mjs +3 -2
  38. package/dist/esm/runtime/outlet.mjs +17 -0
  39. package/dist/esm/runtime/plugin.mjs +197 -96
  40. package/dist/esm/runtime/plugin.node.mjs +30 -12
  41. package/dist/esm/runtime/plugin.worker.mjs +1 -0
  42. package/dist/esm/runtime/prefetchLink.mjs +1 -1
  43. package/dist/esm/runtime/routeTree.mjs +73 -13
  44. package/dist/esm/runtime/types.mjs +7 -0
  45. package/dist/esm-node/cli/index.mjs +28 -6
  46. package/dist/esm-node/cli/routeSplitting.mjs +44 -0
  47. package/dist/esm-node/cli/tanstackTypes.mjs +219 -59
  48. package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
  49. package/dist/esm-node/runtime/index.mjs +3 -2
  50. package/dist/esm-node/runtime/outlet.mjs +18 -0
  51. package/dist/esm-node/runtime/plugin.mjs +197 -96
  52. package/dist/esm-node/runtime/plugin.node.mjs +30 -12
  53. package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
  54. package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
  55. package/dist/esm-node/runtime/routeTree.mjs +73 -13
  56. package/dist/esm-node/runtime/types.mjs +7 -0
  57. package/dist/types/cli/index.d.ts +7 -1
  58. package/dist/types/cli/routeSplitting.d.ts +29 -0
  59. package/dist/types/cli/tanstackTypes.d.ts +9 -0
  60. package/dist/types/runtime/hooks.d.ts +9 -24
  61. package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
  62. package/dist/types/runtime/index.d.ts +5 -2
  63. package/dist/types/runtime/outlet.d.ts +2 -0
  64. package/dist/types/runtime/plugin.d.ts +1 -1
  65. package/dist/types/runtime/plugin.node.d.ts +1 -1
  66. package/dist/types/runtime/plugin.worker.d.ts +1 -0
  67. package/dist/types/runtime/types.d.ts +7 -0
  68. package/package.json +20 -20
  69. package/src/cli/index.ts +59 -2
  70. package/src/cli/routeSplitting.ts +81 -0
  71. package/src/cli/tanstackTypes.ts +347 -67
  72. package/src/runtime/hydrationBoundary.tsx +12 -0
  73. package/src/runtime/index.tsx +107 -2
  74. package/src/runtime/outlet.tsx +48 -0
  75. package/src/runtime/plugin.node.tsx +58 -8
  76. package/src/runtime/plugin.tsx +372 -157
  77. package/src/runtime/plugin.worker.tsx +4 -0
  78. package/src/runtime/prefetchLink.tsx +1 -1
  79. package/src/runtime/routeTree.ts +194 -23
  80. package/src/runtime/ssr-shim.d.ts +1 -3
  81. package/src/runtime/types.ts +13 -0
  82. package/tests/router/cli.test.ts +315 -0
  83. package/tests/router/fastDefaults.test.ts +25 -0
  84. package/tests/router/hydrationBoundary.test.tsx +23 -0
  85. package/tests/router/prefetchLink.test.tsx +43 -7
  86. package/tests/router/routeTree.test.ts +416 -1
  87. package/tests/router/tanstackTypes.test.ts +415 -1
@@ -24,11 +24,15 @@ function __webpack_require__(moduleId) {
24
24
  };
25
25
  })();
26
26
  (()=>{
27
- __webpack_require__.d = (exports1, definition)=>{
28
- for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
29
- enumerable: true,
30
- get: definition[key]
31
- });
27
+ __webpack_require__.d = (exports1, getters, values)=>{
28
+ var define = (defs, kind)=>{
29
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
30
+ enumerable: true,
31
+ [kind]: defs[key]
32
+ });
33
+ };
34
+ define(getters, "get");
35
+ define(values, "value");
32
36
  };
33
37
  })();
34
38
  (()=>{
@@ -48,9 +52,13 @@ var __webpack_exports__ = {};
48
52
  (()=>{
49
53
  __webpack_require__.r(__webpack_exports__);
50
54
  __webpack_require__.d(__webpack_exports__, {
55
+ collectCanonicalRoutesForEntry: ()=>external_tanstackTypes_js_namespaceObject.collectCanonicalRoutesForEntry,
56
+ createTanstackRsbuildRouteSplittingProfile: ()=>external_routeSplitting_js_namespaceObject.createTanstackRsbuildRouteSplittingProfile,
51
57
  default: ()=>src_cli,
52
58
  generateTanstackRouterTypesSourceForEntry: ()=>external_tanstackTypes_js_namespaceObject.generateTanstackRouterTypesSourceForEntry,
53
59
  isTanstackRouterFrameworkEnabled: ()=>external_tanstackTypes_js_namespaceObject.isTanstackRouterFrameworkEnabled,
60
+ isTanstackStartRouteModuleSource: ()=>external_routeSplitting_js_namespaceObject.isTanstackStartRouteModuleSource,
61
+ resolveTanstackRouteCodeSplittingEnabled: ()=>external_routeSplitting_js_namespaceObject.resolveTanstackRouteCodeSplittingEnabled,
54
62
  tanstackRouterPlugin: ()=>tanstackRouterPlugin,
55
63
  writeTanstackRegisterFile: ()=>writeTanstackRegisterFile,
56
64
  writeTanstackRouterTypesForEntries: ()=>writeTanstackRouterTypesForEntries
@@ -58,6 +66,7 @@ var __webpack_exports__ = {};
58
66
  const external_node_path_namespaceObject = require("node:path");
59
67
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
60
68
  const utils_namespaceObject = require("@modern-js/utils");
69
+ const external_routeSplitting_js_namespaceObject = require("./routeSplitting.js");
61
70
  const external_tanstackTypes_js_namespaceObject = require("./tanstackTypes.js");
62
71
  const DEFAULT_ROUTES_DIR = 'routes';
63
72
  const DEFAULT_GENERATED_DIR_NAME = 'modern-tanstack';
@@ -82,6 +91,14 @@ var __webpack_exports__ = {};
82
91
  function createRegisterDtsContent(opts) {
83
92
  const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
84
93
  const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
94
+ const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
95
+ const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
96
+ declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
97
+ interface UltramodernCanonicalRoutes {
98
+ ${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
99
+ }
100
+ }
101
+ ` : '';
85
102
  return `// This file is auto-generated by Modern.js. Do not edit manually.
86
103
 
87
104
  ${importStatements}
@@ -91,15 +108,17 @@ declare module '${opts.runtimeModule}' {
91
108
  router: ${routerUnionType};
92
109
  }
93
110
  }
94
- `;
111
+ ${canonicalRoutesAugmentation}`;
95
112
  }
96
113
  async function writeTanstackRegisterFile(opts) {
97
- const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory } = opts;
114
+ const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
98
115
  if (0 === entries.length) return;
99
116
  const registerDtsPath = external_node_path_default().join(srcDirectory, generatedDirName, 'register.gen.d.ts');
100
117
  await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
101
118
  entries,
102
- runtimeModule
119
+ runtimeModule,
120
+ canonicalRoutes,
121
+ i18nRuntimeModule
103
122
  }));
104
123
  }
105
124
  async function writeTanstackRouterTypesForEntries(opts) {
@@ -120,15 +139,25 @@ declare module '${opts.runtimeModule}' {
120
139
  if (mainEntryName && b === mainEntryName) return 1;
121
140
  return a.localeCompare(b);
122
141
  });
142
+ let canonicalRoutes = null;
143
+ for (const entryName of registerEntries){
144
+ const entryCanonicalRoutes = (0, external_tanstackTypes_js_namespaceObject.collectCanonicalRoutesForEntry)(routesByEntry[entryName]);
145
+ if (entryCanonicalRoutes) canonicalRoutes = {
146
+ ...entryCanonicalRoutes,
147
+ ...canonicalRoutes ?? {}
148
+ };
149
+ }
123
150
  await writeTanstackRegisterFile({
124
151
  entries: registerEntries,
125
152
  generatedDirName,
126
- srcDirectory: appContext.srcDirectory
153
+ srcDirectory: appContext.srcDirectory,
154
+ canonicalRoutes
127
155
  });
128
156
  }
129
157
  function tanstackRouterPlugin(options = {}) {
130
158
  const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
131
159
  const generatedDirName = options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
160
+ const routeSplittingProfile = (0, external_routeSplitting_js_namespaceObject.createTanstackRsbuildRouteSplittingProfile)(options);
132
161
  return {
133
162
  name: '@modern-js/plugin-tanstack',
134
163
  required: [
@@ -164,6 +193,7 @@ declare module '${opts.runtimeModule}' {
164
193
  entry: entry || getRuntimeRouterCli().isRouteEntry(entryPath, routesDir)
165
194
  }));
166
195
  api.config(()=>({
196
+ ...routeSplittingProfile.defaultConfig,
167
197
  source: {
168
198
  include: [
169
199
  /[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
@@ -246,16 +276,24 @@ declare module '${opts.runtimeModule}' {
246
276
  }
247
277
  const src_cli = tanstackRouterPlugin;
248
278
  })();
279
+ exports.collectCanonicalRoutesForEntry = __webpack_exports__.collectCanonicalRoutesForEntry;
280
+ exports.createTanstackRsbuildRouteSplittingProfile = __webpack_exports__.createTanstackRsbuildRouteSplittingProfile;
249
281
  exports["default"] = __webpack_exports__["default"];
250
282
  exports.generateTanstackRouterTypesSourceForEntry = __webpack_exports__.generateTanstackRouterTypesSourceForEntry;
251
283
  exports.isTanstackRouterFrameworkEnabled = __webpack_exports__.isTanstackRouterFrameworkEnabled;
284
+ exports.isTanstackStartRouteModuleSource = __webpack_exports__.isTanstackStartRouteModuleSource;
285
+ exports.resolveTanstackRouteCodeSplittingEnabled = __webpack_exports__.resolveTanstackRouteCodeSplittingEnabled;
252
286
  exports.tanstackRouterPlugin = __webpack_exports__.tanstackRouterPlugin;
253
287
  exports.writeTanstackRegisterFile = __webpack_exports__.writeTanstackRegisterFile;
254
288
  exports.writeTanstackRouterTypesForEntries = __webpack_exports__.writeTanstackRouterTypesForEntries;
255
289
  for(var __rspack_i in __webpack_exports__)if (-1 === [
290
+ "collectCanonicalRoutesForEntry",
291
+ "createTanstackRsbuildRouteSplittingProfile",
256
292
  "default",
257
293
  "generateTanstackRouterTypesSourceForEntry",
258
294
  "isTanstackRouterFrameworkEnabled",
295
+ "isTanstackStartRouteModuleSource",
296
+ "resolveTanstackRouteCodeSplittingEnabled",
259
297
  "tanstackRouterPlugin",
260
298
  "writeTanstackRegisterFile",
261
299
  "writeTanstackRouterTypesForEntries"
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ const TANSTACK_START_ROUTE_FACTORY_CALLS = [
31
+ 'createFileRoute',
32
+ 'createRootRoute',
33
+ 'createRootRouteWithContext'
34
+ ];
35
+ const TANSTACK_START_ROUTE_FACTORY_REGEX = /\b(createFileRoute|createRootRoute|createRootRouteWithContext)\s*(?:<|\()/;
36
+ function isTanstackStartRouteModuleSource(source) {
37
+ return TANSTACK_START_ROUTE_FACTORY_REGEX.test(source);
38
+ }
39
+ function resolveTanstackRouteCodeSplittingEnabled(option) {
40
+ if ('boolean' == typeof option) return option;
41
+ return option?.enabled ?? true;
42
+ }
43
+ function createTanstackRsbuildRouteSplittingProfile(opts) {
44
+ return {
45
+ defaultConfig: {
46
+ output: {
47
+ splitRouteChunks: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting)
48
+ }
49
+ },
50
+ modernRouteChunks: {
51
+ enabled: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting),
52
+ owner: 'modern'
53
+ },
54
+ builderChunkSplit: {
55
+ owner: 'modern-rsbuild',
56
+ preserved: true
57
+ },
58
+ tanstackStartRspackSplitter: {
59
+ compatible: false,
60
+ reason: 'TanStack Start Rsbuild route splitting is tied to TanStack file-route factory modules; Modern generates TanStack route trees from Modern route metadata and owns route chunking through output.splitRouteChunks.',
61
+ clientDeleteNodes: [
62
+ 'ssr',
63
+ 'server',
64
+ 'headers'
65
+ ],
66
+ routeFactoryCalls: [
67
+ ...TANSTACK_START_ROUTE_FACTORY_CALLS
68
+ ]
69
+ }
70
+ };
71
+ }
72
+ __webpack_require__.d(__webpack_exports__, {
73
+ createTanstackRsbuildRouteSplittingProfile: ()=>createTanstackRsbuildRouteSplittingProfile,
74
+ isTanstackStartRouteModuleSource: ()=>isTanstackStartRouteModuleSource,
75
+ resolveTanstackRouteCodeSplittingEnabled: ()=>resolveTanstackRouteCodeSplittingEnabled
76
+ });
77
+ exports.createTanstackRsbuildRouteSplittingProfile = __webpack_exports__.createTanstackRsbuildRouteSplittingProfile;
78
+ exports.isTanstackStartRouteModuleSource = __webpack_exports__.isTanstackStartRouteModuleSource;
79
+ exports.resolveTanstackRouteCodeSplittingEnabled = __webpack_exports__.resolveTanstackRouteCodeSplittingEnabled;
80
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
81
+ "createTanstackRsbuildRouteSplittingProfile",
82
+ "isTanstackStartRouteModuleSource",
83
+ "resolveTanstackRouteCodeSplittingEnabled"
84
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
85
+ Object.defineProperty(exports, '__esModule', {
86
+ value: true
87
+ });
@@ -10,11 +10,15 @@ var __webpack_require__ = {};
10
10
  };
11
11
  })();
12
12
  (()=>{
13
- __webpack_require__.d = (exports1, definition)=>{
14
- for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
15
- enumerable: true,
16
- get: definition[key]
17
- });
13
+ __webpack_require__.d = (exports1, getters, values)=>{
14
+ var define = (defs, kind)=>{
15
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
16
+ enumerable: true,
17
+ [kind]: defs[key]
18
+ });
19
+ };
20
+ define(getters, "get");
21
+ define(values, "value");
18
22
  };
19
23
  })();
20
24
  (()=>{
@@ -33,6 +37,7 @@ var __webpack_require__ = {};
33
37
  var __webpack_exports__ = {};
34
38
  __webpack_require__.r(__webpack_exports__);
35
39
  __webpack_require__.d(__webpack_exports__, {
40
+ collectCanonicalRoutesForEntry: ()=>collectCanonicalRoutesForEntry,
36
41
  generateTanstackRouterTypesSourceForEntry: ()=>generateTanstackRouterTypesSourceForEntry,
37
42
  isTanstackRouterFrameworkEnabled: ()=>isTanstackRouterFrameworkEnabled
38
43
  });
@@ -94,6 +99,14 @@ function pickModernLoaderModule(route) {
94
99
  inline
95
100
  };
96
101
  }
102
+ function pickRouteSearchContractModules(route) {
103
+ const validateSearchPath = route.validateSearch;
104
+ const loaderDepsPath = route.loaderDeps;
105
+ return {
106
+ validateSearchPath: 'string' == typeof validateSearchPath ? validateSearchPath : null,
107
+ loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
108
+ };
109
+ }
97
110
  function isPathlessLayout(route) {
98
111
  return 'nested' === route.type && 'boolean' != typeof route.index && void 0 === route.path;
99
112
  }
@@ -108,6 +121,78 @@ function createRouteStaticDataSnippet(opts) {
108
121
  if (!staticDataLines.length) return null;
109
122
  return `staticData: createRouteStaticData({\n ${staticDataLines.join('\n ')}\n }),`;
110
123
  }
124
+ const LOCALE_PARAM_SEGMENTS = new Set([
125
+ ':lang',
126
+ ':locale',
127
+ ':language',
128
+ '$lang',
129
+ '$locale',
130
+ '$language'
131
+ ]);
132
+ function paramsTypeForCanonicalPath(canonicalPath) {
133
+ const fields = [];
134
+ for (const segment of canonicalPath.split('/'))if (segment) {
135
+ if ('*' === segment || '$' === segment) {
136
+ fields.push("'_splat'?: string");
137
+ continue;
138
+ }
139
+ if (segment.startsWith('{-$') && segment.endsWith('}')) {
140
+ fields.push(`${JSON.stringify(segment.slice(3, -1))}?: string`);
141
+ continue;
142
+ }
143
+ if (segment.startsWith('$')) {
144
+ fields.push(`${JSON.stringify(segment.slice(1))}: string`);
145
+ continue;
146
+ }
147
+ if (segment.startsWith(':')) {
148
+ const optional = segment.endsWith('?');
149
+ const name = segment.slice(1, optional ? void 0 : segment.length);
150
+ fields.push(`${JSON.stringify(optional ? name.slice(0, -1) : name)}${optional ? '?' : ''}: string`);
151
+ }
152
+ }
153
+ return fields.length > 0 ? `{ ${fields.join('; ')} }` : 'Record<string, never>';
154
+ }
155
+ function collectCanonicalRoutesForEntry(routes) {
156
+ const canonicalParams = new Map();
157
+ let hasI18nSurface = false;
158
+ const normalizeJoined = (joined)=>{
159
+ const collapsed = joined.replace(/\/+/g, '/');
160
+ const withLeading = collapsed.startsWith('/') ? collapsed : `/${collapsed}`;
161
+ return withLeading.length > 1 ? withLeading.replace(/\/+$/, '') : withLeading;
162
+ };
163
+ const record = (canonicalPath)=>{
164
+ const normalized = normalizeJoined(canonicalPath || '/');
165
+ const key = toTanstackPath(normalized);
166
+ if (!canonicalParams.has(key)) canonicalParams.set(key, paramsTypeForCanonicalPath(normalized));
167
+ };
168
+ const visit = (route, parentPath)=>{
169
+ let currentPath = parentPath;
170
+ if ('string' == typeof route.modernCanonicalPath) {
171
+ hasI18nSurface = true;
172
+ currentPath = normalizeJoined(route.modernCanonicalPath);
173
+ } else if ('string' == typeof route.path && route.path.length > 0) {
174
+ const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
175
+ if ('' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
176
+ hasI18nSurface = true;
177
+ segments.shift();
178
+ }
179
+ currentPath = segments.length ? normalizeJoined(`${parentPath}/${segments.join('/')}`) : parentPath;
180
+ }
181
+ const children = route.children;
182
+ if (children && children.length > 0) {
183
+ for (const child of children)visit(child, currentPath);
184
+ return;
185
+ }
186
+ record(currentPath || '/');
187
+ };
188
+ const rootModern = routes.find((route)=>route.isRoot);
189
+ const topLevel = rootModern ? rootModern.children ?? [] : routes;
190
+ for (const route of topLevel)visit(route, '');
191
+ if (!hasI18nSurface || 0 === canonicalParams.size) return null;
192
+ return Object.fromEntries([
193
+ ...canonicalParams.entries()
194
+ ].sort(([a], [b])=>a.localeCompare(b)));
195
+ }
111
196
  async function isTanstackRouterFrameworkEnabled(appContext) {
112
197
  const runtimeConfigBase = external_path_default().join(appContext.srcDirectory, appContext.runtimeConfigFile);
113
198
  const runtimeConfigFile = (0, utils_namespaceObject.findExists)(JS_OR_TS_EXTS.map((ext)=>`${runtimeConfigBase}${ext}`));
@@ -127,8 +212,21 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
127
212
  const imports = [];
128
213
  const statements = [];
129
214
  const loaderImportMap = new Map();
215
+ const searchContractImportMap = new Map();
216
+ const usedRouteVarNames = new Set();
130
217
  let loaderIndex = 0;
218
+ let validateSearchIndex = 0;
219
+ let loaderDepsIndex = 0;
131
220
  let routeIndex = 0;
221
+ const resolveRouteModuleNoExt = async (aliasedNoExtPath)=>{
222
+ const prefix = `${appContext.internalSrcAlias}/`;
223
+ let absNoExt;
224
+ if (aliasedNoExtPath.startsWith(prefix)) {
225
+ const rel = aliasedNoExtPath.slice(prefix.length);
226
+ absNoExt = external_path_default().join(appContext.srcDirectory, rel);
227
+ } else absNoExt = external_path_default().isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : external_path_default().join(appContext.srcDirectory, aliasedNoExtPath);
228
+ return resolveFileNoExt(absNoExt);
229
+ };
132
230
  const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
133
231
  const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
134
232
  const existing = loaderImportMap.get(key);
@@ -136,13 +234,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
136
234
  loaderName: existing,
137
235
  actionName: hasAction ? existing.replace(/^loader_/, 'action_') : null
138
236
  };
139
- const prefix = `${appContext.internalSrcAlias}/`;
140
- let absNoExt;
141
- if (aliasedNoExtPath.startsWith(prefix)) {
142
- const rel = aliasedNoExtPath.slice(prefix.length);
143
- absNoExt = external_path_default().join(appContext.srcDirectory, rel);
144
- } else absNoExt = external_path_default().isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : external_path_default().join(appContext.srcDirectory, aliasedNoExtPath);
145
- const resolvedNoExt = await resolveFileNoExt(absNoExt);
237
+ const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
146
238
  if (!resolvedNoExt) return null;
147
239
  const relImport = normalizeRelativeImport(external_path_default().relative(outDir, resolvedNoExt));
148
240
  const importName = `loader_${loaderIndex++}`;
@@ -160,10 +252,29 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
160
252
  actionName
161
253
  };
162
254
  };
255
+ const getImportNameForSearchContract = async (aliasedNoExtPath, exportName)=>{
256
+ const key = `${exportName}:${aliasedNoExtPath}`;
257
+ const existing = searchContractImportMap.get(key);
258
+ if (existing) return existing;
259
+ const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
260
+ if (!resolvedNoExt) return null;
261
+ const relImport = normalizeRelativeImport(external_path_default().relative(outDir, resolvedNoExt));
262
+ const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
263
+ imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
264
+ searchContractImportMap.set(key, importName);
265
+ return importName;
266
+ };
267
+ const reserveRouteVarName = (preferred)=>{
268
+ let candidate = preferred;
269
+ let suffix = 1;
270
+ while(usedRouteVarNames.has(candidate))candidate = `${preferred}_${suffix++}`;
271
+ usedRouteVarNames.add(candidate);
272
+ return candidate;
273
+ };
163
274
  const createRouteVarName = (route)=>{
164
275
  const id = route.id;
165
276
  const base = id ? makeLegalIdentifier(id) : `r_${routeIndex++}`;
166
- return `route_${base}`;
277
+ return reserveRouteVarName(`route_${base}`);
167
278
  };
168
279
  const buildRoute = async (opts)=>{
169
280
  const { parentVar, route } = opts;
@@ -173,6 +284,9 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
173
284
  const loaderImports = loaderInfo ? await getImportNamesForLoader(loaderInfo.loaderPath, loaderInfo.inline, Boolean(loaderInfo.inline && routeAction === loaderInfo.loaderPath)) : null;
174
285
  const loaderName = loaderImports?.loaderName || null;
175
286
  const actionName = loaderImports?.actionName || null;
287
+ const searchContractInfo = pickRouteSearchContractModules(route);
288
+ const validateSearchName = searchContractInfo.validateSearchPath ? await getImportNameForSearchContract(searchContractInfo.validateSearchPath, 'validateSearch') : null;
289
+ const loaderDepsName = searchContractInfo.loaderDepsPath ? await getImportNameForSearchContract(searchContractInfo.loaderDepsPath, 'loaderDeps') : null;
176
290
  const rawPath = route.path;
177
291
  const hasSplat = 'string' == typeof rawPath && rawPath.includes('*');
178
292
  const routeOpts = [
@@ -186,20 +300,24 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
186
300
  routeOpts.push(`path: ${quote(p)},`);
187
301
  }
188
302
  if (loaderName) routeOpts.push(`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`);
303
+ if (validateSearchName) routeOpts.push(`validateSearch: ${validateSearchName},`);
304
+ if (loaderDepsName) routeOpts.push(`loaderDeps: ${loaderDepsName},`);
189
305
  const staticDataSnippet = createRouteStaticDataSnippet({
190
306
  modernRouteId: route.id,
191
307
  loaderName,
192
308
  actionName
193
309
  });
194
310
  if (staticDataSnippet) routeOpts.push(staticDataSnippet);
195
- statements.push(`const ${varName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
196
311
  const children = route.children;
312
+ const hasChildren = Boolean(children && children.length > 0);
313
+ const routeCtorVarName = hasChildren ? reserveRouteVarName(`${varName}__base`) : varName;
314
+ statements.push(`const ${routeCtorVarName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
197
315
  if (children && children.length > 0) {
198
316
  const childVars = await Promise.all(children.map((child)=>buildRoute({
199
- parentVar: varName,
317
+ parentVar: routeCtorVarName,
200
318
  route: child
201
319
  })));
202
- statements.push(`${varName}.addChildren([${childVars.join(', ')}]);`);
320
+ statements.push(`const ${varName} = ${routeCtorVarName}.addChildren([${childVars.join(', ')}]);`);
203
321
  }
204
322
  return varName;
205
323
  };
@@ -208,17 +326,23 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
208
326
  const rootLoaderImports = rootLoaderInfo?.loaderPath ? await getImportNamesForLoader(rootLoaderInfo.loaderPath, rootLoaderInfo.inline, Boolean(rootLoaderInfo.inline && rootAction === rootLoaderInfo.loaderPath)) : null;
209
327
  const rootLoaderName = rootLoaderImports?.loaderName || null;
210
328
  const rootActionName = rootLoaderImports?.actionName || null;
329
+ const rootSearchContractInfo = rootModern ? pickRouteSearchContractModules(rootModern) : null;
330
+ const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath ? await getImportNameForSearchContract(rootSearchContractInfo.validateSearchPath, 'validateSearch') : null;
331
+ const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath ? await getImportNameForSearchContract(rootSearchContractInfo.loaderDepsPath, 'loaderDeps') : null;
211
332
  const topLevelVars = await Promise.all(topLevel.map((route)=>buildRoute({
212
333
  parentVar: 'rootRoute',
213
334
  route
214
335
  })));
215
336
  const rootOpts = [];
216
337
  if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
338
+ if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
339
+ if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
217
340
  const routerGenTs = `/* eslint-disable */
218
341
  // This file is auto-generated by Modern.js. Do not edit manually.
219
342
 
220
343
  import {
221
344
  createMemoryHistory,
345
+ modernTanstackRouterFastDefaults,
222
346
  createRootRouteWithContext,
223
347
  createRoute,
224
348
  createRouter,
@@ -246,7 +370,7 @@ function isRedirectResponse(res: Response) {
246
370
  }
247
371
 
248
372
  function throwTanstackRedirect(location: string) {
249
- const target = location || '/';
373
+ const target = location.length > 0 ? location : '/';
250
374
  try {
251
375
  void new URL(target);
252
376
  throw redirect({ href: target });
@@ -272,21 +396,87 @@ function createRouteStaticData(opts: {
272
396
  modernRouteAction?: unknown;
273
397
  modernRouteLoader?: unknown;
274
398
  }) {
275
- const staticData: Record<string, unknown> = {};
399
+ const staticData: {
400
+ modernRouteId?: string;
401
+ modernRouteAction?: unknown;
402
+ modernRouteLoader?: unknown;
403
+ } = {};
276
404
 
277
- if (opts.modernRouteId) {
405
+ if (typeof opts.modernRouteId === 'string' && opts.modernRouteId.length > 0) {
278
406
  staticData.modernRouteId = opts.modernRouteId;
279
407
  }
280
408
 
281
- if (opts.modernRouteLoader) {
409
+ if (typeof opts.modernRouteLoader !== 'undefined') {
282
410
  staticData.modernRouteLoader = opts.modernRouteLoader;
283
411
  }
284
412
 
285
- if (opts.modernRouteAction) {
413
+ if (typeof opts.modernRouteAction !== 'undefined') {
286
414
  staticData.modernRouteAction = opts.modernRouteAction;
287
415
  }
288
416
 
289
- return Object.keys(staticData).length > 0 ? staticData : undefined;
417
+ return staticData;
418
+ }
419
+
420
+ function getLoaderSignal(ctx: any): AbortSignal {
421
+ const abortSignal = ctx?.abortController?.signal;
422
+ if (abortSignal instanceof AbortSignal) {
423
+ return abortSignal;
424
+ }
425
+ if (ctx?.signal instanceof AbortSignal) {
426
+ return ctx.signal;
427
+ }
428
+ return new AbortController().signal;
429
+ }
430
+
431
+ function getLoaderHref(ctx: any): string {
432
+ if (typeof ctx?.location === 'string') {
433
+ return ctx.location;
434
+ }
435
+
436
+ const publicHref = ctx?.location?.publicHref;
437
+ if (typeof publicHref === 'string') {
438
+ return publicHref;
439
+ }
440
+
441
+ const href = ctx?.location?.href;
442
+ if (typeof href === 'string') {
443
+ return href;
444
+ }
445
+
446
+ const urlHref = ctx?.location?.url?.href;
447
+ return typeof urlHref === 'string' ? urlHref : '';
448
+ }
449
+
450
+ function getLoaderParams(ctx: any): Record<string, string> {
451
+ return typeof ctx?.params === 'object' && ctx.params !== null ? ctx.params : {};
452
+ }
453
+
454
+ function handleModernLoaderResult<LoaderResult>(result: LoaderResult): LoaderResult {
455
+ if (isResponse(result)) {
456
+ if (isRedirectResponse(result)) {
457
+ const location = result.headers.get('Location') ?? '/';
458
+ throwTanstackRedirect(location);
459
+ }
460
+ if (result.status === 404) {
461
+ throw notFound();
462
+ }
463
+ }
464
+
465
+ return result;
466
+ }
467
+
468
+ function handleModernLoaderError(err: unknown): never {
469
+ if (isResponse(err)) {
470
+ if (isRedirectResponse(err)) {
471
+ const location = err.headers.get('Location') ?? '/';
472
+ throwTanstackRedirect(location);
473
+ }
474
+ if (err.status === 404) {
475
+ throw notFound();
476
+ }
477
+ }
478
+
479
+ throw err;
290
480
  }
291
481
 
292
482
  function modernLoaderToTanstack<TLoader extends (args: any) => any>(
@@ -295,57 +485,31 @@ function modernLoaderToTanstack<TLoader extends (args: any) => any>(
295
485
  ) {
296
486
  type LoaderResult = Awaited<ReturnType<TLoader>>;
297
487
 
298
- return async (ctx: any): Promise<LoaderResult> => {
488
+ return (ctx: any): Promise<LoaderResult> => {
299
489
  try {
300
- const signal: AbortSignal =
301
- ctx?.abortController?.signal ||
302
- ctx?.signal ||
303
- new AbortController().signal;
490
+ const signal = getLoaderSignal(ctx);
304
491
  const baseRequest: Request | undefined =
305
492
  ctx?.context?.request instanceof Request ? ctx.context.request : undefined;
306
493
 
307
- const href =
308
- typeof ctx?.location === 'string'
309
- ? ctx.location
310
- : ctx?.location?.publicHref ||
311
- ctx?.location?.href ||
312
- ctx?.location?.url?.href ||
313
- '';
494
+ const href = getLoaderHref(ctx);
314
495
 
315
- const request = baseRequest
496
+ const request = baseRequest !== undefined
316
497
  ? new Request(baseRequest, { signal })
317
498
  : new Request(href, { signal });
318
499
 
319
- const params = mapParamsForModernLoader(ctx?.params || {}, opts.hasSplat);
320
-
321
- const result = await (modernLoader as any)({
322
- request,
323
- params,
324
- context: ctx?.context?.requestContext,
325
- });
326
-
327
- if (isResponse(result)) {
328
- if (isRedirectResponse(result)) {
329
- const location = result.headers.get('Location') || '/';
330
- throwTanstackRedirect(location);
331
- }
332
- if (result.status === 404) {
333
- throw notFound();
334
- }
335
- }
500
+ const params = mapParamsForModernLoader(getLoaderParams(ctx), opts.hasSplat);
336
501
 
337
- return result as LoaderResult;
502
+ return Promise.resolve(
503
+ (modernLoader as any)({
504
+ request,
505
+ params,
506
+ context: ctx?.context?.requestContext,
507
+ }),
508
+ )
509
+ .then((result: LoaderResult) => handleModernLoaderResult(result))
510
+ .catch(handleModernLoaderError);
338
511
  } catch (err) {
339
- if (isResponse(err)) {
340
- if (isRedirectResponse(err)) {
341
- const location = err.headers.get('Location') || '/';
342
- throwTanstackRedirect(location);
343
- }
344
- if (err.status === 404) {
345
- throw notFound();
346
- }
347
- }
348
- throw err;
512
+ handleModernLoaderError(err);
349
513
  }
350
514
  };
351
515
  }
@@ -366,6 +530,7 @@ ${statements.join('\n\n')}
366
530
  export const routeTree = rootRoute.addChildren([${topLevelVars.join(', ')}]);
367
531
 
368
532
  export const router = createRouter({
533
+ ...modernTanstackRouterFastDefaults,
369
534
  routeTree,
370
535
  history: createMemoryHistory({
371
536
  initialEntries: ['/'],
@@ -377,9 +542,11 @@ export const router = createRouter({
377
542
  routerGenTs
378
543
  };
379
544
  }
545
+ exports.collectCanonicalRoutesForEntry = __webpack_exports__.collectCanonicalRoutesForEntry;
380
546
  exports.generateTanstackRouterTypesSourceForEntry = __webpack_exports__.generateTanstackRouterTypesSourceForEntry;
381
547
  exports.isTanstackRouterFrameworkEnabled = __webpack_exports__.isTanstackRouterFrameworkEnabled;
382
548
  for(var __rspack_i in __webpack_exports__)if (-1 === [
549
+ "collectCanonicalRoutesForEntry",
383
550
  "generateTanstackRouterTypesSourceForEntry",
384
551
  "isTanstackRouterFrameworkEnabled"
385
552
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];