@prismicio/next 1.1.0-alpha.1 → 1.1.0

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 (66) hide show
  1. package/dist/PrismicNextLink.d.ts +3 -3
  2. package/dist/PrismicPreview.cjs +5 -74
  3. package/dist/PrismicPreview.cjs.map +1 -1
  4. package/dist/PrismicPreview.d.ts +8 -11
  5. package/dist/PrismicPreview.js +5 -57
  6. package/dist/PrismicPreview.js.map +1 -1
  7. package/dist/PrismicPreviewClient.cjs +85 -0
  8. package/dist/PrismicPreviewClient.cjs.map +1 -0
  9. package/dist/PrismicPreviewClient.d.ts +4 -0
  10. package/dist/PrismicPreviewClient.js +85 -0
  11. package/dist/PrismicPreviewClient.js.map +1 -0
  12. package/dist/_node_modules/@prismicio/client/dist/errors/PrismicError.cjs +19 -0
  13. package/dist/_node_modules/@prismicio/client/dist/errors/PrismicError.cjs.map +1 -0
  14. package/dist/_node_modules/@prismicio/client/dist/errors/PrismicError.js +19 -0
  15. package/dist/_node_modules/@prismicio/client/dist/errors/PrismicError.js.map +1 -0
  16. package/dist/_node_modules/@prismicio/client/dist/getToolbarSrc.cjs +13 -0
  17. package/dist/_node_modules/@prismicio/client/dist/getToolbarSrc.cjs.map +1 -0
  18. package/dist/_node_modules/@prismicio/client/dist/getToolbarSrc.js +13 -0
  19. package/dist/_node_modules/@prismicio/client/dist/getToolbarSrc.js.map +1 -0
  20. package/dist/_node_modules/@prismicio/client/dist/isRepositoryName.cjs +7 -0
  21. package/dist/_node_modules/@prismicio/client/dist/isRepositoryName.cjs.map +1 -0
  22. package/dist/_node_modules/@prismicio/client/dist/isRepositoryName.js +7 -0
  23. package/dist/_node_modules/@prismicio/client/dist/isRepositoryName.js.map +1 -0
  24. package/dist/enableAutoPreviews.cjs +17 -6
  25. package/dist/enableAutoPreviews.cjs.map +1 -1
  26. package/dist/enableAutoPreviews.d.ts +11 -12
  27. package/dist/enableAutoPreviews.js +17 -6
  28. package/dist/enableAutoPreviews.js.map +1 -1
  29. package/dist/exitPreview.cjs +1 -1
  30. package/dist/exitPreview.cjs.map +1 -1
  31. package/dist/exitPreview.d.ts +11 -16
  32. package/dist/exitPreview.js +1 -1
  33. package/dist/exitPreview.js.map +1 -1
  34. package/dist/package.json.cjs +1 -1
  35. package/dist/package.json.js +1 -1
  36. package/dist/redirectToPreviewURL.cjs +13 -12
  37. package/dist/redirectToPreviewURL.cjs.map +1 -1
  38. package/dist/redirectToPreviewURL.d.ts +23 -21
  39. package/dist/redirectToPreviewURL.js +13 -12
  40. package/dist/redirectToPreviewURL.js.map +1 -1
  41. package/dist/setPreviewData.cjs.map +1 -1
  42. package/dist/setPreviewData.d.ts +9 -14
  43. package/dist/setPreviewData.js.map +1 -1
  44. package/dist/types.d.ts +52 -9
  45. package/package.json +5 -10
  46. package/src/PrismicPreview.tsx +13 -131
  47. package/src/PrismicPreviewClient.tsx +159 -0
  48. package/src/enableAutoPreviews.ts +73 -45
  49. package/src/exitPreview.ts +14 -26
  50. package/src/redirectToPreviewURL.ts +58 -64
  51. package/src/setPreviewData.ts +10 -14
  52. package/src/types.ts +58 -9
  53. package/dist/react-server/PrismicPreview.d.ts +0 -22
  54. package/dist/react-server/index.d.ts +0 -2
  55. package/dist/react-server/unsupported.cjs +0 -26
  56. package/dist/react-server/unsupported.cjs.map +0 -1
  57. package/dist/react-server/unsupported.d.ts +0 -6
  58. package/dist/react-server/unsupported.js +0 -26
  59. package/dist/react-server/unsupported.js.map +0 -1
  60. package/dist/react-server.cjs +0 -15
  61. package/dist/react-server.cjs.map +0 -1
  62. package/dist/react-server.js +0 -15
  63. package/dist/react-server.js.map +0 -1
  64. package/src/react-server/PrismicPreview.tsx +0 -74
  65. package/src/react-server/index.ts +0 -11
  66. package/src/react-server/unsupported.ts +0 -26
