"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "draftMode", { enumerable: true, get: function() { return draftMode; } }); const _workunitasyncstorageexternal = require("../app-render/work-unit-async-storage.external"); const _workasyncstorageexternal = require("../app-render/work-async-storage.external"); const _dynamicrendering = require("../app-render/dynamic-rendering"); const _creatededupedbycallsiteservererrorlogger = require("../create-deduped-by-callsite-server-error-logger"); const _staticgenerationbailout = require("../../client/components/static-generation-bailout"); const _hooksservercontext = require("../../client/components/hooks-server-context"); const _invarianterror = require("../../shared/lib/invariant-error"); const _reflect = require("../web/spec-extension/adapters/reflect"); function draftMode() { const callingExpression = 'draftMode'; const workStore = _workasyncstorageexternal.workAsyncStorage.getStore(); const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore(); if (!workStore || !workUnitStore) { (0, _workunitasyncstorageexternal.throwForMissingRequestStore)(callingExpression); } switch(workUnitStore.type){ case 'prerender-runtime': // TODO(runtime-ppr): does it make sense to delay this? normally it's always microtasky return (0, _dynamicrendering.delayUntilRuntimeStage)(workUnitStore, createOrGetCachedDraftMode(workUnitStore.draftMode, workStore)); case 'request': return createOrGetCachedDraftMode(workUnitStore.draftMode, workStore); case 'cache': case 'private-cache': case 'unstable-cache': // Inside of `"use cache"` or `unstable_cache`, draft mode is available if // the outmost work unit store is a request store (or a runtime prerender), // and if draft mode is enabled. const draftModeProvider = (0, _workunitasyncstorageexternal.getDraftModeProviderForCacheScope)(workStore, workUnitStore); if (draftModeProvider) { return createOrGetCachedDraftMode(draftModeProvider, workStore); } // Otherwise, we fall through to providing an empty draft mode. // eslint-disable-next-line no-fallthrough case 'prerender': case 'prerender-client': case 'prerender-ppr': case 'prerender-legacy': // Return empty draft mode 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; } // Similar to `createExoticDraftModeWithDevWarnings`, but just logging the sync // access without actually defining the draftMode properties on the 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: { // We only warn for well-defined properties of the draftMode object. } } return _reflect.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() { // We have a store we want to track dynamic data access to ensure we // don't statically generate routes that manipulate draft mode. 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 = _workunitasyncstorageexternal.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. (0, _dynamicrendering.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 warnForSyncAccess(route, expression); } const warnForSyncAccess = (0, _creatededupedbycallsiteservererrorlogger.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 = _workasyncstorageexternal.workAsyncStorage.getStore(); const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore(); if (workStore) { // We have a store we want to track dynamic data access to ensure we // don't statically generate routes that manipulate draft mode. 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 _staticgenerationbailout.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 (0, _dynamicrendering.abortAndThrowOnSynchronousRequestDataAccess)(workStore.route, expression, error, workUnitStore); } case 'prerender-client': const exportName = '`draftMode`'; throw Object.defineProperty(new _invarianterror.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 (0, _dynamicrendering.postponeWithTracking)(workStore.route, expression, workUnitStore.dynamicTracking); case 'prerender-legacy': workUnitStore.revalidate = 0; const err = Object.defineProperty(new _hooksservercontext.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': (0, _dynamicrendering.trackDynamicDataInDynamicRender)(workUnitStore); break; default: workUnitStore; } } } } //# sourceMappingURL=draft-mode.js.map