@prismicio/svelte 3.0.0-pr.70.0fcf71f → 3.0.0-pr.71.9e4af9f
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.
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
|
|
24
24
|
const { repositoryName, routePrefix = "preview", routePrefixName = routePrefix }: Props = $props()
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// `v=5` opts into the toolbar's modern flow, which follows the session set by
|
|
27
|
+
// `redirectToPreviewURL()`.
|
|
28
|
+
const toolbarSrc = $derived(`${getToolbarSrc(repositoryName)}&v=5`)
|
|
27
29
|
|
|
28
30
|
/** Set to `true` when the next `beforeNavigate()` call should not prefix the route. */
|
|
29
31
|
let endingPreview = $state(false)
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
(event) => {
|
|
46
48
|
event.preventDefault()
|
|
47
49
|
|
|
50
|
+
document.cookie = "io.prismic.previewSession=; Path=/; Max-Age=0"
|
|
48
51
|
endingPreview = true
|
|
49
52
|
|
|
50
53
|
goto(
|
|
@@ -2,7 +2,7 @@ import * as prismic from "@prismicio/client";
|
|
|
2
2
|
import type { Cookies } from "@sveltejs/kit";
|
|
3
3
|
export type RedirectToPreviewURLConfig = {
|
|
4
4
|
/** The Prismic client configured for the preview session's repository. */
|
|
5
|
-
client: Pick<prismic.Client, "resolvePreviewURL">;
|
|
5
|
+
client: Pick<prismic.Client, "resolvePreviewURL" | "documentAPIEndpoint">;
|
|
6
6
|
/**
|
|
7
7
|
* The `request` object from a `+server` file.
|
|
8
8
|
*
|
|
@@ -18,26 +18,59 @@ import * as prismic from "@prismicio/client";
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export const redirectToPreviewURL = async (config) => {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
21
|
+
const { searchParams } = new URL(config.request.url);
|
|
22
|
+
const session = searchParams.get("session");
|
|
23
|
+
const documentID = searchParams.get("documentId") ?? undefined;
|
|
23
24
|
const routePrefix = config.routePrefix ?? "preview";
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
// Share links from the toolbar's modern flow only carry the session.
|
|
26
|
+
const previewToken = searchParams.get("token") ??
|
|
27
|
+
(session ? await getSessionRef(config.client.documentAPIEndpoint, session) : undefined);
|
|
28
|
+
const path = session ? getSafePath(searchParams.get("path")) : undefined;
|
|
29
|
+
const location = path ??
|
|
30
|
+
"/" +
|
|
31
|
+
routePrefix +
|
|
32
|
+
(await config.client.resolvePreviewURL({
|
|
33
|
+
previewToken,
|
|
34
|
+
documentID,
|
|
35
|
+
defaultURL: config.defaultURL || "/",
|
|
36
|
+
}));
|
|
29
37
|
// Prevent a flash of non-preview content by setting the preview token
|
|
30
38
|
// on the initial page load.
|
|
31
39
|
if (previewToken) {
|
|
32
|
-
config.cookies.set(prismic.cookie.preview, previewToken,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
config.cookies.set(prismic.cookie.preview, previewToken, cookieOptions);
|
|
41
|
+
}
|
|
42
|
+
// The toolbar follows the preview session with this cookie.
|
|
43
|
+
if (session) {
|
|
44
|
+
config.cookies.set("io.prismic.previewSession", session, cookieOptions);
|
|
36
45
|
}
|
|
37
46
|
return new Response(undefined, {
|
|
38
47
|
status: 307,
|
|
39
48
|
headers: {
|
|
40
|
-
Location:
|
|
49
|
+
Location: location,
|
|
41
50
|
},
|
|
42
51
|
});
|
|
43
52
|
};
|
|
53
|
+
const cookieOptions = { path: "/", httpOnly: false };
|
|
54
|
+
/** Returns the session's current ref from the repository's public endpoint. */
|
|
55
|
+
const getSessionRef = async (documentAPIEndpoint, session) => {
|
|
56
|
+
const url = new URL(`/previews/token/${encodeURIComponent(session)}`, documentAPIEndpoint);
|
|
57
|
+
url.hostname = url.hostname.replace(".cdn.", ".");
|
|
58
|
+
const { ref } = await (await fetch(url)).json();
|
|
59
|
+
if (!ref) {
|
|
60
|
+
throw new prismic.PreviewTokenExpiredError("The preview session has ended.", url.href, undefined);
|
|
61
|
+
}
|
|
62
|
+
return ref;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Returns `path` if it is a path on this website. The path already includes SvelteKit's
|
|
66
|
+
* `paths.base`.
|
|
67
|
+
*/
|
|
68
|
+
const getSafePath = (path) => {
|
|
69
|
+
if (!path?.startsWith("/")) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Paths like `//evil.com` and `/\evil.com` resolve to another origin.
|
|
73
|
+
const origin = "https://placeholder.invalid";
|
|
74
|
+
const url = new URL(path, origin);
|
|
75
|
+
return url.origin === origin ? url.pathname + url.search + url.hash : undefined;
|
|
76
|
+
};
|
package/package.json
CHANGED
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
|
|
24
24
|
const { repositoryName, routePrefix = "preview", routePrefixName = routePrefix }: Props = $props()
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// `v=5` opts into the toolbar's modern flow, which follows the session set by
|
|
27
|
+
// `redirectToPreviewURL()`.
|
|
28
|
+
const toolbarSrc = $derived(`${getToolbarSrc(repositoryName)}&v=5`)
|
|
27
29
|
|
|
28
30
|
/** Set to `true` when the next `beforeNavigate()` call should not prefix the route. */
|
|
29
31
|
let endingPreview = $state(false)
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
(event) => {
|
|
46
48
|
event.preventDefault()
|
|
47
49
|
|
|
50
|
+
document.cookie = "io.prismic.previewSession=; Path=/; Max-Age=0"
|
|
48
51
|
endingPreview = true
|
|
49
52
|
|
|
50
53
|
goto(
|
|
@@ -6,7 +6,7 @@ export type RedirectToPreviewURLConfig = {
|
|
|
6
6
|
// `Pick` is used to use the smallest possible subset of
|
|
7
7
|
// `prismic.Client`. Doing this reduces the surface area for breaking
|
|
8
8
|
// type changes.
|
|
9
|
-
client: Pick<prismic.Client, "resolvePreviewURL">
|
|
9
|
+
client: Pick<prismic.Client, "resolvePreviewURL" | "documentAPIEndpoint">
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* The `request` object from a `+server` file.
|
|
@@ -50,29 +50,77 @@ export type RedirectToPreviewURLConfig = {
|
|
|
50
50
|
export const redirectToPreviewURL = async (
|
|
51
51
|
config: RedirectToPreviewURLConfig,
|
|
52
52
|
): Promise<Response> => {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
53
|
+
const { searchParams } = new URL(config.request.url)
|
|
54
|
+
const session = searchParams.get("session")
|
|
55
|
+
const documentID = searchParams.get("documentId") ?? undefined
|
|
55
56
|
const routePrefix = config.routePrefix ?? "preview"
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
// Share links from the toolbar's modern flow only carry the session.
|
|
59
|
+
const previewToken =
|
|
60
|
+
searchParams.get("token") ??
|
|
61
|
+
(session ? await getSessionRef(config.client.documentAPIEndpoint, session) : undefined)
|
|
62
|
+
|
|
63
|
+
const path = session ? getSafePath(searchParams.get("path")) : undefined
|
|
64
|
+
const location =
|
|
65
|
+
path ??
|
|
66
|
+
"/" +
|
|
67
|
+
routePrefix +
|
|
68
|
+
(await config.client.resolvePreviewURL({
|
|
69
|
+
previewToken,
|
|
70
|
+
documentID,
|
|
71
|
+
defaultURL: config.defaultURL || "/",
|
|
72
|
+
}))
|
|
62
73
|
|
|
63
74
|
// Prevent a flash of non-preview content by setting the preview token
|
|
64
75
|
// on the initial page load.
|
|
65
76
|
if (previewToken) {
|
|
66
|
-
config.cookies.set(prismic.cookie.preview, previewToken,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
config.cookies.set(prismic.cookie.preview, previewToken, cookieOptions)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The toolbar follows the preview session with this cookie.
|
|
81
|
+
if (session) {
|
|
82
|
+
config.cookies.set("io.prismic.previewSession", session, cookieOptions)
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
return new Response(undefined, {
|
|
73
86
|
status: 307,
|
|
74
87
|
headers: {
|
|
75
|
-
Location:
|
|
88
|
+
Location: location,
|
|
76
89
|
},
|
|
77
90
|
})
|
|
78
91
|
}
|
|
92
|
+
|
|
93
|
+
const cookieOptions = { path: "/", httpOnly: false }
|
|
94
|
+
|
|
95
|
+
/** Returns the session's current ref from the repository's public endpoint. */
|
|
96
|
+
const getSessionRef = async (documentAPIEndpoint: string, session: string): Promise<string> => {
|
|
97
|
+
const url = new URL(`/previews/token/${encodeURIComponent(session)}`, documentAPIEndpoint)
|
|
98
|
+
url.hostname = url.hostname.replace(".cdn.", ".")
|
|
99
|
+
|
|
100
|
+
const { ref } = await (await fetch(url)).json()
|
|
101
|
+
if (!ref) {
|
|
102
|
+
throw new prismic.PreviewTokenExpiredError(
|
|
103
|
+
"The preview session has ended.",
|
|
104
|
+
url.href,
|
|
105
|
+
undefined,
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return ref
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns `path` if it is a path on this website. The path already includes SvelteKit's
|
|
114
|
+
* `paths.base`.
|
|
115
|
+
*/
|
|
116
|
+
const getSafePath = (path: string | null): string | undefined => {
|
|
117
|
+
if (!path?.startsWith("/")) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Paths like `//evil.com` and `/\evil.com` resolve to another origin.
|
|
122
|
+
const origin = "https://placeholder.invalid"
|
|
123
|
+
const url = new URL(path, origin)
|
|
124
|
+
|
|
125
|
+
return url.origin === origin ? url.pathname + url.search + url.hash : undefined
|
|
126
|
+
}
|