@prismicio/next 2.3.1-pr.147.05dde81 → 2.3.1-pr.147.286b2d0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/PrismicPreviewClient.cjs +34 -13
  2. package/dist/PrismicPreviewClient.cjs.map +1 -1
  3. package/dist/PrismicPreviewClient.js +34 -13
  4. package/dist/PrismicPreviewClient.js.map +1 -1
  5. package/dist/getPreviewRef.cjs +2 -2
  6. package/dist/getPreviewRef.cjs.map +1 -1
  7. package/dist/getPreviewRef.d.cts.map +1 -1
  8. package/dist/getPreviewRef.d.ts.map +1 -1
  9. package/dist/getPreviewRef.js +2 -2
  10. package/dist/getPreviewRef.js.map +1 -1
  11. package/dist/lib/expiredPreviewCookies.cjs +5 -0
  12. package/dist/lib/expiredPreviewCookies.cjs.map +1 -1
  13. package/dist/lib/expiredPreviewCookies.js +5 -1
  14. package/dist/lib/expiredPreviewCookies.js.map +1 -1
  15. package/dist/lib/previewRefFromCookie.cjs +24 -0
  16. package/dist/lib/previewRefFromCookie.cjs.map +1 -0
  17. package/dist/lib/previewRefFromCookie.js +24 -0
  18. package/dist/lib/previewRefFromCookie.js.map +1 -0
  19. package/dist/package.cjs +1 -1
  20. package/dist/package.js +1 -1
  21. package/dist/pages/PrismicPreview.cjs +36 -12
  22. package/dist/pages/PrismicPreview.cjs.map +1 -1
  23. package/dist/pages/PrismicPreview.js +36 -12
  24. package/dist/pages/PrismicPreview.js.map +1 -1
  25. package/dist/pages/exitPreview.cjs +5 -1
  26. package/dist/pages/exitPreview.cjs.map +1 -1
  27. package/dist/pages/exitPreview.d.cts.map +1 -1
  28. package/dist/pages/exitPreview.d.ts.map +1 -1
  29. package/dist/pages/exitPreview.js +6 -2
  30. package/dist/pages/exitPreview.js.map +1 -1
  31. package/dist/pages/setPreviewData.cjs +8 -2
  32. package/dist/pages/setPreviewData.cjs.map +1 -1
  33. package/dist/pages/setPreviewData.d.cts.map +1 -1
  34. package/dist/pages/setPreviewData.d.ts.map +1 -1
  35. package/dist/pages/setPreviewData.js +8 -2
  36. package/dist/pages/setPreviewData.js.map +1 -1
  37. package/dist/redirectToPreviewURL.cjs +8 -0
  38. package/dist/redirectToPreviewURL.cjs.map +1 -1
  39. package/dist/redirectToPreviewURL.js +8 -0
  40. package/dist/redirectToPreviewURL.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/PrismicPreviewClient.tsx +36 -5
  43. package/src/getPreviewRef.ts +6 -6
  44. package/src/lib/expiredPreviewCookies.ts +5 -0
  45. package/src/lib/previewRefFromCookie.ts +33 -0
  46. package/src/pages/PrismicPreview.tsx +37 -10
  47. package/src/pages/exitPreview.ts +12 -2
  48. package/src/pages/setPreviewData.ts +19 -2
  49. package/src/redirectToPreviewURL.ts +12 -0
