@prismicio/next 0.0.1

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,112 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const React = require('react');
6
+ const react = require('@prismicio/react');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ const React__default = /*#__PURE__*/_interopDefaultLegacy(React);
11
+
12
+ async function setPreviewData({
13
+ req,
14
+ res
15
+ }) {
16
+ if (req.query.token) {
17
+ const { token: ref } = req.query;
18
+ res.setPreviewData({ ref });
19
+ }
20
+ }
21
+
22
+ function exitPreview(config) {
23
+ const { req } = config;
24
+ config.res.clearPreviewData();
25
+ if (req.headers.referer) {
26
+ const url = new URL(req.headers.referer);
27
+ if (url.pathname !== "/api/exit-preview") {
28
+ config.res.redirect(req.headers.referer);
29
+ return;
30
+ }
31
+ }
32
+ config.res.redirect("/");
33
+ }
34
+
35
+ const isPrismicUpdateToolbarEvent = (event) => {
36
+ return "detail" in event && typeof event.detail.ref === "string";
37
+ };
38
+ function PrismicPreview({
39
+ repositoryName,
40
+ children,
41
+ updatePreviewURL = "/api/preview",
42
+ exitPreviewURL = "/api/exit-preview"
43
+ }) {
44
+ React.useEffect(() => {
45
+ const prismicPreviewUpdate = async (event) => {
46
+ if (isPrismicUpdateToolbarEvent(event)) {
47
+ event.preventDefault();
48
+ await fetch(`${updatePreviewURL}?token=${event.detail.ref}`);
49
+ window.location.reload();
50
+ }
51
+ };
52
+ const prismicPreviewEnd = async (event) => {
53
+ event.preventDefault();
54
+ await fetch(exitPreviewURL);
55
+ window.location.reload();
56
+ };
57
+ if (window) {
58
+ window.addEventListener("prismicPreviewUpdate", prismicPreviewUpdate);
59
+ window.addEventListener("prismicPreviewEnd", prismicPreviewEnd);
60
+ }
61
+ return () => {
62
+ if (window) {
63
+ window.removeEventListener("prismicPreviewUpdate", prismicPreviewUpdate);
64
+ window.removeEventListener("prismicPreviewEnd", prismicPreviewEnd);
65
+ }
66
+ };
67
+ }, []);
68
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement(react.PrismicToolbar, {
69
+ repositoryName
70
+ }), children);
71
+ }
72
+
73
+ const isPrismicNextPreviewData = (previewData) => {
74
+ return typeof previewData === "object" && "ref" in previewData;
75
+ };
76
+ const enableAutoPreviews = (config) => {
77
+ if ("context" in config && config.context) {
78
+ const previewData = config.context.previewData;
79
+ if (isPrismicNextPreviewData(previewData) && previewData.ref) {
80
+ config.client.queryContentFromRef(previewData.ref);
81
+ }
82
+ } else if ("req" in config && config.req) {
83
+ config.client.enableAutoPreviewsFromReq(config.req);
84
+ }
85
+ };
86
+
87
+ const isPrismicNextQuery = (query) => typeof query.documentId === "string" && typeof query.token === "string";
88
+ async function redirectToPreviewURL({
89
+ req,
90
+ res,
91
+ client,
92
+ linkResolver,
93
+ defaultURL = "/"
94
+ }) {
95
+ if (isPrismicNextQuery(req.query)) {
96
+ const { documentId, token } = req.query;
97
+ const previewUrl = await client.resolvePreviewURL({
98
+ linkResolver,
99
+ defaultURL,
100
+ documentID: documentId,
101
+ previewToken: token
102
+ });
103
+ res.redirect(previewUrl);
104
+ }
105
+ res.redirect(defaultURL);
106
+ }
107
+
108
+ exports.PrismicPreview = PrismicPreview;
109
+ exports.enableAutoPreviews = enableAutoPreviews;
110
+ exports.exitPreview = exitPreview;
111
+ exports.redirectToPreviewURL = redirectToPreviewURL;
112
+ exports.setPreviewData = setPreviewData;
@@ -0,0 +1,206 @@
1
+ import { NextApiRequest, NextApiResponse, PreviewData } from 'next';
2
+ import { Client, HttpRequestLike } from '@prismicio/client';
3
+ import { LinkResolverFunction } from '@prismicio/helpers';
4
+ import React from 'react';
5
+
6
+ /**
7
+ * Configuration for `setPreviewData`.
8
+ */
9
+ declare type SetPreviewDataConfig = {
10
+ /**
11
+ * The `req` object from a Next.js API route. This is given as a parameter to
12
+ * the API route.
13
+ *
14
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
15
+ */
16
+ req: {
17
+ query: NextApiRequest["query"];
18
+ };
19
+ /**
20
+ * The `res` object from a Next.js API route. This is given as a parameter to
21
+ * the API route.
22
+ *
23
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
24
+ */
25
+ res: {
26
+ setPreviewData: NextApiResponse["setPreviewData"];
27
+ };
28
+ };
29
+ /**
30
+ * Set Prismic preview data for Next.js's Preview Mode.
31
+ */
32
+ declare function setPreviewData({ req, res, }: SetPreviewDataConfig): Promise<void>;
33
+
34
+ /**
35
+ * Next.js context object from APIs supporting Preview Mode. This includes the
36
+ * context object from `getStaticProps` and `getServerSideProps`.
37
+ */
38
+ declare type NextContextLike<TPreviewData extends PreviewData = PreviewData> = {
39
+ previewData?: TPreviewData;
40
+ };
41
+ /**
42
+ * Configuration for creating a Prismic client with automatic preview support in
43
+ * Next.js apps.
44
+ */
45
+ declare type CreateClientConfig = {
46
+ /**
47
+ * A Next.js context object (such as the context object from `getStaticProps`
48
+ * or `getServerSideProps`).
49
+ *
50
+ * Pass a `context` when using outside a Next.js API endpoint.
51
+ */
52
+ context?: NextContextLike;
53
+ /**
54
+ * A Next.js API endpoint request object.
55
+ *
56
+ * Pass a `req` object when using in a Next.js API endpoint.
57
+ */
58
+ req?: NextApiRequest;
59
+ };
60
+ /**
61
+ * Preview config for enabling previews with redirectToPreviewURL
62
+ */
63
+ declare type PreviewConfig = {
64
+ /**
65
+ * The `req` object from a Next.js API route. This is given as a parameter to
66
+ * the API route.
67
+ *
68
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
69
+ */
70
+ req: {
71
+ query: NextApiRequest["query"];
72
+ };
73
+ /**
74
+ * The `res` object from a Next.js API route. This is given as a parameter to
75
+ * the API route.
76
+ *
77
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
78
+ */
79
+ res: {
80
+ redirect: NextApiResponse["redirect"];
81
+ };
82
+ /**
83
+ * The Prismic client configured for the preview session's repository.
84
+ */
85
+ client: Client;
86
+ /**
87
+ * A Link Resolver used to resolve the previewed document's URL.
88
+ *
89
+ * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
90
+ */
91
+ linkResolver?: LinkResolverFunction;
92
+ /**
93
+ * The default redirect URL if a URL cannot be determined for the previewed document.
94
+ */
95
+ defaultURL?: string;
96
+ };
97
+
98
+ /**
99
+ * Configuration for `enableAutoPreviews`.
100
+ *
101
+ * @typeParam TPreviewData - Next.js preview data object.
102
+ */
103
+ declare type EnableAutoPreviewsConfig<TPreviewData extends PreviewData = PreviewData> = {
104
+ /**
105
+ * Prismic client with which automatic previews will be enabled.
106
+ */
107
+ client: Client;
108
+ } & ({
109
+ /**
110
+ * A Next.js context object (such as the context object from
111
+ * `getStaticProps` or `getServerSideProps`).
112
+ *
113
+ * Pass a `context` object when using `enableAutoPreviews` outside a
114
+ * Next.js API endpoint.
115
+ */
116
+ context?: NextContextLike<TPreviewData>;
117
+ } | {
118
+ /**
119
+ * A Next.js API endpoint request object.
120
+ *
121
+ * Pass a `req` object when using `enableAutoPreviews` in a Next.js API endpoint.
122
+ */
123
+ req?: HttpRequestLike;
124
+ });
125
+ /**
126
+ * Configures a Prismic client to automatically query draft content during a
127
+ * preview session. It either takes in a Next.js `getStaticProps` context object
128
+ * or a Next.js API endpoint request object.
129
+ *
130
+ * @param config - Configuration for the function.
131
+ */
132
+ declare const enableAutoPreviews: <TPreviewData extends PreviewData = PreviewData>(config: EnableAutoPreviewsConfig<TPreviewData>) => void;
133
+
134
+ /**
135
+ * Configuration for `exitPreview`.
136
+ */
137
+ declare type ExitPreviewConfig = {
138
+ /**
139
+ * The `req` object from a Next.js API route. This is given as a parameter to
140
+ * the API route.
141
+ *
142
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
143
+ */
144
+ req: {
145
+ headers: {
146
+ referer?: NextApiRequest["headers"]["referer"];
147
+ };
148
+ };
149
+ /**
150
+ * The `res` object from a Next.js API route. This is given as a parameter to
151
+ * the API route.
152
+ *
153
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
154
+ */
155
+ res: {
156
+ clearPreviewData: NextApiResponse["clearPreviewData"];
157
+ redirect: NextApiResponse["redirect"];
158
+ };
159
+ };
160
+ /**
161
+ * Exits Next.js's Preview Mode from within a Next.js API route.
162
+ *
163
+ * If the user was sent to the endpoint from a page, the user will be redirected
164
+ * back to that page after exiting Preview Mode.
165
+ */
166
+ declare function exitPreview(config: ExitPreviewConfig): void;
167
+
168
+ /**
169
+ * Props for `<PrismicPreview>`.
170
+ */
171
+ declare type PrismicPreviewProps = {
172
+ /**
173
+ * The name of your Prismic repository. A Prismic Toolbar will be registered
174
+ * using this repository.
175
+ */
176
+ repositoryName: string;
177
+ /**
178
+ * The URL of your app's Prismic preview endpoint (default: `/api/preview`).
179
+ * This URL will be fetched on preview update events.
180
+ */
181
+ updatePreviewURL?: string;
182
+ /**
183
+ * The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
184
+ * This URL will be fetched on preview exit events.
185
+ */
186
+ exitPreviewURL?: string;
187
+ children?: React.ReactNode;
188
+ };
189
+ /**
190
+ * React component that sets up Prismic Previews using the Prismic Toolbar. When
191
+ * the Prismic Toolbar send events to the browser, such as on preview updates
192
+ * and exiting, this component will automatically update the Next.js preview
193
+ * cookie and refresh the page.
194
+ *
195
+ * This component can be wrapped around your app or added anywhere in your app's
196
+ * tree. It must be rendered on every page.
197
+ */
198
+ declare function PrismicPreview({ repositoryName, children, updatePreviewURL, exitPreviewURL, }: PrismicPreviewProps): JSX.Element;
199
+
200
+ /**
201
+ * Redirects a user to the URL of a previewed Prismic document from within a
202
+ * Next.js API route.
203
+ */
204
+ declare function redirectToPreviewURL({ req, res, client, linkResolver, defaultURL, }: PreviewConfig): Promise<void>;
205
+
206
+ export { CreateClientConfig, EnableAutoPreviewsConfig, ExitPreviewConfig as ExitPreviewParams, NextContextLike, PreviewConfig, PrismicPreview, SetPreviewDataConfig, enableAutoPreviews, exitPreview, redirectToPreviewURL, setPreviewData };
package/dist/index.mjs ADDED
@@ -0,0 +1,100 @@
1
+ import React, { useEffect } from 'react';
2
+ import { PrismicToolbar } from '@prismicio/react';
3
+
4
+ async function setPreviewData({
5
+ req,
6
+ res
7
+ }) {
8
+ if (req.query.token) {
9
+ const { token: ref } = req.query;
10
+ res.setPreviewData({ ref });
11
+ }
12
+ }
13
+
14
+ function exitPreview(config) {
15
+ const { req } = config;
16
+ config.res.clearPreviewData();
17
+ if (req.headers.referer) {
18
+ const url = new URL(req.headers.referer);
19
+ if (url.pathname !== "/api/exit-preview") {
20
+ config.res.redirect(req.headers.referer);
21
+ return;
22
+ }
23
+ }
24
+ config.res.redirect("/");
25
+ }
26
+
27
+ const isPrismicUpdateToolbarEvent = (event) => {
28
+ return "detail" in event && typeof event.detail.ref === "string";
29
+ };
30
+ function PrismicPreview({
31
+ repositoryName,
32
+ children,
33
+ updatePreviewURL = "/api/preview",
34
+ exitPreviewURL = "/api/exit-preview"
35
+ }) {
36
+ useEffect(() => {
37
+ const prismicPreviewUpdate = async (event) => {
38
+ if (isPrismicUpdateToolbarEvent(event)) {
39
+ event.preventDefault();
40
+ await fetch(`${updatePreviewURL}?token=${event.detail.ref}`);
41
+ window.location.reload();
42
+ }
43
+ };
44
+ const prismicPreviewEnd = async (event) => {
45
+ event.preventDefault();
46
+ await fetch(exitPreviewURL);
47
+ window.location.reload();
48
+ };
49
+ if (window) {
50
+ window.addEventListener("prismicPreviewUpdate", prismicPreviewUpdate);
51
+ window.addEventListener("prismicPreviewEnd", prismicPreviewEnd);
52
+ }
53
+ return () => {
54
+ if (window) {
55
+ window.removeEventListener("prismicPreviewUpdate", prismicPreviewUpdate);
56
+ window.removeEventListener("prismicPreviewEnd", prismicPreviewEnd);
57
+ }
58
+ };
59
+ }, []);
60
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(PrismicToolbar, {
61
+ repositoryName
62
+ }), children);
63
+ }
64
+
65
+ const isPrismicNextPreviewData = (previewData) => {
66
+ return typeof previewData === "object" && "ref" in previewData;
67
+ };
68
+ const enableAutoPreviews = (config) => {
69
+ if ("context" in config && config.context) {
70
+ const previewData = config.context.previewData;
71
+ if (isPrismicNextPreviewData(previewData) && previewData.ref) {
72
+ config.client.queryContentFromRef(previewData.ref);
73
+ }
74
+ } else if ("req" in config && config.req) {
75
+ config.client.enableAutoPreviewsFromReq(config.req);
76
+ }
77
+ };
78
+
79
+ const isPrismicNextQuery = (query) => typeof query.documentId === "string" && typeof query.token === "string";
80
+ async function redirectToPreviewURL({
81
+ req,
82
+ res,
83
+ client,
84
+ linkResolver,
85
+ defaultURL = "/"
86
+ }) {
87
+ if (isPrismicNextQuery(req.query)) {
88
+ const { documentId, token } = req.query;
89
+ const previewUrl = await client.resolvePreviewURL({
90
+ linkResolver,
91
+ defaultURL,
92
+ documentID: documentId,
93
+ previewToken: token
94
+ });
95
+ res.redirect(previewUrl);
96
+ }
97
+ res.redirect(defaultURL);
98
+ }
99
+
100
+ export { PrismicPreview, enableAutoPreviews, exitPreview, redirectToPreviewURL, setPreviewData };
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@prismicio/next",
3
+ "version": "0.0.1",
4
+ "description": "Integrate Prismic into a Next.js app",
5
+ "keywords": [
6
+ "typescript",
7
+ "prismic",
8
+ "next",
9
+ "vercel",
10
+ "preview"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/prismicio/prismic-next"
15
+ },
16
+ "license": "Apache-2.0",
17
+ "author": "Prismic <contact@prismic.io> (https://prismic.io)",
18
+ "type": "module",
19
+ "exports": {
20
+ ".": {
21
+ "require": "./dist/index.cjs",
22
+ "import": "./dist/index.mjs"
23
+ },
24
+ "./package.json": "./package.json"
25
+ },
26
+ "main": "./dist/index.cjs",
27
+ "module": "dist/index.mjs",
28
+ "types": "dist/index.d.ts",
29
+ "files": [
30
+ "dist",
31
+ "src"
32
+ ],
33
+ "scripts": {
34
+ "build": "siroc build",
35
+ "dev": "siroc build --watch",
36
+ "format": "prettier --write .",
37
+ "lint": "eslint --ext .js,.ts .",
38
+ "prepare": "npm run build",
39
+ "release": "npm run build && npm run test && standard-version && git push --follow-tags && npm run build && npm publish",
40
+ "release:alpha": "npm run build && npm run test && standard-version --release-as major --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha",
41
+ "release:alpha:dry": "standard-version --release-as major --prerelease alpha --dry-run",
42
+ "release:dry": "standard-version --dry-run",
43
+ "test": "npm run lint && npm run unit",
44
+ "unit": "nyc --reporter=lcovonly --reporter=text --exclude-after-remap=false ava"
45
+ },
46
+ "dependencies": {
47
+ "@prismicio/react": "^2.0.2"
48
+ },
49
+ "devDependencies": {
50
+ "@prismicio/client": "^6.0.0-beta.0",
51
+ "@prismicio/mock": "^0.0.6",
52
+ "@prismicio/types": "^0.1.13",
53
+ "@testing-library/react": "^12.1.2",
54
+ "@types/jsdom": "^16.2.13",
55
+ "@types/jsdom-global": "^3.0.2",
56
+ "@types/node-fetch": "^3.0.3",
57
+ "@types/sinon": "^10.0.6",
58
+ "@typescript-eslint/eslint-plugin": "^4.29.1",
59
+ "@typescript-eslint/parser": "^4.29.1",
60
+ "ava": "^3.15.0",
61
+ "eslint": "^7.32.0",
62
+ "eslint-config-prettier": "^8.3.0",
63
+ "eslint-plugin-prettier": "^3.4.0",
64
+ "eslint-plugin-tsdoc": "^0.2.14",
65
+ "jsdom": "^18.1.1",
66
+ "jsdom-global": "^3.0.2",
67
+ "msw": "^0.35.0",
68
+ "node-fetch": "^2.6.6",
69
+ "nyc": "^15.1.0",
70
+ "prettier": "^2.3.2",
71
+ "prettier-plugin-jsdoc": "^0.3.30",
72
+ "react-test-renderer": "^17.0.2",
73
+ "sinon": "^12.0.1",
74
+ "siroc": "^0.15.0",
75
+ "standard-version": "^9.3.1",
76
+ "ts-eager": "^2.0.2",
77
+ "typescript": "^4.3.5"
78
+ },
79
+ "peerDependencies": {
80
+ "@prismicio/client": "^6.0.0-beta.0",
81
+ "next": "^11 || ^12",
82
+ "react": "^17"
83
+ },
84
+ "engines": {
85
+ "node": ">=12.7.0"
86
+ },
87
+ "publishConfig": {
88
+ "access": "public"
89
+ }
90
+ }
@@ -0,0 +1,101 @@
1
+ import React, { useEffect } from "react";
2
+ import { PrismicToolbar } from "@prismicio/react";
3
+
4
+ /**
5
+ * Props for `<PrismicPreview>`.
6
+ */
7
+ type PrismicPreviewProps = {
8
+ /**
9
+ * The name of your Prismic repository. A Prismic Toolbar will be registered
10
+ * using this repository.
11
+ */
12
+ repositoryName: string;
13
+
14
+ /**
15
+ * The URL of your app's Prismic preview endpoint (default: `/api/preview`).
16
+ * This URL will be fetched on preview update events.
17
+ */
18
+ updatePreviewURL?: string;
19
+
20
+ /**
21
+ * The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
22
+ * This URL will be fetched on preview exit events.
23
+ */
24
+ exitPreviewURL?: string;
25
+
26
+ children?: React.ReactNode;
27
+ };
28
+
29
+ /**
30
+ * Determines if an Event object came from the Prismic Toolbar.
31
+ *
32
+ * @param event - Event to check.
33
+ *
34
+ * @returns `true` if `event` came from the Prismic Toolbar, `false` otherwise.
35
+ */
36
+ const isPrismicUpdateToolbarEvent = (
37
+ event: Event,
38
+ ): event is CustomEvent<{ ref: string }> => {
39
+ return (
40
+ "detail" in event && typeof (event as CustomEvent).detail.ref === "string"
41
+ );
42
+ };
43
+
44
+ /**
45
+ * React component that sets up Prismic Previews using the Prismic Toolbar. When
46
+ * the Prismic Toolbar send events to the browser, such as on preview updates
47
+ * and exiting, this component will automatically update the Next.js preview
48
+ * cookie and refresh the page.
49
+ *
50
+ * This component can be wrapped around your app or added anywhere in your app's
51
+ * tree. It must be rendered on every page.
52
+ */
53
+ export function PrismicPreview({
54
+ repositoryName,
55
+ children,
56
+ updatePreviewURL = "/api/preview",
57
+ exitPreviewURL = "/api/exit-preview",
58
+ }: PrismicPreviewProps): JSX.Element {
59
+ useEffect(() => {
60
+ const prismicPreviewUpdate = async (event: Event) => {
61
+ if (isPrismicUpdateToolbarEvent(event)) {
62
+ // Prevent the toolbar from reloading the page.
63
+ event.preventDefault();
64
+ // Update the preview cookie.
65
+ await fetch(`${updatePreviewURL}?token=${event.detail.ref}`);
66
+
67
+ // Reload the page with the updated token.
68
+ window.location.reload();
69
+ }
70
+ };
71
+
72
+ const prismicPreviewEnd = async (event: Event) => {
73
+ event.preventDefault();
74
+ await fetch(exitPreviewURL);
75
+ window.location.reload();
76
+ };
77
+
78
+ if (window) {
79
+ window.addEventListener("prismicPreviewUpdate", prismicPreviewUpdate);
80
+
81
+ window.addEventListener("prismicPreviewEnd", prismicPreviewEnd);
82
+ }
83
+
84
+ return () => {
85
+ if (window) {
86
+ window.removeEventListener(
87
+ "prismicPreviewUpdate",
88
+ prismicPreviewUpdate,
89
+ );
90
+ window.removeEventListener("prismicPreviewEnd", prismicPreviewEnd);
91
+ }
92
+ };
93
+ }, []);
94
+
95
+ return (
96
+ <>
97
+ <PrismicToolbar repositoryName={repositoryName} />
98
+ {children}
99
+ </>
100
+ );
101
+ }
@@ -0,0 +1,81 @@
1
+ import { PreviewData } from "next";
2
+ import { Client, HttpRequestLike } from "@prismicio/client";
3
+ import { NextContextLike } from "./types";
4
+
5
+ interface PrismicNextPreviewData {
6
+ ref: string;
7
+ }
8
+
9
+ /**
10
+ * Determines if a Next.js preview data object contains Prismic preview data.
11
+ *
12
+ * @param previewData - The Next.js preview data object to check.
13
+ *
14
+ * @returns `true` if `previewData` contains Prismic preview data, `false` otherwise.
15
+ */
16
+ const isPrismicNextPreviewData = (
17
+ previewData: PreviewData,
18
+ ): previewData is PrismicNextPreviewData => {
19
+ return typeof previewData === "object" && "ref" in previewData;
20
+ };
21
+
22
+ /**
23
+ * Configuration for `enableAutoPreviews`.
24
+ *
25
+ * @typeParam TPreviewData - Next.js preview data object.
26
+ */
27
+ export type EnableAutoPreviewsConfig<
28
+ TPreviewData extends PreviewData = PreviewData,
29
+ > = {
30
+ /**
31
+ * Prismic client with which automatic previews will be enabled.
32
+ */
33
+ client: Client;
34
+ } & (
35
+ | {
36
+ /**
37
+ * A Next.js context object (such as the context object from
38
+ * `getStaticProps` or `getServerSideProps`).
39
+ *
40
+ * Pass a `context` object when using `enableAutoPreviews` outside a
41
+ * Next.js API endpoint.
42
+ */
43
+ context?: NextContextLike<TPreviewData>;
44
+ }
45
+ | {
46
+ /**
47
+ * A Next.js API endpoint request object.
48
+ *
49
+ * Pass a `req` object when using `enableAutoPreviews` in a Next.js API endpoint.
50
+ */
51
+ req?: HttpRequestLike;
52
+ }
53
+ );
54
+ /**
55
+ * Configures a Prismic client to automatically query draft content during a
56
+ * preview session. It either takes in a Next.js `getStaticProps` context object
57
+ * or a Next.js API endpoint request object.
58
+ *
59
+ * @param config - Configuration for the function.
60
+ */
61
+ export const enableAutoPreviews = <
62
+ TPreviewData extends PreviewData = PreviewData,
63
+ >(
64
+ config: EnableAutoPreviewsConfig<TPreviewData>,
65
+ ): void => {
66
+ /**
67
+ * If preview data is being passed from Next Context then use queryContentFromRef
68
+ */
69
+ if ("context" in config && config.context) {
70
+ const previewData = config.context.previewData;
71
+
72
+ if (isPrismicNextPreviewData(previewData) && previewData.ref) {
73
+ config.client.queryContentFromRef(previewData.ref);
74
+ }
75
+ /**
76
+ * If the req object is passed then use enableAutoPreviewsFromReq
77
+ */
78
+ } else if ("req" in config && config.req) {
79
+ config.client.enableAutoPreviewsFromReq(config.req);
80
+ }
81
+ };
@@ -0,0 +1,54 @@
1
+ import { NextApiResponse, NextApiRequest } from "next";
2
+
3
+ /**
4
+ * Configuration for `exitPreview`.
5
+ */
6
+ export type ExitPreviewConfig = {
7
+ /**
8
+ * The `req` object from a Next.js API route. This is given as a parameter to
9
+ * the API route.
10
+ *
11
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
12
+ */
13
+ req: {
14
+ headers: {
15
+ referer?: NextApiRequest["headers"]["referer"];
16
+ };
17
+ };
18
+
19
+ /**
20
+ * The `res` object from a Next.js API route. This is given as a parameter to
21
+ * the API route.
22
+ *
23
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
24
+ */
25
+ res: {
26
+ clearPreviewData: NextApiResponse["clearPreviewData"];
27
+ redirect: NextApiResponse["redirect"];
28
+ };
29
+ };
30
+
31
+ /**
32
+ * Exits Next.js's Preview Mode from within a Next.js API route.
33
+ *
34
+ * If the user was sent to the endpoint from a page, the user will be redirected
35
+ * back to that page after exiting Preview Mode.
36
+ */
37
+ export function exitPreview(config: ExitPreviewConfig): void {
38
+ const { req } = config;
39
+ // Exit the current user from "Preview Mode". This function accepts no args.
40
+ config.res.clearPreviewData();
41
+
42
+ if (req.headers.referer) {
43
+ const url = new URL(req.headers.referer);
44
+
45
+ if (url.pathname !== "/api/exit-preview") {
46
+ // Redirect the user to the referrer page.
47
+ config.res.redirect(req.headers.referer);
48
+
49
+ return;
50
+ }
51
+ }
52
+
53
+ config.res.redirect("/");
54
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export type { SetPreviewDataConfig } from "./setPreviewData";
2
+ export type { EnableAutoPreviewsConfig } from "./enableAutoPreviews";
3
+ export type { ExitPreviewConfig as ExitPreviewParams } from "./exitPreview";
4
+ export { setPreviewData } from "./setPreviewData";
5
+ export { exitPreview } from "./exitPreview";
6
+ export { PrismicPreview } from "./PrismicPreview";
7
+ export { enableAutoPreviews } from "./enableAutoPreviews";
8
+ export { redirectToPreviewURL } from "./redirectToPreviewURL";
9
+ export type {
10
+ NextContextLike,
11
+ CreateClientConfig,
12
+ PreviewConfig,
13
+ } from "./types";
@@ -0,0 +1,46 @@
1
+ import { NextApiRequest } from "next";
2
+ import { PreviewConfig } from "./";
3
+
4
+ type PrismicNextQuery = {
5
+ documentId: string;
6
+ token: string;
7
+ };
8
+
9
+ /**
10
+ * Determines if a query object from a Next.js API route request contains
11
+ * Prismic preview data.
12
+ *
13
+ * @param query - Query object to check.
14
+ *
15
+ * @returns `true` if `query` contains Prismic preview data, `false` otherwise.
16
+ */
17
+ const isPrismicNextQuery = (
18
+ query: NextApiRequest["query"],
19
+ ): query is PrismicNextQuery =>
20
+ typeof query.documentId === "string" && typeof query.token === "string";
21
+
22
+ /**
23
+ * Redirects a user to the URL of a previewed Prismic document from within a
24
+ * Next.js API route.
25
+ */
26
+ export async function redirectToPreviewURL({
27
+ req,
28
+ res,
29
+ client,
30
+ linkResolver,
31
+ defaultURL = "/",
32
+ }: PreviewConfig): Promise<void> {
33
+ if (isPrismicNextQuery(req.query)) {
34
+ const { documentId, token } = req.query;
35
+ const previewUrl = await client.resolvePreviewURL({
36
+ linkResolver,
37
+ defaultURL,
38
+ documentID: documentId,
39
+ previewToken: token,
40
+ });
41
+
42
+ res.redirect(previewUrl);
43
+ }
44
+
45
+ res.redirect(defaultURL);
46
+ }
@@ -0,0 +1,39 @@
1
+ import { NextApiResponse, NextApiRequest } from "next";
2
+
3
+ /**
4
+ * Configuration for `setPreviewData`.
5
+ */
6
+ export type SetPreviewDataConfig = {
7
+ /**
8
+ * The `req` object from a Next.js API route. This is given as a parameter to
9
+ * the API route.
10
+ *
11
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
12
+ */
13
+ req: {
14
+ query: NextApiRequest["query"];
15
+ };
16
+
17
+ /**
18
+ * The `res` object from a Next.js API route. This is given as a parameter to
19
+ * the API route.
20
+ *
21
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
22
+ */
23
+ res: {
24
+ setPreviewData: NextApiResponse["setPreviewData"];
25
+ };
26
+ };
27
+
28
+ /**
29
+ * Set Prismic preview data for Next.js's Preview Mode.
30
+ */
31
+ export async function setPreviewData({
32
+ req,
33
+ res,
34
+ }: SetPreviewDataConfig): Promise<void> {
35
+ if (req.query.token) {
36
+ const { token: ref } = req.query;
37
+ res.setPreviewData({ ref });
38
+ }
39
+ }
package/src/types.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { PreviewData, NextApiRequest, NextApiResponse } from "next";
2
+ import { LinkResolverFunction } from "@prismicio/helpers";
3
+ import { Client } from "@prismicio/client";
4
+
5
+ /**
6
+ * Next.js context object from APIs supporting Preview Mode. This includes the
7
+ * context object from `getStaticProps` and `getServerSideProps`.
8
+ */
9
+ export type NextContextLike<TPreviewData extends PreviewData = PreviewData> = {
10
+ previewData?: TPreviewData;
11
+ };
12
+
13
+ /**
14
+ * Configuration for creating a Prismic client with automatic preview support in
15
+ * Next.js apps.
16
+ */
17
+ export type CreateClientConfig = {
18
+ /**
19
+ * A Next.js context object (such as the context object from `getStaticProps`
20
+ * or `getServerSideProps`).
21
+ *
22
+ * Pass a `context` when using outside a Next.js API endpoint.
23
+ */
24
+ context?: NextContextLike;
25
+
26
+ /**
27
+ * A Next.js API endpoint request object.
28
+ *
29
+ * Pass a `req` object when using in a Next.js API endpoint.
30
+ */
31
+ req?: NextApiRequest;
32
+ };
33
+
34
+ /**
35
+ * Preview config for enabling previews with redirectToPreviewURL
36
+ */
37
+ export type PreviewConfig = {
38
+ /**
39
+ * The `req` object from a Next.js API route. This is given as a parameter to
40
+ * the API route.
41
+ *
42
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
43
+ */
44
+ req: {
45
+ query: NextApiRequest["query"];
46
+ };
47
+
48
+ /**
49
+ * The `res` object from a Next.js API route. This is given as a parameter to
50
+ * the API route.
51
+ *
52
+ * @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
53
+ */
54
+ res: {
55
+ redirect: NextApiResponse["redirect"];
56
+ };
57
+
58
+ /**
59
+ * The Prismic client configured for the preview session's repository.
60
+ */
61
+ client: Client;
62
+
63
+ /**
64
+ * A Link Resolver used to resolve the previewed document's URL.
65
+ *
66
+ * @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
67
+ */
68
+ linkResolver?: LinkResolverFunction;
69
+
70
+ /**
71
+ * The default redirect URL if a URL cannot be determined for the previewed document.
72
+ */
73
+ defaultURL?: string;
74
+ };