Spaces:
Sleeping
Sleeping
| import { workAsyncStorage } from '../app-render/work-async-storage.external'; | |
| import { ReflectAdapter } from '../web/spec-extension/adapters/reflect'; | |
| import { throwToInterruptStaticGeneration, postponeWithTracking, trackSynchronousRequestDataAccessInDev, delayUntilRuntimeStage } from '../app-render/dynamic-rendering'; | |
| import { workUnitAsyncStorage, throwInvariantForMissingStore } from '../app-render/work-unit-async-storage.external'; | |
| import { InvariantError } from '../../shared/lib/invariant-error'; | |
| import { describeStringPropertyAccess, wellKnownProperties } from '../../shared/lib/utils/reflect-utils'; | |
| import { makeDevtoolsIOAwarePromise, makeHangingPromise } from '../dynamic-rendering-utils'; | |
| import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'; | |
| import { dynamicAccessAsyncStorage } from '../app-render/dynamic-access-async-storage.external'; | |
| export function createParamsFromClient(underlyingParams, workStore) { | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender': | |
| case 'prerender-client': | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| return createStaticPrerenderParams(underlyingParams, workStore, workUnitStore); | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| throw Object.defineProperty(new InvariantError('createParamsFromClient should not be called in cache contexts.'), "__NEXT_ERROR_CODE", { | |
| value: "E736", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'prerender-runtime': | |
| throw Object.defineProperty(new InvariantError('createParamsFromClient should not be called in a runtime prerender.'), "__NEXT_ERROR_CODE", { | |
| value: "E770", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'request': | |
| if (process.env.NODE_ENV === 'development') { | |
| // Semantically we only need the dev tracking when running in `next dev` | |
| // but since you would never use next dev with production NODE_ENV we use this | |
| // as a proxy so we can statically exclude this code from production builds. | |
| const devFallbackParams = workUnitStore.devFallbackParams; | |
| return createRenderParamsInDev(underlyingParams, devFallbackParams, workStore); | |
| } else { | |
| return createRenderParamsInProd(underlyingParams); | |
| } | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| throwInvariantForMissingStore(); | |
| } | |
| export const createServerParamsForMetadata = createServerParamsForServerSegment; | |
| // routes always runs in RSC context so it is equivalent to a Server Page Component | |
| export function createServerParamsForRoute(underlyingParams, workStore) { | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender': | |
| case 'prerender-client': | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| return createStaticPrerenderParams(underlyingParams, workStore, workUnitStore); | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| throw Object.defineProperty(new InvariantError('createServerParamsForRoute should not be called in cache contexts.'), "__NEXT_ERROR_CODE", { | |
| value: "E738", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'prerender-runtime': | |
| return createRuntimePrerenderParams(underlyingParams, workUnitStore); | |
| case 'request': | |
| if (process.env.NODE_ENV === 'development') { | |
| // Semantically we only need the dev tracking when running in `next dev` | |
| // but since you would never use next dev with production NODE_ENV we use this | |
| // as a proxy so we can statically exclude this code from production builds. | |
| const devFallbackParams = workUnitStore.devFallbackParams; | |
| return createRenderParamsInDev(underlyingParams, devFallbackParams, workStore); | |
| } else { | |
| return createRenderParamsInProd(underlyingParams); | |
| } | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| throwInvariantForMissingStore(); | |
| } | |
| export function createServerParamsForServerSegment(underlyingParams, workStore) { | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender': | |
| case 'prerender-client': | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| return createStaticPrerenderParams(underlyingParams, workStore, workUnitStore); | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| throw Object.defineProperty(new InvariantError('createServerParamsForServerSegment should not be called in cache contexts.'), "__NEXT_ERROR_CODE", { | |
| value: "E743", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'prerender-runtime': | |
| return createRuntimePrerenderParams(underlyingParams, workUnitStore); | |
| case 'request': | |
| if (process.env.NODE_ENV === 'development') { | |
| // Semantically we only need the dev tracking when running in `next dev` | |
| // but since you would never use next dev with production NODE_ENV we use this | |
| // as a proxy so we can statically exclude this code from production builds. | |
| const devFallbackParams = workUnitStore.devFallbackParams; | |
| return createRenderParamsInDev(underlyingParams, devFallbackParams, workStore); | |
| } else { | |
| return createRenderParamsInProd(underlyingParams); | |
| } | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| throwInvariantForMissingStore(); | |
| } | |
| export function createPrerenderParamsForClientSegment(underlyingParams) { | |
| const workStore = workAsyncStorage.getStore(); | |
| if (!workStore) { | |
| throw Object.defineProperty(new InvariantError('Missing workStore in createPrerenderParamsForClientSegment'), "__NEXT_ERROR_CODE", { | |
| value: "E773", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'prerender': | |
| case 'prerender-client': | |
| const fallbackParams = workUnitStore.fallbackRouteParams; | |
| if (fallbackParams) { | |
| for(let key in underlyingParams){ | |
| if (fallbackParams.has(key)) { | |
| // This params object has one or more fallback params, so we need | |
| // to consider the awaiting of this params object "dynamic". Since | |
| // we are in cacheComponents mode we encode this as a promise that never | |
| // resolves. | |
| return makeHangingPromise(workUnitStore.renderSignal, workStore.route, '`params`'); | |
| } | |
| } | |
| } | |
| break; | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| throw Object.defineProperty(new InvariantError('createPrerenderParamsForClientSegment should not be called in cache contexts.'), "__NEXT_ERROR_CODE", { | |
| value: "E734", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| case 'prerender-runtime': | |
| case 'request': | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| // We're prerendering in a mode that does not abort. We resolve the promise without | |
| // any tracking because we're just transporting a value from server to client where the tracking | |
| // will be applied. | |
| return Promise.resolve(underlyingParams); | |
| } | |
| function createStaticPrerenderParams(underlyingParams, workStore, prerenderStore) { | |
| switch(prerenderStore.type){ | |
| case 'prerender': | |
| case 'prerender-client': | |
| { | |
| const fallbackParams = prerenderStore.fallbackRouteParams; | |
| if (fallbackParams) { | |
| for(const key in underlyingParams){ | |
| if (fallbackParams.has(key)) { | |
| // This params object has one or more fallback params, so we need | |
| // to consider the awaiting of this params object "dynamic". Since | |
| // we are in cacheComponents mode we encode this as a promise that never | |
| // resolves. | |
| return makeHangingParams(underlyingParams, workStore, prerenderStore); | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| case 'prerender-ppr': | |
| { | |
| const fallbackParams = prerenderStore.fallbackRouteParams; | |
| if (fallbackParams) { | |
| for(const key in underlyingParams){ | |
| if (fallbackParams.has(key)) { | |
| return makeErroringExoticParams(underlyingParams, fallbackParams, workStore, prerenderStore); | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| case 'prerender-legacy': | |
| break; | |
| default: | |
| prerenderStore; | |
| } | |
| if (process.env.__NEXT_CACHE_COMPONENTS) { | |
| return makeUntrackedParams(underlyingParams); | |
| } else { | |
| return makeUntrackedExoticParams(underlyingParams); | |
| } | |
| } | |
| function createRuntimePrerenderParams(underlyingParams, workUnitStore) { | |
| return delayUntilRuntimeStage(workUnitStore, process.env.__NEXT_CACHE_COMPONENTS ? makeUntrackedParams(underlyingParams) : makeUntrackedExoticParams(underlyingParams)); | |
| } | |
| function createRenderParamsInProd(underlyingParams) { | |
| if (process.env.__NEXT_CACHE_COMPONENTS) { | |
| return makeUntrackedParams(underlyingParams); | |
| } | |
| return makeUntrackedExoticParams(underlyingParams); | |
| } | |
| function createRenderParamsInDev(underlyingParams, devFallbackParams, workStore) { | |
| let hasFallbackParams = false; | |
| if (devFallbackParams) { | |
| for(let key in underlyingParams){ | |
| if (devFallbackParams.has(key)) { | |
| hasFallbackParams = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (process.env.__NEXT_CACHE_COMPONENTS) { | |
| return makeDynamicallyTrackedParamsWithDevWarnings(underlyingParams, hasFallbackParams, workStore); | |
| } | |
| return makeDynamicallyTrackedExoticParamsWithDevWarnings(underlyingParams, hasFallbackParams, workStore); | |
| } | |
| const CachedParams = new WeakMap(); | |
| const fallbackParamsProxyHandler = { | |
| get: function get(target, prop, receiver) { | |
| if (prop === 'then' || prop === 'catch' || prop === 'finally') { | |
| const originalMethod = ReflectAdapter.get(target, prop, receiver); | |
| return ({ | |
| [prop]: (...args)=>{ | |
| const store = dynamicAccessAsyncStorage.getStore(); | |
| if (store) { | |
| store.abortController.abort(Object.defineProperty(new Error(`Accessed fallback \`params\` during prerendering.`), "__NEXT_ERROR_CODE", { | |
| value: "E691", | |
| enumerable: false, | |
| configurable: true | |
| })); | |
| } | |
| return new Proxy(originalMethod.apply(target, args), fallbackParamsProxyHandler); | |
| } | |
| })[prop]; | |
| } | |
| return ReflectAdapter.get(target, prop, receiver); | |
| } | |
| }; | |
| function makeHangingParams(underlyingParams, workStore, prerenderStore) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| const promise = new Proxy(makeHangingPromise(prerenderStore.renderSignal, workStore.route, '`params`'), fallbackParamsProxyHandler); | |
| CachedParams.set(underlyingParams, promise); | |
| return promise; | |
| } | |
| function makeErroringExoticParams(underlyingParams, fallbackParams, workStore, prerenderStore) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| const augmentedUnderlying = { | |
| ...underlyingParams | |
| }; | |
| // We don't use makeResolvedReactPromise here because params | |
| // supports copying with spread and we don't want to unnecessarily | |
| // instrument the promise with spreadable properties of ReactPromise. | |
| const promise = Promise.resolve(augmentedUnderlying); | |
| CachedParams.set(underlyingParams, promise); | |
| Object.keys(underlyingParams).forEach((prop)=>{ | |
| if (wellKnownProperties.has(prop)) { | |
| // These properties cannot be shadowed because they need to be the | |
| // true underlying value for Promises to work correctly at runtime | |
| } else { | |
| if (fallbackParams.has(prop)) { | |
| Object.defineProperty(augmentedUnderlying, prop, { | |
| get () { | |
| const expression = describeStringPropertyAccess('params', prop); | |
| // In most dynamic APIs we also throw if `dynamic = "error"` however | |
| // for params is only dynamic when we're generating a fallback shell | |
| // and even when `dynamic = "error"` we still support generating dynamic | |
| // fallback shells | |
| // TODO remove this comment when cacheComponents is the default since there | |
| // will be no `dynamic = "error"` | |
| if (prerenderStore.type === 'prerender-ppr') { | |
| // PPR Prerender (no cacheComponents) | |
| postponeWithTracking(workStore.route, expression, prerenderStore.dynamicTracking); | |
| } else { | |
| // Legacy Prerender | |
| throwToInterruptStaticGeneration(expression, workStore, prerenderStore); | |
| } | |
| }, | |
| enumerable: true | |
| }); | |
| Object.defineProperty(promise, prop, { | |
| get () { | |
| const expression = describeStringPropertyAccess('params', prop); | |
| // In most dynamic APIs we also throw if `dynamic = "error"` however | |
| // for params is only dynamic when we're generating a fallback shell | |
| // and even when `dynamic = "error"` we still support generating dynamic | |
| // fallback shells | |
| // TODO remove this comment when cacheComponents is the default since there | |
| // will be no `dynamic = "error"` | |
| if (prerenderStore.type === 'prerender-ppr') { | |
| // PPR Prerender (no cacheComponents) | |
| postponeWithTracking(workStore.route, expression, prerenderStore.dynamicTracking); | |
| } else { | |
| // Legacy Prerender | |
| throwToInterruptStaticGeneration(expression, workStore, prerenderStore); | |
| } | |
| }, | |
| set (newValue) { | |
| Object.defineProperty(promise, prop, { | |
| value: newValue, | |
| writable: true, | |
| enumerable: true | |
| }); | |
| }, | |
| enumerable: true, | |
| configurable: true | |
| }); | |
| } else { | |
| ; | |
| promise[prop] = underlyingParams[prop]; | |
| } | |
| } | |
| }); | |
| return promise; | |
| } | |
| function makeUntrackedExoticParams(underlyingParams) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| // We don't use makeResolvedReactPromise here because params | |
| // supports copying with spread and we don't want to unnecessarily | |
| // instrument the promise with spreadable properties of ReactPromise. | |
| const promise = Promise.resolve(underlyingParams); | |
| CachedParams.set(underlyingParams, promise); | |
| Object.keys(underlyingParams).forEach((prop)=>{ | |
| if (wellKnownProperties.has(prop)) { | |
| // These properties cannot be shadowed because they need to be the | |
| // true underlying value for Promises to work correctly at runtime | |
| } else { | |
| ; | |
| promise[prop] = underlyingParams[prop]; | |
| } | |
| }); | |
| return promise; | |
| } | |
| function makeUntrackedParams(underlyingParams) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| const promise = Promise.resolve(underlyingParams); | |
| CachedParams.set(underlyingParams, promise); | |
| return promise; | |
| } | |
| function makeDynamicallyTrackedExoticParamsWithDevWarnings(underlyingParams, hasFallbackParams, store) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| // We don't use makeResolvedReactPromise here because params | |
| // supports copying with spread and we don't want to unnecessarily | |
| // instrument the promise with spreadable properties of ReactPromise. | |
| const promise = hasFallbackParams ? makeDevtoolsIOAwarePromise(underlyingParams) : Promise.resolve(underlyingParams); | |
| const proxiedProperties = new Set(); | |
| const unproxiedProperties = []; | |
| Object.keys(underlyingParams).forEach((prop)=>{ | |
| if (wellKnownProperties.has(prop)) { | |
| // These properties cannot be shadowed because they need to be the | |
| // true underlying value for Promises to work correctly at runtime | |
| unproxiedProperties.push(prop); | |
| } else { | |
| proxiedProperties.add(prop); | |
| promise[prop] = underlyingParams[prop]; | |
| } | |
| }); | |
| const proxiedPromise = new Proxy(promise, { | |
| get (target, prop, receiver) { | |
| if (typeof prop === 'string') { | |
| if (// We are accessing a property that was proxied to the promise instance | |
| proxiedProperties.has(prop)) { | |
| const expression = describeStringPropertyAccess('params', prop); | |
| syncIODev(store.route, expression); | |
| } | |
| } | |
| return ReflectAdapter.get(target, prop, receiver); | |
| }, | |
| set (target, prop, value, receiver) { | |
| if (typeof prop === 'string') { | |
| proxiedProperties.delete(prop); | |
| } | |
| return ReflectAdapter.set(target, prop, value, receiver); | |
| }, | |
| ownKeys (target) { | |
| const expression = '`...params` or similar expression'; | |
| syncIODev(store.route, expression, unproxiedProperties); | |
| return Reflect.ownKeys(target); | |
| } | |
| }); | |
| CachedParams.set(underlyingParams, proxiedPromise); | |
| return proxiedPromise; | |
| } | |
| // Similar to `makeDynamicallyTrackedExoticParamsWithDevWarnings`, but just | |
| // logging the sync access without actually defining the params on the promise. | |
| function makeDynamicallyTrackedParamsWithDevWarnings(underlyingParams, hasFallbackParams, store) { | |
| const cachedParams = CachedParams.get(underlyingParams); | |
| if (cachedParams) { | |
| return cachedParams; | |
| } | |
| // We don't use makeResolvedReactPromise here because params | |
| // supports copying with spread and we don't want to unnecessarily | |
| // instrument the promise with spreadable properties of ReactPromise. | |
| const promise = hasFallbackParams ? makeDevtoolsIOAwarePromise(underlyingParams) : Promise.resolve(underlyingParams); | |
| const proxiedProperties = new Set(); | |
| const unproxiedProperties = []; | |
| Object.keys(underlyingParams).forEach((prop)=>{ | |
| if (wellKnownProperties.has(prop)) { | |
| // These properties cannot be shadowed because they need to be the | |
| // true underlying value for Promises to work correctly at runtime | |
| unproxiedProperties.push(prop); | |
| } else { | |
| proxiedProperties.add(prop); | |
| } | |
| }); | |
| const proxiedPromise = new Proxy(promise, { | |
| get (target, prop, receiver) { | |
| if (typeof prop === 'string') { | |
| if (// We are accessing a property that was proxied to the promise instance | |
| proxiedProperties.has(prop)) { | |
| const expression = describeStringPropertyAccess('params', prop); | |
| warnForSyncAccess(store.route, expression); | |
| } | |
| } | |
| return ReflectAdapter.get(target, prop, receiver); | |
| }, | |
| set (target, prop, value, receiver) { | |
| if (typeof prop === 'string') { | |
| proxiedProperties.delete(prop); | |
| } | |
| return ReflectAdapter.set(target, prop, value, receiver); | |
| }, | |
| ownKeys (target) { | |
| const expression = '`...params` or similar expression'; | |
| warnForIncompleteEnumeration(store.route, expression, unproxiedProperties); | |
| return Reflect.ownKeys(target); | |
| } | |
| }); | |
| CachedParams.set(underlyingParams, proxiedPromise); | |
| return proxiedPromise; | |
| } | |
| function syncIODev(route, expression, missingProperties) { | |
| const workUnitStore = workUnitAsyncStorage.getStore(); | |
| if (workUnitStore) { | |
| switch(workUnitStore.type){ | |
| case 'request': | |
| if (workUnitStore.prerenderPhase === true) { | |
| // When we're rendering dynamically in dev, we need to advance out of | |
| // the Prerender environment when we read Request data synchronously. | |
| trackSynchronousRequestDataAccessInDev(workUnitStore); | |
| } | |
| break; | |
| case 'prerender': | |
| case 'prerender-client': | |
| case 'prerender-runtime': | |
| case 'prerender-ppr': | |
| case 'prerender-legacy': | |
| case 'cache': | |
| case 'private-cache': | |
| case 'unstable-cache': | |
| break; | |
| default: | |
| workUnitStore; | |
| } | |
| } | |
| // In all cases we warn normally | |
| if (missingProperties && missingProperties.length > 0) { | |
| warnForIncompleteEnumeration(route, expression, missingProperties); | |
| } else { | |
| warnForSyncAccess(route, expression); | |
| } | |
| } | |
| const warnForSyncAccess = createDedupedByCallsiteServerErrorLoggerDev(createParamsAccessError); | |
| const warnForIncompleteEnumeration = createDedupedByCallsiteServerErrorLoggerDev(createIncompleteEnumerationError); | |
| function createParamsAccessError(route, expression) { | |
| const prefix = route ? `Route "${route}" ` : 'This route '; | |
| return Object.defineProperty(new Error(`${prefix}used ${expression}. ` + `\`params\` should be awaited before using its properties. ` + `Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`), "__NEXT_ERROR_CODE", { | |
| value: "E307", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| function createIncompleteEnumerationError(route, expression, missingProperties) { | |
| const prefix = route ? `Route "${route}" ` : 'This route '; | |
| return Object.defineProperty(new Error(`${prefix}used ${expression}. ` + `\`params\` should be awaited before using its properties. ` + `The following properties were not available through enumeration ` + `because they conflict with builtin property names: ` + `${describeListOfPropertyNames(missingProperties)}. ` + `Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`), "__NEXT_ERROR_CODE", { | |
| value: "E482", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| } | |
| function describeListOfPropertyNames(properties) { | |
| switch(properties.length){ | |
| case 0: | |
| throw Object.defineProperty(new InvariantError('Expected describeListOfPropertyNames to be called with a non-empty list of strings.'), "__NEXT_ERROR_CODE", { | |
| value: "E531", | |
| enumerable: false, | |
| configurable: true | |
| }); | |
| case 1: | |
| return `\`${properties[0]}\``; | |
| case 2: | |
| return `\`${properties[0]}\` and \`${properties[1]}\``; | |
| default: | |
| { | |
| let description = ''; | |
| for(let i = 0; i < properties.length - 1; i++){ | |
| description += `\`${properties[i]}\`, `; | |
| } | |
| description += `, and \`${properties[properties.length - 1]}\``; | |
| return description; | |
| } | |
| } | |
| } | |
| //# sourceMappingURL=params.js.map |