import type { AsyncLocalStorage } from 'async_hooks'
import type { IncrementalCache } from '../lib/incremental-cache'
import type { FetchMetrics } from '../base-http'
import type { DeepReadonly } from '../../shared/lib/deep-readonly'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'
import type { AfterContext } from '../after/after-context'
import type { CacheLife } from '../use-cache/cache-life'
import type { SharedCacheResult } from '../use-cache/use-cache-wrapper'
// Share the instance module in the next-shared layer
import { workAsyncStorageInstance } from './work-async-storage-instance' with { 'turbopack-transition': 'next-shared' }
import type { LazyResult } from '../lib/lazy-result'
import type { DigestedError } from './create-error-handler'
import type { ActionRevalidationKind } from '../../shared/lib/action-revalidation-kind'
export interface WorkStore {
readonly isStaticGeneration: boolean
/**
* The page that is being rendered. This relates to the path to the page file.
*/
readonly page: string
/**
* The route that is being rendered. This is the page property without the
* trailing `/page` or `/route` suffix.
*/
readonly route: string
readonly incrementalCache?: IncrementalCache
readonly cacheLifeProfiles?: { [profile: string]: CacheLife }
readonly useCacheTimeout: number
readonly staticPageGenerationTimeout: number
readonly isOnDemandRevalidate?: boolean
readonly isBuildTimePrerendering?: boolean
forceDynamic?: boolean
fetchCache?: AppSegmentConfig['fetchCache']
forceStatic?: boolean
dynamicShouldError?: boolean
pendingRevalidates?: Record<string, Promise<any>>
pendingRevalidateWrites?: Array<Promise<void>> // This is like pendingRevalidates but isn't used for deduping.
readonly afterContext: AfterContext
dynamicUsageDescription?: string
dynamicUsageStack?: string
/**
* Invalid dynamic usage errors might be caught in userland. We attach them to
* the work store to ensure we can still fail the build, or show en error in
* dev mode.
*/
// TODO: Collect an array of errors, and throw as AggregateError when
// `serializeError` and the Dev Overlay support it.
invalidDynamicUsageError?: Error
nextFetchId?: number
pathWasRevalidated?: ActionRevalidationKind
/**
* Tags that were revalidated during the current request. They need to be sent
* to cache handlers to propagate their revalidation.
*/
pendingRevalidatedTags?: Array<{
tag: string
profile?: string | { stale?: number; revalidate?: number; expire?: number }
}>
/**
* Tags that were previously revalidated (e.g. by a redirecting server action)
* and have already been sent to cache handlers. Retrieved cache entries that
* include any of these tags must be discarded.
*/
readonly previouslyRevalidatedTags: readonly string[]
/**
* This map contains lazy results so that we can evaluate them when the first
* cache entry is read. It allows us to skip refreshing tags if no caches are
* read at all.
*/
readonly refreshTagsByCacheKind: Map<string, LazyResult<void>>
fetchMetrics?: FetchMetrics
shouldTrackFetchMetrics: boolean
/**
* Tracks pending `"use cache"` invocations within the current request scope,
* keyed by the serialized cache key (coarse key). Used for intra-request
* deduplication: when multiple components call the same cache function within
* a single request, only the first one runs (cache handler lookup +
* generation), and joiners tee its result stream.
* Root params are identical within a request, so the coarse key is sufficient.
*/
pendingCacheInvocations?: Map<string, Promise<SharedCacheResult>>
isDraftMode?: boolean
isUnstableNoStore?: boolean
isPrefetchRequest?: boolean
/**
* This only exists because it's needed in use-cache-wrapper
*/
deploymentId: string
/**
* Prefer `sharedContext.buildId` instead. This only exists because it's needed in use-cache-wrapper
*/
buildId: string
readonly reactLoadableManifest?: DeepReadonly<
Record<string, { files: string[] }>
>
readonly assetPrefix?: string
readonly nonce?: string
cacheComponentsEnabled: boolean
/**
* Run the given function inside a clean AsyncLocalStorage snapshot. This is
* useful when generating cache entries, to ensure that the cache generation
* cannot read anything from the context we're currently executing in, which
* might include request-specific things like `cookies()` inside a
* `React.cache()`.
*/
runInCleanSnapshot: <R, TArgs extends any[]>(
fn: (...args: TArgs) => R,
...args: TArgs
) => R
reactServerErrorsByDigest: Map<string, DigestedError>
}
export type WorkAsyncStorage = AsyncLocalStorage<WorkStore>
export { workAsyncStorageInstance as workAsyncStorage }