package/dist/types.d.ts CHANGED
@@ -1,21 +1,64 @@
1
- import type { PreviewData, NextApiRequest } from "next";
1
+ import type { PreviewData } from "next";
2
2
  import type { ClientConfig } from "@prismicio/client";
3
+ declare module "@prismicio/client" {
4
+ interface RequestInitLike {
5
+ next?: RequestInit["next"];
6
+ }
7
+ }
3
8
  /**
4
9
  * Configuration for creating a Prismic client with automatic preview support in
5
10
  * Next.js apps.
6
11
  */
7
- export type CreateClientConfig = {
12
+ export type CreateClientConfig = ClientConfig & {
8
13
  /**
9
- * Preview data coming from Next.js context object. This context object comes
10
- * from `getStaticProps` or `getServerSideProps`.
14
+ * **Only used in the Pages Directory (/pages).**
11
15
  *
12
- * Pass `previewData` when using outside a Next.js API endpoint.
16
+ * The `previewData` object provided in the `getStaticProps()` or
17
+ * `getServerSideProps()` context object.
13
18
  */
14
19
  previewData?: PreviewData;
15
20
  /**
16
- * A Next.js API endpoint request object.
21
+ * **Only used in the Pages Directory (/pages).**
17
22
  *
18
- * Pass a `req` object when using in a Next.js API endpoint.
23
+ * The `req` object from a Next.js API route.
24
+ *
25
+ * @see Next.js API route docs: \<https://nextjs.org/docs/api-routes/introduction\>
19
26
  */
20
- req?: NextApiRequest;
21
- } & ClientConfig;
27
+ req?: NextApiRequestLike;
28
+ };
29
+ /**
30
+ * The minimal set of properties needed from `next`'s `NextRequest` type.
31
+ *
32
+ * This request type is only compatible with Route Handlers defined in the `app`
33
+ * directory.
34
+ */
35
+ export type NextRequestLike = {
36
+ headers: {
37
+ get(name: string): string | null;
38
+ };
39
+ url: string;
40
+ nextUrl: unknown;
41
+ };
42
+ /**
43
+ * The minimal set of properties needed from `next`'s `NextApiRequest` type.
44
+ *
45
+ * This request type is only compatible with API routes defined in the `pages`
46
+ * directory.
47
+ */
48
+ export type NextApiRequestLike = {
49
+ query: Partial<Record<string, string | string[]>>;
50
+ cookies: Partial<Record<string, string>>;
51
+ };
52
+ /**
53
+ * The minimal set of properties needed from `next`'s `NextApiResponse` type.
54
+ *
55
+ * This request type is only compatible with API routes defined in the `pages`
56
+ * directory.
57
+ */
58
+ export type NextApiResponseLike = {
59
+ redirect(url: string): NextApiResponseLike;
60
+ clearPreviewData(): NextApiResponseLike;
61
+ status(statusCode: number): NextApiResponseLike;
62
+ json(body: any): void;
63
+ setPreviewData(data: object | string): NextApiResponseLike;
64
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismicio/next",
3
- "version": "1.1.0-alpha.1",
3
+ "version": "1.1.0",
4
4
  "description": "Helpers to integrate Prismic into Next.js apps",
5
5
  "keywords": [
6
6
  "typescript",
@@ -18,14 +18,8 @@
18
18
  "sideEffects": false,
19
19
  "exports": {
20
20
  ".": {
21
- "react-server": {
22
- "import": "./dist/react-server.js",
23
- "require": "./dist/react-server.cjs"
24
- },
25
- "default": {
26
- "import": "./dist/index.js",
27
- "require": "./dist/index.cjs"
28
- }
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
29
23
  },
30
24
  "./package.json": "./package.json"
31
25
  },
@@ -70,7 +64,8 @@
70
64
  "eslint-plugin-react-hooks": "^4.6.0",
71
65
  "eslint-plugin-tsdoc": "^0.2.17",
72
66
  "happy-dom": "^9.9.2",
73
- "next": "^13.0.0",
67
+ "next": "^13.4.0",
68
+ "node-fetch": "^3.3.1",
74
69
  "prettier": "^2.8.8",
75
70
  "prettier-plugin-jsdoc": "^0.4.2",
76
71
  "react": "^18.1.0",
@@ -1,11 +1,8 @@
1
- "use client";
2
-
3
1
  import * as React from "react";
4
- import { useRouter } from "next/router";
2
+ import * as prismic from "@prismicio/client";
5
3
  import Script from "next/script";
6
4
 
7
- import { getPrismicPreviewCookie } from "./lib/getPrismicPreviewCookie";
8
- import { getPreviewCookieRepositoryName } from "./lib/getPreviewCookieRepositoryName";
5
+ import { PrismicPreviewClient } from "./PrismicPreviewClient";
9
6
 
10
7
  /**
11
8
  * Props for `<PrismicPreview>`.
@@ -18,26 +15,23 @@ export type PrismicPreviewProps = {
18
15
  repositoryName: string;
19
16
 
20
17
  /**
18
+ * **Only used in the Pages Directory (/pages).**
19
+ *
21
20
  * The URL of your app's Prismic preview endpoint (default: `/api/preview`).
22
21
  * This URL will be fetched on preview update events.
23
- *
24
- * **Note**: If your `next.config.js` file contains a `basePath`, it is
25
- * automatically included.
26
22
  */
27
23
  updatePreviewURL?: string;
28
24
 
29
25
  /**
26
+ * **Only used in the Pages Directory (/pages).**
27
+ *
30
28
  * The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
31
29
  * This URL will be fetched on preview exit events.
32
- *
33
- * **Note**: If your `next.config.js` file contains a `basePath`, it is
34
- * automatically included.
35
30
  */
36
31
  exitPreviewURL?: string;
37
32
 
38
33
  /**
39
- * Children to render adjacent to the Prismic Toolbar. The Prismic Toolbar
40
- * will be rendered last.
34
+ * Children to render adjacent to the Prismic Toolbar.
41
35
  */
42
36
  children?: React.ReactNode;
43
37
  };
@@ -45,8 +39,8 @@ export type PrismicPreviewProps = {
45
39
  /**
46
40
  * React component that sets up Prismic Previews using the Prismic Toolbar. When
47
41
  * the Prismic Toolbar send events to the browser, such as on preview updates
48
- * and exiting, this component will automatically update the Next.js preview
49
- * cookie and refresh the page.
42
+ * and exiting, this component will automatically refresh the page with the
43
+ * changes.
50
44
  *
51
45
  * This component can be wrapped around your app or added anywhere in your app's
52
46
  * tree. It must be rendered on every page.
@@ -54,127 +48,15 @@ export type PrismicPreviewProps = {
54
48
  export function PrismicPreview({
55
49
  repositoryName,
56
50
  children,
57
- updatePreviewURL = "/api/preview",
58
- exitPreviewURL = "/api/exit-preview",
51
+ ...props
59
52
  }: PrismicPreviewProps): JSX.Element {
60
- const router = useRouter();
61
-
62
- const resolvedUpdatePreviewURL = router.basePath + updatePreviewURL;
63
- const resolvedExitPreviewURL = router.basePath + exitPreviewURL;
64
-
65
- React.useEffect(() => {
66
- /**
67
- * Starts Preview Mode and refreshes the page's props.
68
- */
69
- const startPreviewMode = async () => {
70
- // Start Next.js Preview Mode via the given preview API endpoint.
71
- const res = await globalThis.fetch(resolvedUpdatePreviewURL);
72
-
73
- // We check for `res.redirected` rather than `res.ok`
74
- // since the update preview endpoint may redirect to a
75
- // 404 page. As long as it redirects, we know the
76
- // endpoint exists and at least attempted to set
77
- // preview data.
78
- if (res.redirected) {
79
- globalThis.location.reload();
80
- } else {
81
- console.error(
82
- `[<PrismicPreview>] Failed to start or update Preview Mode using the "${resolvedUpdatePreviewURL}" API endpoint. Does it exist?`,
83
- );
84
- }
85
- };
86
-
87
- const handlePrismicPreviewUpdate = async (event: Event) => {
88
- // Prevent the toolbar from reloading the page.
89
- event.preventDefault();
90
-
91
- await startPreviewMode();
92
- };
93
-
94
- const handlePrismicPreviewEnd = async (event: Event) => {
95
- // Prevent the toolbar from reloading the page.
96
- event.preventDefault();
97
-
98
- // Exit Next.js Preview Mode via the given preview API endpoint.
99
- const res = await globalThis.fetch(resolvedExitPreviewURL);
100
-
101
- if (res.ok) {
102
- globalThis.location.reload();
103
- } else {
104
- console.error(
105
- `[<PrismicPreview>] Failed to exit Preview Mode using the "${resolvedExitPreviewURL}" API endpoint. Does it exist?`,
106
- );
107
- }
108
- };
109
-
110
- if (router.isPreview) {
111
- // Register Prismic Toolbar event handlers.
112
- window.addEventListener(
113
- "prismicPreviewUpdate",
114
- handlePrismicPreviewUpdate,
115
- );
116
- window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
117
- } else {
118
- const prismicPreviewCookie = getPrismicPreviewCookie(
119
- globalThis.document.cookie,
120
- );
121
-
122
- if (prismicPreviewCookie) {
123
- // If a Prismic preview cookie is present, but Next.js Preview
124
- // Mode is not active, we must activate Preview Mode manually.
125
- //
126
- // This will happen when a visitor accesses the page using a
127
- // Prismic preview share link.
128
-
129
- /**
130
- * Determines if the current location is a descendant of the app's base
131
- * path.
132
- *
133
- * This is used to prevent infinite refrehes; when
134
- * `isDescendantOfBasePath` is `false`, `router.isPreview` is also
135
- * `false`.
136
- *
137
- * If the app does not have a base path, this should always be `true`.
138
- */
139
- const locationIsDescendantOfBasePath = window.location.href.startsWith(
140
- window.location.origin + router.basePath,
141
- );
142
-
143
- const prismicPreviewCookieRepositoryName =
144
- getPreviewCookieRepositoryName(prismicPreviewCookie);
145
-
146
- if (
147
- locationIsDescendantOfBasePath &&
148
- prismicPreviewCookieRepositoryName === repositoryName
149
- ) {
150
- startPreviewMode();
151
- }
152
- }
153
- }
154
-
155
- // On cleanup, unregister Prismic Toolbar event handlers.
156
- return () => {
157
- window.removeEventListener(
158
- "prismicPreviewUpdate",
159
- handlePrismicPreviewUpdate,
160
- );
161
- window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
162
- };
163
- }, [
164
- repositoryName,
165
- resolvedExitPreviewURL,
166
- resolvedUpdatePreviewURL,
167
- router.isPreview,
168
- router.basePath,
169
- ]);
53
+ const toolbarSrc = prismic.getToolbarSrc(repositoryName);
170
54
 
