UNPKG

next

Version:

The React Framework

212 lines (211 loc) • 8.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { MutableRequestCookiesAdapter: null, ReadonlyRequestCookiesError: null, RequestCookiesAdapter: null, appendMutableCookies: null, areCookiesMutableInCurrentPhase: null, getModifiedCookieValues: null, responseCookiesToRequestCookies: null, wrapWithMutableAccessCheck: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { MutableRequestCookiesAdapter: function() { return MutableRequestCookiesAdapter; }, ReadonlyRequestCookiesError: function() { return ReadonlyRequestCookiesError; }, RequestCookiesAdapter: function() { return RequestCookiesAdapter; }, appendMutableCookies: function() { return appendMutableCookies; }, areCookiesMutableInCurrentPhase: function() { return areCookiesMutableInCurrentPhase; }, getModifiedCookieValues: function() { return getModifiedCookieValues; }, responseCookiesToRequestCookies: function() { return responseCookiesToRequestCookies; }, wrapWithMutableAccessCheck: function() { return wrapWithMutableAccessCheck; } }); const _cookies = require("../cookies"); const _reflect = require("./reflect"); const _workasyncstorageexternal = require("../../../app-render/work-async-storage.external"); const _workunitasyncstorageexternal = require("../../../app-render/work-unit-async-storage.external"); class ReadonlyRequestCookiesError extends Error { constructor(){ super('Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#options'); } static callable() { throw new ReadonlyRequestCookiesError(); } } class RequestCookiesAdapter { static seal(cookies) { return new Proxy(cookies, { get (target, prop, receiver) { switch(prop){ case 'clear': case 'delete': case 'set': return ReadonlyRequestCookiesError.callable; default: return _reflect.ReflectAdapter.get(target, prop, receiver); } } }); } } const SYMBOL_MODIFY_COOKIE_VALUES = Symbol.for('next.mutated.cookies'); function getModifiedCookieValues(cookies) { const modified = cookies[SYMBOL_MODIFY_COOKIE_VALUES]; if (!modified || !Array.isArray(modified) || modified.length === 0) { return []; } return modified; } function appendMutableCookies(headers, mutableCookies) { const modifiedCookieValues = getModifiedCookieValues(mutableCookies); if (modifiedCookieValues.length === 0) { return false; } // Return a new response that extends the response with // the modified cookies as fallbacks. `res` cookies // will still take precedence. const resCookies = new _cookies.ResponseCookies(headers); const returnedCookies = resCookies.getAll(); // Set the modified cookies as fallbacks. for (const cookie of modifiedCookieValues){ resCookies.set(cookie); } // Set the original cookies as the final values. for (const cookie of returnedCookies){ resCookies.set(cookie); } return true; } class MutableRequestCookiesAdapter { static wrap(cookies, onUpdateCookies) { const responseCookies = new _cookies.ResponseCookies(new Headers()); for (const cookie of cookies.getAll()){ responseCookies.set(cookie); } let modifiedValues = []; const modifiedCookies = new Set(); const updateResponseCookies = ()=>{ // TODO-APP: change method of getting workStore const workStore = _workasyncstorageexternal.workAsyncStorage.getStore(); if (workStore) { workStore.pathWasRevalidated = true; } const allCookies = responseCookies.getAll(); modifiedValues = allCookies.filter((c)=>modifiedCookies.has(c.name)); if (onUpdateCookies) { const serializedCookies = []; for (const cookie of modifiedValues){ const tempCookies = new _cookies.ResponseCookies(new Headers()); tempCookies.set(cookie); serializedCookies.push(tempCookies.toString()); } onUpdateCookies(serializedCookies); } }; const wrappedCookies = new Proxy(responseCookies, { get (target, prop, receiver) { switch(prop){ // A special symbol to get the modified cookie values case SYMBOL_MODIFY_COOKIE_VALUES: return modifiedValues; // TODO: Throw error if trying to set a cookie after the response // headers have been set. case 'delete': return function(...args) { modifiedCookies.add(typeof args[0] === 'string' ? args[0] : args[0].name); try { target.delete(...args); return wrappedCookies; } finally{ updateResponseCookies(); } }; case 'set': return function(...args) { modifiedCookies.add(typeof args[0] === 'string' ? args[0] : args[0].name); try { target.set(...args); return wrappedCookies; } finally{ updateResponseCookies(); } }; default: return _reflect.ReflectAdapter.get(target, prop, receiver); } } }); return wrappedCookies; } } function wrapWithMutableAccessCheck(responseCookies) { const wrappedCookies = new Proxy(responseCookies, { get (target, prop, receiver) { switch(prop){ case 'delete': return function(...args) { ensureCookiesAreStillMutable('cookies().delete'); target.delete(...args); return wrappedCookies; }; case 'set': return function(...args) { ensureCookiesAreStillMutable('cookies().set'); target.set(...args); return wrappedCookies; }; default: return _reflect.ReflectAdapter.get(target, prop, receiver); } } }); return wrappedCookies; } function areCookiesMutableInCurrentPhase(requestStore) { return requestStore.phase === 'action'; } /** Ensure that cookies() starts throwing on mutation * if we changed phases and can no longer mutate. * * This can happen when going: * 'render' -> 'after' * 'action' -> 'render' * */ function ensureCookiesAreStillMutable(callingExpression) { const requestStore = (0, _workunitasyncstorageexternal.getExpectedRequestStore)(callingExpression); if (!areCookiesMutableInCurrentPhase(requestStore)) { // TODO: maybe we can give a more precise error message based on callingExpression? throw new ReadonlyRequestCookiesError(); } } function responseCookiesToRequestCookies(responseCookies) { const requestCookies = new _cookies.RequestCookies(new Headers()); for (const cookie of responseCookies.getAll()){ requestCookies.set(cookie); } return requestCookies; } //# sourceMappingURL=request-cookies.js.map