| import { InvariantError } from '../../shared/lib/invariant-error' |
| import { |
| postponeWithTracking, |
| throwToInterruptStaticGeneration, |
| } from '../app-render/dynamic-rendering' |
| import { |
| workAsyncStorage, |
| type WorkStore, |
| } from '../app-render/work-async-storage.external' |
| import { |
| workUnitAsyncStorage, |
| type PrerenderStoreLegacy, |
| type PrerenderStorePPR, |
| type StaticPrerenderStore, |
| } from '../app-render/work-unit-async-storage.external' |
| import { makeHangingPromise } from '../dynamic-rendering-utils' |
| import type { ParamValue } from './params' |
| import { describeStringPropertyAccess } from '../../shared/lib/utils/reflect-utils' |
| import { actionAsyncStorage } from '../app-render/action-async-storage.external' |
|
|
| |
| |
| |
| |
| export function getRootParam(paramName: string): Promise<ParamValue> { |
| const apiName = `\`import('next/root-params').${paramName}()\`` |
|
|
| const workStore = workAsyncStorage.getStore() |
| if (!workStore) { |
| throw new InvariantError(`Missing workStore in ${apiName}`) |
| } |
|
|
| const workUnitStore = workUnitAsyncStorage.getStore() |
| if (!workUnitStore) { |
| throw new Error( |
| `Route ${workStore.route} used ${apiName} outside of a Server Component. This is not allowed.` |
| ) |
| } |
|
|
| const actionStore = actionAsyncStorage.getStore() |
| if (actionStore) { |
| if (actionStore.isAppRoute) { |
| |
| throw new Error( |
| `Route ${workStore.route} used ${apiName} inside a Route Handler. Support for this API in Route Handlers is planned for a future version of Next.js.` |
| ) |
| } |
| if (actionStore.isAction && workUnitStore.phase === 'action') { |
| |
| |
| |
| |
| throw new Error( |
| `${apiName} was used inside a Server Action. This is not supported. Functions from 'next/root-params' can only be called in the context of a route.` |
| ) |
| } |
| } |
|
|
| switch (workUnitStore.type) { |
| case 'unstable-cache': |
| case 'cache': { |
| throw new Error( |
| `Route ${workStore.route} used ${apiName} inside \`"use cache"\` or \`unstable_cache\`. Support for this API inside cache scopes is planned for a future version of Next.js.` |
| ) |
| } |
| case 'prerender': |
| case 'prerender-client': |
| case 'prerender-ppr': |
| case 'prerender-legacy': { |
| return createPrerenderRootParamPromise( |
| paramName, |
| workStore, |
| workUnitStore, |
| apiName |
| ) |
| } |
| case 'private-cache': |
| case 'prerender-runtime': |
| case 'request': { |
| break |
| } |
| default: { |
| workUnitStore satisfies never |
| } |
| } |
| return Promise.resolve(workUnitStore.rootParams[paramName]) |
| } |
|
|
| function createPrerenderRootParamPromise( |
| paramName: string, |
| workStore: WorkStore, |
| prerenderStore: StaticPrerenderStore, |
| apiName: string |
| ): Promise<ParamValue> { |
| switch (prerenderStore.type) { |
| case 'prerender-client': { |
| throw new InvariantError( |
| `${apiName} must not be used within a client component. Next.js should be preventing ${apiName} from being included in client components statically, but did not in this case.` |
| ) |
| } |
| case 'prerender': |
| case 'prerender-legacy': |
| case 'prerender-ppr': |
| default: |
| } |
|
|
| const underlyingParams = prerenderStore.rootParams |
|
|
| switch (prerenderStore.type) { |
| case 'prerender': { |
| |
| |
| if ( |
| prerenderStore.fallbackRouteParams && |
| prerenderStore.fallbackRouteParams.has(paramName) |
| ) { |
| return makeHangingPromise<ParamValue>( |
| prerenderStore.renderSignal, |
| workStore.route, |
| apiName |
| ) |
| } |
| break |
| } |
| case 'prerender-ppr': { |
| |
| |
| if ( |
| prerenderStore.fallbackRouteParams && |
| prerenderStore.fallbackRouteParams.has(paramName) |
| ) { |
| return makeErroringRootParamPromise( |
| paramName, |
| workStore, |
| prerenderStore, |
| apiName |
| ) |
| } |
| break |
| } |
| case 'prerender-legacy': { |
| |
| break |
| } |
| default: { |
| prerenderStore satisfies never |
| } |
| } |
|
|
| |
| return Promise.resolve(underlyingParams[paramName]) |
| } |
|
|
| |
| async function makeErroringRootParamPromise( |
| paramName: string, |
| workStore: WorkStore, |
| prerenderStore: PrerenderStorePPR | PrerenderStoreLegacy, |
| apiName: string |
| ): Promise<ParamValue> { |
| const expression = describeStringPropertyAccess(apiName, paramName) |
| |
| |
| |
| |
| switch (prerenderStore.type) { |
| case 'prerender-ppr': { |
| return postponeWithTracking( |
| workStore.route, |
| expression, |
| prerenderStore.dynamicTracking |
| ) |
| } |
| case 'prerender-legacy': { |
| return throwToInterruptStaticGeneration( |
| expression, |
| workStore, |
| prerenderStore |
| ) |
| } |
| default: { |
| prerenderStore satisfies never |
| } |
| } |
| } |
|
|