next
Version:
The React Framework
146 lines (145 loc) • 6.55 kB
TypeScript
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 { ResolvedCacheLifeProfiles } from '../config-shared';
import type { SharedCacheResult } from '../use-cache/use-cache-wrapper';
import type { ValidationLevel } from '../config-shared';
import { workAsyncStorageInstance } from './work-async-storage-instance';
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: ResolvedCacheLifeProfiles;
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>>;
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.
*/
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>>;
/**
* Set by the dev-server's hang-detection probe worker (see
* `use-cache-probe-worker.ts`) to switch `cache()` into a one-shot fill
* path: run `generateCacheEntry` as for a cold fill, drain the resulting
* stream, return. No cache-handler or resume-data-cache I/O, no
* intra-request leader election — the probe just needs to learn whether
* the body completes in module-scope isolation.
*/
readonly useCacheProbeMode?: {
/**
* Max wall time the probe fill may take. `cache()` enforces this with
* `UseCacheTimeoutError`, which the probe worker translates to
* `{ outcome: 'hung' }` for the parent process.
*/
readonly timeoutMs: number;
};
isDraftMode?: boolean;
isUnstableNoStore?: boolean;
isPrefetchRequest?: boolean;
/**
* Dev-only request identity used by local request insights. requestId
* identifies one server request, while htmlRequestId groups requests that
* originated from the same browser page.
*/
requestId?: string;
htmlRequestId?: string;
/**
* 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;
validationLevel: ValidationLevel;
/**
* Pages, other than the one being rendered, whose client reference manifest
* supplied a client reference for this render. Only populated by the dev
* server, where React's I/O tracking can carry a reference from another page
* into this render, which `createProxiedClientReferenceManifest` resolves by
* searching the other pages' manifests. The dev validation worker rebuilds
* that registry in its own thread from the route it validates, so it relies
* on this to know which other manifests to register.
*/
additionalClientReferenceManifestPages?: Set<string>;
/**
* 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 };