171
55
  return (
172
56
  <>
173
57
  {children}
174
- <Script
175
- src={`https://static.cdn.prismic.io/prismic.js?repo=${repositoryName}&new=true`}
176
- strategy="lazyOnload"
177
- />
58
+ <PrismicPreviewClient repositoryName={repositoryName} {...props} />
59
+ <Script src={toolbarSrc} strategy="lazyOnload" />
178
60
  </>
179
61
  );
180
62
  }
@@ -0,0 +1,159 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+ import { useRouter as usePagesRouter } from "next/router";
5
+ import { useRouter } from "next/navigation";
6
+
7
+ import { getPrismicPreviewCookie } from "./lib/getPrismicPreviewCookie";
8
+ import { getPreviewCookieRepositoryName } from "./lib/getPreviewCookieRepositoryName";
9
+
10
+ import { PrismicPreviewProps } from "./PrismicPreview";
11
+
12
+ type PrismicPreviewClientProps = Omit<PrismicPreviewProps, "children">;
13
+
14
+ export function PrismicPreviewClient({
15
+ repositoryName,
16
+ updatePreviewURL = "/api/preview",
17
+ exitPreviewURL = "/api/exit-preview",
18
+ }: PrismicPreviewClientProps): null {
19
+ let isAppRouter = true;
20
+ let isPreviewMode = false;
21
+ let basePath = "";
22
+ let refresh: () => void;
23
+
24
+ try {
25
+ // eslint-disable-next-line react-hooks/rules-of-hooks
26
+ const router = usePagesRouter();
27
+
28
+ isAppRouter = false;
29
+ basePath = router.basePath;
30
+ isPreviewMode = router.isPreview;
31
+ refresh = () => router.replace(router.asPath, undefined, { scroll: false });
32
+ } catch {
33
+ // Assume we are in App Router. Ignore the error.
34
+
35
+ // eslint-disable-next-line react-hooks/rules-of-hooks
36
+ const router = useRouter();
37
+
38
+ refresh = router.refresh;
39
+ }
40
+
41
+ useEffect(() => {
42
+ /**
43
+ * Starts Preview Mode and refreshes the page's props.
44
+ */
45
+ const startPreviewMode = async () => {
46
+ const resolvedUpdatePreviewURL = basePath + updatePreviewURL;
47
+
48
+ // Start Next.js Preview Mode via the given preview API endpoint.
49
+ const res = await globalThis.fetch(resolvedUpdatePreviewURL);
50
+
51
+ // We check for `res.redirected` rather than `res.ok`
52
+ // since the update preview endpoint may redirect to a
53
+ // 404 page. As long as it redirects, we know the
54
+ // endpoint exists and at least attempted to set
55
+ // preview data.
56
+ if (res.redirected) {
57
+ refresh();
58
+ } else {
59
+ console.error(
60
+ `[<PrismicPreview>] Failed to start or update Preview Mode using the "${resolvedUpdatePreviewURL}" API endpoint. Does it exist?`,
61
+ );
62
+ }
63
+ };
64
+
65
+ const handlePrismicPreviewUpdate = async (event: Event) => {
66
+ // Prevent the toolbar from reloading the page.
67
+ event.preventDefault();
68
+
69
+ if (isAppRouter) {
70
+ refresh();
71
+ } else {
72
+ await startPreviewMode();
73
+ }
74
+ };
75
+
76
+ const handlePrismicPreviewEnd = async (event: Event) => {
77
+ // Prevent the toolbar from reloading the page.
78
+ event.preventDefault();
79
+
80
+ if (isAppRouter) {
81
+ refresh();
82
+ } else {
83
+ const resolvedExitPreviewURL = basePath + exitPreviewURL;
84
+
85
+ // Exit Next.js Preview Mode via the given preview API endpoint.
86
+ const res = await globalThis.fetch(resolvedExitPreviewURL);
87
+
88
+ if (res.ok) {
89
+ // TODO: Can we do better than a full page reload?
90
+ // globalThis.location.reload();
91
+ refresh();
92
+ } else {
93
+ console.error(
94
+ `[<PrismicPreview>] Failed to exit Preview Mode using the "${resolvedExitPreviewURL}" API endpoint. Does it exist?`,
95
+ );
96
+ }
97
+ }
98
+ };
99
+
100
+ window.addEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
101
+ window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
102
+
103
+ if (!isPreviewMode) {
104
+ const prismicPreviewCookie = getPrismicPreviewCookie(
105
+ globalThis.document.cookie,
106
+ );
107
+
108
+ if (prismicPreviewCookie) {
109
+ // If a Prismic preview cookie is present, but Next.js Preview
110
+ // Mode is not active, we must activate Preview Mode manually.
111
+ //
112
+ // This will happen when a visitor accesses the page using a
113
+ // Prismic preview share link.
114
+
115
+ /**
116
+ * Determines if the current location is a descendant of the app's base
117
+ * path.
118
+ *
119
+ * This is used to prevent infinite refrehes; when
120
+ * `isDescendantOfBasePath` is `false`, `router.isPreview` is also
121
+ * `false`.
122
+ *
123
+ * If the app does not have a base path, this should always be `true`.
124
+ */
125
+ const locationIsDescendantOfBasePath = window.location.href.startsWith(
126
+ window.location.origin + basePath,
127
+ );
128
+
129
+ const prismicPreviewCookieRepositoryName =
130
+ getPreviewCookieRepositoryName(prismicPreviewCookie);
131
+
132
+ if (
133
+ locationIsDescendantOfBasePath &&
134
+ prismicPreviewCookieRepositoryName === repositoryName
135
+ ) {
136
+ startPreviewMode();
137
+ }
138
+ }
139
+ }
140
+
141
+ return () => {
142
+ window.removeEventListener(
143
+ "prismicPreviewUpdate",
144
+ handlePrismicPreviewUpdate,
145
+ );
146
+ window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
147
+ };
148
+ }, [
149
+ basePath,
150
+ exitPreviewURL,
151
+ isAppRouter,
152
+ isPreviewMode,
153
+ refresh,
154
+ repositoryName,
155
+ updatePreviewURL,
156
+ ]);
157
+
158
+ return null;
159
+ }
@@ -1,23 +1,8 @@
1
1
  import { PreviewData } from "next";
