@prismicio/next 0.1.2 → 0.2.0-alpha.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.
- package/dist/index.cjs +65 -67
- package/dist/index.d.ts +85 -81
- package/dist/index.js +65 -65
- package/package.json +13 -19
- package/src/PrismicPreview.tsx +109 -56
- package/src/enableAutoPreviews.ts +4 -6
- package/src/exitPreview.ts +15 -27
- package/src/index.ts +11 -5
- package/src/lib/getCookie.ts +15 -22
- package/src/redirectToPreviewURL.ts +74 -21
- package/src/setPreviewData.ts +2 -7
- package/src/types.ts +1 -48
package/dist/index.cjs
CHANGED
|
@@ -7,8 +7,6 @@ const React = require('react');
|
|
|
7
7
|
const react = require('@prismicio/react');
|
|
8
8
|
const router = require('next/router');
|
|
9
9
|
|
|
10
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
|
-
|
|
12
10
|
function _interopNamespace(e) {
|
|
13
11
|
if (e && e.__esModule) return e;
|
|
14
12
|
const n = Object.create(null);
|
|
@@ -28,7 +26,7 @@ function _interopNamespace(e) {
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
const prismic__namespace = /*#__PURE__*/_interopNamespace(prismic);
|
|
31
|
-
const
|
|
29
|
+
const React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
32
30
|
|
|
33
31
|
function setPreviewData({ req, res }) {
|
|
34
32
|
const ref = req.query.token || req.cookies[prismic__namespace.cookie.preview];
|
|
@@ -38,34 +36,24 @@ function setPreviewData({ req, res }) {
|
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
function exitPreview(config) {
|
|
41
|
-
const { req } = config;
|
|
42
39
|
config.res.clearPreviewData();
|
|
43
|
-
|
|
44
|
-
const url = new URL(req.headers.referer);
|
|
45
|
-
if (url.pathname !== "/api/exit-preview") {
|
|
46
|
-
config.res.redirect(req.headers.referer);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
config.res.redirect("/");
|
|
40
|
+
config.res.json({ success: true });
|
|
51
41
|
}
|
|
52
42
|
|
|
53
43
|
const readValue = (value) => {
|
|
54
44
|
return value.replace(/%3B/g, ";");
|
|
55
45
|
};
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const cookies = cookieString.split("; ");
|
|
46
|
+
const getCookie = (name) => {
|
|
47
|
+
const cookies = document.cookie.split("; ");
|
|
59
48
|
for (const cookie of cookies) {
|
|
60
49
|
const parts = cookie.split("=");
|
|
61
50
|
const value = parts.slice(1).join("=");
|
|
62
|
-
const
|
|
63
|
-
|
|
51
|
+
const thisName = readValue(parts[0]).replace(/%3D/g, "=");
|
|
52
|
+
if (thisName === name) {
|
|
53
|
+
return readValue(value);
|
|
54
|
+
}
|
|
64
55
|
}
|
|
65
|
-
return result;
|
|
66
56
|
};
|
|
67
|
-
const getAll = (cookieStore) => parse(cookieStore);
|
|
68
|
-
const getCookie = (name, cookieStore) => getAll(cookieStore)[name];
|
|
69
57
|
|
|
70
58
|
const extractFirstSubdomain = (host) => host.split(".")[0];
|
|
71
59
|
const extractRepositoryNameFromObjectRef = (previewRef) => {
|
|
@@ -94,51 +82,64 @@ const extractPreviewRefRepositoryName = (previewRef) => {
|
|
|
94
82
|
return extractRepositoryNameFromObjectRef(previewRef) || extractRepositoryNameFromURLRef(previewRef);
|
|
95
83
|
};
|
|
96
84
|
|
|
97
|
-
const
|
|
98
|
-
|
|
85
|
+
const updatePreviewMode = async (updatePreviewURL) => {
|
|
86
|
+
const res = await globalThis.fetch(updatePreviewURL);
|
|
87
|
+
if (res.ok) {
|
|
88
|
+
window.location.reload();
|
|
89
|
+
} else {
|
|
90
|
+
console.error(`[<PrismicPreview>] Failed to start or update Preview Mode using the "${updatePreviewURL}" API endpoint. Does it exist?`);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const exitPreviewMode = async (exitPreviewURL) => {
|
|
94
|
+
const res = await globalThis.fetch(exitPreviewURL);
|
|
95
|
+
if (res.ok) {
|
|
96
|
+
window.location.reload();
|
|
97
|
+
} else {
|
|
98
|
+
console.error(`[<PrismicPreview>] Failed to exit Preview Mode using the "${exitPreviewURL}" API endpoint. Does it exist?`);
|
|
99
|
+
}
|
|
99
100
|
};
|
|
100
101
|
function PrismicPreview({
|
|
101
102
|
repositoryName,
|
|
102
|
-
children,
|
|
103
103
|
updatePreviewURL = "/api/preview",
|
|
104
|
-
exitPreviewURL = "/api/exit-preview"
|
|
104
|
+
exitPreviewURL = "/api/exit-preview",
|
|
105
|
+
children
|
|
105
106
|
}) {
|
|
106
107
|
const router$1 = router.useRouter();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
const resolvedUpdatePreviewURL = router$1.basePath + updatePreviewURL;
|
|
109
|
+
const resolvedExitPreviewURL = router$1.basePath + exitPreviewURL;
|
|
110
|
+
React__namespace.useEffect(() => {
|
|
111
|
+
const previewCookie = getCookie(prismic__namespace.cookie.preview);
|
|
112
|
+
const prismicPreviewSessionIsForThisRepo = Boolean(previewCookie && extractPreviewRefRepositoryName(previewCookie) === repositoryName);
|
|
113
|
+
const locationIsDescendantOfBasePath = window.location.href.startsWith(window.location.origin + router$1.basePath);
|
|
114
|
+
const loadedFromShareLink = !router$1.isPreview && previewCookie;
|
|
115
|
+
if (prismicPreviewSessionIsForThisRepo && locationIsDescendantOfBasePath && loadedFromShareLink) {
|
|
116
|
+
updatePreviewMode(resolvedUpdatePreviewURL);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
116
119
|
const handlePrismicPreviewUpdate = async (event) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
await fetch(updatePreviewURL);
|
|
120
|
-
window.location.reload();
|
|
121
|
-
}
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
await updatePreviewMode(resolvedUpdatePreviewURL);
|
|
122
122
|
};
|
|
123
123
|
const handlePrismicPreviewEnd = async (event) => {
|
|
124
124
|
event.preventDefault();
|
|
125
|
-
await
|
|
126
|
-
window.location.reload();
|
|
125
|
+
await exitPreviewMode(resolvedExitPreviewURL);
|
|
127
126
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
131
|
-
}
|
|
127
|
+
window.addEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
|
|
128
|
+
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
132
129
|
return () => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
136
|
-
}
|
|
130
|
+
window.removeEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
|
|
131
|
+
window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
137
132
|
};
|
|
138
|
-
}, [
|
|
139
|
-
|
|
133
|
+
}, [
|
|
134
|
+
repositoryName,
|
|
135
|
+
resolvedUpdatePreviewURL,
|
|
136
|
+
resolvedExitPreviewURL,
|
|
137
|
+
router$1.isPreview,
|
|
138
|
+
router$1.basePath
|
|
139
|
+
]);
|
|
140
|
+
return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, children, /* @__PURE__ */ React__namespace.createElement(react.PrismicToolbar, {
|
|
140
141
|
repositoryName
|
|
141
|
-
})
|
|
142
|
+
}));
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
const isPrismicNextPreviewData = (previewData) => {
|
|
@@ -155,26 +156,23 @@ const enableAutoPreviews = (config) => {
|
|
|
155
156
|
}
|
|
156
157
|
};
|
|
157
158
|
|
|
158
|
-
const isPrismicNextQuery = (query) =>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const { documentId, token } = req.query;
|
|
168
|
-
const previewUrl = await client.resolvePreviewURL({
|
|
169
|
-
linkResolver,
|
|
159
|
+
const isPrismicNextQuery = (query) => {
|
|
160
|
+
return typeof query.documentId === "string" && typeof query.token === "string";
|
|
161
|
+
};
|
|
162
|
+
async function redirectToPreviewURL(config) {
|
|
163
|
+
const defaultURL = config.defaultURL || "/";
|
|
164
|
+
const basePath = config.basePath || "";
|
|
165
|
+
if (isPrismicNextQuery(config.req.query)) {
|
|
166
|
+
const previewUrl = await config.client.resolvePreviewURL({
|
|
167
|
+
linkResolver: config.linkResolver,
|
|
170
168
|
defaultURL,
|
|
171
|
-
documentID: documentId,
|
|
172
|
-
previewToken: token
|
|
169
|
+
documentID: config.req.query.documentId,
|
|
170
|
+
previewToken: config.req.query.token
|
|
173
171
|
});
|
|
174
|
-
res.redirect(previewUrl);
|
|
172
|
+
config.res.redirect(basePath + previewUrl);
|
|
175
173
|
return;
|
|
176
174
|
}
|
|
177
|
-
res.redirect(defaultURL);
|
|
175
|
+
config.res.redirect(basePath + defaultURL);
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
exports.PrismicPreview = PrismicPreview;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextApiRequest, NextApiResponse, PreviewData } from 'next';
|
|
2
|
+
import * as React from 'react';
|
|
2
3
|
import { Client, HttpRequestLike } from '@prismicio/client';
|
|
3
|
-
import React from 'react';
|
|
4
4
|
import { LinkResolverFunction } from '@prismicio/helpers';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -13,61 +13,20 @@ declare type SetPreviewDataConfig = {
|
|
|
13
13
|
*
|
|
14
14
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
15
15
|
*/
|
|
16
|
-
req:
|
|
17
|
-
query: NextApiRequest["query"];
|
|
18
|
-
cookies: NextApiRequest["cookies"];
|
|
19
|
-
};
|
|
16
|
+
req: Pick<NextApiRequest, "query" | "cookies">;
|
|
20
17
|
/**
|
|
21
18
|
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
22
19
|
* the API route.
|
|
23
20
|
*
|
|
24
21
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
25
22
|
*/
|
|
26
|
-
res:
|
|
27
|
-
setPreviewData: NextApiResponse["setPreviewData"];
|
|
28
|
-
};
|
|
23
|
+
res: Pick<NextApiResponse, "setPreviewData">;
|
|
29
24
|
};
|
|
30
25
|
/**
|
|
31
26
|
* Set Prismic preview data for Next.js's Preview Mode.
|
|
32
27
|
*/
|
|
33
28
|
declare function setPreviewData({ req, res }: SetPreviewDataConfig): void;
|
|
34
29
|
|
|
35
|
-
/**
|
|
36
|
-
* Configuration for `enableAutoPreviews`.
|
|
37
|
-
*
|
|
38
|
-
* @typeParam TPreviewData - Next.js preview data object.
|
|
39
|
-
*/
|
|
40
|
-
declare type EnableAutoPreviewsConfig<TPreviewData extends PreviewData = PreviewData> = {
|
|
41
|
-
/**
|
|
42
|
-
* Prismic client with which automatic previews will be enabled.
|
|
43
|
-
*/
|
|
44
|
-
client: Client;
|
|
45
|
-
} & ({
|
|
46
|
-
/**
|
|
47
|
-
* A Next.js context object (such as the context object from
|
|
48
|
-
* `getStaticProps` or `getServerSideProps`).
|
|
49
|
-
*
|
|
50
|
-
* Pass a `context` object when using `enableAutoPreviews` outside a
|
|
51
|
-
* Next.js API endpoint.
|
|
52
|
-
*/
|
|
53
|
-
previewData?: TPreviewData;
|
|
54
|
-
} | {
|
|
55
|
-
/**
|
|
56
|
-
* A Next.js API endpoint request object.
|
|
57
|
-
*
|
|
58
|
-
* Pass a `req` object when using `enableAutoPreviews` in a Next.js API endpoint.
|
|
59
|
-
*/
|
|
60
|
-
req?: HttpRequestLike;
|
|
61
|
-
});
|
|
62
|
-
/**
|
|
63
|
-
* Configures a Prismic client to automatically query draft content during a
|
|
64
|
-
* preview session. It either takes in a Next.js `getStaticProps` context object
|
|
65
|
-
* or a Next.js API endpoint request object.
|
|
66
|
-
*
|
|
67
|
-
* @param config - Configuration for the function.
|
|
68
|
-
*/
|
|
69
|
-
declare const enableAutoPreviews: <TPreviewData extends PreviewData>(config: EnableAutoPreviewsConfig<TPreviewData>) => void;
|
|
70
|
-
|
|
71
30
|
/**
|
|
72
31
|
* Configuration for `exitPreview`.
|
|
73
32
|
*/
|
|
@@ -78,27 +37,17 @@ declare type ExitPreviewConfig = {
|
|
|
78
37
|
*
|
|
79
38
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
80
39
|
*/
|
|
81
|
-
req:
|
|
82
|
-
headers: {
|
|
83
|
-
referer?: NextApiRequest["headers"]["referer"];
|
|
84
|
-
};
|
|
85
|
-
};
|
|
40
|
+
req: Pick<NextApiRequest, "headers">;
|
|
86
41
|
/**
|
|
87
42
|
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
88
43
|
* the API route.
|
|
89
44
|
*
|
|
90
45
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
91
46
|
*/
|
|
92
|
-
res:
|
|
93
|
-
clearPreviewData: NextApiResponse["clearPreviewData"];
|
|
94
|
-
redirect: NextApiResponse["redirect"];
|
|
95
|
-
};
|
|
47
|
+
res: Pick<NextApiResponse, "clearPreviewData" | "json">;
|
|
96
48
|
};
|
|
97
49
|
/**
|
|
98
50
|
* Exits Next.js's Preview Mode from within a Next.js API route.
|
|
99
|
-
*
|
|
100
|
-
* If the user was sent to the endpoint from a page, the user will be redirected
|
|
101
|
-
* back to that page after exiting Preview Mode.
|
|
102
51
|
*/
|
|
103
52
|
declare function exitPreview(config: ExitPreviewConfig): void;
|
|
104
53
|
|
|
@@ -114,13 +63,23 @@ declare type PrismicPreviewProps = {
|
|
|
114
63
|
/**
|
|
115
64
|
* The URL of your app's Prismic preview endpoint (default: `/api/preview`).
|
|
116
65
|
* This URL will be fetched on preview update events.
|
|
66
|
+
*
|
|
67
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, it is
|
|
68
|
+
* automatically included.
|
|
117
69
|
*/
|
|
118
70
|
updatePreviewURL?: string;
|
|
119
71
|
/**
|
|
120
72
|
* The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
|
|
121
73
|
* This URL will be fetched on preview exit events.
|
|
74
|
+
*
|
|
75
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, it is
|
|
76
|
+
* automatically included.
|
|
122
77
|
*/
|
|
123
78
|
exitPreviewURL?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Children to render adjacent to the Prismic Toolbar. The Prismic Toolbar
|
|
81
|
+
* will be rendered last.
|
|
82
|
+
*/
|
|
124
83
|
children?: React.ReactNode;
|
|
125
84
|
};
|
|
126
85
|
/**
|
|
@@ -132,55 +91,62 @@ declare type PrismicPreviewProps = {
|
|
|
132
91
|
* This component can be wrapped around your app or added anywhere in your app's
|
|
133
92
|
* tree. It must be rendered on every page.
|
|
134
93
|
*/
|
|
135
|
-
declare function PrismicPreview({ repositoryName,
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Redirects a user to the URL of a previewed Prismic document from within a
|
|
139
|
-
* Next.js API route.
|
|
140
|
-
*/
|
|
141
|
-
declare function redirectToPreviewURL<TLinkResolverFunction extends LinkResolverFunction<any>>({ req, res, client, linkResolver, defaultURL, }: PreviewConfig<TLinkResolverFunction>): Promise<void>;
|
|
94
|
+
declare function PrismicPreview({ repositoryName, updatePreviewURL, exitPreviewURL, children, }: PrismicPreviewProps): JSX.Element;
|
|
142
95
|
|
|
143
96
|
/**
|
|
144
|
-
* Configuration for
|
|
145
|
-
*
|
|
97
|
+
* Configuration for `enableAutoPreviews`.
|
|
98
|
+
*
|
|
99
|
+
* @typeParam TPreviewData - Next.js preview data object.
|
|
146
100
|
*/
|
|
147
|
-
declare type
|
|
101
|
+
declare type EnableAutoPreviewsConfig<TPreviewData extends PreviewData = PreviewData> = {
|
|
148
102
|
/**
|
|
149
|
-
*
|
|
150
|
-
|
|
103
|
+
* Prismic client with which automatic previews will be enabled.
|
|
104
|
+
*/
|
|
105
|
+
client: Client;
|
|
106
|
+
} & ({
|
|
107
|
+
/**
|
|
108
|
+
* A Next.js context object (such as the context object from
|
|
109
|
+
* `getStaticProps` or `getServerSideProps`).
|
|
151
110
|
*
|
|
152
|
-
* Pass `
|
|
111
|
+
* Pass a `context` object when using `enableAutoPreviews` outside a
|
|
112
|
+
* Next.js API endpoint.
|
|
153
113
|
*/
|
|
154
|
-
previewData?:
|
|
114
|
+
previewData?: TPreviewData;
|
|
115
|
+
} | {
|
|
155
116
|
/**
|
|
156
117
|
* A Next.js API endpoint request object.
|
|
157
118
|
*
|
|
158
|
-
* Pass a `req` object when using in a Next.js API endpoint.
|
|
119
|
+
* Pass a `req` object when using `enableAutoPreviews` in a Next.js API endpoint.
|
|
159
120
|
*/
|
|
160
|
-
req?:
|
|
161
|
-
};
|
|
121
|
+
req?: HttpRequestLike;
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* Configures a Prismic client to automatically query draft content during a
|
|
125
|
+
* preview session. It either takes in a Next.js `getStaticProps` context object
|
|
126
|
+
* or a Next.js API endpoint request object.
|
|
127
|
+
*
|
|
128
|
+
* @param config - Configuration for the function.
|
|
129
|
+
*/
|
|
130
|
+
declare const enableAutoPreviews: <TPreviewData extends PreviewData>(config: EnableAutoPreviewsConfig<TPreviewData>) => void;
|
|
131
|
+
|
|
162
132
|
/**
|
|
163
133
|
* Preview config for enabling previews with redirectToPreviewURL
|
|
164
134
|
*/
|
|
165
|
-
declare type
|
|
135
|
+
declare type RedirectToPreviewURLConfig<TLinkResolverFunction extends LinkResolverFunction<any> = LinkResolverFunction> = {
|
|
166
136
|
/**
|
|
167
137
|
* The `req` object from a Next.js API route. This is given as a parameter to
|
|
168
138
|
* the API route.
|
|
169
139
|
*
|
|
170
140
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
171
141
|
*/
|
|
172
|
-
req:
|
|
173
|
-
query: NextApiRequest["query"];
|
|
174
|
-
};
|
|
142
|
+
req: Pick<NextApiRequest, "query">;
|
|
175
143
|
/**
|
|
176
144
|
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
177
145
|
* the API route.
|
|
178
146
|
*
|
|
179
147
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
180
148
|
*/
|
|
181
|
-
res:
|
|
182
|
-
redirect: NextApiResponse["redirect"];
|
|
183
|
-
};
|
|
149
|
+
res: Pick<NextApiResponse, "redirect">;
|
|
184
150
|
/**
|
|
185
151
|
* The Prismic client configured for the preview session's repository.
|
|
186
152
|
*/
|
|
@@ -193,8 +159,46 @@ declare type PreviewConfig<TLinkResolverFunction extends LinkResolverFunction<an
|
|
|
193
159
|
linkResolver?: TLinkResolverFunction;
|
|
194
160
|
/**
|
|
195
161
|
* The default redirect URL if a URL cannot be determined for the previewed document.
|
|
162
|
+
*
|
|
163
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, you must
|
|
164
|
+
* include the `basePath` as part of this option. `redirectToPreviewURL()`
|
|
165
|
+
* cannot read your global `basePath`.
|
|
196
166
|
*/
|
|
197
167
|
defaultURL?: string;
|
|
168
|
+
/**
|
|
169
|
+
* The `basePath` for the Next.js app as it is defined in `next.config.js`.
|
|
170
|
+
* This option can be omitted if the app does not have a `basePath`.
|
|
171
|
+
*
|
|
172
|
+
* @remarks
|
|
173
|
+
* The API route is unable to detect the app's `basePath` automatically. It
|
|
174
|
+
* must be provided to `redirectToPreviewURL()` manually.
|
|
175
|
+
*/
|
|
176
|
+
basePath?: string;
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Redirects a user to the URL of a previewed Prismic document from within a
|
|
180
|
+
* Next.js API route.
|
|
181
|
+
*/
|
|
182
|
+
declare function redirectToPreviewURL<TLinkResolverFunction extends LinkResolverFunction<any>>(config: RedirectToPreviewURLConfig<TLinkResolverFunction>): Promise<void>;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Configuration for creating a Prismic client with automatic preview support in
|
|
186
|
+
* Next.js apps.
|
|
187
|
+
*/
|
|
188
|
+
declare type CreateClientConfig = {
|
|
189
|
+
/**
|
|
190
|
+
* Preview data coming from Next.js context object. This context object comes
|
|
191
|
+
* from `getStaticProps` or `getServerSideProps`.
|
|
192
|
+
*
|
|
193
|
+
* Pass `previewData` when using outside a Next.js API endpoint.
|
|
194
|
+
*/
|
|
195
|
+
previewData?: PreviewData;
|
|
196
|
+
/**
|
|
197
|
+
* A Next.js API endpoint request object.
|
|
198
|
+
*
|
|
199
|
+
* Pass a `req` object when using in a Next.js API endpoint.
|
|
200
|
+
*/
|
|
201
|
+
req?: NextApiRequest;
|
|
198
202
|
};
|
|
199
203
|
|
|
200
|
-
export { CreateClientConfig, EnableAutoPreviewsConfig, ExitPreviewConfig
|
|
204
|
+
export { CreateClientConfig, EnableAutoPreviewsConfig, ExitPreviewConfig, PrismicPreview, PrismicPreviewProps, RedirectToPreviewURLConfig, SetPreviewDataConfig, enableAutoPreviews, exitPreview, redirectToPreviewURL, setPreviewData };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as prismic from '@prismicio/client';
|
|
2
|
-
import
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
import { PrismicToolbar } from '@prismicio/react';
|
|
4
4
|
import { useRouter } from 'next/router';
|
|
5
5
|
|
|
@@ -11,34 +11,24 @@ function setPreviewData({ req, res }) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function exitPreview(config) {
|
|
14
|
-
const { req } = config;
|
|
15
14
|
config.res.clearPreviewData();
|
|
16
|
-
|
|
17
|
-
const url = new URL(req.headers.referer);
|
|
18
|
-
if (url.pathname !== "/api/exit-preview") {
|
|
19
|
-
config.res.redirect(req.headers.referer);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
config.res.redirect("/");
|
|
15
|
+
config.res.json({ success: true });
|
|
24
16
|
}
|
|
25
17
|
|
|
26
18
|
const readValue = (value) => {
|
|
27
19
|
return value.replace(/%3B/g, ";");
|
|
28
20
|
};
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const cookies = cookieString.split("; ");
|
|
21
|
+
const getCookie = (name) => {
|
|
22
|
+
const cookies = document.cookie.split("; ");
|
|
32
23
|
for (const cookie of cookies) {
|
|
33
24
|
const parts = cookie.split("=");
|
|
34
25
|
const value = parts.slice(1).join("=");
|
|
35
|
-
const
|
|
36
|
-
|
|
26
|
+
const thisName = readValue(parts[0]).replace(/%3D/g, "=");
|
|
27
|
+
if (thisName === name) {
|
|
28
|
+
return readValue(value);
|
|
29
|
+
}
|
|
37
30
|
}
|
|
38
|
-
return result;
|
|
39
31
|
};
|
|
40
|
-
const getAll = (cookieStore) => parse(cookieStore);
|
|
41
|
-
const getCookie = (name, cookieStore) => getAll(cookieStore)[name];
|
|
42
32
|
|
|
43
33
|
const extractFirstSubdomain = (host) => host.split(".")[0];
|
|
44
34
|
const extractRepositoryNameFromObjectRef = (previewRef) => {
|
|
@@ -67,51 +57,64 @@ const extractPreviewRefRepositoryName = (previewRef) => {
|
|
|
67
57
|
return extractRepositoryNameFromObjectRef(previewRef) || extractRepositoryNameFromURLRef(previewRef);
|
|
68
58
|
};
|
|
69
59
|
|
|
70
|
-
const
|
|
71
|
-
|
|
60
|
+
const updatePreviewMode = async (updatePreviewURL) => {
|
|
61
|
+
const res = await globalThis.fetch(updatePreviewURL);
|
|
62
|
+
if (res.ok) {
|
|
63
|
+
window.location.reload();
|
|
64
|
+
} else {
|
|
65
|
+
console.error(`[<PrismicPreview>] Failed to start or update Preview Mode using the "${updatePreviewURL}" API endpoint. Does it exist?`);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const exitPreviewMode = async (exitPreviewURL) => {
|
|
69
|
+
const res = await globalThis.fetch(exitPreviewURL);
|
|
70
|
+
if (res.ok) {
|
|
71
|
+
window.location.reload();
|
|
72
|
+
} else {
|
|
73
|
+
console.error(`[<PrismicPreview>] Failed to exit Preview Mode using the "${exitPreviewURL}" API endpoint. Does it exist?`);
|
|
74
|
+
}
|
|
72
75
|
};
|
|
73
76
|
function PrismicPreview({
|
|
74
77
|
repositoryName,
|
|
75
|
-
children,
|
|
76
78
|
updatePreviewURL = "/api/preview",
|
|
77
|
-
exitPreviewURL = "/api/exit-preview"
|
|
79
|
+
exitPreviewURL = "/api/exit-preview",
|
|
80
|
+
children
|
|
78
81
|
}) {
|
|
79
82
|
const router = useRouter();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
const resolvedUpdatePreviewURL = router.basePath + updatePreviewURL;
|
|
84
|
+
const resolvedExitPreviewURL = router.basePath + exitPreviewURL;
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
const previewCookie = getCookie(prismic.cookie.preview);
|
|
87
|
+
const prismicPreviewSessionIsForThisRepo = Boolean(previewCookie && extractPreviewRefRepositoryName(previewCookie) === repositoryName);
|
|
88
|
+
const locationIsDescendantOfBasePath = window.location.href.startsWith(window.location.origin + router.basePath);
|
|
89
|
+
const loadedFromShareLink = !router.isPreview && previewCookie;
|
|
90
|
+
if (prismicPreviewSessionIsForThisRepo && locationIsDescendantOfBasePath && loadedFromShareLink) {
|
|
91
|
+
updatePreviewMode(resolvedUpdatePreviewURL);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
89
94
|
const handlePrismicPreviewUpdate = async (event) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
await fetch(updatePreviewURL);
|
|
93
|
-
window.location.reload();
|
|
94
|
-
}
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
await updatePreviewMode(resolvedUpdatePreviewURL);
|
|
95
97
|
};
|
|
96
98
|
const handlePrismicPreviewEnd = async (event) => {
|
|
97
99
|
event.preventDefault();
|
|
98
|
-
await
|
|
99
|
-
window.location.reload();
|
|
100
|
+
await exitPreviewMode(resolvedExitPreviewURL);
|
|
100
101
|
};
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
104
|
-
}
|
|
102
|
+
window.addEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
|
|
103
|
+
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
105
104
|
return () => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
109
|
-
}
|
|
105
|
+
window.removeEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
|
|
106
|
+
window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
110
107
|
};
|
|
111
|
-
}, [
|
|
112
|
-
|
|
108
|
+
}, [
|
|
109
|
+
repositoryName,
|
|
110
|
+
resolvedUpdatePreviewURL,
|
|
111
|
+
resolvedExitPreviewURL,
|
|
112
|
+
router.isPreview,
|
|
113
|
+
router.basePath
|
|
114
|
+
]);
|
|
115
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, children, /* @__PURE__ */ React.createElement(PrismicToolbar, {
|
|
113
116
|
repositoryName
|
|
114
|
-
})
|
|
117
|
+
}));
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
const isPrismicNextPreviewData = (previewData) => {
|
|
@@ -128,26 +131,23 @@ const enableAutoPreviews = (config) => {
|
|
|
128
131
|
}
|
|
129
132
|
};
|
|
130
133
|
|
|
131
|
-
const isPrismicNextQuery = (query) =>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const { documentId, token } = req.query;
|
|
141
|
-
const previewUrl = await client.resolvePreviewURL({
|
|
142
|
-
linkResolver,
|
|
134
|
+
const isPrismicNextQuery = (query) => {
|
|
135
|
+
return typeof query.documentId === "string" && typeof query.token === "string";
|
|
136
|
+
};
|
|
137
|
+
async function redirectToPreviewURL(config) {
|
|
138
|
+
const defaultURL = config.defaultURL || "/";
|
|
139
|
+
const basePath = config.basePath || "";
|
|
140
|
+
if (isPrismicNextQuery(config.req.query)) {
|
|
141
|
+
const previewUrl = await config.client.resolvePreviewURL({
|
|
142
|
+
linkResolver: config.linkResolver,
|
|
143
143
|
defaultURL,
|
|
144
|
-
documentID: documentId,
|
|
145
|
-
previewToken: token
|
|
144
|
+
documentID: config.req.query.documentId,
|
|
145
|
+
previewToken: config.req.query.token
|
|
146
146
|
});
|
|
147
|
-
res.redirect(previewUrl);
|
|
147
|
+
config.res.redirect(basePath + previewUrl);
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
|
-
res.redirect(defaultURL);
|
|
150
|
+
config.res.redirect(basePath + defaultURL);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
export { PrismicPreview, enableAutoPreviews, exitPreview, redirectToPreviewURL, setPreviewData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prismicio/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-alpha.0",
|
|
4
4
|
"description": "Helpers to integrate Prismic into Next.js apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -41,44 +41,38 @@
|
|
|
41
41
|
"release:dry": "standard-version --dry-run",
|
|
42
42
|
"size": "size-limit",
|
|
43
43
|
"test": "npm run lint && npm run unit && npm run build && npm run size",
|
|
44
|
-
"unit": "
|
|
44
|
+
"unit": "vitest run --coverage",
|
|
45
|
+
"unit:watch": "vitest watch"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@prismicio/
|
|
48
|
+
"@prismicio/client": "^6.0.0",
|
|
49
|
+
"@prismicio/react": "^2.2.0",
|
|
50
|
+
"@prismicio/types": "^0.1.27"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
|
-
"@prismicio/client": "^6.4.2",
|
|
51
|
-
"@prismicio/mock": "^0.0.9",
|
|
52
|
-
"@prismicio/types": "^0.1.27",
|
|
53
53
|
"@size-limit/preset-small-lib": "^7.0.8",
|
|
54
|
-
"@testing-library/react": "^13.0.0",
|
|
55
|
-
"@types/jsdom": "^16.2.14",
|
|
56
|
-
"@types/jsdom-global": "^3.0.2",
|
|
57
54
|
"@types/react-test-renderer": "^17.0.1",
|
|
58
|
-
"@types/sinon": "^10.0.11",
|
|
59
55
|
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
|
60
56
|
"@typescript-eslint/parser": "^5.17.0",
|
|
61
|
-
"
|
|
57
|
+
"c8": "^7.11.0",
|
|
62
58
|
"eslint": "^8.12.0",
|
|
63
59
|
"eslint-config-prettier": "^8.5.0",
|
|
64
60
|
"eslint-plugin-prettier": "^4.0.0",
|
|
61
|
+
"eslint-plugin-react": "^7.29.4",
|
|
62
|
+
"eslint-plugin-react-hooks": "^4.4.0",
|
|
65
63
|
"eslint-plugin-tsdoc": "^0.2.14",
|
|
66
|
-
"
|
|
67
|
-
"jsdom-global": "^3.0.2",
|
|
68
|
-
"msw": "^0.39.2",
|
|
64
|
+
"happy-dom": "^2.55.0",
|
|
69
65
|
"next": "^12.1.4",
|
|
70
|
-
"node-fetch": "^3.2.3",
|
|
71
66
|
"nyc": "^15.1.0",
|
|
72
67
|
"prettier": "^2.6.1",
|
|
73
68
|
"prettier-plugin-jsdoc": "^0.3.35",
|
|
74
69
|
"react": "^18.0.0",
|
|
75
|
-
"react-
|
|
76
|
-
"sinon": "^13.0.1",
|
|
70
|
+
"react-test-renderer": "^18.0.0",
|
|
77
71
|
"siroc": "^0.16.0",
|
|
78
72
|
"size-limit": "^7.0.8",
|
|
79
73
|
"standard-version": "^9.3.2",
|
|
80
|
-
"
|
|
81
|
-
"
|
|
74
|
+
"typescript": "^4.6.3",
|
|
75
|
+
"vitest": "^0.8.1"
|
|
82
76
|
},
|
|
83
77
|
"peerDependencies": {
|
|
84
78
|
"@prismicio/client": "^6.0.0",
|
package/src/PrismicPreview.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as prismic from "@prismicio/client";
|
|
2
3
|
import { PrismicToolbar } from "@prismicio/react";
|
|
3
4
|
import { useRouter } from "next/router";
|
|
4
5
|
|
|
@@ -18,31 +19,65 @@ export type PrismicPreviewProps = {
|
|
|
18
19
|
/**
|
|
19
20
|
* The URL of your app's Prismic preview endpoint (default: `/api/preview`).
|
|
20
21
|
* This URL will be fetched on preview update events.
|
|
22
|
+
*
|
|
23
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, it is
|
|
24
|
+
* automatically included.
|
|
21
25
|
*/
|
|
22
26
|
updatePreviewURL?: string;
|
|
23
27
|
|
|
24
28
|
/**
|
|
25
29
|
* The URL of your app's exit preview endpoint (default: `/api/exit-preview`).
|
|
26
30
|
* This URL will be fetched on preview exit events.
|
|
31
|
+
*
|
|
32
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, it is
|
|
33
|
+
* automatically included.
|
|
27
34
|
*/
|
|
28
35
|
exitPreviewURL?: string;
|
|
29
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Children to render adjacent to the Prismic Toolbar. The Prismic Toolbar
|
|
39
|
+
* will be rendered last.
|
|
40
|
+
*/
|
|
30
41
|
children?: React.ReactNode;
|
|
31
42
|
};
|
|
32
43
|
|
|
33
44
|
/**
|
|
34
|
-
*
|
|
45
|
+
* Updates (or starts) Next.js Preview Mode using a given API endpoint and
|
|
46
|
+
* reloads the page.
|
|
35
47
|
*
|
|
36
|
-
* @param
|
|
48
|
+
* @param updatePreviewURL - The API endpoint that sets Preview Mode data.
|
|
49
|
+
*/
|
|
50
|
+
const updatePreviewMode = async (updatePreviewURL: string): Promise<void> => {
|
|
51
|
+
// Start Next.js Preview Mode via the given preview API endpoint.
|
|
52
|
+
const res = await globalThis.fetch(updatePreviewURL);
|
|
53
|
+
|
|
54
|
+
if (res.ok) {
|
|
55
|
+
// Reload the page with an active Preview Mode.
|
|
56
|
+
window.location.reload();
|
|
57
|
+
} else {
|
|
58
|
+
console.error(
|
|
59
|
+
`[<PrismicPreview>] Failed to start or update Preview Mode using the "${updatePreviewURL}" API endpoint. Does it exist?`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Exits Next.js Preview Mode using a given API endpoint and reloads the page.
|
|
37
66
|
*
|
|
38
|
-
* @
|
|
67
|
+
* @param exitPreviewURL - The API endpoint that exits Preview Mode.
|
|
39
68
|
*/
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
69
|
+
const exitPreviewMode = async (exitPreviewURL: string): Promise<void> => {
|
|
70
|
+
// Exit Next.js Preview Mode via the given exit preview API endpoint.
|
|
71
|
+
const res = await globalThis.fetch(exitPreviewURL);
|
|
72
|
+
|
|
73
|
+
if (res.ok) {
|
|
74
|
+
// Reload the page with an inactive Preview Mode.
|
|
75
|
+
window.location.reload();
|
|
76
|
+
} else {
|
|
77
|
+
console.error(
|
|
78
|
+
`[<PrismicPreview>] Failed to exit Preview Mode using the "${exitPreviewURL}" API endpoint. Does it exist?`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
46
81
|
};
|
|
47
82
|
|
|
48
83
|
/**
|
|
@@ -56,78 +91,96 @@ const isPrismicUpdateToolbarEvent = (
|
|
|
56
91
|
*/
|
|
57
92
|
export function PrismicPreview({
|
|
58
93
|
repositoryName,
|
|
59
|
-
children,
|
|
60
94
|
updatePreviewURL = "/api/preview",
|
|
61
95
|
exitPreviewURL = "/api/exit-preview",
|
|
96
|
+
children,
|
|
62
97
|
}: PrismicPreviewProps): JSX.Element {
|
|
63
98
|
const router = useRouter();
|
|
64
99
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
100
|
+
const resolvedUpdatePreviewURL = router.basePath + updatePreviewURL;
|
|
101
|
+
const resolvedExitPreviewURL = router.basePath + exitPreviewURL;
|
|
102
|
+
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
/**
|
|
105
|
+
* The Prismic preview cookie.
|
|
106
|
+
*/
|
|
107
|
+
const previewCookie = getCookie(prismic.cookie.preview);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Determines if the current Prismic preview session is for the repository
|
|
111
|
+
* configured for this instance of `<PrismicPreview>`.
|
|
112
|
+
*/
|
|
113
|
+
const prismicPreviewSessionIsForThisRepo = Boolean(
|
|
114
|
+
previewCookie &&
|
|
115
|
+
extractPreviewRefRepositoryName(previewCookie) === repositoryName,
|
|
68
116
|
);
|
|
69
117
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Determines if the current location is a descendant of the app's base path.
|
|
120
|
+
*
|
|
121
|
+
* This is used to prevent infinite refrehes; when `isDescendantOfBasePath`
|
|
122
|
+
* is `false`, `router.isPreview` is also `false`.
|
|
123
|
+
*
|
|
124
|
+
* If the app does not have a base path, this should always be `true`.
|
|
125
|
+
*/
|
|
126
|
+
const locationIsDescendantOfBasePath = window.location.href.startsWith(
|
|
127
|
+
window.location.origin + router.basePath,
|
|
128
|
+
);
|
|
76
129
|
|
|
77
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Determines if the current user loaded the page from a share link.
|
|
132
|
+
*
|
|
133
|
+
* Currently, we can only deduce this by checking if router.isPreview is
|
|
134
|
+
* false (i.e. Preview Mode is inactive) and a Prismic preview cookie is present.
|
|
135
|
+
*/
|
|
136
|
+
const loadedFromShareLink = !router.isPreview && previewCookie;
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
prismicPreviewSessionIsForThisRepo &&
|
|
140
|
+
locationIsDescendantOfBasePath &&
|
|
141
|
+
loadedFromShareLink
|
|
142
|
+
) {
|
|
143
|
+
updatePreviewMode(resolvedUpdatePreviewURL);
|
|
144
|
+
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
78
147
|
|
|
79
148
|
const handlePrismicPreviewUpdate = async (event: Event) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// Start Next.js Preview Mode via the given preview API endpoint.
|
|
85
|
-
await fetch(updatePreviewURL);
|
|
86
|
-
|
|
87
|
-
// Reload the page with an active Preview Mode.
|
|
88
|
-
window.location.reload();
|
|
89
|
-
}
|
|
149
|
+
// Prevent the toolbar from reloading the page.
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
await updatePreviewMode(resolvedUpdatePreviewURL);
|
|
90
152
|
};
|
|
91
153
|
|
|
92
154
|
const handlePrismicPreviewEnd = async (event: Event) => {
|
|
93
155
|
// Prevent the toolbar from reloading the page.
|
|
94
156
|
event.preventDefault();
|
|
95
|
-
|
|
96
|
-
// Exit Next.js Preview Mode via the given preview API endpoint.
|
|
97
|
-
await fetch(exitPreviewURL);
|
|
98
|
-
|
|
99
|
-
// Reload the page with an active Preview Mode.
|
|
100
|
-
window.location.reload();
|
|
157
|
+
await exitPreviewMode(resolvedExitPreviewURL);
|
|
101
158
|
};
|
|
102
159
|
|
|
103
160
|
// Register Prismic Toolbar event handlers.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"prismicPreviewUpdate",
|
|
107
|
-
handlePrismicPreviewUpdate,
|
|
108
|
-
);
|
|
109
|
-
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
110
|
-
}
|
|
161
|
+
window.addEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
|
|
162
|
+
window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
111
163
|
|
|
112
164
|
// On cleanup, unregister Prismic Toolbar event handlers.
|
|
113
165
|
return () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
window.removeEventListener(
|
|
120
|
-
"prismicPreviewEnd",
|
|
121
|
-
handlePrismicPreviewEnd,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
166
|
+
window.removeEventListener(
|
|
167
|
+
"prismicPreviewUpdate",
|
|
168
|
+
handlePrismicPreviewUpdate,
|
|
169
|
+
);
|
|
170
|
+
window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
|
|
124
171
|
};
|
|
125
|
-
}, [
|
|
172
|
+
}, [
|
|
173
|
+
repositoryName,
|
|
174
|
+
resolvedUpdatePreviewURL,
|
|
175
|
+
resolvedExitPreviewURL,
|
|
176
|
+
router.isPreview,
|
|
177
|
+
router.basePath,
|
|
178
|
+
]);
|
|
126
179
|
|
|
127
180
|
return (
|
|
128
181
|
<>
|
|
129
|
-
<PrismicToolbar repositoryName={repositoryName} />
|
|
130
182
|
{children}
|
|
183
|
+
<PrismicToolbar repositoryName={repositoryName} />
|
|
131
184
|
</>
|
|
132
185
|
);
|
|
133
186
|
}
|
|
@@ -60,19 +60,17 @@ export type EnableAutoPreviewsConfig<
|
|
|
60
60
|
export const enableAutoPreviews = <TPreviewData extends PreviewData>(
|
|
61
61
|
config: EnableAutoPreviewsConfig<TPreviewData>,
|
|
62
62
|
): void => {
|
|
63
|
-
/**
|
|
64
|
-
* If preview data is being passed from Next Context then use queryContentFromRef
|
|
65
|
-
*/
|
|
66
63
|
if ("previewData" in config && config.previewData) {
|
|
64
|
+
// If preview data is being passed from Next Context then use queryContentFromRef
|
|
65
|
+
|
|
67
66
|
const { previewData } = config;
|
|
68
67
|
|
|
69
68
|
if (isPrismicNextPreviewData(previewData) && previewData.ref) {
|
|
70
69
|
config.client.queryContentFromRef(previewData.ref);
|
|
71
70
|
}
|
|
72
|
-
/**
|
|
73
|
-
* If the req object is passed then use enableAutoPreviewsFromReq
|
|
74
|
-
*/
|
|
75
71
|
} else if ("req" in config && config.req) {
|
|
72
|
+
// If the req object is passed then use enableAutoPreviewsFromReq
|
|
73
|
+
|
|
76
74
|
config.client.enableAutoPreviewsFromReq(config.req);
|
|
77
75
|
}
|
|
78
76
|
};
|
package/src/exitPreview.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { NextApiRequest, NextApiResponse } from "next";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Configuration for `exitPreview`.
|
|
@@ -10,11 +10,17 @@ export type ExitPreviewConfig = {
|
|
|
10
10
|
*
|
|
11
11
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
12
12
|
*/
|
|
13
|
-
req
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
18
|
+
// exit preview API route easier (this eliminates the awkward need to
|
|
19
|
+
// handle an 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: Pick<NextApiRequest, "headers">;
|
|
18
24
|
|
|
19
25
|
/**
|
|
20
26
|
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
@@ -22,33 +28,15 @@ export type ExitPreviewConfig = {
|
|
|
22
28
|
*
|
|
23
29
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
24
30
|
*/
|
|
25
|
-
res:
|
|
26
|
-
clearPreviewData: NextApiResponse["clearPreviewData"];
|
|
27
|
-
redirect: NextApiResponse["redirect"];
|
|
28
|
-
};
|
|
31
|
+
res: Pick<NextApiResponse, "clearPreviewData" | "json">;
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
35
|
* 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
36
|
*/
|
|
37
37
|
export function exitPreview(config: ExitPreviewConfig): void {
|
|
38
|
-
|
|
39
|
-
// Exit the current user from "Preview Mode". This function accepts no args.
|
|
38
|
+
// Exit the current user from Preview Mode.
|
|
40
39
|
config.res.clearPreviewData();
|
|
41
40
|
|
|
42
|
-
|
|
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("/");
|
|
41
|
+
config.res.json({ success: true });
|
|
54
42
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
export type { SetPreviewDataConfig } from "./setPreviewData";
|
|
2
|
-
export type { EnableAutoPreviewsConfig } from "./enableAutoPreviews";
|
|
3
|
-
export type { ExitPreviewConfig as ExitPreviewParams } from "./exitPreview";
|
|
4
|
-
export type { PrismicPreviewProps } from "./PrismicPreview";
|
|
5
1
|
export { setPreviewData } from "./setPreviewData";
|
|
2
|
+
export type { SetPreviewDataConfig } from "./setPreviewData";
|
|
3
|
+
|
|
6
4
|
export { exitPreview } from "./exitPreview";
|
|
5
|
+
export type { ExitPreviewConfig } from "./exitPreview";
|
|
6
|
+
|
|
7
7
|
export { PrismicPreview } from "./PrismicPreview";
|
|
8
|
+
export type { PrismicPreviewProps } from "./PrismicPreview";
|
|
9
|
+
|
|
8
10
|
export { enableAutoPreviews } from "./enableAutoPreviews";
|
|
11
|
+
export type { EnableAutoPreviewsConfig } from "./enableAutoPreviews";
|
|
12
|
+
|
|
9
13
|
export { redirectToPreviewURL } from "./redirectToPreviewURL";
|
|
10
|
-
export type {
|
|
14
|
+
export type { RedirectToPreviewURLConfig } from "./redirectToPreviewURL";
|
|
15
|
+
|
|
16
|
+
export type { CreateClientConfig } from "./types";
|
package/src/lib/getCookie.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* The following code is a modifed version of `es-cookie` taken from
|
|
3
3
|
* https://github.com/theodorejb/es-cookie
|
|
4
4
|
*
|
|
5
|
+
* It only contains a simplified version of `get()`.
|
|
6
|
+
*
|
|
5
7
|
* Copyright 2017 Theodore Brown
|
|
6
8
|
*
|
|
7
9
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -27,32 +29,23 @@ const readValue = (value: string): string => {
|
|
|
27
29
|
return value.replace(/%3B/g, ";");
|
|
28
30
|
};
|
|
29
31
|
|
|
30
|
-
export const parse = (cookieString: string): { [name: string]: string } => {
|
|
31
|
-
const result: { [name: string]: string } = {};
|
|
32
|
-
const cookies = cookieString.split("; ");
|
|
33
|
-
|
|
34
|
-
for (const cookie of cookies) {
|
|
35
|
-
const parts = cookie.split("=");
|
|
36
|
-
const value = parts.slice(1).join("=");
|
|
37
|
-
const name = readValue(parts[0]).replace(/%3D/g, "=");
|
|
38
|
-
result[name] = readValue(value);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return result;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const getAll = (cookieStore: string): { [name: string]: string } =>
|
|
45
|
-
parse(cookieStore);
|
|
46
|
-
|
|
47
32
|
/**
|
|
48
33
|
* Returns the value of a cookie from a given cookie store.
|
|
49
34
|
*
|
|
50
35
|
* @param name - Of the cookie.
|
|
51
|
-
* @param cookieStore - The stringified cookie store from which to read the cookie.
|
|
52
36
|
*
|
|
53
37
|
* @returns The value of the cookie, if it exists.
|
|
54
38
|
*/
|
|
55
|
-
export const getCookie = (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
39
|
+
export const getCookie = (name: string): string | undefined => {
|
|
40
|
+
const cookies = document.cookie.split("; ");
|
|
41
|
+
|
|
42
|
+
for (const cookie of cookies) {
|
|
43
|
+
const parts = cookie.split("=");
|
|
44
|
+
const value = parts.slice(1).join("=");
|
|
45
|
+
const thisName = readValue(parts[0]).replace(/%3D/g, "=");
|
|
46
|
+
|
|
47
|
+
if (thisName === name) {
|
|
48
|
+
return readValue(value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { PreviewConfig } from "./";
|
|
1
|
+
import type { Client } from "@prismicio/client";
|
|
2
|
+
import type { NextApiRequest, NextApiResponse } from "next";
|
|
3
|
+
import type { LinkResolverFunction } from "@prismicio/helpers";
|
|
5
4
|
|
|
6
5
|
type PrismicNextQuery = {
|
|
7
6
|
documentId: string;
|
|
@@ -18,8 +17,66 @@ type PrismicNextQuery = {
|
|
|
18
17
|
*/
|
|
19
18
|
const isPrismicNextQuery = (
|
|
20
19
|
query: NextApiRequest["query"],
|
|
21
|
-
): query is PrismicNextQuery =>
|
|
22
|
-
|
|
20
|
+
): query is PrismicNextQuery => {
|
|
21
|
+
return (
|
|
22
|
+
typeof query.documentId === "string" && typeof query.token === "string"
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Preview config for enabling previews with redirectToPreviewURL
|
|
28
|
+
*/
|
|
29
|
+
export type RedirectToPreviewURLConfig<
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
TLinkResolverFunction extends LinkResolverFunction<any> = LinkResolverFunction,
|
|
32
|
+
> = {
|
|
33
|
+
/**
|
|
34
|
+
* The `req` object from a Next.js API route. This is given as a parameter to
|
|
35
|
+
* the API route.
|
|
36
|
+
*
|
|
37
|
+
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
38
|
+
*/
|
|
39
|
+
req: Pick<NextApiRequest, "query">;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
43
|
+
* the API route.
|
|
44
|
+
*
|
|
45
|
+
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
46
|
+
*/
|
|
47
|
+
res: Pick<NextApiResponse, "redirect">;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The Prismic client configured for the preview session's repository.
|
|
51
|
+
*/
|
|
52
|
+
client: Client;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A Link Resolver used to resolve the previewed document's URL.
|
|
56
|
+
*
|
|
57
|
+
* @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
|
|
58
|
+
*/
|
|
59
|
+
linkResolver?: TLinkResolverFunction;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The default redirect URL if a URL cannot be determined for the previewed document.
|
|
63
|
+
*
|
|
64
|
+
* **Note**: If your `next.config.js` file contains a `basePath`, you must
|
|
65
|
+
* include the `basePath` as part of this option. `redirectToPreviewURL()`
|
|
66
|
+
* cannot read your global `basePath`.
|
|
67
|
+
*/
|
|
68
|
+
defaultURL?: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The `basePath` for the Next.js app as it is defined in `next.config.js`.
|
|
72
|
+
* This option can be omitted if the app does not have a `basePath`.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* The API route is unable to detect the app's `basePath` automatically. It
|
|
76
|
+
* must be provided to `redirectToPreviewURL()` manually.
|
|
77
|
+
*/
|
|
78
|
+
basePath?: string;
|
|
79
|
+
};
|
|
23
80
|
|
|
24
81
|
/**
|
|
25
82
|
* Redirects a user to the URL of a previewed Prismic document from within a
|
|
@@ -28,26 +85,22 @@ const isPrismicNextQuery = (
|
|
|
28
85
|
export async function redirectToPreviewURL<
|
|
29
86
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
87
|
TLinkResolverFunction extends LinkResolverFunction<any>,
|
|
31
|
-
>({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (isPrismicNextQuery(req.query)) {
|
|
39
|
-
const { documentId, token } = req.query;
|
|
40
|
-
const previewUrl = await client.resolvePreviewURL({
|
|
41
|
-
linkResolver,
|
|
88
|
+
>(config: RedirectToPreviewURLConfig<TLinkResolverFunction>): Promise<void> {
|
|
89
|
+
const defaultURL = config.defaultURL || "/";
|
|
90
|
+
const basePath = config.basePath || "";
|
|
91
|
+
|
|
92
|
+
if (isPrismicNextQuery(config.req.query)) {
|
|
93
|
+
const previewUrl = await config.client.resolvePreviewURL({
|
|
94
|
+
linkResolver: config.linkResolver,
|
|
42
95
|
defaultURL,
|
|
43
|
-
documentID: documentId,
|
|
44
|
-
previewToken: token,
|
|
96
|
+
documentID: config.req.query.documentId,
|
|
97
|
+
previewToken: config.req.query.token,
|
|
45
98
|
});
|
|
46
99
|
|
|
47
|
-
res.redirect(previewUrl);
|
|
100
|
+
config.res.redirect(basePath + previewUrl);
|
|
48
101
|
|
|
49
102
|
return;
|
|
50
103
|
}
|
|
51
104
|
|
|
52
|
-
res.redirect(defaultURL);
|
|
105
|
+
config.res.redirect(basePath + defaultURL);
|
|
53
106
|
}
|
package/src/setPreviewData.ts
CHANGED
|
@@ -11,10 +11,7 @@ export type SetPreviewDataConfig = {
|
|
|
11
11
|
*
|
|
12
12
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
13
13
|
*/
|
|
14
|
-
req:
|
|
15
|
-
query: NextApiRequest["query"];
|
|
16
|
-
cookies: NextApiRequest["cookies"];
|
|
17
|
-
};
|
|
14
|
+
req: Pick<NextApiRequest, "query" | "cookies">;
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
17
|
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
@@ -22,9 +19,7 @@ export type SetPreviewDataConfig = {
|
|
|
22
19
|
*
|
|
23
20
|
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
24
21
|
*/
|
|
25
|
-
res:
|
|
26
|
-
setPreviewData: NextApiResponse["setPreviewData"];
|
|
27
|
-
};
|
|
22
|
+
res: Pick<NextApiResponse, "setPreviewData">;
|
|
28
23
|
};
|
|
29
24
|
|
|
30
25
|
/**
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { PreviewData, NextApiRequest
|
|
2
|
-
import { LinkResolverFunction } from "@prismicio/helpers";
|
|
3
|
-
import { Client } from "@prismicio/client";
|
|
1
|
+
import { PreviewData, NextApiRequest } from "next";
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Configuration for creating a Prismic client with automatic preview support in
|
|
@@ -22,48 +20,3 @@ export type CreateClientConfig = {
|
|
|
22
20
|
*/
|
|
23
21
|
req?: NextApiRequest;
|
|
24
22
|
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Preview config for enabling previews with redirectToPreviewURL
|
|
28
|
-
*/
|
|
29
|
-
export type PreviewConfig<
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
-
TLinkResolverFunction extends LinkResolverFunction<any> = LinkResolverFunction,
|
|
32
|
-
> = {
|
|
33
|
-
/**
|
|
34
|
-
* The `req` object from a Next.js API route. This is given as a parameter to
|
|
35
|
-
* the API route.
|
|
36
|
-
*
|
|
37
|
-
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
38
|
-
*/
|
|
39
|
-
req: {
|
|
40
|
-
query: NextApiRequest["query"];
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The `res` object from a Next.js API route. This is given as a parameter to
|
|
45
|
-
* the API route.
|
|
46
|
-
*
|
|
47
|
-
* @see Next.js API route docs: {@link https://nextjs.org/docs/api-routes/introduction}
|
|
48
|
-
*/
|
|
49
|
-
res: {
|
|
50
|
-
redirect: NextApiResponse["redirect"];
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The Prismic client configured for the preview session's repository.
|
|
55
|
-
*/
|
|
56
|
-
client: Client;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* A Link Resolver used to resolve the previewed document's URL.
|
|
60
|
-
*
|
|
61
|
-
* @see To learn more about Link Resolver: {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
|
|
62
|
-
*/
|
|
63
|
-
linkResolver?: TLinkResolverFunction;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* The default redirect URL if a URL cannot be determined for the previewed document.
|
|
67
|
-
*/
|
|
68
|
-
defaultURL?: string;
|
|
69
|
-
};
|