@@ -1 +1 @@
1
- {"version":3,"file":"PrismicPreview.js","names":["cookie","prismicCookie"],"sources":["../../src/pages/PrismicPreview.tsx"],"sourcesContent":["import { getToolbarSrc, cookie as prismicCookie } from \"@prismicio/client\"\nimport { useRouter } from \"next/router\"\nimport Script from \"next/script\"\nimport type { FC } from \"react\"\nimport { type ReactNode, useEffect } from \"react\"\n\n/** Props for `<PrismicPreview>`. */\nexport type PrismicPreviewProps = {\n\t/**\n\t * The name of your Prismic repository. A Prismic Toolbar will be registered using this\n\t * repository.\n\t */\n\trepositoryName: string\n\n\t/**\n\t * The URL of your app's Prismic preview endpoint (default: `/api/preview`). This URL will be\n\t * fetched on preview update events.\n\t */\n\tupdatePreviewURL?: string\n\n\t/**\n\t * The URL of your app's exit preview endpoint (default: `/api/exit-preview`). This URL will be\n\t * fetched on preview exit events.\n\t */\n\texitPreviewURL?: string\n\n\t/** Children to render adjacent to the Prismic Toolbar. */\n\tchildren?: ReactNode\n}\n\n/**\n * React component that sets up Prismic Previews using the Prismic Toolbar. When the Prismic Toolbar\n * send events to the browser, such as on preview updates and exiting, this component will\n * automatically refresh the page with the changes.\n *\n * This component can be wrapped around your app or added anywhere in your app's tree. It must be\n * rendered on every page.\n */\nexport const PrismicPreview: FC<PrismicPreviewProps> = (props) => {\n\tconst {\n\t\trepositoryName,\n\t\tupdatePreviewURL = \"/api/preview\",\n\t\texitPreviewURL = \"/api/exit-preview\",\n\t\tchildren,\n\t} = props\n\n\tconst router = useRouter()\n\n\tconst toolbarSrc = getToolbarSrc(repositoryName)\n\n\tuseEffect(() => {\n\t\tconst controller = new AbortController()\n\n\t\twindow.addEventListener(\"prismicPreviewUpdate\", onUpdate, {\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\twindow.addEventListener(\"prismicPreviewEnd\", onEnd, {\n\t\t\tsignal: controller.signal,\n\t\t})\n\n\t\t// Start the preview for preview share links. Previews from\n\t\t// share links do not go to the `updatePreviewURL` like a normal\n\t\t// preview.\n\t\t//\n\t\t// We check that the current URL is a descendant of the base\n\t\t// path to prevent infinite refrehes.\n\t\tif (\n\t\t\twindow.location.href.startsWith(window.location.origin + router.basePath) &&\n\t\t\tgetPreviewCookieRepositoryName() === repositoryName &&\n\t\t\t!router.isPreview\n\t\t) {\n\t\t\tstart()\n\t\t}\n\n\t\tfunction onEnd(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\tfetch(router.basePath + exitPreviewURL, { signal: controller.signal })\n\t\t\t\t.then((res) => {\n\t\t\t\t\tif (!res.ok) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t`[<PrismicPreview>] Failed to exit Preview Mode using the \"${exitPreviewURL}\" API endpoint. Does it exist?`,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\trefresh()\n\t\t\t\t})\n\t\t\t\t.catch(() => {})\n\t\t}\n\n\t\tfunction onUpdate(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\tstart()\n\t\t}\n\n\t\tfunction start() {\n\t\t\t// We check `opaqueredirect` because we don't care if\n\t\t\t// the redirect was successful or not. As long as it\n\t\t\t// redirects, we know the endpoint exists and at least\n\t\t\t// attempted to set preview data.\n\t\t\tfetch(router.basePath + updatePreviewURL, {\n\t\t\t\tredirect: \"manual\",\n\t\t\t\tsignal: controller.signal,\n\t\t\t})\n\t\t\t\t.then((res) => {\n\t\t\t\t\tif (res.type !== \"opaqueredirect\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t`[<PrismicPreview>] Failed to start or update the preview using \"${updatePreviewURL}\". Does it exist?`,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\trefresh()\n\t\t\t\t})\n\t\t\t\t.catch(() => {})\n\t\t}\n\n\t\tfunction refresh() {\n\t\t\trouter.replace(router.asPath, undefined, { scroll: false })\n\t\t}\n\n\t\treturn () => controller.abort()\n\t}, [exitPreviewURL, updatePreviewURL, repositoryName, router])\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t<Script src={toolbarSrc} strategy=\"lazyOnload\" />\n\t\t</>\n\t)\n}\n\nfunction getPreviewCookieRepositoryName() {\n\tconst cookie = window.document.cookie\n\t\t.split(\"; \")\n\t\t.find((row) => row.startsWith(`${prismicCookie.preview}=`))\n\t\t?.split(\"=\")[1]\n\n\treturn (decodeURIComponent(cookie ?? \"\").match(/\"([^\"]+)\\.prismic\\.io\"/) || [])[1]\n}\n"],"mappings":";;;;;;;;;;;;;;AAsCA,MAAa,kBAA2C,UAAU;CACjE,MAAM,EACL,gBACA,mBAAmB,gBACnB,iBAAiB,qBACjB,aACG;CAEJ,MAAM,SAAS,WAAW;CAE1B,MAAM,aAAa,cAAc,eAAe;AAEhD,iBAAgB;EACf,MAAM,aAAa,IAAI,iBAAiB;AAExC,SAAO,iBAAiB,wBAAwB,UAAU,EACzD,QAAQ,WAAW,QACnB,CAAC;AACF,SAAO,iBAAiB,qBAAqB,OAAO,EACnD,QAAQ,WAAW,QACnB,CAAC;AAQF,MACC,OAAO,SAAS,KAAK,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS,IACzE,gCAAgC,KAAK,kBACrC,CAAC,OAAO,UAER,QAAO;EAGR,SAAS,MAAM,OAAc;AAC5B,SAAM,gBAAgB;AACtB,SAAM,OAAO,WAAW,gBAAgB,EAAE,QAAQ,WAAW,QAAQ,CAAC,CACpE,MAAM,QAAQ;AACd,QAAI,CAAC,IAAI,IAAI;AACZ,aAAQ,MACP,6DAA6D,eAAe,gCAC5E;AAED;;AAGD,aAAS;KACR,CACD,YAAY,GAAG;;EAGlB,SAAS,SAAS,OAAc;AAC/B,SAAM,gBAAgB;AACtB,UAAO;;EAGR,SAAS,QAAQ;AAKhB,SAAM,OAAO,WAAW,kBAAkB;IACzC,UAAU;IACV,QAAQ,WAAW;IACnB,CAAC,CACA,MAAM,QAAQ;AACd,QAAI,IAAI,SAAS,kBAAkB;AAClC,aAAQ,MACP,mEAAmE,iBAAiB,mBACpF;AAED;;AAGD,aAAS;KACR,CACD,YAAY,GAAG;;EAGlB,SAAS,UAAU;AAClB,UAAO,QAAQ,OAAO,QAAQ,KAAA,GAAW,EAAE,QAAQ,OAAO,CAAC;;AAG5D,eAAa,WAAW,OAAO;IAC7B;EAAC;EAAgB;EAAkB;EAAgB;EAAO,CAAC;AAE9D,QACC,qBAAA,UAAA,EAAA,UAAA,CACE,UACD,oBAAC,QAAD;EAAQ,KAAK;EAAY,UAAS;EAAe,CAAA,CAC/C,EAAA,CAAA;;AAIL,SAAS,iCAAiC;CACzC,MAAMA,WAAS,OAAO,SAAS,OAC7B,MAAM,KAAK,CACX,MAAM,QAAQ,IAAI,WAAW,GAAGC,OAAc,QAAQ,GAAG,CAAC,EACzD,MAAM,IAAI,CAAC;AAEd,SAAQ,mBAAmBD,YAAU,GAAG,CAAC,MAAM,yBAAyB,IAAI,EAAE,EAAE"}
1
+ {"version":3,"file":"PrismicPreview.js","names":["cookie","prismicCookie"],"sources":["../../src/pages/PrismicPreview.tsx"],"sourcesContent":["import { getToolbarSrc, cookie as prismicCookie } from \"@prismicio/client\"\nimport { useRouter } from \"next/router\"\nimport Script from \"next/script\"\nimport type { FC } from \"react\"\nimport { type ReactNode, useEffect } from \"react\"\n\n/** Props for `<PrismicPreview>`. */\nexport type PrismicPreviewProps = {\n\t/**\n\t * The name of your Prismic repository. A Prismic Toolbar will be registered using this\n\t * repository.\n\t */\n\trepositoryName: string\n\n\t/**\n\t * The URL of your app's Prismic preview endpoint (default: `/api/preview`). This URL will be\n\t * fetched on preview update events.\n\t */\n\tupdatePreviewURL?: string\n\n\t/**\n\t * The URL of your app's exit preview endpoint (default: `/api/exit-preview`). This URL will be\n\t * fetched on preview exit events.\n\t */\n\texitPreviewURL?: string\n\n\t/** Children to render adjacent to the Prismic Toolbar. */\n\tchildren?: ReactNode\n}\n\n/**\n * React component that sets up Prismic Previews using the Prismic Toolbar. When the Prismic Toolbar\n * send events to the browser, such as on preview updates and exiting, this component will\n * automatically refresh the page with the changes.\n *\n * This component can be wrapped around your app or added anywhere in your app's tree. It must be\n * rendered on every page.\n */\nexport const PrismicPreview: FC<PrismicPreviewProps> = (props) => {\n\tconst {\n\t\trepositoryName,\n\t\tupdatePreviewURL = \"/api/preview\",\n\t\texitPreviewURL = \"/api/exit-preview\",\n\t\tchildren,\n\t} = props\n\n\tconst router = useRouter()\n\n\tconst toolbarSrc = getToolbarSrc(repositoryName)\n\n\tuseEffect(() => {\n\t\tconst controller = new AbortController()\n\t\tlet starting: Promise<void> | undefined\n\t\tlet startController: AbortController | undefined\n\t\tlet updateRequested = false\n\t\tlet ending = false\n\n\t\twindow.addEventListener(\"prismicPreviewUpdate\", onUpdate, {\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\twindow.addEventListener(\"prismicPreviewEnd\", onEnd, {\n\t\t\tsignal: controller.signal,\n\t\t})\n\n\t\t// Start the preview for preview share links. Previews from\n\t\t// share links do not go to the `updatePreviewURL` like a normal\n\t\t// preview.\n\t\t//\n\t\t// We check that the current URL is a descendant of the base\n\t\t// path to prevent infinite refrehes.\n\t\tif (\n\t\t\twindow.location.href.startsWith(window.location.origin + router.basePath) &&\n\t\t\tgetPreviewCookieRepositoryName() === repositoryName &&\n\t\t\t!router.isPreview\n\t\t) {\n\t\t\tstart()\n\t\t}\n\n\t\tfunction onEnd(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\tif (ending) return\n\t\t\tending = true\n\t\t\tupdateRequested = false\n\t\t\tstartController?.abort()\n\t\t\tfetch(router.basePath + exitPreviewURL, { signal: controller.signal })\n\t\t\t\t.then((res) => {\n\t\t\t\t\tif (!res.ok) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t`[<PrismicPreview>] Failed to exit Preview Mode using the \"${exitPreviewURL}\" API endpoint. Does it exist?`,\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\trefresh()\n\t\t\t\t})\n\t\t\t\t.catch(() => {})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tending = false\n\t\t\t\t})\n\t\t}\n\n\t\tfunction onUpdate(event: Event) {\n\t\t\tevent.preventDefault()\n\t\t\tif (ending) return\n\t\t\tstart()\n\t\t}\n\n\t\tfunction start() {\n\t\t\tupdateRequested = true\n\t\t\tif (starting) return\n\t\t\tconst requestController = new AbortController()\n\t\t\tstartController = requestController\n\n\t\t\t// We check `opaqueredirect` because we don't care if\n\t\t\t// the redirect was successful or not. As long as it\n\t\t\t// redirects, we know the endpoint exists and at least\n\t\t\t// attempted to set preview data.\n\t\t\tstarting = (async () => {\n\t\t\t\tdo {\n\t\t\t\t\tupdateRequested = false\n\t\t\t\t\tconst res = await fetch(router.basePath + updatePreviewURL, {\n\t\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\t\tsignal: requestController.signal,\n\t\t\t\t\t})\n\t\t\t\t\tif (res.type !== \"opaqueredirect\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t`[<PrismicPreview>] Failed to start or update the preview using \"${updatePreviewURL}\". Does it exist?`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\t// Preview Data captures the cookie when the request starts.\n\t\t\t\t\t// If edits arrived meanwhile, store the latest ref before rendering.\n\t\t\t\t} while (updateRequested && !requestController.signal.aborted)\n\t\t\t\tif (!requestController.signal.aborted) refresh()\n\t\t\t})()\n\t\t\t\t.catch(() => {})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tstarting = undefined\n\t\t\t\t\tstartController = undefined\n\t\t\t\t})\n\t\t}\n\n\t\tfunction refresh() {\n\t\t\trouter.replace(router.asPath, undefined, { scroll: false })\n\t\t}\n\n\t\treturn () => {\n\t\t\tcontroller.abort()\n\t\t\tstartController?.abort()\n\t\t}\n\t}, [exitPreviewURL, updatePreviewURL, repositoryName, router])\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t<Script src={toolbarSrc} strategy=\"lazyOnload\" />\n\t\t</>\n\t)\n}\n\nfunction getPreviewCookieRepositoryName() {\n\tconst cookie = window.document.cookie\n\t\t.split(\"; \")\n\t\t.find((row) => row.startsWith(`${prismicCookie.preview}=`))\n\t\t?.split(\"=\")[1]\n\n\treturn (decodeURIComponent(cookie ?? \"\").match(/\"([^\"]+)\\.prismic\\.io\"/) || [])[1]\n}\n"],"mappings":";;;;;;;;;;;;;;AAsCA,MAAa,kBAA2C,UAAU;CACjE,MAAM,EACL,gBACA,mBAAmB,gBACnB,iBAAiB,qBACjB,aACG;CAEJ,MAAM,SAAS,WAAW;CAE1B,MAAM,aAAa,cAAc,eAAe;AAEhD,iBAAgB;EACf,MAAM,aAAa,IAAI,iBAAiB;EACxC,IAAI;EACJ,IAAI;EACJ,IAAI,kBAAkB;EACtB,IAAI,SAAS;AAEb,SAAO,iBAAiB,wBAAwB,UAAU,EACzD,QAAQ,WAAW,QACnB,CAAC;AACF,SAAO,iBAAiB,qBAAqB,OAAO,EACnD,QAAQ,WAAW,QACnB,CAAC;AAQF,MACC,OAAO,SAAS,KAAK,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS,IACzE,gCAAgC,KAAK,kBACrC,CAAC,OAAO,UAER,QAAO;EAGR,SAAS,MAAM,OAAc;AAC5B,SAAM,gBAAgB;AACtB,OAAI,OAAQ;AACZ,YAAS;AACT,qBAAkB;AAClB,oBAAiB,OAAO;AACxB,SAAM,OAAO,WAAW,gBAAgB,EAAE,QAAQ,WAAW,QAAQ,CAAC,CACpE,MAAM,QAAQ;AACd,QAAI,CAAC,IAAI,IAAI;AACZ,aAAQ,MACP,6DAA6D,eAAe,gCAC5E;AAED;;AAGD,aAAS;KACR,CACD,YAAY,GAAG,CACf,cAAc;AACd,aAAS;KACR;;EAGJ,SAAS,SAAS,OAAc;AAC/B,SAAM,gBAAgB;AACtB,OAAI,OAAQ;AACZ,UAAO;;EAGR,SAAS,QAAQ;AAChB,qBAAkB;AAClB,OAAI,SAAU;GACd,MAAM,oBAAoB,IAAI,iBAAiB;AAC/C,qBAAkB;AAMlB,eAAY,YAAY;AACvB,OAAG;AACF,uBAAkB;AAKlB,UAJY,MAAM,MAAM,OAAO,WAAW,kBAAkB;MAC3D,UAAU;MACV,QAAQ,kBAAkB;MAC1B,CAAC,EACM,SAAS,kBAAkB;AAClC,cAAQ,MACP,mEAAmE,iBAAiB,mBACpF;AACD;;aAIO,mBAAmB,CAAC,kBAAkB,OAAO;AACtD,QAAI,CAAC,kBAAkB,OAAO,QAAS,UAAS;OAC7C,CACF,YAAY,GAAG,CACf,cAAc;AACd,eAAW,KAAA;AACX,sBAAkB,KAAA;KACjB;;EAGJ,SAAS,UAAU;AAClB,UAAO,QAAQ,OAAO,QAAQ,KAAA,GAAW,EAAE,QAAQ,OAAO,CAAC;;AAG5D,eAAa;AACZ,cAAW,OAAO;AAClB,oBAAiB,OAAO;;IAEvB;EAAC;EAAgB;EAAkB;EAAgB;EAAO,CAAC;AAE9D,QACC,qBAAA,UAAA,EAAA,UAAA,CACE,UACD,oBAAC,QAAD;EAAQ,KAAK;EAAY,UAAS;EAAe,CAAA,CAC/C,EAAA,CAAA;;AAIL,SAAS,iCAAiC;CACzC,MAAMA,WAAS,OAAO,SAAS,OAC7B,MAAM,KAAK,CACX,MAAM,QAAQ,IAAI,WAAW,GAAGC,OAAc,QAAQ,GAAG,CAAC,EACzD,MAAM,IAAI,CAAC;AAEd,SAAQ,mBAAmBD,YAAU,GAAG,CAAC,MAAM,yBAAyB,IAAI,EAAE,EAAE"}
@@ -18,7 +18,11 @@ const require_expiredPreviewCookies = require("../lib/expiredPreviewCookies.cjs"
18
18
  function exitPreview(config) {
19
19
  config.res.clearPreviewData();
20
20
  const existingSetCookie = config.res.getHeader("Set-Cookie");
21
- const expiredPreviewCookies = require_expiredPreviewCookies.expiredPreviewCookieHeaders();
21
+ const expiredPreviewCookies = [
22
+ ...require_expiredPreviewCookies.expiredPreviewCookieHeaders(),
23
+ ...require_expiredPreviewCookies.expiredDraftModeCookieHeaders(),
24
+ ...require_expiredPreviewCookies.expiredPreviewDataCookieHeaders()
25
+ ];
22
26
  config.res.setHeader("Set-Cookie", existingSetCookie == null ? expiredPreviewCookies : [...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(String), ...expiredPreviewCookies]);
23
27
  config.res.setHeader("Cache-Control", "no-store");
24
28
  config.res.json({ success: true });
@@ -1 +1 @@
1
- {"version":3,"file":"exitPreview.cjs","names":["expiredPreviewCookieHeaders"],"sources":["../../src/pages/exitPreview.ts"],"sourcesContent":["import { expiredPreviewCookieHeaders } from \"../lib/expiredPreviewCookies\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `exitPreview()`. */\nexport type ExitPreviewAPIRouteConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq?: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/**\n * Ends a Prismic preview session within a Next.js app. This function should be used in an API\n * route.\n *\n * @example\n * \t;```typescript\n * \t// src/pages/api/exit-preview.js\n *\n * \timport { exitPreview } from \"@prismicio/next\"\n *\n * \texport default function handler(_req, res) {\n * \t\treturn exitPreview({ res })\n * \t}\n * \t```\n */\nexport function exitPreview(config: ExitPreviewAPIRouteConfig): void {\n\tconfig.res.clearPreviewData()\n\n\t// `clearPreviewData()` only clears Next.js preview cookies. Expire both\n\t// leftover `io.prismic.preview` shapes (toolbar Lax, not Secure; and the\n\t// iframe SameSite=None; Secure write). If either survives,\n\t// `<PrismicPreview>` calls `start()` → `/api/preview` and preview returns.\n\t// Do not use `cookies().set` — that is the App Router helper. Do not\n\t// replace the existing Set-Cookie header from `clearPreviewData()`.\n\tconst existingSetCookie = config.res.getHeader(\"Set-Cookie\")\n\tconst expiredPreviewCookies = expiredPreviewCookieHeaders()\n\tconfig.res.setHeader(\n\t\t\"Set-Cookie\",\n\t\texistingSetCookie == null\n\t\t\t? expiredPreviewCookies\n\t\t\t: [\n\t\t\t\t\t...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(\n\t\t\t\t\t\tString,\n\t\t\t\t\t),\n\t\t\t\t\t...expiredPreviewCookies,\n\t\t\t\t],\n\t)\n\n\t// `Cache-Control` header is used to prevent CDN-level caching.\n\tconfig.res.setHeader(\"Cache-Control\", \"no-store\")\n\n\tconfig.res.json({ success: true })\n\n\treturn\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmCA,SAAgB,YAAY,QAAyC;AACpE,QAAO,IAAI,kBAAkB;CAQ7B,MAAM,oBAAoB,OAAO,IAAI,UAAU,aAAa;CAC5D,MAAM,wBAAwBA,8BAAAA,6BAA6B;AAC3D,QAAO,IAAI,UACV,cACA,qBAAqB,OAClB,wBACA,CACA,IAAI,MAAM,QAAQ,kBAAkB,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,IAC/E,OACA,EACD,GAAG,sBACH,CACH;AAGD,QAAO,IAAI,UAAU,iBAAiB,WAAW;AAEjD,QAAO,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC"}
1
+ {"version":3,"file":"exitPreview.cjs","names":["expiredPreviewCookieHeaders","expiredDraftModeCookieHeaders","expiredPreviewDataCookieHeaders"],"sources":["../../src/pages/exitPreview.ts"],"sourcesContent":["import {\n\texpiredDraftModeCookieHeaders,\n\texpiredPreviewCookieHeaders,\n\texpiredPreviewDataCookieHeaders,\n} from \"../lib/expiredPreviewCookies\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `exitPreview()`. */\nexport type ExitPreviewAPIRouteConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq?: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/**\n * Ends a Prismic preview session within a Next.js app. This function should be used in an API\n * route.\n *\n * @example\n * \t;```typescript\n * \t// src/pages/api/exit-preview.js\n *\n * \timport { exitPreview } from \"@prismicio/next\"\n *\n * \texport default function handler(_req, res) {\n * \t\treturn exitPreview({ res })\n * \t}\n * \t```\n */\nexport function exitPreview(config: ExitPreviewAPIRouteConfig): void {\n\tconfig.res.clearPreviewData()\n\n\t// `clearPreviewData()` only clears Next.js preview cookies. Expire both\n\t// leftover `io.prismic.preview` shapes (toolbar Lax, not Secure; and the\n\t// iframe SameSite=None; Secure write). If either survives,\n\t// `<PrismicPreview>` calls `start()` → `/api/preview` and preview returns.\n\t// Next also emits Lax expiries in development, so explicitly clear the\n\t// Secure Next preview cookies written by `setPreviewData()`.\n\t// Do not use `cookies().set` — that is the App Router helper. Do not\n\t// replace the existing Set-Cookie header from `clearPreviewData()`.\n\tconst existingSetCookie = config.res.getHeader(\"Set-Cookie\")\n\tconst expiredPreviewCookies = [\n\t\t...expiredPreviewCookieHeaders(),\n\t\t...expiredDraftModeCookieHeaders(),\n\t\t...expiredPreviewDataCookieHeaders(),\n\t]\n\tconfig.res.setHeader(\n\t\t\"Set-Cookie\",\n\t\texistingSetCookie == null\n\t\t\t? expiredPreviewCookies\n\t\t\t: [\n\t\t\t\t\t...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(\n\t\t\t\t\t\tString,\n\t\t\t\t\t),\n\t\t\t\t\t...expiredPreviewCookies,\n\t\t\t\t],\n\t)\n\n\t// `Cache-Control` header is used to prevent CDN-level caching.\n\tconfig.res.setHeader(\"Cache-Control\", \"no-store\")\n\n\tconfig.res.json({ success: true })\n\n\treturn\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,QAAyC;AACpE,QAAO,IAAI,kBAAkB;CAU7B,MAAM,oBAAoB,OAAO,IAAI,UAAU,aAAa;CAC5D,MAAM,wBAAwB;EAC7B,GAAGA,8BAAAA,6BAA6B;EAChC,GAAGC,8BAAAA,+BAA+B;EAClC,GAAGC,8BAAAA,iCAAiC;EACpC;AACD,QAAO,IAAI,UACV,cACA,qBAAqB,OAClB,wBACA,CACA,IAAI,MAAM,QAAQ,kBAAkB,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,IAC/E,OACA,EACD,GAAG,sBACH,CACH;AAGD,QAAO,IAAI,UAAU,iBAAiB,WAAW;AAEjD,QAAO,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"exitPreview.d.cts","names":[],"sources":["../../src/pages/exitPreview.ts"],"mappings":";;;;KAIY,yBAAA;EAAA;;;;;EAMX,GAAA,GAAM,kBAAA;EAON;;;;AAkBD;EAlBC,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;;;;;;iBAkBU,WAAA,CAAY,MAAA,EAAQ,yBAAA"}
1
+ {"version":3,"file":"exitPreview.d.cts","names":[],"sources":["../../src/pages/exitPreview.ts"],"mappings":";;;;KAQY,yBAAA;EAAA;;;;;EAMX,GAAA,GAAM,kBAAA;EAON;;;;AAkBD;EAlBC,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;;;;;;iBAkBU,WAAA,CAAY,MAAA,EAAQ,yBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"exitPreview.d.ts","names":[],"sources":["../../src/pages/exitPreview.ts"],"mappings":";;;;KAIY,yBAAA;EAAA;;;;;EAMX,GAAA,GAAM,kBAAA;EAON;;;;AAkBD;EAlBC,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;;;;;;iBAkBU,WAAA,CAAY,MAAA,EAAQ,yBAAA"}
1
+ {"version":3,"file":"exitPreview.d.ts","names":[],"sources":["../../src/pages/exitPreview.ts"],"mappings":";;;;KAQY,yBAAA;EAAA;;;;;EAMX,GAAA,GAAM,kBAAA;EAON;;;;AAkBD;EAlBC,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;;;;;;iBAkBU,WAAA,CAAY,MAAA,EAAQ,yBAAA"}
@@ -1,4 +1,4 @@
1
- import { expiredPreviewCookieHeaders } from "../lib/expiredPreviewCookies.js";
1
+ import { expiredDraftModeCookieHeaders, expiredPreviewCookieHeaders, expiredPreviewDataCookieHeaders } from "../lib/expiredPreviewCookies.js";
2
2
  //#region src/pages/exitPreview.ts
3
3
  /**
4
4
  * Ends a Prismic preview session within a Next.js app. This function should be used in an API
@@ -18,7 +18,11 @@ import { expiredPreviewCookieHeaders } from "../lib/expiredPreviewCookies.js";
18
18
  function exitPreview(config) {
19
19
  config.res.clearPreviewData();
20
20
  const existingSetCookie = config.res.getHeader("Set-Cookie");
21
- const expiredPreviewCookies = expiredPreviewCookieHeaders();
21
+ const expiredPreviewCookies = [
22
+ ...expiredPreviewCookieHeaders(),
23
+ ...expiredDraftModeCookieHeaders(),
24
+ ...expiredPreviewDataCookieHeaders()
25
+ ];
22
26
  config.res.setHeader("Set-Cookie", existingSetCookie == null ? expiredPreviewCookies : [...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(String), ...expiredPreviewCookies]);
23
27
  config.res.setHeader("Cache-Control", "no-store");
24
28
  config.res.json({ success: true });
@@ -1 +1 @@
1
- {"version":3,"file":"exitPreview.js","names":[],"sources":["../../src/pages/exitPreview.ts"],"sourcesContent":["import { expiredPreviewCookieHeaders } from \"../lib/expiredPreviewCookies\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `exitPreview()`. */\nexport type ExitPreviewAPIRouteConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq?: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/**\n * Ends a Prismic preview session within a Next.js app. This function should be used in an API\n * route.\n *\n * @example\n * \t;```typescript\n * \t// src/pages/api/exit-preview.js\n *\n * \timport { exitPreview } from \"@prismicio/next\"\n *\n * \texport default function handler(_req, res) {\n * \t\treturn exitPreview({ res })\n * \t}\n * \t```\n */\nexport function exitPreview(config: ExitPreviewAPIRouteConfig): void {\n\tconfig.res.clearPreviewData()\n\n\t// `clearPreviewData()` only clears Next.js preview cookies. Expire both\n\t// leftover `io.prismic.preview` shapes (toolbar Lax, not Secure; and the\n\t// iframe SameSite=None; Secure write). If either survives,\n\t// `<PrismicPreview>` calls `start()` → `/api/preview` and preview returns.\n\t// Do not use `cookies().set` — that is the App Router helper. Do not\n\t// replace the existing Set-Cookie header from `clearPreviewData()`.\n\tconst existingSetCookie = config.res.getHeader(\"Set-Cookie\")\n\tconst expiredPreviewCookies = expiredPreviewCookieHeaders()\n\tconfig.res.setHeader(\n\t\t\"Set-Cookie\",\n\t\texistingSetCookie == null\n\t\t\t? expiredPreviewCookies\n\t\t\t: [\n\t\t\t\t\t...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(\n\t\t\t\t\t\tString,\n\t\t\t\t\t),\n\t\t\t\t\t...expiredPreviewCookies,\n\t\t\t\t],\n\t)\n\n\t// `Cache-Control` header is used to prevent CDN-level caching.\n\tconfig.res.setHeader(\"Cache-Control\", \"no-store\")\n\n\tconfig.res.json({ success: true })\n\n\treturn\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmCA,SAAgB,YAAY,QAAyC;AACpE,QAAO,IAAI,kBAAkB;CAQ7B,MAAM,oBAAoB,OAAO,IAAI,UAAU,aAAa;CAC5D,MAAM,wBAAwB,6BAA6B;AAC3D,QAAO,IAAI,UACV,cACA,qBAAqB,OAClB,wBACA,CACA,IAAI,MAAM,QAAQ,kBAAkB,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,IAC/E,OACA,EACD,GAAG,sBACH,CACH;AAGD,QAAO,IAAI,UAAU,iBAAiB,WAAW;AAEjD,QAAO,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC"}
1
+ {"version":3,"file":"exitPreview.js","names":[],"sources":["../../src/pages/exitPreview.ts"],"sourcesContent":["import {\n\texpiredDraftModeCookieHeaders,\n\texpiredPreviewCookieHeaders,\n\texpiredPreviewDataCookieHeaders,\n} from \"../lib/expiredPreviewCookies\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `exitPreview()`. */\nexport type ExitPreviewAPIRouteConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq?: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/**\n * Ends a Prismic preview session within a Next.js app. This function should be used in an API\n * route.\n *\n * @example\n * \t;```typescript\n * \t// src/pages/api/exit-preview.js\n *\n * \timport { exitPreview } from \"@prismicio/next\"\n *\n * \texport default function handler(_req, res) {\n * \t\treturn exitPreview({ res })\n * \t}\n * \t```\n */\nexport function exitPreview(config: ExitPreviewAPIRouteConfig): void {\n\tconfig.res.clearPreviewData()\n\n\t// `clearPreviewData()` only clears Next.js preview cookies. Expire both\n\t// leftover `io.prismic.preview` shapes (toolbar Lax, not Secure; and the\n\t// iframe SameSite=None; Secure write). If either survives,\n\t// `<PrismicPreview>` calls `start()` → `/api/preview` and preview returns.\n\t// Next also emits Lax expiries in development, so explicitly clear the\n\t// Secure Next preview cookies written by `setPreviewData()`.\n\t// Do not use `cookies().set` — that is the App Router helper. Do not\n\t// replace the existing Set-Cookie header from `clearPreviewData()`.\n\tconst existingSetCookie = config.res.getHeader(\"Set-Cookie\")\n\tconst expiredPreviewCookies = [\n\t\t...expiredPreviewCookieHeaders(),\n\t\t...expiredDraftModeCookieHeaders(),\n\t\t...expiredPreviewDataCookieHeaders(),\n\t]\n\tconfig.res.setHeader(\n\t\t\"Set-Cookie\",\n\t\texistingSetCookie == null\n\t\t\t? expiredPreviewCookies\n\t\t\t: [\n\t\t\t\t\t...(Array.isArray(existingSetCookie) ? existingSetCookie : [existingSetCookie]).map(\n\t\t\t\t\t\tString,\n\t\t\t\t\t),\n\t\t\t\t\t...expiredPreviewCookies,\n\t\t\t\t],\n\t)\n\n\t// `Cache-Control` header is used to prevent CDN-level caching.\n\tconfig.res.setHeader(\"Cache-Control\", \"no-store\")\n\n\tconfig.res.json({ success: true })\n\n\treturn\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,SAAgB,YAAY,QAAyC;AACpE,QAAO,IAAI,kBAAkB;CAU7B,MAAM,oBAAoB,OAAO,IAAI,UAAU,aAAa;CAC5D,MAAM,wBAAwB;EAC7B,GAAG,6BAA6B;EAChC,GAAG,+BAA+B;EAClC,GAAG,iCAAiC;EACpC;AACD,QAAO,IAAI,UACV,cACA,qBAAqB,OAClB,wBACA,CACA,IAAI,MAAM,QAAQ,kBAAkB,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,IAC/E,OACA,EACD,GAAG,sBACH,CACH;AAGD,QAAO,IAAI,UAAU,iBAAiB,WAAW;AAEjD,QAAO,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC"}
@@ -1,10 +1,16 @@
1
1
  require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_previewRefFromCookie = require("../lib/previewRefFromCookie.cjs");
2
3
  let _prismicio_client = require("@prismicio/client");
3
4
  //#region src/pages/setPreviewData.ts
4
5
  /** Set Prismic preview data for Next.js's Preview Mode. */
5
6
  function setPreviewData({ req, res }) {
6
- const ref = req.query.token || req.cookies[_prismicio_client.cookie.preview];
7
- if (ref) res.setPreviewData({ ref });
7
+ const previewCookie = req.cookies[_prismicio_client.cookie.preview];
8
+ const ref = req.query.token || previewCookie && require_previewRefFromCookie.previewRefFromCookie(previewCookie);
9
+ if (ref) {
10
+ res.setPreviewData({ ref });
11
+ const setCookie = res.getHeader("Set-Cookie");
12
+ if (typeof setCookie === "string" || Array.isArray(setCookie)) res.setHeader("Set-Cookie", (typeof setCookie === "string" ? [setCookie] : setCookie).map((header) => /^__(?:prerender_bypass|next_preview_data)=/.test(header) ? `${header.replace(/;\s*(?:Secure|SameSite=[^;]*)(?=;|$)/gi, "")}; SameSite=None; Secure` : header));
13
+ }
8
14
  }
9
15
  //#endregion
10
16
  exports.setPreviewData = setPreviewData;
@@ -1 +1 @@
1
- {"version":3,"file":"setPreviewData.cjs","names":["cookie"],"sources":["../../src/pages/setPreviewData.ts"],"sourcesContent":["import { cookie } from \"@prismicio/client\"\n\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `setPreviewData`. */\nexport type SetPreviewDataConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/** Set Prismic preview data for Next.js's Preview Mode. */\nexport function setPreviewData({ req, res }: SetPreviewDataConfig): void {\n\tconst ref = req.query.token || req.cookies[cookie.preview]\n\n\tif (ref) {\n\t\tres.setPreviewData({ ref })\n\t}\n}\n"],"mappings":";;;;AAsBA,SAAgB,eAAe,EAAE,KAAK,OAAmC;CACxE,MAAM,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQA,kBAAAA,OAAO;AAElD,KAAI,IACH,KAAI,eAAe,EAAE,KAAK,CAAC"}
1
+ {"version":3,"file":"setPreviewData.cjs","names":["cookie","previewRefFromCookie"],"sources":["../../src/pages/setPreviewData.ts"],"sourcesContent":["import { cookie } from \"@prismicio/client\"\n\nimport { previewRefFromCookie } from \"../lib/previewRefFromCookie\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `setPreviewData`. */\nexport type SetPreviewDataConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/** Set Prismic preview data for Next.js's Preview Mode. */\nexport function setPreviewData({ req, res }: SetPreviewDataConfig): void {\n\t// Only unwrap the cookie. Query tokens, including arrays, stay as-is.\n\tconst previewCookie = req.cookies[cookie.preview]\n\tconst ref = req.query.token || (previewCookie && previewRefFromCookie(previewCookie))\n\tif (ref) {\n\t\tres.setPreviewData({ ref })\n\n\t\t// Next.js uses Lax preview cookies in development. Preserve its\n\t\t// signed/encrypted values and all other attributes, but allow both\n\t\t// cookies to reach the site inside the editor's cross-site iframe.\n\t\tconst setCookie = res.getHeader(\"Set-Cookie\")\n\t\tif (typeof setCookie === \"string\" || Array.isArray(setCookie)) {\n\t\t\tres.setHeader(\n\t\t\t\t\"Set-Cookie\",\n\t\t\t\t(typeof setCookie === \"string\" ? [setCookie] : setCookie).map((header) =>\n\t\t\t\t\t/^__(?:prerender_bypass|next_preview_data)=/.test(header)\n\t\t\t\t\t\t? `${header.replace(/;\\s*(?:Secure|SameSite=[^;]*)(?=;|$)/gi, \"\")}; SameSite=None; Secure`\n\t\t\t\t\t\t: header,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAuBA,SAAgB,eAAe,EAAE,KAAK,OAAmC;CAExE,MAAM,gBAAgB,IAAI,QAAQA,kBAAAA,OAAO;CACzC,MAAM,MAAM,IAAI,MAAM,SAAU,iBAAiBC,6BAAAA,qBAAqB,cAAc;AACpF,KAAI,KAAK;AACR,MAAI,eAAe,EAAE,KAAK,CAAC;EAK3B,MAAM,YAAY,IAAI,UAAU,aAAa;AAC7C,MAAI,OAAO,cAAc,YAAY,MAAM,QAAQ,UAAU,CAC5D,KAAI,UACH,eACC,OAAO,cAAc,WAAW,CAAC,UAAU,GAAG,WAAW,KAAK,WAC9D,6CAA6C,KAAK,OAAO,GACtD,GAAG,OAAO,QAAQ,0CAA0C,GAAG,CAAC,2BAChE,OACH,CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"setPreviewData.d.cts","names":[],"sources":["../../src/pages/setPreviewData.ts"],"mappings":";;;;KAKY,oBAAA;EAAA;;;;;EAMX,GAAA,EAAK,kBAAA;EAOL;;;;AAID;EAJC,GAAA,EAAK,mBAAA;AAAA;;iBAIU,cAAA,CAAA;EAAiB,GAAA;EAAK;AAAA,GAAO,oBAAA"}
1
+ {"version":3,"file":"setPreviewData.d.cts","names":[],"sources":["../../src/pages/setPreviewData.ts"],"mappings":";;;;KAMY,oBAAA;EAAA;;;;;EAMX,GAAA,EAAK,kBAAA;EAOL;;;;AAID;EAJC,GAAA,EAAK,mBAAA;AAAA;;iBAIU,cAAA,CAAA;EAAiB,GAAA;EAAK;AAAA,GAAO,oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"setPreviewData.d.ts","names":[],"sources":["../../src/pages/setPreviewData.ts"],"mappings":";;;;KAKY,oBAAA;EAAA;;;;;EAMX,GAAA,EAAK,kBAAA;EAOL;;;;AAID;EAJC,GAAA,EAAK,mBAAA;AAAA;;iBAIU,cAAA,CAAA;EAAiB,GAAA;EAAK;AAAA,GAAO,oBAAA"}
1
+ {"version":3,"file":"setPreviewData.d.ts","names":[],"sources":["../../src/pages/setPreviewData.ts"],"mappings":";;;;KAMY,oBAAA;EAAA;;;;;EAMX,GAAA,EAAK,kBAAA;EAOL;;;;AAID;EAJC,GAAA,EAAK,mBAAA;AAAA;;iBAIU,cAAA,CAAA;EAAiB,GAAA;EAAK;AAAA,GAAO,oBAAA"}
@@ -1,9 +1,15 @@
1
+ import { previewRefFromCookie } from "../lib/previewRefFromCookie.js";
1
2
  import { cookie } from "@prismicio/client";
2
3
  //#region src/pages/setPreviewData.ts
3
4
  /** Set Prismic preview data for Next.js's Preview Mode. */
4
5
  function setPreviewData({ req, res }) {
5
- const ref = req.query.token || req.cookies[cookie.preview];
6
- if (ref) res.setPreviewData({ ref });
6
+ const previewCookie = req.cookies[cookie.preview];
7
+ const ref = req.query.token || previewCookie && previewRefFromCookie(previewCookie);
8
+ if (ref) {
9
+ res.setPreviewData({ ref });
10
+ const setCookie = res.getHeader("Set-Cookie");
11
+ if (typeof setCookie === "string" || Array.isArray(setCookie)) res.setHeader("Set-Cookie", (typeof setCookie === "string" ? [setCookie] : setCookie).map((header) => /^__(?:prerender_bypass|next_preview_data)=/.test(header) ? `${header.replace(/;\s*(?:Secure|SameSite=[^;]*)(?=;|$)/gi, "")}; SameSite=None; Secure` : header));
12
+ }
7
13
  }
8
14
  //#endregion
9
15
  export { setPreviewData };
@@ -1 +1 @@
1
- {"version":3,"file":"setPreviewData.js","names":[],"sources":["../../src/pages/setPreviewData.ts"],"sourcesContent":["import { cookie } from \"@prismicio/client\"\n\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `setPreviewData`. */\nexport type SetPreviewDataConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/** Set Prismic preview data for Next.js's Preview Mode. */\nexport function setPreviewData({ req, res }: SetPreviewDataConfig): void {\n\tconst ref = req.query.token || req.cookies[cookie.preview]\n\n\tif (ref) {\n\t\tres.setPreviewData({ ref })\n\t}\n}\n"],"mappings":";;;AAsBA,SAAgB,eAAe,EAAE,KAAK,OAAmC;CACxE,MAAM,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,OAAO;AAElD,KAAI,IACH,KAAI,eAAe,EAAE,KAAK,CAAC"}
1
+ {"version":3,"file":"setPreviewData.js","names":[],"sources":["../../src/pages/setPreviewData.ts"],"sourcesContent":["import { cookie } from \"@prismicio/client\"\n\nimport { previewRefFromCookie } from \"../lib/previewRefFromCookie\"\nimport type { NextApiRequestLike, NextApiResponseLike } from \"./types\"\n\n/** Configuration for `setPreviewData`. */\nexport type SetPreviewDataConfig = {\n\t/**\n\t * The `req` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\treq: NextApiRequestLike\n\n\t/**\n\t * The `res` object from a Next.js API route.\n\t *\n\t * @see Next.js API route docs: \\<https://nextjs.org/docs/api-routes/introduction\\>\n\t */\n\tres: NextApiResponseLike\n}\n\n/** Set Prismic preview data for Next.js's Preview Mode. */\nexport function setPreviewData({ req, res }: SetPreviewDataConfig): void {\n\t// Only unwrap the cookie. Query tokens, including arrays, stay as-is.\n\tconst previewCookie = req.cookies[cookie.preview]\n\tconst ref = req.query.token || (previewCookie && previewRefFromCookie(previewCookie))\n\tif (ref) {\n\t\tres.setPreviewData({ ref })\n\n\t\t// Next.js uses Lax preview cookies in development. Preserve its\n\t\t// signed/encrypted values and all other attributes, but allow both\n\t\t// cookies to reach the site inside the editor's cross-site iframe.\n\t\tconst setCookie = res.getHeader(\"Set-Cookie\")\n\t\tif (typeof setCookie === \"string\" || Array.isArray(setCookie)) {\n\t\t\tres.setHeader(\n\t\t\t\t\"Set-Cookie\",\n\t\t\t\t(typeof setCookie === \"string\" ? [setCookie] : setCookie).map((header) =>\n\t\t\t\t\t/^__(?:prerender_bypass|next_preview_data)=/.test(header)\n\t\t\t\t\t\t? `${header.replace(/;\\s*(?:Secure|SameSite=[^;]*)(?=;|$)/gi, \"\")}; SameSite=None; Secure`\n\t\t\t\t\t\t: header,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t}\n}\n"],"mappings":";;;;AAuBA,SAAgB,eAAe,EAAE,KAAK,OAAmC;CAExE,MAAM,gBAAgB,IAAI,QAAQ,OAAO;CACzC,MAAM,MAAM,IAAI,MAAM,SAAU,iBAAiB,qBAAqB,cAAc;AACpF,KAAI,KAAK;AACR,MAAI,eAAe,EAAE,KAAK,CAAC;EAK3B,MAAM,YAAY,IAAI,UAAU,aAAa;AAC7C,MAAI,OAAO,cAAc,YAAY,MAAM,QAAQ,UAAU,CAC5D,KAAI,UACH,eACC,OAAO,cAAc,WAAW,CAAC,UAAU,GAAG,WAAW,KAAK,WAC9D,6CAA6C,KAAK,OAAO,GACtD,GAAG,OAAO,QAAQ,0CAA0C,GAAG,CAAC,2BAChE,OACH,CACD"}
@@ -20,6 +20,14 @@ async function redirectToPreviewURL(config) {
20
20
  linkResolver
21
21
  });
22
22
  (await draftMode()).enable();
23
+ const cookieJar = await cookies();
24
+ const draftCookie = cookieJar.get("__prerender_bypass");
25
+ if (draftCookie) cookieJar.set(draftCookie.name, draftCookie.value, {
26
+ path: "/",
27
+ sameSite: "none",
28
+ secure: true,
29
+ httpOnly: true
30
+ });
23
31
  return redirect(previewURL);
24
32
  }
25
33
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"redirectToPreviewURL.cjs","names":["prismicCookie"],"sources":["../src/redirectToPreviewURL.ts"],"sourcesContent":["import { cookie as prismicCookie, type Client, type LinkResolverFunction } from \"@prismicio/client\"\n\nimport type { NextRequestLike } from \"./types\"\n\nexport type RedirectToPreviewURLConfig = {\n\t/** The Prismic client configured for the preview session's repository. */\n\t// `Pick` is used to use the smallest possible subset of\n\t// `prismic.Client`. Doing this reduces the surface area for breaking\n\t// type changes.\n\tclient: Pick<Client, \"resolvePreviewURL\">\n\n\t/**\n\t * The `request` object from a Next.js Route Handler.\n\t *\n\t * @see Next.js Route Handler docs: \\<https://nextjs.org/docs/app/building-your-application/routing/route-handlers\\>\n\t */\n\trequest: NextRequestLike\n\n\t/**\n\t * A Link Resolver used to resolve the previewed document's URL.\n\t *\n\t * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}\n\t */\n\tlinkResolver?: LinkResolverFunction\n\n\t/**\n\t * The default redirect URL if a URL cannot be determined for the previewed document.\n\t *\n\t * **Note**: If you `next.config.js` file contains a `basePath`, the `defaultURL` option must\n\t * _not_ include it. Instead, provide the `basePath` property using the `basePath` option.\n\t */\n\tdefaultURL?: string\n}\n\nexport async function redirectToPreviewURL(config: RedirectToPreviewURLConfig): Promise<never> {\n\tconst { client, request, linkResolver, defaultURL = \"/\" } = config\n\n\t// Need this to avoid the following Next.js build-time error:\n\t// You're importing a component that needs next/headers. That only works\n\t// in a Server Component which is not supported in the pages/ directory.\n\tconst { cookies, draftMode } = await import(\"next/headers\")\n\n\t// Dynamic so Node.js can load this module: the bare specifier (kept by\n\t// tsdown.config.ts for Next.js's server alias) is not resolvable by Node.js.\n\tconst { redirect } = await import(\"next/navigation\")\n\n\tconst documentID = request.nextUrl.searchParams.get(\"documentId\") ?? undefined\n\n\t// Set the initial preview cookie. Setting the cookie here is necessary\n\t// to support unpublished previews. Without setting it here, the page\n\t// will try to render without the preview cookie, leading to a\n\t// PrismicNotFound error.\n\t//\n\t// Path=/; SameSite=None; Secure so the cookie is sent when the site is\n\t// embedded in a cross-site iframe (e.g. the Platform editor). Chrome\n\t// defaults omitted SameSite to Lax and strips the cookie from those\n\t// requests. Do not set HttpOnly: the toolbar reads `document.cookie`.\n\tconst previewToken = request.nextUrl.searchParams.get(\"token\") ?? undefined\n\tif (previewToken) {\n\t\tconst cookieJar = await cookies()\n\t\tcookieJar.set(prismicCookie.preview, previewToken, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: false,\n\t\t})\n\t}\n\n\tconst previewURL = await client.resolvePreviewURL({\n\t\tdocumentID,\n\t\tpreviewToken,\n\t\tdefaultURL,\n\t\tlinkResolver,\n\t})\n\n\t;(await draftMode()).enable()\n\n\treturn redirect(previewURL)\n}\n"],"mappings":";;;AAkCA,eAAsB,qBAAqB,QAAoD;CAC9F,MAAM,EAAE,QAAQ,SAAS,cAAc,aAAa,QAAQ;CAK5D,MAAM,EAAE,SAAS,cAAc,MAAM,OAAO;CAI5C,MAAM,EAAE,aAAa,MAAM,OAAO;CAElC,MAAM,aAAa,QAAQ,QAAQ,aAAa,IAAI,aAAa,IAAI,KAAA;CAWrE,MAAM,eAAe,QAAQ,QAAQ,aAAa,IAAI,QAAQ,IAAI,KAAA;AAClE,KAAI,aAEH,EADkB,MAAM,SAAS,EACvB,IAAIA,kBAAAA,OAAc,SAAS,cAAc;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;CAGH,MAAM,aAAa,MAAM,OAAO,kBAAkB;EACjD;EACA;EACA;EACA;EACA,CAAC;AAED,EAAC,MAAM,WAAW,EAAE,QAAQ;AAE7B,QAAO,SAAS,WAAW"}
1
+ {"version":3,"file":"redirectToPreviewURL.cjs","names":["prismicCookie"],"sources":["../src/redirectToPreviewURL.ts"],"sourcesContent":["import { cookie as prismicCookie, type Client, type LinkResolverFunction } from \"@prismicio/client\"\n\nimport type { NextRequestLike } from \"./types\"\n\nexport type RedirectToPreviewURLConfig = {\n\t/** The Prismic client configured for the preview session's repository. */\n\t// `Pick` is used to use the smallest possible subset of\n\t// `prismic.Client`. Doing this reduces the surface area for breaking\n\t// type changes.\n\tclient: Pick<Client, \"resolvePreviewURL\">\n\n\t/**\n\t * The `request` object from a Next.js Route Handler.\n\t *\n\t * @see Next.js Route Handler docs: \\<https://nextjs.org/docs/app/building-your-application/routing/route-handlers\\>\n\t */\n\trequest: NextRequestLike\n\n\t/**\n\t * A Link Resolver used to resolve the previewed document's URL.\n\t *\n\t * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}\n\t */\n\tlinkResolver?: LinkResolverFunction\n\n\t/**\n\t * The default redirect URL if a URL cannot be determined for the previewed document.\n\t *\n\t * **Note**: If you `next.config.js` file contains a `basePath`, the `defaultURL` option must\n\t * _not_ include it. Instead, provide the `basePath` property using the `basePath` option.\n\t */\n\tdefaultURL?: string\n}\n\nexport async function redirectToPreviewURL(config: RedirectToPreviewURLConfig): Promise<never> {\n\tconst { client, request, linkResolver, defaultURL = \"/\" } = config\n\n\t// Need this to avoid the following Next.js build-time error:\n\t// You're importing a component that needs next/headers. That only works\n\t// in a Server Component which is not supported in the pages/ directory.\n\tconst { cookies, draftMode } = await import(\"next/headers\")\n\n\t// Dynamic so Node.js can load this module: the bare specifier (kept by\n\t// tsdown.config.ts for Next.js's server alias) is not resolvable by Node.js.\n\tconst { redirect } = await import(\"next/navigation\")\n\n\tconst documentID = request.nextUrl.searchParams.get(\"documentId\") ?? undefined\n\n\t// Set the initial preview cookie. Setting the cookie here is necessary\n\t// to support unpublished previews. Without setting it here, the page\n\t// will try to render without the preview cookie, leading to a\n\t// PrismicNotFound error.\n\t//\n\t// Path=/; SameSite=None; Secure so the cookie is sent when the site is\n\t// embedded in a cross-site iframe (e.g. the Platform editor). Chrome\n\t// defaults omitted SameSite to Lax and strips the cookie from those\n\t// requests. Do not set HttpOnly: the toolbar reads `document.cookie`.\n\tconst previewToken = request.nextUrl.searchParams.get(\"token\") ?? undefined\n\tif (previewToken) {\n\t\tconst cookieJar = await cookies()\n\t\tcookieJar.set(prismicCookie.preview, previewToken, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: false,\n\t\t})\n\t}\n\n\tconst previewURL = await client.resolvePreviewURL({\n\t\tdocumentID,\n\t\tpreviewToken,\n\t\tdefaultURL,\n\t\tlinkResolver,\n\t})\n\n\t;(await draftMode()).enable()\n\t// Next.js uses SameSite=Lax for Draft Mode in development. Keep its\n\t// generated value, but allow the editor iframe to send this cookie too.\n\tconst cookieJar = await cookies()\n\tconst draftCookie = cookieJar.get(\"__prerender_bypass\")\n\tif (draftCookie) {\n\t\tcookieJar.set(draftCookie.name, draftCookie.value, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: true,\n\t\t})\n\t}\n\n\treturn redirect(previewURL)\n}\n"],"mappings":";;;AAkCA,eAAsB,qBAAqB,QAAoD;CAC9F,MAAM,EAAE,QAAQ,SAAS,cAAc,aAAa,QAAQ;CAK5D,MAAM,EAAE,SAAS,cAAc,MAAM,OAAO;CAI5C,MAAM,EAAE,aAAa,MAAM,OAAO;CAElC,MAAM,aAAa,QAAQ,QAAQ,aAAa,IAAI,aAAa,IAAI,KAAA;CAWrE,MAAM,eAAe,QAAQ,QAAQ,aAAa,IAAI,QAAQ,IAAI,KAAA;AAClE,KAAI,aAEH,EADkB,MAAM,SAAS,EACvB,IAAIA,kBAAAA,OAAc,SAAS,cAAc;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;CAGH,MAAM,aAAa,MAAM,OAAO,kBAAkB;EACjD;EACA;EACA;EACA;EACA,CAAC;AAED,EAAC,MAAM,WAAW,EAAE,QAAQ;CAG7B,MAAM,YAAY,MAAM,SAAS;CACjC,MAAM,cAAc,UAAU,IAAI,qBAAqB;AACvD,KAAI,YACH,WAAU,IAAI,YAAY,MAAM,YAAY,OAAO;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;AAGH,QAAO,SAAS,WAAW"}
@@ -19,6 +19,14 @@ async function redirectToPreviewURL(config) {
19
19
  linkResolver
20
20
  });
21
21
  (await draftMode()).enable();
22
+ const cookieJar = await cookies();
23
+ const draftCookie = cookieJar.get("__prerender_bypass");
24
+ if (draftCookie) cookieJar.set(draftCookie.name, draftCookie.value, {
25
+ path: "/",
26
+ sameSite: "none",
27
+ secure: true,
28
+ httpOnly: true
29
+ });
22
30
  return redirect(previewURL);
23
31
  }
24
32
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"redirectToPreviewURL.js","names":["prismicCookie"],"sources":["../src/redirectToPreviewURL.ts"],"sourcesContent":["import { cookie as prismicCookie, type Client, type LinkResolverFunction } from \"@prismicio/client\"\n\nimport type { NextRequestLike } from \"./types\"\n\nexport type RedirectToPreviewURLConfig = {\n\t/** The Prismic client configured for the preview session's repository. */\n\t// `Pick` is used to use the smallest possible subset of\n\t// `prismic.Client`. Doing this reduces the surface area for breaking\n\t// type changes.\n\tclient: Pick<Client, \"resolvePreviewURL\">\n\n\t/**\n\t * The `request` object from a Next.js Route Handler.\n\t *\n\t * @see Next.js Route Handler docs: \\<https://nextjs.org/docs/app/building-your-application/routing/route-handlers\\>\n\t */\n\trequest: NextRequestLike\n\n\t/**\n\t * A Link Resolver used to resolve the previewed document's URL.\n\t *\n\t * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}\n\t */\n\tlinkResolver?: LinkResolverFunction\n\n\t/**\n\t * The default redirect URL if a URL cannot be determined for the previewed document.\n\t *\n\t * **Note**: If you `next.config.js` file contains a `basePath`, the `defaultURL` option must\n\t * _not_ include it. Instead, provide the `basePath` property using the `basePath` option.\n\t */\n\tdefaultURL?: string\n}\n\nexport async function redirectToPreviewURL(config: RedirectToPreviewURLConfig): Promise<never> {\n\tconst { client, request, linkResolver, defaultURL = \"/\" } = config\n\n\t// Need this to avoid the following Next.js build-time error:\n\t// You're importing a component that needs next/headers. That only works\n\t// in a Server Component which is not supported in the pages/ directory.\n\tconst { cookies, draftMode } = await import(\"next/headers\")\n\n\t// Dynamic so Node.js can load this module: the bare specifier (kept by\n\t// tsdown.config.ts for Next.js's server alias) is not resolvable by Node.js.\n\tconst { redirect } = await import(\"next/navigation\")\n\n\tconst documentID = request.nextUrl.searchParams.get(\"documentId\") ?? undefined\n\n\t// Set the initial preview cookie. Setting the cookie here is necessary\n\t// to support unpublished previews. Without setting it here, the page\n\t// will try to render without the preview cookie, leading to a\n\t// PrismicNotFound error.\n\t//\n\t// Path=/; SameSite=None; Secure so the cookie is sent when the site is\n\t// embedded in a cross-site iframe (e.g. the Platform editor). Chrome\n\t// defaults omitted SameSite to Lax and strips the cookie from those\n\t// requests. Do not set HttpOnly: the toolbar reads `document.cookie`.\n\tconst previewToken = request.nextUrl.searchParams.get(\"token\") ?? undefined\n\tif (previewToken) {\n\t\tconst cookieJar = await cookies()\n\t\tcookieJar.set(prismicCookie.preview, previewToken, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: false,\n\t\t})\n\t}\n\n\tconst previewURL = await client.resolvePreviewURL({\n\t\tdocumentID,\n\t\tpreviewToken,\n\t\tdefaultURL,\n\t\tlinkResolver,\n\t})\n\n\t;(await draftMode()).enable()\n\n\treturn redirect(previewURL)\n}\n"],"mappings":";;AAkCA,eAAsB,qBAAqB,QAAoD;CAC9F,MAAM,EAAE,QAAQ,SAAS,cAAc,aAAa,QAAQ;CAK5D,MAAM,EAAE,SAAS,cAAc,MAAM,OAAO;CAI5C,MAAM,EAAE,aAAa,MAAM,OAAO;CAElC,MAAM,aAAa,QAAQ,QAAQ,aAAa,IAAI,aAAa,IAAI,KAAA;CAWrE,MAAM,eAAe,QAAQ,QAAQ,aAAa,IAAI,QAAQ,IAAI,KAAA;AAClE,KAAI,aAEH,EADkB,MAAM,SAAS,EACvB,IAAIA,OAAc,SAAS,cAAc;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;CAGH,MAAM,aAAa,MAAM,OAAO,kBAAkB;EACjD;EACA;EACA;EACA;EACA,CAAC;AAED,EAAC,MAAM,WAAW,EAAE,QAAQ;AAE7B,QAAO,SAAS,WAAW"}
1
+ {"version":3,"file":"redirectToPreviewURL.js","names":["prismicCookie"],"sources":["../src/redirectToPreviewURL.ts"],"sourcesContent":["import { cookie as prismicCookie, type Client, type LinkResolverFunction } from \"@prismicio/client\"\n\nimport type { NextRequestLike } from \"./types\"\n\nexport type RedirectToPreviewURLConfig = {\n\t/** The Prismic client configured for the preview session's repository. */\n\t// `Pick` is used to use the smallest possible subset of\n\t// `prismic.Client`. Doing this reduces the surface area for breaking\n\t// type changes.\n\tclient: Pick<Client, \"resolvePreviewURL\">\n\n\t/**\n\t * The `request` object from a Next.js Route Handler.\n\t *\n\t * @see Next.js Route Handler docs: \\<https://nextjs.org/docs/app/building-your-application/routing/route-handlers\\>\n\t */\n\trequest: NextRequestLike\n\n\t/**\n\t * A Link Resolver used to resolve the previewed document's URL.\n\t *\n\t * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}\n\t */\n\tlinkResolver?: LinkResolverFunction\n\n\t/**\n\t * The default redirect URL if a URL cannot be determined for the previewed document.\n\t *\n\t * **Note**: If you `next.config.js` file contains a `basePath`, the `defaultURL` option must\n\t * _not_ include it. Instead, provide the `basePath` property using the `basePath` option.\n\t */\n\tdefaultURL?: string\n}\n\nexport async function redirectToPreviewURL(config: RedirectToPreviewURLConfig): Promise<never> {\n\tconst { client, request, linkResolver, defaultURL = \"/\" } = config\n\n\t// Need this to avoid the following Next.js build-time error:\n\t// You're importing a component that needs next/headers. That only works\n\t// in a Server Component which is not supported in the pages/ directory.\n\tconst { cookies, draftMode } = await import(\"next/headers\")\n\n\t// Dynamic so Node.js can load this module: the bare specifier (kept by\n\t// tsdown.config.ts for Next.js's server alias) is not resolvable by Node.js.\n\tconst { redirect } = await import(\"next/navigation\")\n\n\tconst documentID = request.nextUrl.searchParams.get(\"documentId\") ?? undefined\n\n\t// Set the initial preview cookie. Setting the cookie here is necessary\n\t// to support unpublished previews. Without setting it here, the page\n\t// will try to render without the preview cookie, leading to a\n\t// PrismicNotFound error.\n\t//\n\t// Path=/; SameSite=None; Secure so the cookie is sent when the site is\n\t// embedded in a cross-site iframe (e.g. the Platform editor). Chrome\n\t// defaults omitted SameSite to Lax and strips the cookie from those\n\t// requests. Do not set HttpOnly: the toolbar reads `document.cookie`.\n\tconst previewToken = request.nextUrl.searchParams.get(\"token\") ?? undefined\n\tif (previewToken) {\n\t\tconst cookieJar = await cookies()\n\t\tcookieJar.set(prismicCookie.preview, previewToken, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: false,\n\t\t})\n\t}\n\n\tconst previewURL = await client.resolvePreviewURL({\n\t\tdocumentID,\n\t\tpreviewToken,\n\t\tdefaultURL,\n\t\tlinkResolver,\n\t})\n\n\t;(await draftMode()).enable()\n\t// Next.js uses SameSite=Lax for Draft Mode in development. Keep its\n\t// generated value, but allow the editor iframe to send this cookie too.\n\tconst cookieJar = await cookies()\n\tconst draftCookie = cookieJar.get(\"__prerender_bypass\")\n\tif (draftCookie) {\n\t\tcookieJar.set(draftCookie.name, draftCookie.value, {\n\t\t\tpath: \"/\",\n\t\t\tsameSite: \"none\",\n\t\t\tsecure: true,\n\t\t\thttpOnly: true,\n\t\t})\n\t}\n\n\treturn redirect(previewURL)\n}\n"],"mappings":";;AAkCA,eAAsB,qBAAqB,QAAoD;CAC9F,MAAM,EAAE,QAAQ,SAAS,cAAc,aAAa,QAAQ;CAK5D,MAAM,EAAE,SAAS,cAAc,MAAM,OAAO;CAI5C,MAAM,EAAE,aAAa,MAAM,OAAO;CAElC,MAAM,aAAa,QAAQ,QAAQ,aAAa,IAAI,aAAa,IAAI,KAAA;CAWrE,MAAM,eAAe,QAAQ,QAAQ,aAAa,IAAI,QAAQ,IAAI,KAAA;AAClE,KAAI,aAEH,EADkB,MAAM,SAAS,EACvB,IAAIA,OAAc,SAAS,cAAc;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;CAGH,MAAM,aAAa,MAAM,OAAO,kBAAkB;EACjD;EACA;EACA;EACA;EACA,CAAC;AAED,EAAC,MAAM,WAAW,EAAE,QAAQ;CAG7B,MAAM,YAAY,MAAM,SAAS;CACjC,MAAM,cAAc,UAAU,IAAI,qBAAqB;AACvD,KAAI,YACH,WAAU,IAAI,YAAY,MAAM,YAAY,OAAO;EAClD,MAAM;EACN,UAAU;EACV,QAAQ;EACR,UAAU;EACV,CAAC;AAGH,QAAO,SAAS,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismicio/next",
3
- "version": "2.3.1-pr.147.05dde81",
3
+ "version": "2.3.1-pr.147.286b2d0",
4
4
  "description": "Helpers to integrate Prismic into Next.js apps",
5
5
  "keywords": [
6
6
  "next",
@@ -24,6 +24,9 @@ export const PrismicPreviewClient: FC<PrismicPreviewClientProps> = (props) => {
24
24
 
25
25
  useEffect(() => {
26
26
  const controller = new AbortController()
27
+ let starting: Promise<void> | undefined
28
+ let startController: AbortController | undefined
29
+ let ending = false
27
30
 
28
31
  window.addEventListener("prismicPreviewUpdate", onUpdate, {
29
32
  signal: controller.signal,
@@ -42,14 +45,21 @@ export const PrismicPreviewClient: FC<PrismicPreviewClientProps> = (props) => {
42
45
  // share links do not go to the `updatePreviewURL` like a normal
43
46
  // preview.
44
47
  if (hasCookieForRepository && !isDraftMode) {
48
+ start()
49
+ }
50
+
51
+ function start() {
52
+ if (starting) return
53
+ startController = new AbortController()
54
+
45
55
  // We check `opaqueredirect` because we don't care if
46
56
  // the redirect was successful or not. As long as it
47
57
  // redirects, we know the endpoint exists and draft mode
48
58
  // is active.
49
- globalThis
59
+ starting = globalThis
50
60
  .fetch(updatePreviewURL, {
51
61
  redirect: "manual",
52
- signal: controller.signal,
62
+ signal: startController.signal,
53
63
  })
54
64
  .then((res) => {
55
65
  if (res.type !== "opaqueredirect") {
@@ -60,20 +70,35 @@ export const PrismicPreviewClient: FC<PrismicPreviewClientProps> = (props) => {
60
70
  return
61
71
  }
62
72
 
63
- refresh()
73
+ // A soft refresh does not reset Next.js's not-found boundary
74
+ // when an unpublished page enters Draft Mode at the same URL.
75
+ // Only this initial activation navigates; active previews stay soft.
76
+ window.location.reload()
64
77
  })
65
78
  .catch(() => {
66
79
  // noop
67
80
  })
81
+ .finally(() => {
82
+ starting = undefined
83
+ startController = undefined
84
+ })
68
85
  }
69
86
 
70
87
  function onUpdate(event: Event) {
71
88
  event.preventDefault()
72
- refresh()
89
+ if (ending) return
90
+ if (isDraftMode) {
91
+ refresh()
92
+ } else {
93
+ start()
94
+ }
73
95
  }
74
96
 
75
97
  function onEnd(event: Event) {
76
98
  event.preventDefault()
99
+ if (ending) return
100
+ ending = true
101
+ startController?.abort()
77
102
  globalThis
78
103
  .fetch(exitPreviewURL, { signal: controller.signal })
79
104
  .then((res) => {
@@ -90,9 +115,15 @@ export const PrismicPreviewClient: FC<PrismicPreviewClientProps> = (props) => {
90
115
  .catch(() => {
91
116
  // noop
92
117
  })
118
+ .finally(() => {
119
+ ending = false
120
+ })
93
121
  }
94
122
 
95
- return () => controller.abort()
123
+ return () => {
124
+ controller.abort()
125
+ startController?.abort()
126
+ }
96
127
  }, [repositoryName, isDraftMode, updatePreviewURL, exitPreviewURL, refresh])
97
128
 
98
129
  return null
@@ -1,5 +1,7 @@
1
1
  import { cookie as prismicCookie } from "@prismicio/client"
2
2
 
3
+ import { previewRefFromCookie } from "./lib/previewRefFromCookie"
4
+
3
5
  /**
4
6
  * Reads the Prismic preview ref for the current request when an active preview session exists.
5
7
  *
@@ -42,10 +44,8 @@ export async function getPreviewRef(): Promise<string | undefined> {
42
44
  return
43
45
  }
44
46
 
45
- const isActiveCookie = cookie.includes("websitePreviewId=")
46
- if (!isActiveCookie) {
47
- return
48
- }
49
-
50
- return cookie
47
+ // Draft Mode gates preview reads. The cookie may be a raw token or the
48
+ // toolbar jar (`{ "<repo>.prismic.io": { preview } }`). Only `preview` is a
49
+ // Content API ref; the jar string is not.
50
+ return previewRefFromCookie(cookie)
51
51
  }
@@ -30,3 +30,8 @@ export function expiredDraftModeCookieHeaders(): string[] {
30
30
  `${name}=; Path=/; ${expires}; SameSite=None; Secure; HttpOnly`,
31
31
  ]
32
32
  }
33
+
34
+ /** Expire Pages Router's signed preview data in development and production. */
35
+ export function expiredPreviewDataCookieHeaders(): string[] {
36
+ return expiredPreviewCookieHeaders("__next_preview_data").map((header) => `${header}; HttpOnly`)
37
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Unwraps `io.prismic.preview` to a Content API ref.
3
+ *
4
+ * After toolbar `PreviewCookie.sync` / `upsertPreviewForDomain`, the cookie is
5
+ * `{ [domain]: { preview: string } }`. Returning that jar makes `enableAutoPreviews`
6
+ * / Cache Components send a non-ref (ParsingError / 404). A jar with more than one
7
+ * repository `preview` is ambiguous and is ignored.
8
+ */
9
+ export function previewRefFromCookie(cookie: string): string | undefined {
10
+ try {
11
+ const parsed: unknown = JSON.parse(cookie)
12
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
13
+ return
14
+ }
15
+
16
+ const previewRefs: string[] = []
17
+ for (const value of Object.values(parsed)) {
18
+ if (
19
+ value !== null &&
20
+ typeof value === "object" &&
21
+ !Array.isArray(value) &&
22
+ "preview" in value &&
23
+ typeof value.preview === "string"
24
+ ) {
25
+ previewRefs.push(value.preview)
26
+ }
27
+ }
28
+
29
+ return previewRefs.length === 1 ? previewRefs[0] : undefined
30
+ } catch {
31
+ return cookie
32
+ }
33
+ }
@@ -50,6 +50,10 @@ export const PrismicPreview: FC<PrismicPreviewProps> = (props) => {
50
50
 
51
51
  useEffect(() => {
52
52
  const controller = new AbortController()
53
+ let starting: Promise<void> | undefined
54
+ let startController: AbortController | undefined
55
+ let updateRequested = false
56
+ let ending = false
53
57
 
54
58
  window.addEventListener("prismicPreviewUpdate", onUpdate, {
55
59
  signal: controller.signal,
@@ -74,6 +78,10 @@ export const PrismicPreview: FC<PrismicPreviewProps> = (props) => {
74
78
 
75
79
  function onEnd(event: Event) {
76
80
  event.preventDefault()
81
+ if (ending) return
82
+ ending = true
83
+ updateRequested = false
84
+ startController?.abort()
77
85
  fetch(router.basePath + exitPreviewURL, { signal: controller.signal })
78
86
  .then((res) => {
79
87
  if (!res.ok) {
@@ -87,41 +95,60 @@ export const PrismicPreview: FC<PrismicPreviewProps> = (props) => {
87
95
  refresh()
88
96
  })
89
97
  .catch(() => {})
98
+ .finally(() => {
99
+ ending = false
100
+ })
90
101
  }
91
102
 
92
103
  function onUpdate(event: Event) {
93
104
  event.preventDefault()
105
+ if (ending) return
94
106
  start()
95
107
  }
96
108
 
97
109
  function start() {
110
+ updateRequested = true
111
+ if (starting) return
112
+ const requestController = new AbortController()
113
+ startController = requestController
114
+
98
115
  // We check `opaqueredirect` because we don't care if
99
116
  // the redirect was successful or not. As long as it
100
117
  // redirects, we know the endpoint exists and at least
101
118
  // attempted to set preview data.
102
- fetch(router.basePath + updatePreviewURL, {
103
- redirect: "manual",
104
- signal: controller.signal,
105
- })
106
- .then((res) => {
119
+ starting = (async () => {
120
+ do {
121
+ updateRequested = false
122
+ const res = await fetch(router.basePath + updatePreviewURL, {
123
+ redirect: "manual",
124
+ signal: requestController.signal,
125
+ })
107
126
  if (res.type !== "opaqueredirect") {
108
127
  console.error(
109
128
  `[<PrismicPreview>] Failed to start or update the preview using "${updatePreviewURL}". Does it exist?`,
110
129
  )
111
-
112
130
  return
113
131
  }
114
-
115
- refresh()
116
- })
132
+ // Preview Data captures the cookie when the request starts.
133
+ // If edits arrived meanwhile, store the latest ref before rendering.
134
+ } while (updateRequested && !requestController.signal.aborted)
135
+ if (!requestController.signal.aborted) refresh()
136
+ })()
117
137
  .catch(() => {})
138
+ .finally(() => {
139
+ starting = undefined
140
+ startController = undefined
141
+ })
118
142
  }
119
143
 
120
144
  function refresh() {
121
145
  router.replace(router.asPath, undefined, { scroll: false })
122
146
  }
123
147
 
124
- return () => controller.abort()
148
+ return () => {
149
+ controller.abort()
150
+ startController?.abort()
151
+ }
125
152
  }, [exitPreviewURL, updatePreviewURL, repositoryName, router])
126
153
 
127
154
  return (
@@ -1,4 +1,8 @@
1
- import { expiredPreviewCookieHeaders } from "../lib/expiredPreviewCookies"
1
+ import {
2
+ expiredDraftModeCookieHeaders,
3
+ expiredPreviewCookieHeaders,
4
+ expiredPreviewDataCookieHeaders,
5
+ } from "../lib/expiredPreviewCookies"
2
6
  import type { NextApiRequestLike, NextApiResponseLike } from "./types"
3
7
 
4
8
  /** Configuration for `exitPreview()`. */
@@ -40,10 +44,16 @@ export function exitPreview(config: ExitPreviewAPIRouteConfig): void {
40
44
  // leftover `io.prismic.preview` shapes (toolbar Lax, not Secure; and the
41
45
  // iframe SameSite=None; Secure write). If either survives,
42
46
  // `<PrismicPreview>` calls `start()` → `/api/preview` and preview returns.
47
+ // Next also emits Lax expiries in development, so explicitly clear the
48
+ // Secure Next preview cookies written by `setPreviewData()`.
43
49
  // Do not use `cookies().set` — that is the App Router helper. Do not
44
50
  // replace the existing Set-Cookie header from `clearPreviewData()`.
45
51
  const existingSetCookie = config.res.getHeader("Set-Cookie")
46
- const expiredPreviewCookies = expiredPreviewCookieHeaders()
52
+ const expiredPreviewCookies = [
53
+ ...expiredPreviewCookieHeaders(),
54
+ ...expiredDraftModeCookieHeaders(),
55
+ ...expiredPreviewDataCookieHeaders(),
56
+ ]
47
57
  config.res.setHeader(
48
58
  "Set-Cookie",
49
59
  existingSetCookie == null
@@ -1,5 +1,6 @@
1
1
  import { cookie } from "@prismicio/client"
2
2
 
3
+ import { previewRefFromCookie } from "../lib/previewRefFromCookie"
3
4
  import type { NextApiRequestLike, NextApiResponseLike } from "./types"
4
5
 
5
6
  /** Configuration for `setPreviewData`. */
@@ -21,9 +22,25 @@ export type SetPreviewDataConfig = {
21
22
 
22
23
  /** Set Prismic preview data for Next.js's Preview Mode. */
23
24
  export function setPreviewData({ req, res }: SetPreviewDataConfig): void {
24
- const ref = req.query.token || req.cookies[cookie.preview]
25
-
25
+ // Only unwrap the cookie. Query tokens, including arrays, stay as-is.
26
+ const previewCookie = req.cookies[cookie.preview]
27
+ const ref = req.query.token || (previewCookie && previewRefFromCookie(previewCookie))
26
28
  if (ref) {
27
29
  res.setPreviewData({ ref })
30
+
31
+ // Next.js uses Lax preview cookies in development. Preserve its
32
+ // signed/encrypted values and all other attributes, but allow both
33
+ // cookies to reach the site inside the editor's cross-site iframe.
34
+ const setCookie = res.getHeader("Set-Cookie")
35
+ if (typeof setCookie === "string" || Array.isArray(setCookie)) {
36
+ res.setHeader(
37
+ "Set-Cookie",
38
+ (typeof setCookie === "string" ? [setCookie] : setCookie).map((header) =>
39
+ /^__(?:prerender_bypass|next_preview_data)=/.test(header)
40
+ ? `${header.replace(/;\s*(?:Secure|SameSite=[^;]*)(?=;|$)/gi, "")}; SameSite=None; Secure`
41
+ : header,
42
+ ),
43
+ )
44
+ }
28
45
  }
29
46
  }
@@ -74,6 +74,18 @@ export async function redirectToPreviewURL(config: RedirectToPreviewURLConfig):
74
74
  })
75
75
 
76
76
  ;(await draftMode()).enable()
77
+ // Next.js uses SameSite=Lax for Draft Mode in development. Keep its
78
+ // generated value, but allow the editor iframe to send this cookie too.
79
+ const cookieJar = await cookies()
80
+ const draftCookie = cookieJar.get("__prerender_bypass")
81
+ if (draftCookie) {
82
+ cookieJar.set(draftCookie.name, draftCookie.value, {
83
+ path: "/",
84
+ sameSite: "none",
85
+ secure: true,
86
+ httpOnly: true,
87
+ })
88
+ }
77
89
 
78
90
  return redirect(previewURL)
79
91
  }