@@ -223,6 +223,8 @@ import {
223
223
createRouteTypesManifest ,
224
224
writeRouteTypesManifest ,
225
225
writeValidatorFile ,
226
+ writeServerTypesFile ,
227
+ writeCacheLifeTypesFile ,
226
228
} from '../server/lib/router-utils/route-types-utils'
227
229
228
230
type Fallback = null | boolean | string
@@ -1340,6 +1342,34 @@ export default async function build(
1340
1342
layoutRoutes = processLayoutRoutes ( mappedAppLayouts , dir )
1341
1343
}
1342
1344
1345
+ // Collect layout parameters for root params extraction
1346
+ // Find the root layout (shortest path with dynamic segments)
1347
+ const collectedRootParams : Record < string , string [ ] > = { }
1348
+
1349
+ // Find layouts that could be root layouts (have dynamic segments)
1350
+ const layoutsWithParams = layoutRoutes
1351
+ . map ( ( { route } ) => {
1352
+ const foundParams = Array . from (
1353
+ route . matchAll ( / \[ ( .* ?) \] / g) ,
1354
+ ( match ) => match [ 1 ]
1355
+ )
1356
+ return { route, params : foundParams }
1357
+ } )
1358
+ . filter ( ( { params } ) => params . length > 0 )
1359
+
1360
+ // Sort by path depth (ascending) to find the shallowest layout with params
1361
+ layoutsWithParams . sort ( ( a , b ) => {
1362
+ const aDepth = a . route . split ( '/' ) . length
1363
+ const bDepth = b . route . split ( '/' ) . length
1364
+ return aDepth - bDepth
1365
+ } )
1366
+
1367
+ // The root layout is the shallowest layout with dynamic segments
1368
+ if ( layoutsWithParams . length > 0 ) {
1369
+ const rootLayout = layoutsWithParams [ 0 ]
1370
+ collectedRootParams [ rootLayout . route ] = rootLayout . params
1371
+ }
1372
+
1343
1373
const routeTypesManifest = await createRouteTypesManifest ( {
1344
1374
dir,
1345
1375
pageRoutes,
@@ -1352,8 +1382,35 @@ export default async function build(
1352
1382
rewrites : config . rewrites ,
1353
1383
} )
1354
1384
1385
+ // Add collected root params and cache life config to manifest
1386
+ routeTypesManifest . collectedRootParams = collectedRootParams
1387
+ routeTypesManifest . cacheLifeConfig = config . experimental ?. cacheLife
1388
+
1355
1389
await writeRouteTypesManifest ( routeTypesManifest , routeTypesFilePath )
1356
1390
await writeValidatorFile ( routeTypesManifest , validatorFilePath )
1391
+
1392
+ // Generate server types if we have root params
1393
+ if ( Object . keys ( collectedRootParams ) . length > 0 ) {
1394
+ const serverTypesFilePath = path . join (
1395
+ distDir ,
1396
+ 'types' ,
1397
+ 'server.d.ts'
1398
+ )
1399
+ await writeServerTypesFile ( routeTypesManifest , serverTypesFilePath )
1400
+ }
1401
+
1402
+ // Generate cache life types if we have cache life config
1403
+ if ( config . experimental ?. cacheLife ) {
1404
+ const cacheLifeTypesFilePath = path . join (
1405
+ distDir ,
1406
+ 'types' ,
1407
+ 'cache-life.d.ts'
1408
+ )
1409
+ await writeCacheLifeTypesFile (
1410
+ routeTypesManifest ,
1411
+ cacheLifeTypesFilePath
1412
+ )
1413
+ }
1357
1414
} )
1358
1415
1359
1416
// Turbopack already handles conflicting app and page routes.
0 commit comments