2
- import type * as prismic from "@prismicio/client";
2
+ import { cookies } from "next/headers";
3
+ import * as prismic from "@prismicio/client";
3
4
 
4
- interface PrismicNextPreviewData {
5
- ref: string;
6
- }
7
-
8
- /**
9
- * Determines if a Next.js preview data object contains Prismic preview data.
10
- *
11
- * @param previewData - The Next.js preview data object to check.
12
- *
13
- * @returns `true` if `previewData` contains Prismic preview data, `false`
14
- * otherwise.
15
- */
16
- const isPrismicNextPreviewData = (
17
- previewData: PreviewData,
18
- ): previewData is PrismicNextPreviewData => {
19
- return typeof previewData === "object" && "ref" in previewData;
20
- };
5
+ import { NextApiRequestLike } from "./types";
21
6
 
22
7
  /**
23
8
  * Configuration for `enableAutoPreviews`.
@@ -37,27 +22,25 @@ export type EnableAutoPreviewsConfig<
37
22
  prismic.Client,
38
23
  "queryContentFromRef" | "enableAutoPreviewsFromReq"
39
24
  >;
40
- } & (
41
- | {
42
- /**
43
- * A Next.js context object (such as the context object from
44
- * `getStaticProps` or `getServerSideProps`).
45
- *
46
- * Pass a `context` object when using `enableAutoPreviews` outside a
47
- * Next.js API endpoint.
48
- */
49
- previewData?: TPreviewData;
50
- }
51
- | {
52
- /**
53
- * A Next.js API endpoint request object.
54
- *
55
- * Pass a `req` object when using `enableAutoPreviews` in a Next.js API
56
- * endpoint.
57
- */
58
- req?: prismic.HttpRequestLike;
59
- }
60
- );
25
+
26
+ /**
27
+ * **Only used in the Pages Directory (/pages).**
28
+ *
29
+ * The `previewData` object provided in the `getStaticProps()` or
30
+ * `getServerSideProps()` context object.
31
+ */
32
+ previewData?: TPreviewData;
33
+
34
+ /**
35
+ * **Only used in the Pages Directory (/pages).**
36
+ *
37
+ * The `req` object from a Next.js API route.
38
+ *
39
+ * @see Next.js API route docs: \<https://nextjs.org/docs/api-routes/introduction\>
40
+ */
41
+ req?: NextApiRequestLike;
42
+ };
43
+
61
44
  /**
62
45
  * Configures a Prismic client to automatically query draft content during a
63
46
  * preview session. It either takes in a Next.js `getStaticProps` context object
@@ -69,16 +52,61 @@ export const enableAutoPreviews = <TPreviewData extends PreviewData>(
69
52
  config: EnableAutoPreviewsConfig<TPreviewData>,
70
53
  ): void => {
71
54
  if ("previewData" in config && config.previewData) {
72
- // If preview data is being passed from Next Context then use queryContentFromRef
73
-
74
- const { previewData } = config;
55
+ // Assume we are in `getStaticProps()` or
56
+ // `getServerSideProps()` with active Preview Mode (`pages`
57
+ // directory).
75
58
 
76
- if (isPrismicNextPreviewData(previewData) && previewData.ref) {
77
- config.client.queryContentFromRef(previewData.ref);
59
+ if (
60
+ typeof config.previewData === "object" &&
61
+ "ref" in config.previewData &&
62
+ typeof config.previewData.ref === "string"
63
+ ) {
64
+ config.client.queryContentFromRef(config.previewData.ref);
78
65
  }
79
66
  } else if ("req" in config && config.req) {
80
- // If the req object is passed then use enableAutoPreviewsFromReq
67
+ // Assume we are in an API Route (`pages` directory).
81
68
 
82
69
  config.client.enableAutoPreviewsFromReq(config.req);
70
+ } else {
71
+ // Assume we are in App Router (`app` directory) OR
72
+ // `getStaticProps()`/`getServerSideProps()` with an inactive
73
+ // Preview Mode (`pages` directory).
74
+
75
+ // We use a function value so the cookie is checked on every
76
+ // request. We don't have a static value to read from.
77
+ config.client.queryContentFromRef(() => {
78
+ let cookie: string | undefined;
79
+ try {
80
+ cookie = cookies().get(prismic.cookie.preview)?.value;
81
+ } catch {
82
+ // noop - We are probably in
83
+ // `getStaticProps()` or `getServerSideProps()`
84
+ // with inactive Preview Mode where `cookies()`
85
+ // does not work. We don't need to do any
86
+ // preview handling.
87
+
88
+ return;
89
+ }
90
+
91
+ // We are probably in App Router (`app` directory).
92
+
93
+ // We only return the cookie if a Prismic Preview session is active.
94
+ //
95
+ // An inactive cookie looks like this (URL encoded):
96
+ // {
97
+ // "_tracker": "abc123"
98
+ // }
99
+ //
100
+ // An active cookie looks like this (URL encoded):
101
+ // {
102
+ // "_tracker": "abc123",
103
+ // "example-prismic-repo.prismic.io": {
104
+ // preview: "https://example-prismic-repo.prismic.io/previews/abc:123?websitePreviewId=xyz"
105
+ // }
106
+ // }
107
+ if (cookie && /\.prismic\.io/.test(cookie)) {
108
+ return cookie;
109
+ }
110
+ });
83
111
  }
84
112
  };
@@ -1,46 +1,34 @@
1
- import type { NextApiResponse, NextApiRequest } from "next";
1
+ import { NextResponse } from "next/server";
2
+
3
+ import { NextApiRequestLike, NextApiResponseLike } from "./types";
2
4
 
3
5
  /**
4
6
  * Configuration for `exitPreview`.
5
7
  */
