Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ import {
writeRouteTypesManifest,
writeValidatorFile,
writeRouteTypesEntryFile,
writeCacheLifeTypesFile,
} from '../server/lib/router-utils/route-types-utils'
import { Lockfile } from './lockfile'
import {
Expand Down Expand Up @@ -1406,6 +1407,20 @@ export default async function build(
strictRouteTypes: Boolean(config.experimental.strictRouteTypes),
typedRoutes: Boolean(config.typedRoutes),
})

// Generate cache-life types if custom profiles are configured
if (config.cacheLife) {
routeTypesManifest.cacheLifeConfig = config.cacheLife
const cacheLifeTypesFilePath = path.join(
distDir,
'types',
'cache-life.d.ts'
)
await writeCacheLifeTypesFile(
routeTypesManifest,
cacheLifeTypesFilePath
)
}
})

// Turbopack already handles conflicting app and page routes.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CacheLife } from '../../use-cache/cache-life'
import { INFINITE_CACHE } from '../../../lib/constants'
import fs from 'fs'
import path from 'path'

Expand Down Expand Up @@ -52,7 +53,7 @@ function formatTimespanWithSeconds(seconds: undefined | number): string {
if (seconds === undefined) {
return 'default'
}
if (seconds >= 0xfffffffe) {
if (seconds >= INFINITE_CACHE) {
return 'never'
}
const text = seconds + ' seconds'
Expand Down Expand Up @@ -86,7 +87,7 @@ export function generateCacheLifeTypes(cacheLife: {
if (profile.stale === undefined) {
description += `
* This cache may be stale on clients for the default stale time of the scope before checking with the server.`
} else if (profile.stale >= 0xfffffffe) {
} else if (profile.stale >= INFINITE_CACHE) {
description += `
* This cache may be stale on clients indefinitely before checking with the server.`
} else {
Expand All @@ -104,7 +105,7 @@ export function generateCacheLifeTypes(cacheLife: {
if (profile.revalidate === undefined) {
description += `
* It will inherit the default revalidate time of its scope since it does not define its own.`
} else if (profile.revalidate >= 0xfffffffe) {
} else if (profile.revalidate >= INFINITE_CACHE) {
// Nothing to mention.
} else {
description += `
Expand All @@ -113,7 +114,7 @@ export function generateCacheLifeTypes(cacheLife: {
if (profile.expire === undefined) {
description += `
* It will inherit the default expiration time of its scope since it does not define its own.`
} else if (profile.expire >= 0xfffffffe) {
} else if (profile.expire >= INFINITE_CACHE) {
description += `
* It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.`
} else {
Expand Down
11 changes: 11 additions & 0 deletions packages/next/src/server/lib/router-utils/route-types-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
generateValidatorFileStrict,
generateRouteTypesFileStrict,
} from './typegen'
import { writeCacheLifeTypes } from './cache-life-type-utils'
import { tryToParsePath } from '../../../lib/try-to-parse-path'
import {
extractInterceptionRouteInformation,
Expand All @@ -24,6 +25,7 @@ import {
} from '../../../shared/lib/entry-constants'
import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep'
import type { RouteInfo, SlotInfo } from '../../../build/file-classifier'
import type { CacheLife } from '../../use-cache/cache-life'

// Internal route info with extracted params for the manifest
interface ManifestRouteInfo {
Expand All @@ -48,6 +50,8 @@ export interface RouteTypesManifest {
pageApiRoutes: Set<string>
/** Direct mapping from file paths to routes for validation */
filePathToRoute: Map<string, string>
/** Cache life configuration for generating cache-life.d.ts */
cacheLifeConfig?: { [profile: string]: CacheLife }
}

// Convert a custom-route source string (`/blog/:slug`, `/docs/:path*`, ...)
Expand Down Expand Up @@ -445,3 +449,10 @@ export async function writeRouteTypesEntryFile(

await fs.promises.writeFile(entryFilePath, lines.join('\n'))
}

export async function writeCacheLifeTypesFile(
manifest: RouteTypesManifest,
filePath: string
) {
writeCacheLifeTypes(manifest.cacheLifeConfig, filePath)
}
Comment on lines +453 to +458
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The writeCacheLifeTypesFile function is declared as async but does not await anything. The underlying writeCacheLifeTypes function uses synchronous file operations (fs.writeFileSync). This creates an inconsistency with other similar functions in this file like writeRouteTypesManifest and writeValidatorFile which use fs.promises.writeFile and are truly async.

Either:

  1. Remove the async keyword from writeCacheLifeTypesFile (and remove await when calling it in build/index.ts), OR
  2. Update writeCacheLifeTypes in cache-life-type-utils.ts to use async file operations and await it here

Option 2 would be more consistent with the other write functions in this file.

Copilot uses AI. Check for mistakes.
Loading