diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index d7c7cd3ba57a2d..cb774ede9cde6b 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -218,6 +218,7 @@ import { writeRouteTypesManifest, writeValidatorFile, writeRouteTypesEntryFile, + writeCacheLifeTypesFile, } from '../server/lib/router-utils/route-types-utils' import { Lockfile } from './lockfile' import { @@ -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. diff --git a/packages/next/src/server/lib/router-utils/cache-life-type-utils.ts b/packages/next/src/server/lib/router-utils/cache-life-type-utils.ts index 89b21c210c4de8..434f1b7eab412e 100644 --- a/packages/next/src/server/lib/router-utils/cache-life-type-utils.ts +++ b/packages/next/src/server/lib/router-utils/cache-life-type-utils.ts @@ -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' @@ -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' @@ -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 { @@ -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 += ` @@ -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 { diff --git a/packages/next/src/server/lib/router-utils/route-types-utils.ts b/packages/next/src/server/lib/router-utils/route-types-utils.ts index b68aaddefe1607..fb11a30e17a82c 100644 --- a/packages/next/src/server/lib/router-utils/route-types-utils.ts +++ b/packages/next/src/server/lib/router-utils/route-types-utils.ts @@ -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, @@ -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 { @@ -48,6 +50,8 @@ export interface RouteTypesManifest { pageApiRoutes: Set /** Direct mapping from file paths to routes for validation */ filePathToRoute: Map + /** Cache life configuration for generating cache-life.d.ts */ + cacheLifeConfig?: { [profile: string]: CacheLife } } // Convert a custom-route source string (`/blog/:slug`, `/docs/:path*`, ...) @@ -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) +}