6
8
  export type ExitPreviewConfig = {
7
9
  /**
8
- * The `req` object from a Next.js API route. This is given as a parameter to
9
- * the API route.
10
+ * The `req` object from a Next.js API route.
10
11
  *
11
- * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
12
+ * @see Next.js API route docs: \<https://nextjs.org/docs/api-routes/introduction\>
12
13
  */
13
- // `req` is no longer used in `exitPreview()`. It previously would
14
- // redirect the user to the referring URL, but it no longer has that
15
- // behavior.
16
- //
17
- // `req` is retained as a parameter to make setting up an exit preview
18
- // API route easier (this eliminates the awkward need to handle an
19
- // unused `req` param).
20
- //
21
- // It is also retained in case it is needed in the future, such as
22
- // reading headers or metadata about the request.
23
- req: {
24
- headers: NextApiRequest["headers"];
25
- };
14
+ req: NextApiRequestLike;
26
15
 
27
16
  /**
28
- * The `res` object from a Next.js API route. This is given as a parameter to
29
- * the API route.
17
+ * The `res` object from a Next.js API route.
30
18
  *
31
- * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
19
+ * @see Next.js API route docs: \<https://nextjs.org/docs/api-routes/introduction\>
32
20
  */
33
- res: {
34
- clearPreviewData: NextApiResponse["clearPreviewData"];
35
- status: NextApiResponse["status"];
36
- json: NextApiResponse["json"];
37
- };
21
+ res: NextApiResponseLike;
38
22
  };
39
23
 
40
24
  /**
25
+ * **Only use this function in the Pages Directory (/pages).**
26
+ *
41
27
  * Exits Next.js's Preview Mode from within a Next.js API route.
42
28
  */
43
- export function exitPreview(config: ExitPreviewConfig): void {
29
+ export async function exitPreview(
30
+ config: ExitPreviewConfig,
31
+ ): Promise<NextResponse | void> {
44
32
  // Exit the current user from Preview Mode.
45
33
  config.res.clearPreviewData();
46
34