AbdulElahGwaith's picture
Upload folder using huggingface_hub
b91e262 verified
import type { WorkStore } from '../app-render/work-async-storage.external'
import type { IncrementalCache } from '../lib/incremental-cache'
import type { RenderOpts } from '../app-render/types'
import type { FetchMetric } from '../base-http'
import type { RequestLifecycleOpts } from '../base-server'
import type { AppSegmentConfig } from '../../build/segment-config/app/app-segment-config'
import type { CacheLife } from '../use-cache/cache-life'
import { AfterContext } from '../after/after-context'
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
import { createLazyResult, type LazyResult } from '../lib/lazy-result'
import { getCacheHandlerEntries } from '../use-cache/handlers'
import { createSnapshot } from '../app-render/async-local-storage'
export type WorkStoreContext = {
/**
* The page that is being rendered. This relates to the path to the page file.
*/
page: string
isPrefetchRequest?: boolean
nonce?: string
renderOpts: {
cacheLifeProfiles?: { [profile: string]: CacheLife }
incrementalCache?: IncrementalCache
isOnDemandRevalidate?: boolean
cacheComponents: boolean
fetchCache?: AppSegmentConfig['fetchCache']
isPossibleServerAction?: boolean
pendingWaitUntil?: Promise<any>
experimental: Pick<
RenderOpts['experimental'],
'isRoutePPREnabled' | 'authInterrupts'
>
/**
* Fetch metrics attached in patch-fetch.ts
**/
fetchMetrics?: FetchMetric[]
/**
* A hack around accessing the store value outside the context of the
* request.
*
* @internal
* @deprecated should only be used as a temporary workaround
*/
// TODO: remove this when we resolve accessing the store outside the execution context
store?: WorkStore
} & Pick<
// Pull some properties from RenderOpts so that the docs are also
// mirrored.
RenderOpts,
| 'assetPrefix'
| 'supportsDynamicResponse'
| 'shouldWaitOnAllReady'
| 'nextExport'
| 'isDraftMode'
| 'isDebugDynamicAccesses'
| 'dev'
| 'hasReadableErrorStacks'
> &
RequestLifecycleOpts &
Partial<Pick<RenderOpts, 'reactLoadableManifest'>>
/**
* The build ID of the current build.
*/
buildId: string
// Tags that were previously revalidated (e.g. by a redirecting server action)
// and have already been sent to cache handlers.
previouslyRevalidatedTags: string[]
}
export function createWorkStore({
page,
renderOpts,
isPrefetchRequest,
buildId,
previouslyRevalidatedTags,
nonce,
}: WorkStoreContext): WorkStore {
/**
* Rules of Static & Dynamic HTML:
*
* 1.) We must generate static HTML unless the caller explicitly opts
* in to dynamic HTML support.
*
* 2.) If dynamic HTML support is requested, we must honor that request
* or throw an error. It is the sole responsibility of the caller to
* ensure they aren't e.g. requesting dynamic HTML for a static page.
*
* 3.) If the request is in draft mode, we must generate dynamic HTML.
*
* 4.) If the request is a server action, we must generate dynamic HTML.
*
* These rules help ensure that other existing features like request caching,
* coalescing, and ISR continue working as intended.
*/
const isStaticGeneration =
!renderOpts.shouldWaitOnAllReady &&
!renderOpts.supportsDynamicResponse &&
!renderOpts.isDraftMode &&
!renderOpts.isPossibleServerAction
const isDevelopment = renderOpts.dev ?? false
const shouldTrackFetchMetrics =
isDevelopment ||
// The only times we want to track fetch metrics outside of development is
// when we are performing a static generation and we either are in debug
// mode, or tracking fetch metrics was specifically opted into.
(isStaticGeneration &&
(!!process.env.NEXT_DEBUG_BUILD ||
process.env.NEXT_SSG_FETCH_METRICS === '1'))
const store: WorkStore = {
isStaticGeneration,
page,
route: normalizeAppPath(page),
incrementalCache:
// we fallback to a global incremental cache for edge-runtime locally
// so that it can access the fs cache without mocks
renderOpts.incrementalCache || (globalThis as any).__incrementalCache,
cacheLifeProfiles: renderOpts.cacheLifeProfiles,
isBuildTimePrerendering: renderOpts.nextExport,
hasReadableErrorStacks: renderOpts.hasReadableErrorStacks,
fetchCache: renderOpts.fetchCache,
isOnDemandRevalidate: renderOpts.isOnDemandRevalidate,
isDraftMode: renderOpts.isDraftMode,
isPrefetchRequest,
buildId,
reactLoadableManifest: renderOpts?.reactLoadableManifest || {},
assetPrefix: renderOpts?.assetPrefix || '',
nonce,
afterContext: createAfterContext(renderOpts),
cacheComponentsEnabled: renderOpts.cacheComponents,
dev: isDevelopment,
previouslyRevalidatedTags,
refreshTagsByCacheKind: createRefreshTagsByCacheKind(),
runInCleanSnapshot: createSnapshot(),
shouldTrackFetchMetrics,
reactServerErrorsByDigest: new Map(),
}
// TODO: remove this when we resolve accessing the store outside the execution context
renderOpts.store = store
return store
}
function createAfterContext(renderOpts: RequestLifecycleOpts): AfterContext {
const { waitUntil, onClose, onAfterTaskError } = renderOpts
return new AfterContext({
waitUntil,
onClose,
onTaskError: onAfterTaskError,
})
}
/**
* Creates a map with lazy results that refresh tags for the respective cache
* kind when they're awaited for the first time.
*/
function createRefreshTagsByCacheKind(): Map<string, LazyResult<void>> {
const refreshTagsByCacheKind = new Map<string, LazyResult<void>>()
const cacheHandlers = getCacheHandlerEntries()
if (cacheHandlers) {
for (const [kind, cacheHandler] of cacheHandlers) {
if ('refreshTags' in cacheHandler) {
refreshTagsByCacheKind.set(
kind,
createLazyResult(async () => cacheHandler.refreshTags())
)
}
}
}
return refreshTagsByCacheKind
}