| import { getDraftModeProviderForCacheScope, throwForMissingRequestStore } from '../app-render/work-unit-async-storage.external'; |
| import { workAsyncStorage } from '../app-render/work-async-storage.external'; |
| import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'; |
| import { abortAndThrowOnSynchronousRequestDataAccess, delayUntilRuntimeStage, postponeWithTracking, trackDynamicDataInDynamicRender, trackSynchronousRequestDataAccessInDev } from '../app-render/dynamic-rendering'; |
| import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-by-callsite-server-error-logger'; |
| import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'; |
| import { DynamicServerError } from '../../client/components/hooks-server-context'; |
| import { InvariantError } from '../../shared/lib/invariant-error'; |
| import { ReflectAdapter } from '../web/spec-extension/adapters/reflect'; |
| export function draftMode() { |
| const callingExpression = 'draftMode'; |
| const workStore = workAsyncStorage.getStore(); |
| const workUnitStore = workUnitAsyncStorage.getStore(); |
| if (!workStore || !workUnitStore) { |
| throwForMissingRequestStore(callingExpression); |
| } |
| switch(workUnitStore.type){ |
| case 'prerender-runtime': |
| |
| return delayUntilRuntimeStage(workUnitStore, createOrGetCachedDraftMode(workUnitStore.draftMode, workStore)); |
| case 'request': |
| return createOrGetCachedDraftMode(workUnitStore.draftMode, workStore); |
| case 'cache': |
| case 'private-cache': |
| case 'unstable-cache': |
| |
| |
| |
| const draftModeProvider = getDraftModeProviderForCacheScope(workStore, workUnitStore); |
| if (draftModeProvider) { |
| return createOrGetCachedDraftMode(draftModeProvider, workStore); |
| } |
| |
| |
| case 'prerender': |
| case 'prerender-client': |
| case 'prerender-ppr': |
| case 'prerender-legacy': |
| |
| return createOrGetCachedDraftMode(null, workStore); |
| default: |
| return workUnitStore; |
| } |
| } |
| function createOrGetCachedDraftMode(draftModeProvider, workStore) { |
| const cacheKey = draftModeProvider ?? NullDraftMode; |
| const cachedDraftMode = CachedDraftModes.get(cacheKey); |
| if (cachedDraftMode) { |
| return cachedDraftMode; |
| } |
| let promise; |
| if (process.env.NODE_ENV === 'development' && !(workStore == null ? void 0 : workStore.isPrefetchRequest)) { |
| const route = workStore == null ? void 0 : workStore.route; |
| if (process.env.__NEXT_CACHE_COMPONENTS) { |
| return createDraftModeWithDevWarnings(draftModeProvider, route); |
| } |
| promise = createExoticDraftModeWithDevWarnings(draftModeProvider, route); |
| } else { |
| if (process.env.__NEXT_CACHE_COMPONENTS) { |
| return Promise.resolve(new DraftMode(draftModeProvider)); |
| } |
| promise = createExoticDraftMode(draftModeProvider); |
| } |
| CachedDraftModes.set(cacheKey, promise); |
| return promise; |
| } |
| const NullDraftMode = {}; |
| const CachedDraftModes = new WeakMap(); |
| function createExoticDraftMode(underlyingProvider) { |
| const instance = new DraftMode(underlyingProvider); |
| const promise = Promise.resolve(instance); |
| Object.defineProperty(promise, 'isEnabled', { |
| get () { |
| return instance.isEnabled; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| promise.enable = instance.enable.bind(instance); |
| promise.disable = instance.disable.bind(instance); |
| return promise; |
| } |
| function createExoticDraftModeWithDevWarnings(underlyingProvider, route) { |
| const instance = new DraftMode(underlyingProvider); |
| const promise = Promise.resolve(instance); |
| Object.defineProperty(promise, 'isEnabled', { |
| get () { |
| const expression = '`draftMode().isEnabled`'; |
| syncIODev(route, expression); |
| return instance.isEnabled; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(promise, 'enable', { |
| value: function get() { |
| const expression = '`draftMode().enable()`'; |
| syncIODev(route, expression); |
| return instance.enable.apply(instance, arguments); |
| } |
| }); |
| Object.defineProperty(promise, 'disable', { |
| value: function get() { |
| const expression = '`draftMode().disable()`'; |
| syncIODev(route, expression); |
| return instance.disable.apply(instance, arguments); |
| } |
| }); |
| return promise; |
| } |
| |
| |
| function createDraftModeWithDevWarnings(underlyingProvider, route) { |
| const instance = new DraftMode(underlyingProvider); |
| const promise = Promise.resolve(instance); |
| const proxiedPromise = new Proxy(promise, { |
| get (target, prop, receiver) { |
| switch(prop){ |
| case 'isEnabled': |
| warnForSyncAccess(route, `\`draftMode().${prop}\``); |
| break; |
| case 'enable': |
| case 'disable': |
| { |
| warnForSyncAccess(route, `\`draftMode().${prop}()\``); |
| break; |
| } |
| default: |
| { |
| |
| } |
| } |
| return ReflectAdapter.get(target, prop, receiver); |
| } |
| }); |
| return proxiedPromise; |
| } |
| class DraftMode { |
| constructor(provider){ |
| this._provider = provider; |
| } |
| get isEnabled() { |
| if (this._provider !== null) { |
| return this._provider.isEnabled; |
| } |
| return false; |
| } |
| enable() { |
| |
| |
| trackDynamicDraftMode('draftMode().enable()', this.enable); |
| if (this._provider !== null) { |
| this._provider.enable(); |
| } |
| } |
| disable() { |
| trackDynamicDraftMode('draftMode().disable()', this.disable); |
| if (this._provider !== null) { |
| this._provider.disable(); |
| } |
| } |
| } |
| function syncIODev(route, expression) { |
| const workUnitStore = workUnitAsyncStorage.getStore(); |
| if (workUnitStore) { |
| switch(workUnitStore.type){ |
| case 'request': |
| if (workUnitStore.prerenderPhase === true) { |
| |
| |
| 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; |
| } |
| } |
| |
| warnForSyncAccess(route, expression); |
| } |
| const warnForSyncAccess = createDedupedByCallsiteServerErrorLoggerDev(createDraftModeAccessError); |
| function createDraftModeAccessError(route, expression) { |
| const prefix = route ? `Route "${route}" ` : 'This route '; |
| return Object.defineProperty(new Error(`${prefix}used ${expression}. ` + `\`draftMode()\` should be awaited before using its value. ` + `Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis`), "__NEXT_ERROR_CODE", { |
| value: "E377", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| function trackDynamicDraftMode(expression, constructorOpt) { |
| const workStore = workAsyncStorage.getStore(); |
| const workUnitStore = workUnitAsyncStorage.getStore(); |
| if (workStore) { |
| |
| |
| if ((workUnitStore == null ? void 0 : workUnitStore.phase) === 'after') { |
| throw Object.defineProperty(new Error(`Route ${workStore.route} used "${expression}" inside \`after\`. The enabled status of draftMode can be read inside \`after\` but you cannot enable or disable draftMode. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`), "__NEXT_ERROR_CODE", { |
| value: "E348", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| if (workStore.dynamicShouldError) { |
| throw Object.defineProperty(new StaticGenBailoutError(`Route ${workStore.route} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`), "__NEXT_ERROR_CODE", { |
| value: "E553", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| if (workUnitStore) { |
| switch(workUnitStore.type){ |
| case 'cache': |
| case 'private-cache': |
| { |
| const error = Object.defineProperty(new Error(`Route ${workStore.route} used "${expression}" inside "use cache". The enabled status of draftMode can be read in caches but you must not enable or disable draftMode inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`), "__NEXT_ERROR_CODE", { |
| value: "E246", |
| enumerable: false, |
| configurable: true |
| }); |
| Error.captureStackTrace(error, constructorOpt); |
| workStore.invalidDynamicUsageError ??= error; |
| throw error; |
| } |
| case 'unstable-cache': |
| throw Object.defineProperty(new Error(`Route ${workStore.route} used "${expression}" inside a function cached with "unstable_cache(...)". The enabled status of draftMode can be read in caches but you must not enable or disable draftMode inside a cache. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`), "__NEXT_ERROR_CODE", { |
| value: "E259", |
| enumerable: false, |
| configurable: true |
| }); |
| case 'prerender': |
| case 'prerender-runtime': |
| { |
| const error = Object.defineProperty(new Error(`Route ${workStore.route} used ${expression} without first calling \`await connection()\`. See more info here: https://nextjs.org/docs/messages/next-prerender-sync-headers`), "__NEXT_ERROR_CODE", { |
| value: "E126", |
| enumerable: false, |
| configurable: true |
| }); |
| return abortAndThrowOnSynchronousRequestDataAccess(workStore.route, expression, error, workUnitStore); |
| } |
| case 'prerender-client': |
| const exportName = '`draftMode`'; |
| throw Object.defineProperty(new InvariantError(`${exportName} must not be used within a client component. Next.js should be preventing ${exportName} from being included in client components statically, but did not in this case.`), "__NEXT_ERROR_CODE", { |
| value: "E693", |
| enumerable: false, |
| configurable: true |
| }); |
| case 'prerender-ppr': |
| return postponeWithTracking(workStore.route, expression, workUnitStore.dynamicTracking); |
| case 'prerender-legacy': |
| workUnitStore.revalidate = 0; |
| const err = Object.defineProperty(new DynamicServerError(`Route ${workStore.route} couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`), "__NEXT_ERROR_CODE", { |
| value: "E558", |
| enumerable: false, |
| configurable: true |
| }); |
| workStore.dynamicUsageDescription = expression; |
| workStore.dynamicUsageStack = err.stack; |
| throw err; |
| case 'request': |
| trackDynamicDataInDynamicRender(workUnitStore); |
| break; |
| default: |
| workUnitStore; |
| } |
| } |
| } |
| } |
|
|
| |