sanity-plugin-iframe-pane 2.3.2-canary.2 → 2.4.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/README.md +2 -12
- package/lib/index.cjs +43 -9
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +36 -2
- package/lib/index.js.map +1 -1
- package/package.json +1 -21
- package/src/Iframe.tsx +3 -3
- package/src/defineUrlResolver.tsx +2 -2
- package/src/previewUrl.ts +2 -2
- package/lib/_chunks/is-valid-secret-57fea7e5.js +0 -35
- package/lib/_chunks/is-valid-secret-57fea7e5.js.map +0 -1
- package/lib/_chunks/is-valid-secret-7b704c76.cjs +0 -41
- package/lib/_chunks/is-valid-secret-7b704c76.cjs.map +0 -1
- package/lib/_chunks/types-107599a1.js +0 -34
- package/lib/_chunks/types-107599a1.js.map +0 -1
- package/lib/_chunks/types-4a29b6ac.cjs +0 -38
- package/lib/_chunks/types-4a29b6ac.cjs.map +0 -1
- package/lib/is-valid-secret.cjs +0 -8
- package/lib/is-valid-secret.cjs.js +0 -4
- package/lib/is-valid-secret.cjs.map +0 -1
- package/lib/is-valid-secret.d.ts +0 -41
- package/lib/is-valid-secret.js +0 -2
- package/lib/is-valid-secret.js.map +0 -1
- package/lib/preview-url.cjs +0 -77
- package/lib/preview-url.cjs.js +0 -4
- package/lib/preview-url.cjs.map +0 -1
- package/lib/preview-url.d.ts +0 -17
- package/lib/preview-url.js +0 -72
- package/lib/preview-url.js.map +0 -1
- package/src/is-valid-secret.ts +0 -2
- package/src/preview-url.ts +0 -2
package/README.md
CHANGED
|
@@ -49,10 +49,10 @@ A basic example of a custom `defaultDocumentNode` function, to only show the Ifr
|
|
|
49
49
|
|
|
50
50
|
import {DefaultDocumentNodeResolver} from 'sanity/desk'
|
|
51
51
|
import {Iframe} from 'sanity-plugin-iframe-pane'
|
|
52
|
-
import {
|
|
52
|
+
import {SanityDocument} from 'sanity'
|
|
53
53
|
|
|
54
54
|
// Customise this function to show the correct URL based on the current document
|
|
55
|
-
function getPreviewUrl(doc:
|
|
55
|
+
function getPreviewUrl(doc: SanityDocument) {
|
|
56
56
|
return doc?.slug?.current
|
|
57
57
|
? `${window.location.host}/${doc.slug.current}`
|
|
58
58
|
: `${window.location.host}`
|
|
@@ -111,16 +111,6 @@ attributes: {
|
|
|
111
111
|
}
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
## `sanity-plugin-iframe-pane/preview-url`
|
|
115
|
-
|
|
116
|
-
This plugin also exports a `preview-url` tool, which can be used to generate a URL for the current document.
|
|
117
|
-
|
|
118
|
-
SCREENSHOT OF OPEN PREVIEW BUTTON
|
|
119
|
-
|
|
120
|
-
## `sanity-plugin-iframe-pane/is-valid-secret`
|
|
121
|
-
|
|
122
|
-
If the `urlSecretId` feature is used, to secure preview URLs, this plugin also exports a `is-valid-secret` tool, which can be used to validate a secret inside an API handler. In Next.js you would typically do this before calling `draftMode().enable()` or `res.setPreviewData()`.
|
|
123
|
-
|
|
124
114
|
## License
|
|
125
115
|
|
|
126
116
|
MIT-licensed. See LICENSE.
|
package/lib/index.cjs
CHANGED
|
@@ -9,9 +9,42 @@ var ui = require('@sanity/ui');
|
|
|
9
9
|
var framerMotion = require('framer-motion');
|
|
10
10
|
var react = require('react');
|
|
11
11
|
var sanity = require('sanity');
|
|
12
|
-
var isValidSecret = require('./_chunks/is-valid-secret-7b704c76.cjs');
|
|
13
|
-
var types = require('./_chunks/types-4a29b6ac.cjs');
|
|
14
12
|
var usehooksTs = require('usehooks-ts');
|
|
13
|
+
var name = "sanity-plugin-iframe-pane";
|
|
14
|
+
const SECRET_TTL = 60 * 60;
|
|
15
|
+
const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
|
|
16
|
+
const tag = name;
|
|
17
|
+
const apiVersion = "2023-08-08";
|
|
18
|
+
function getExpiresAt(_updatedAt) {
|
|
19
|
+
return new Date(_updatedAt.getTime() + 1e3 * SECRET_TTL);
|
|
20
|
+
}
|
|
21
|
+
function generateUrlSecret() {
|
|
22
|
+
if (typeof crypto !== "undefined") {
|
|
23
|
+
const array = new Uint8Array(16);
|
|
24
|
+
crypto.getRandomValues(array);
|
|
25
|
+
let key = "";
|
|
26
|
+
for (let i = 0; i < array.length; i++) {
|
|
27
|
+
key += array[i].toString(16).padStart(2, "0");
|
|
28
|
+
}
|
|
29
|
+
key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
|
|
30
|
+
return key;
|
|
31
|
+
}
|
|
32
|
+
return Math.random().toString(36).slice(2);
|
|
33
|
+
}
|
|
34
|
+
async function patchUrlSecret(client, urlSecretId, signal) {
|
|
35
|
+
const newSecret = generateUrlSecret();
|
|
36
|
+
const patch = client.patch(urlSecretId).set({
|
|
37
|
+
secret: newSecret
|
|
38
|
+
});
|
|
39
|
+
await client.transaction().createIfNotExists({
|
|
40
|
+
_id: urlSecretId,
|
|
41
|
+
_type: urlSecretId
|
|
42
|
+
}).patch(patch).commit({
|
|
43
|
+
tag,
|
|
44
|
+
signal
|
|
45
|
+
});
|
|
46
|
+
return newSecret;
|
|
47
|
+
}
|
|
15
48
|
function GetUrlSecret(props) {
|
|
16
49
|
const {
|
|
17
50
|
urlSecretId,
|
|
@@ -20,7 +53,7 @@ function GetUrlSecret(props) {
|
|
|
20
53
|
setError
|
|
21
54
|
} = props;
|
|
22
55
|
const client = sanity.useClient({
|
|
23
|
-
apiVersion
|
|
56
|
+
apiVersion
|
|
24
57
|
});
|
|
25
58
|
const [secretExpiresAt, setSecretExpiresAt] = react.useState(null);
|
|
26
59
|
if (!urlSecretId.includes(".")) {
|
|
@@ -29,20 +62,20 @@ function GetUrlSecret(props) {
|
|
|
29
62
|
react.useEffect(() => {
|
|
30
63
|
if (urlSecret) return;
|
|
31
64
|
async function getSecret(signal) {
|
|
32
|
-
const data = await client.fetch(
|
|
65
|
+
const data = await client.fetch(fetchSecretQuery, {
|
|
33
66
|
id: urlSecretId
|
|
34
67
|
}, {
|
|
35
68
|
signal,
|
|
36
|
-
tag
|
|
69
|
+
tag
|
|
37
70
|
});
|
|
38
71
|
if (signal.aborted) return;
|
|
39
72
|
if (!(data == null ? void 0 : data.secret) || !(data == null ? void 0 : data._updatedAt)) {
|
|
40
73
|
try {
|
|
41
74
|
const newUpdatedAt = /* @__PURE__ */new Date();
|
|
42
|
-
const newSecret = await
|
|
75
|
+
const newSecret = await patchUrlSecret(client, urlSecretId, signal);
|
|
43
76
|
if (signal.aborted) return;
|
|
44
77
|
setUrlSecret(newSecret);
|
|
45
|
-
setSecretExpiresAt(
|
|
78
|
+
setSecretExpiresAt(getExpiresAt(newUpdatedAt));
|
|
46
79
|
} catch (err) {
|
|
47
80
|
console.error("Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.", err);
|
|
48
81
|
}
|
|
@@ -50,7 +83,7 @@ function GetUrlSecret(props) {
|
|
|
50
83
|
}
|
|
51
84
|
if ((data == null ? void 0 : data.secret) !== urlSecret) {
|
|
52
85
|
setUrlSecret(data == null ? void 0 : data.secret);
|
|
53
|
-
setSecretExpiresAt(
|
|
86
|
+
setSecretExpiresAt(getExpiresAt(new Date(data == null ? void 0 : data._updatedAt)));
|
|
54
87
|
}
|
|
55
88
|
}
|
|
56
89
|
const abort = new AbortController();
|
|
@@ -233,6 +266,7 @@ function Toolbar(props) {
|
|
|
233
266
|
})]
|
|
234
267
|
});
|
|
235
268
|
}
|
|
269
|
+
const MissingSlug = Symbol("MissingSlug");
|
|
236
270
|
const MotionFlex = framerMotion.motion(ui.Flex);
|
|
237
271
|
function Iframe(props) {
|
|
238
272
|
var _a;
|
|
@@ -293,7 +327,7 @@ function Iframe(props) {
|
|
|
293
327
|
showDisplayUrl,
|
|
294
328
|
reloadButton: !!(reload == null ? void 0 : reload.button),
|
|
295
329
|
handleReload
|
|
296
|
-
}), urlState ===
|
|
330
|
+
}), urlState === MissingSlug && !workaroundEmptyDocument ? /* @__PURE__ */jsxRuntime.jsx(MissingSlugScreen, {}) : /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
|
|
297
331
|
tone: "transparent",
|
|
298
332
|
style: {
|
|
299
333
|
height: "100%"
|
package/lib/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/GetUrlSecret.tsx","../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {useEffect, useState} from 'react'\nimport {useClient} from 'sanity'\n\nimport {apiVersion, fetchSecretQuery, FetchSecretResponse, tag, UrlSecretId} from './isValidSecret'\nimport {SetError} from './types'\nimport {getExpiresAt, patchUrlSecret} from './utils'\n\nexport interface GetUrlSecretProps {\n urlSecretId: UrlSecretId\n urlSecret: string | null\n setUrlSecret: (secret: string | null) => void\n setError: SetError\n}\nexport function GetUrlSecret(props: GetUrlSecretProps) {\n const {urlSecretId, setUrlSecret, urlSecret, setError} = props\n const client = useClient({apiVersion})\n const [secretExpiresAt, setSecretExpiresAt] = useState<null | Date>(null)\n\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n\n useEffect(() => {\n if (urlSecret) return\n\n async function getSecret(signal: AbortSignal): Promise<void> {\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {signal, tag},\n )\n\n if (signal.aborted) return\n\n if (!data?.secret || !data?._updatedAt) {\n try {\n const newUpdatedAt = new Date()\n const newSecret = await patchUrlSecret(client, urlSecretId, signal)\n if (signal.aborted) return\n setUrlSecret(newSecret)\n setSecretExpiresAt(getExpiresAt(newUpdatedAt))\n } catch (err) {\n console.error(\n 'Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.',\n err,\n )\n }\n return\n }\n\n if (data?.secret !== urlSecret) {\n setUrlSecret(data?.secret)\n setSecretExpiresAt(getExpiresAt(new Date(data?._updatedAt)))\n }\n }\n\n const abort = new AbortController()\n getSecret(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [client, setError, setUrlSecret, urlSecret, urlSecretId])\n\n useEffect(() => {\n if (!secretExpiresAt) return\n\n const timeout = setTimeout(\n () => {\n setUrlSecret(null)\n setSecretExpiresAt(null)\n },\n Math.max(0, secretExpiresAt.getTime() - new Date().getTime()),\n )\n // eslint-disable-next-line consistent-return\n return () => clearTimeout(timeout)\n }, [secretExpiresAt, setUrlSecret])\n\n return null\n}\n","import {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl({displayUrl}: {displayUrl: string}) {\n const truncatedUrl = useMemo(() => {\n const url = new URL(displayUrl)\n\n if (url.searchParams.has('secret')) {\n url.searchParams.delete('secret')\n url.searchParams.append('secret', '***')\n }\n\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [displayUrl])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\" title={displayUrl}>\n {truncatedUrl}\n </Text>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {ClipboardIcon, LaunchIcon, MobileDeviceIcon, UndoIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n displayUrl: string\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showDisplayUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {\n displayUrl,\n iframeSize,\n setIframeSize,\n reloading,\n showDisplayUrl,\n reloadButton,\n handleReload,\n } = props\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && displayUrl && <DisplayUrl displayUrl={displayUrl} />}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={<UndoIcon style={{transform: 'rotate(90deg) scaleY(-1)'}} />}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!displayUrl}\n fontSize={[1]}\n icon={ClipboardIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={() => window.open(displayUrl)}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {WarningOutlineIcon} from '@sanity/icons'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {forwardRef, useCallback, useDeferredValue, useEffect, useRef, useState} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocumentLike} from 'sanity'\n\nimport {UrlResolver} from './defineUrlResolver'\nimport {GetUrlSecret} from './GetUrlSecret'\nimport {UrlSecretId} from './isValidSecret'\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey, MissingSlug, SetError, type UrlState} from './types'\n\nexport type {UrlResolver, UrlSecretId}\n\nexport type IframeOptions = {\n urlSecretId?: UrlSecretId\n url: UrlState | UrlResolver\n defaultSize?: IframeSizeKey\n loader?: string | boolean\n showDisplayUrl?: boolean\n reload?: {\n revision?: boolean | number\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const [error, setError] = useState<unknown>(null)\n if (error) {\n throw error\n }\n\n const {document: sanityDocument, options} = props\n const {\n url,\n urlSecretId,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader = 'Loading…',\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n // Workaround documents that initially appears to be an empty new document but just hasen't loaded yet\n const [workaroundEmptyDocument, setWorkaroundEmptyDocument] = useState(true)\n useEffect(() => {\n const timeout = setTimeout(() => setWorkaroundEmptyDocument(false), 1000)\n return () => clearTimeout(timeout)\n }, [])\n\n const prefersReducedMotion = usePrefersReducedMotion()\n const [urlState, setUrlState] = useState<UrlState>(() => (typeof url === 'function' ? '' : url))\n\n const [loading, setLoading] = useState(true)\n const [reloading, setReloading] = useState(false)\n\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n const deferredRevision = useDeferredValue(displayed._rev)\n const displayUrl = typeof urlState === 'string' ? urlState : ''\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n displayUrl={displayUrl}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showDisplayUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {urlState === MissingSlug && !workaroundEmptyDocument ? (\n <MissingSlugScreen />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loader={loader}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n displayUrl={displayUrl}\n attributes={attributes}\n />\n </Card>\n )}\n {typeof url === 'function' && (\n <AsyncUrl\n // We use the revision as a key, to force a re-render when the revision changes\n // This allows us to respond to changed props (maybe the url function itself changes)\n // But avoid calling async logic on every render accidentally\n key={deferredRevision}\n url={url}\n displayed={displayed}\n urlSecretId={urlSecretId}\n setDisplayUrl={setUrlState}\n setError={setError}\n />\n )}\n {displayUrl && (reload?.revision || reload?.revision === 0) && (\n <ReloadOnRevision\n revision={reload.revision}\n _rev={deferredRevision}\n handleReload={handleReload}\n />\n )}\n </Flex>\n </MotionConfig>\n )\n}\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'loader' | 'attributes'>> {\n loader: string | boolean\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n displayUrl: string\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loader, loading, setLoading, iframeSize, attributes, reloading, displayUrl, setReloading} =\n props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {loader && loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Flex\n style={{...sizes[iframeSize]}}\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n gap={4}\n >\n <Spinner muted />\n {loader && typeof loader === 'string' && (\n <Text muted size={1}>\n {loader}\n </Text>\n )}\n </Flex>\n </MotionFlex>\n )}\n </AnimatePresence>\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={displayUrl}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loader && loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\ninterface ReloadOnRevisionProps {\n _rev?: string\n revision: number | boolean\n handleReload: () => void\n}\nfunction ReloadOnRevision(props: ReloadOnRevisionProps) {\n const {revision, handleReload, _rev} = props\n const [initialRev] = useState(_rev)\n // Reload on new revisions\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n if (_rev !== initialRev) {\n const timeout = setTimeout(handleReload, Number(revision === true ? 300 : revision))\n return () => clearTimeout(timeout)\n }\n }, [_rev, revision, handleReload, initialRev])\n\n return null\n}\n\ninterface AsyncUrlProps {\n displayed: SanityDocumentLike\n url: UrlResolver\n urlSecretId?: UrlSecretId\n setDisplayUrl: (url: UrlState) => void\n setError: SetError\n}\nfunction AsyncUrl(props: AsyncUrlProps) {\n const {urlSecretId, setDisplayUrl, setError} = props\n // Snapshot values we only care about when the revision changes, done by changing the `key` prop\n const [displayed] = useState(props.displayed)\n const [url] = useState(() => props.url)\n const [urlSecret, setUrlSecret] = useState<null | string>(null)\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n if (urlSecretId && !urlSecret) return\n\n const getUrl = async (signal: AbortSignal) => {\n const resolveUrl = await url(displayed, urlSecret, abort.signal)\n\n // Only update state if URL has changed\n if (!signal.aborted && resolveUrl) {\n setDisplayUrl(resolveUrl)\n }\n }\n\n const abort = new AbortController()\n getUrl(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [displayed, setDisplayUrl, setError, url, urlSecret, urlSecretId])\n\n if (urlSecretId) {\n return (\n <GetUrlSecret\n urlSecretId={urlSecretId}\n urlSecret={urlSecret}\n setUrlSecret={setUrlSecret}\n setError={setError}\n />\n )\n }\n\n return null\n}\n\nexport function MissingSlugScreen() {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n Missing slug\n </Text>\n <Text as=\"p\" muted size={1}>\n Add a slug to see the preview.\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n"],"names":["GetUrlSecret","props","urlSecretId","setUrlSecret","urlSecret","setError","client","useClient","apiVersion","secretExpiresAt","setSecretExpiresAt","useState","includes","TypeError","concat","useEffect","getSecret","signal","data","fetch","fetchSecretQuery","id","tag","aborted","secret","_updatedAt","newUpdatedAt","Date","newSecret","patchUrlSecret","getExpiresAt","err","console","error","abort","AbortController","catch","name","timeout","setTimeout","Math","max","getTime","clearTimeout","DisplayUrl","_ref","displayUrl","truncatedUrl","useMemo","url","URL","searchParams","has","delete","append","origin","location","pathname","search","jsx","Text","size","textOverflow","title","children","sizes","desktop","width","height","mobile","DEFAULT_SIZE","Toolbar","iframeSize","setIframeSize","reloading","showDisplayUrl","reloadButton","handleReload","input","useRef","push","pushToast","useToast","copy","useCopyToClipboard","jsxs","Fragment","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Card","padding","borderBottom","Flex","align","gap","Tooltip","content","whiteSpace","Button","disabled","fontSize","mode","icon","MobileDeviceIcon","onClick","Box","flex","UndoIcon","transform","loading","ClipboardIcon","_a","current","closable","status","LaunchIcon","paddingY","text","window","open","MotionFlex","motion","Iframe","document","sanityDocument","options","defaultSize","reload","loader","attributes","workaroundEmptyDocument","setWorkaroundEmptyDocument","prefersReducedMotion","usePrefersReducedMotion","urlState","setUrlState","setLoading","setReloading","iframe","displayed","useCallback","src","deferredRevision","useDeferredValue","_rev","MotionConfig","transition","duration","direction","button","MissingSlug","MissingSlugScreen","tone","Frame","AsyncUrl","setDisplayUrl","revision","ReloadOnRevision","forwardRef","handleIframeLoad","onLoad","justify","AnimatePresence","initial","animate","exit","variants","spinnerVariants","inset","Spinner","muted","frameBorder","maxHeight","iframeVariants","boxShadow","background","scale","idle","active","initialRev","Number","getUrl","resolveUrl","sizing","Container","radius","shadow","WarningOutlineIcon","Stack","marginLeft","space","as","weight"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/isValidSecret.tsx","../src/utils.ts","../src/GetUrlSecret.tsx","../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/types.ts","../src/Iframe.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n","import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","import {useEffect, useState} from 'react'\nimport {useClient} from 'sanity'\n\nimport {apiVersion, fetchSecretQuery, FetchSecretResponse, tag, UrlSecretId} from './isValidSecret'\nimport {SetError} from './types'\nimport {getExpiresAt, patchUrlSecret} from './utils'\n\nexport interface GetUrlSecretProps {\n urlSecretId: UrlSecretId\n urlSecret: string | null\n setUrlSecret: (secret: string | null) => void\n setError: SetError\n}\nexport function GetUrlSecret(props: GetUrlSecretProps) {\n const {urlSecretId, setUrlSecret, urlSecret, setError} = props\n const client = useClient({apiVersion})\n const [secretExpiresAt, setSecretExpiresAt] = useState<null | Date>(null)\n\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n\n useEffect(() => {\n if (urlSecret) return\n\n async function getSecret(signal: AbortSignal): Promise<void> {\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {signal, tag},\n )\n\n if (signal.aborted) return\n\n if (!data?.secret || !data?._updatedAt) {\n try {\n const newUpdatedAt = new Date()\n const newSecret = await patchUrlSecret(client, urlSecretId, signal)\n if (signal.aborted) return\n setUrlSecret(newSecret)\n setSecretExpiresAt(getExpiresAt(newUpdatedAt))\n } catch (err) {\n console.error(\n 'Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.',\n err,\n )\n }\n return\n }\n\n if (data?.secret !== urlSecret) {\n setUrlSecret(data?.secret)\n setSecretExpiresAt(getExpiresAt(new Date(data?._updatedAt)))\n }\n }\n\n const abort = new AbortController()\n getSecret(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [client, setError, setUrlSecret, urlSecret, urlSecretId])\n\n useEffect(() => {\n if (!secretExpiresAt) return\n\n const timeout = setTimeout(\n () => {\n setUrlSecret(null)\n setSecretExpiresAt(null)\n },\n Math.max(0, secretExpiresAt.getTime() - new Date().getTime()),\n )\n // eslint-disable-next-line consistent-return\n return () => clearTimeout(timeout)\n }, [secretExpiresAt, setUrlSecret])\n\n return null\n}\n","import {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl({displayUrl}: {displayUrl: string}) {\n const truncatedUrl = useMemo(() => {\n const url = new URL(displayUrl)\n\n if (url.searchParams.has('secret')) {\n url.searchParams.delete('secret')\n url.searchParams.append('secret', '***')\n }\n\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [displayUrl])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\" title={displayUrl}>\n {truncatedUrl}\n </Text>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {ClipboardIcon, LaunchIcon, MobileDeviceIcon, UndoIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n displayUrl: string\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showDisplayUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {\n displayUrl,\n iframeSize,\n setIframeSize,\n reloading,\n showDisplayUrl,\n reloadButton,\n handleReload,\n } = props\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && displayUrl && <DisplayUrl displayUrl={displayUrl} />}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={<UndoIcon style={{transform: 'rotate(90deg) scaleY(-1)'}} />}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!displayUrl}\n fontSize={[1]}\n icon={ClipboardIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={() => window.open(displayUrl)}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n","/* eslint-disable react/jsx-no-bind */\nimport {WarningOutlineIcon} from '@sanity/icons'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {forwardRef, useCallback, useDeferredValue, useEffect, useRef, useState} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocument} from 'sanity'\n\nimport {UrlResolver} from './defineUrlResolver'\nimport {GetUrlSecret} from './GetUrlSecret'\nimport {UrlSecretId} from './isValidSecret'\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey, MissingSlug, SetError, type UrlState} from './types'\n\nexport type {UrlResolver, UrlSecretId}\n\nexport type IframeOptions = {\n urlSecretId?: UrlSecretId\n url: UrlState | UrlResolver\n defaultSize?: IframeSizeKey\n loader?: string | boolean\n showDisplayUrl?: boolean\n reload?: {\n revision?: boolean | number\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const [error, setError] = useState<unknown>(null)\n if (error) {\n throw error\n }\n\n const {document: sanityDocument, options} = props\n const {\n url,\n urlSecretId,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader = 'Loading…',\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n // Workaround documents that initially appears to be an empty new document but just hasen't loaded yet\n const [workaroundEmptyDocument, setWorkaroundEmptyDocument] = useState(true)\n useEffect(() => {\n const timeout = setTimeout(() => setWorkaroundEmptyDocument(false), 1000)\n return () => clearTimeout(timeout)\n }, [])\n\n const prefersReducedMotion = usePrefersReducedMotion()\n const [urlState, setUrlState] = useState<UrlState>(() => (typeof url === 'function' ? '' : url))\n\n const [loading, setLoading] = useState(true)\n const [reloading, setReloading] = useState(false)\n\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n const deferredRevision = useDeferredValue(displayed._rev)\n const displayUrl = typeof urlState === 'string' ? urlState : ''\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n displayUrl={displayUrl}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showDisplayUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {urlState === MissingSlug && !workaroundEmptyDocument ? (\n <MissingSlugScreen />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loader={loader}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n displayUrl={displayUrl}\n attributes={attributes}\n />\n </Card>\n )}\n {typeof url === 'function' && (\n <AsyncUrl\n // We use the revision as a key, to force a re-render when the revision changes\n // This allows us to respond to changed props (maybe the url function itself changes)\n // But avoid calling async logic on every render accidentally\n key={deferredRevision}\n url={url}\n displayed={displayed}\n urlSecretId={urlSecretId}\n setDisplayUrl={setUrlState}\n setError={setError}\n />\n )}\n {displayUrl && (reload?.revision || reload?.revision === 0) && (\n <ReloadOnRevision\n revision={reload.revision}\n _rev={deferredRevision}\n handleReload={handleReload}\n />\n )}\n </Flex>\n </MotionConfig>\n )\n}\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'loader' | 'attributes'>> {\n loader: string | boolean\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n displayUrl: string\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loader, loading, setLoading, iframeSize, attributes, reloading, displayUrl, setReloading} =\n props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {loader && loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Flex\n style={{...sizes[iframeSize]}}\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n gap={4}\n >\n <Spinner muted />\n {loader && typeof loader === 'string' && (\n <Text muted size={1}>\n {loader}\n </Text>\n )}\n </Flex>\n </MotionFlex>\n )}\n </AnimatePresence>\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={displayUrl}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loader && loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\ninterface ReloadOnRevisionProps {\n _rev?: string\n revision: number | boolean\n handleReload: () => void\n}\nfunction ReloadOnRevision(props: ReloadOnRevisionProps) {\n const {revision, handleReload, _rev} = props\n const [initialRev] = useState(_rev)\n // Reload on new revisions\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n if (_rev !== initialRev) {\n const timeout = setTimeout(handleReload, Number(revision === true ? 300 : revision))\n return () => clearTimeout(timeout)\n }\n }, [_rev, revision, handleReload, initialRev])\n\n return null\n}\n\ninterface AsyncUrlProps {\n displayed: SanityDocument\n url: UrlResolver\n urlSecretId?: UrlSecretId\n setDisplayUrl: (url: UrlState) => void\n setError: SetError\n}\nfunction AsyncUrl(props: AsyncUrlProps) {\n const {urlSecretId, setDisplayUrl, setError} = props\n // Snapshot values we only care about when the revision changes, done by changing the `key` prop\n const [displayed] = useState(props.displayed)\n const [url] = useState(() => props.url)\n const [urlSecret, setUrlSecret] = useState<null | string>(null)\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n if (urlSecretId && !urlSecret) return\n\n const getUrl = async (signal: AbortSignal) => {\n const resolveUrl = await url(displayed, urlSecret, abort.signal)\n\n // Only update state if URL has changed\n if (!signal.aborted && resolveUrl) {\n setDisplayUrl(resolveUrl)\n }\n }\n\n const abort = new AbortController()\n getUrl(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [displayed, setDisplayUrl, setError, url, urlSecret, urlSecretId])\n\n if (urlSecretId) {\n return (\n <GetUrlSecret\n urlSecretId={urlSecretId}\n urlSecret={urlSecret}\n setUrlSecret={setUrlSecret}\n setError={setError}\n />\n )\n }\n\n return null\n}\n\nexport function MissingSlugScreen() {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n Missing slug\n </Text>\n <Text as=\"p\" muted size={1}>\n Add a slug to see the preview.\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","getExpiresAt","_updatedAt","Date","getTime","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","GetUrlSecret","props","setUrlSecret","urlSecret","setError","useClient","secretExpiresAt","setSecretExpiresAt","useState","includes","TypeError","useEffect","getSecret","data","fetch","id","aborted","newUpdatedAt","err","console","error","abort","AbortController","catch","timeout","setTimeout","max","clearTimeout","DisplayUrl","_ref","displayUrl","truncatedUrl","useMemo","url","URL","searchParams","has","delete","append","origin","location","pathname","search","jsx","Text","size","textOverflow","title","children","sizes","desktop","width","height","mobile","DEFAULT_SIZE","Toolbar","iframeSize","setIframeSize","reloading","showDisplayUrl","reloadButton","handleReload","input","useRef","push","pushToast","useToast","copy","useCopyToClipboard","jsxs","Fragment","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Card","padding","borderBottom","Flex","align","gap","Tooltip","content","whiteSpace","Button","disabled","fontSize","mode","icon","MobileDeviceIcon","onClick","Box","flex","UndoIcon","transform","loading","ClipboardIcon","_a","current","closable","status","LaunchIcon","paddingY","text","window","open","MissingSlug","Symbol","MotionFlex","motion","Iframe","document","sanityDocument","options","defaultSize","reload","loader","attributes","workaroundEmptyDocument","setWorkaroundEmptyDocument","prefersReducedMotion","usePrefersReducedMotion","urlState","setUrlState","setLoading","setReloading","iframe","displayed","useCallback","src","deferredRevision","useDeferredValue","_rev","MotionConfig","transition","duration","direction","button","MissingSlugScreen","tone","Frame","AsyncUrl","setDisplayUrl","revision","ReloadOnRevision","forwardRef","handleIframeLoad","onLoad","justify","AnimatePresence","initial","animate","exit","variants","spinnerVariants","inset","Spinner","muted","frameBorder","maxHeight","iframeVariants","boxShadow","background","scale","idle","active","initialRev","Number","getUrl","resolveUrl","sizing","Container","radius","shadow","WarningOutlineIcon","Stack","marginLeft","space","as","weight"],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {HTMLAttributeReferrerPolicy} from 'react'
|
|
2
2
|
import {JSX as JSX_2} from 'react/jsx-runtime'
|
|
3
|
-
import {
|
|
3
|
+
import {SanityDocument} from 'sanity'
|
|
4
4
|
|
|
5
5
|
declare function Iframe(props: IframeProps): JSX_2.Element
|
|
6
6
|
export {Iframe}
|
|
@@ -26,7 +26,7 @@ export declare type IframeOptions = {
|
|
|
26
26
|
|
|
27
27
|
export declare interface IframeProps {
|
|
28
28
|
document: {
|
|
29
|
-
displayed:
|
|
29
|
+
displayed: SanityDocument
|
|
30
30
|
}
|
|
31
31
|
options: IframeOptions
|
|
32
32
|
}
|
|
@@ -49,7 +49,7 @@ export declare type SizeProps = {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export declare type UrlResolver = (
|
|
52
|
-
document:
|
|
52
|
+
document: SanityDocument,
|
|
53
53
|
urlSecret: string | null | undefined,
|
|
54
54
|
signal?: AbortSignal,
|
|
55
55
|
) => UrlState | Promise<UrlState>
|
package/lib/index.js
CHANGED
|
@@ -4,9 +4,42 @@ import { Text, useToast, Card, Flex, Tooltip, Button, Box, Spinner, usePrefersRe
|
|
|
4
4
|
import { motion, AnimatePresence, MotionConfig } from 'framer-motion';
|
|
5
5
|
import { useState, useEffect, useMemo, useRef, forwardRef, useCallback, useDeferredValue } from 'react';
|
|
6
6
|
import { useClient } from 'sanity';
|
|
7
|
-
import { apiVersion, fetchSecretQuery, tag } from './_chunks/is-valid-secret-57fea7e5.js';
|
|
8
|
-
import { patchUrlSecret, getExpiresAt, MissingSlug } from './_chunks/types-107599a1.js';
|
|
9
7
|
import { useCopyToClipboard } from 'usehooks-ts';
|
|
8
|
+
var name = "sanity-plugin-iframe-pane";
|
|
9
|
+
const SECRET_TTL = 60 * 60;
|
|
10
|
+
const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
|
|
11
|
+
const tag = name;
|
|
12
|
+
const apiVersion = "2023-08-08";
|
|
13
|
+
function getExpiresAt(_updatedAt) {
|
|
14
|
+
return new Date(_updatedAt.getTime() + 1e3 * SECRET_TTL);
|
|
15
|
+
}
|
|
16
|
+
function generateUrlSecret() {
|
|
17
|
+
if (typeof crypto !== "undefined") {
|
|
18
|
+
const array = new Uint8Array(16);
|
|
19
|
+
crypto.getRandomValues(array);
|
|
20
|
+
let key = "";
|
|
21
|
+
for (let i = 0; i < array.length; i++) {
|
|
22
|
+
key += array[i].toString(16).padStart(2, "0");
|
|
23
|
+
}
|
|
24
|
+
key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
|
|
25
|
+
return key;
|
|
26
|
+
}
|
|
27
|
+
return Math.random().toString(36).slice(2);
|
|
28
|
+
}
|
|
29
|
+
async function patchUrlSecret(client, urlSecretId, signal) {
|
|
30
|
+
const newSecret = generateUrlSecret();
|
|
31
|
+
const patch = client.patch(urlSecretId).set({
|
|
32
|
+
secret: newSecret
|
|
33
|
+
});
|
|
34
|
+
await client.transaction().createIfNotExists({
|
|
35
|
+
_id: urlSecretId,
|
|
36
|
+
_type: urlSecretId
|
|
37
|
+
}).patch(patch).commit({
|
|
38
|
+
tag,
|
|
39
|
+
signal
|
|
40
|
+
});
|
|
41
|
+
return newSecret;
|
|
42
|
+
}
|
|
10
43
|
function GetUrlSecret(props) {
|
|
11
44
|
const {
|
|
12
45
|
urlSecretId,
|
|
@@ -228,6 +261,7 @@ function Toolbar(props) {
|
|
|
228
261
|
})]
|
|
229
262
|
});
|
|
230
263
|
}
|
|
264
|
+
const MissingSlug = Symbol("MissingSlug");
|
|
231
265
|
const MotionFlex = motion(Flex);
|
|
232
266
|
function Iframe(props) {
|
|
233
267
|
var _a;
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/GetUrlSecret.tsx","../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/Iframe.tsx"],"sourcesContent":["import {useEffect, useState} from 'react'\nimport {useClient} from 'sanity'\n\nimport {apiVersion, fetchSecretQuery, FetchSecretResponse, tag, UrlSecretId} from './isValidSecret'\nimport {SetError} from './types'\nimport {getExpiresAt, patchUrlSecret} from './utils'\n\nexport interface GetUrlSecretProps {\n urlSecretId: UrlSecretId\n urlSecret: string | null\n setUrlSecret: (secret: string | null) => void\n setError: SetError\n}\nexport function GetUrlSecret(props: GetUrlSecretProps) {\n const {urlSecretId, setUrlSecret, urlSecret, setError} = props\n const client = useClient({apiVersion})\n const [secretExpiresAt, setSecretExpiresAt] = useState<null | Date>(null)\n\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n\n useEffect(() => {\n if (urlSecret) return\n\n async function getSecret(signal: AbortSignal): Promise<void> {\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {signal, tag},\n )\n\n if (signal.aborted) return\n\n if (!data?.secret || !data?._updatedAt) {\n try {\n const newUpdatedAt = new Date()\n const newSecret = await patchUrlSecret(client, urlSecretId, signal)\n if (signal.aborted) return\n setUrlSecret(newSecret)\n setSecretExpiresAt(getExpiresAt(newUpdatedAt))\n } catch (err) {\n console.error(\n 'Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.',\n err,\n )\n }\n return\n }\n\n if (data?.secret !== urlSecret) {\n setUrlSecret(data?.secret)\n setSecretExpiresAt(getExpiresAt(new Date(data?._updatedAt)))\n }\n }\n\n const abort = new AbortController()\n getSecret(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [client, setError, setUrlSecret, urlSecret, urlSecretId])\n\n useEffect(() => {\n if (!secretExpiresAt) return\n\n const timeout = setTimeout(\n () => {\n setUrlSecret(null)\n setSecretExpiresAt(null)\n },\n Math.max(0, secretExpiresAt.getTime() - new Date().getTime()),\n )\n // eslint-disable-next-line consistent-return\n return () => clearTimeout(timeout)\n }, [secretExpiresAt, setUrlSecret])\n\n return null\n}\n","import {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl({displayUrl}: {displayUrl: string}) {\n const truncatedUrl = useMemo(() => {\n const url = new URL(displayUrl)\n\n if (url.searchParams.has('secret')) {\n url.searchParams.delete('secret')\n url.searchParams.append('secret', '***')\n }\n\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [displayUrl])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\" title={displayUrl}>\n {truncatedUrl}\n </Text>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {ClipboardIcon, LaunchIcon, MobileDeviceIcon, UndoIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n displayUrl: string\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showDisplayUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {\n displayUrl,\n iframeSize,\n setIframeSize,\n reloading,\n showDisplayUrl,\n reloadButton,\n handleReload,\n } = props\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && displayUrl && <DisplayUrl displayUrl={displayUrl} />}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={<UndoIcon style={{transform: 'rotate(90deg) scaleY(-1)'}} />}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!displayUrl}\n fontSize={[1]}\n icon={ClipboardIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={() => window.open(displayUrl)}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {WarningOutlineIcon} from '@sanity/icons'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {forwardRef, useCallback, useDeferredValue, useEffect, useRef, useState} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocumentLike} from 'sanity'\n\nimport {UrlResolver} from './defineUrlResolver'\nimport {GetUrlSecret} from './GetUrlSecret'\nimport {UrlSecretId} from './isValidSecret'\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey, MissingSlug, SetError, type UrlState} from './types'\n\nexport type {UrlResolver, UrlSecretId}\n\nexport type IframeOptions = {\n urlSecretId?: UrlSecretId\n url: UrlState | UrlResolver\n defaultSize?: IframeSizeKey\n loader?: string | boolean\n showDisplayUrl?: boolean\n reload?: {\n revision?: boolean | number\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocumentLike\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const [error, setError] = useState<unknown>(null)\n if (error) {\n throw error\n }\n\n const {document: sanityDocument, options} = props\n const {\n url,\n urlSecretId,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader = 'Loading…',\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n // Workaround documents that initially appears to be an empty new document but just hasen't loaded yet\n const [workaroundEmptyDocument, setWorkaroundEmptyDocument] = useState(true)\n useEffect(() => {\n const timeout = setTimeout(() => setWorkaroundEmptyDocument(false), 1000)\n return () => clearTimeout(timeout)\n }, [])\n\n const prefersReducedMotion = usePrefersReducedMotion()\n const [urlState, setUrlState] = useState<UrlState>(() => (typeof url === 'function' ? '' : url))\n\n const [loading, setLoading] = useState(true)\n const [reloading, setReloading] = useState(false)\n\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n const deferredRevision = useDeferredValue(displayed._rev)\n const displayUrl = typeof urlState === 'string' ? urlState : ''\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n displayUrl={displayUrl}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showDisplayUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {urlState === MissingSlug && !workaroundEmptyDocument ? (\n <MissingSlugScreen />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loader={loader}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n displayUrl={displayUrl}\n attributes={attributes}\n />\n </Card>\n )}\n {typeof url === 'function' && (\n <AsyncUrl\n // We use the revision as a key, to force a re-render when the revision changes\n // This allows us to respond to changed props (maybe the url function itself changes)\n // But avoid calling async logic on every render accidentally\n key={deferredRevision}\n url={url}\n displayed={displayed}\n urlSecretId={urlSecretId}\n setDisplayUrl={setUrlState}\n setError={setError}\n />\n )}\n {displayUrl && (reload?.revision || reload?.revision === 0) && (\n <ReloadOnRevision\n revision={reload.revision}\n _rev={deferredRevision}\n handleReload={handleReload}\n />\n )}\n </Flex>\n </MotionConfig>\n )\n}\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'loader' | 'attributes'>> {\n loader: string | boolean\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n displayUrl: string\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loader, loading, setLoading, iframeSize, attributes, reloading, displayUrl, setReloading} =\n props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {loader && loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Flex\n style={{...sizes[iframeSize]}}\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n gap={4}\n >\n <Spinner muted />\n {loader && typeof loader === 'string' && (\n <Text muted size={1}>\n {loader}\n </Text>\n )}\n </Flex>\n </MotionFlex>\n )}\n </AnimatePresence>\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={displayUrl}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loader && loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\ninterface ReloadOnRevisionProps {\n _rev?: string\n revision: number | boolean\n handleReload: () => void\n}\nfunction ReloadOnRevision(props: ReloadOnRevisionProps) {\n const {revision, handleReload, _rev} = props\n const [initialRev] = useState(_rev)\n // Reload on new revisions\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n if (_rev !== initialRev) {\n const timeout = setTimeout(handleReload, Number(revision === true ? 300 : revision))\n return () => clearTimeout(timeout)\n }\n }, [_rev, revision, handleReload, initialRev])\n\n return null\n}\n\ninterface AsyncUrlProps {\n displayed: SanityDocumentLike\n url: UrlResolver\n urlSecretId?: UrlSecretId\n setDisplayUrl: (url: UrlState) => void\n setError: SetError\n}\nfunction AsyncUrl(props: AsyncUrlProps) {\n const {urlSecretId, setDisplayUrl, setError} = props\n // Snapshot values we only care about when the revision changes, done by changing the `key` prop\n const [displayed] = useState(props.displayed)\n const [url] = useState(() => props.url)\n const [urlSecret, setUrlSecret] = useState<null | string>(null)\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n if (urlSecretId && !urlSecret) return\n\n const getUrl = async (signal: AbortSignal) => {\n const resolveUrl = await url(displayed, urlSecret, abort.signal)\n\n // Only update state if URL has changed\n if (!signal.aborted && resolveUrl) {\n setDisplayUrl(resolveUrl)\n }\n }\n\n const abort = new AbortController()\n getUrl(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [displayed, setDisplayUrl, setError, url, urlSecret, urlSecretId])\n\n if (urlSecretId) {\n return (\n <GetUrlSecret\n urlSecretId={urlSecretId}\n urlSecret={urlSecret}\n setUrlSecret={setUrlSecret}\n setError={setError}\n />\n )\n }\n\n return null\n}\n\nexport function MissingSlugScreen() {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n Missing slug\n </Text>\n <Text as=\"p\" muted size={1}>\n Add a slug to see the preview.\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n"],"names":["GetUrlSecret","props","urlSecretId","setUrlSecret","urlSecret","setError","client","useClient","apiVersion","secretExpiresAt","setSecretExpiresAt","useState","includes","TypeError","concat","useEffect","getSecret","signal","data","fetch","fetchSecretQuery","id","tag","aborted","secret","_updatedAt","newUpdatedAt","Date","newSecret","patchUrlSecret","getExpiresAt","err","console","error","abort","AbortController","catch","name","timeout","setTimeout","Math","max","getTime","clearTimeout","DisplayUrl","_ref","displayUrl","truncatedUrl","useMemo","url","URL","searchParams","has","delete","append","origin","location","pathname","search","jsx","Text","size","textOverflow","title","children","sizes","desktop","width","height","mobile","DEFAULT_SIZE","Toolbar","iframeSize","setIframeSize","reloading","showDisplayUrl","reloadButton","handleReload","input","useRef","push","pushToast","useToast","copy","useCopyToClipboard","jsxs","Fragment","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Card","padding","borderBottom","Flex","align","gap","Tooltip","content","whiteSpace","Button","disabled","fontSize","mode","icon","MobileDeviceIcon","onClick","Box","flex","UndoIcon","transform","loading","ClipboardIcon","_a","current","closable","status","LaunchIcon","paddingY","text","window","open","MotionFlex","motion","Iframe","document","sanityDocument","options","defaultSize","reload","loader","attributes","workaroundEmptyDocument","setWorkaroundEmptyDocument","prefersReducedMotion","usePrefersReducedMotion","urlState","setUrlState","setLoading","setReloading","iframe","displayed","useCallback","src","deferredRevision","useDeferredValue","_rev","MotionConfig","transition","duration","direction","button","MissingSlug","MissingSlugScreen","tone","Frame","AsyncUrl","setDisplayUrl","revision","ReloadOnRevision","forwardRef","handleIframeLoad","onLoad","justify","AnimatePresence","initial","animate","exit","variants","spinnerVariants","inset","Spinner","muted","frameBorder","maxHeight","iframeVariants","boxShadow","background","scale","idle","active","initialRev","Number","getUrl","resolveUrl","sizing","Container","radius","shadow","WarningOutlineIcon","Stack","marginLeft","space","as","weight"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/isValidSecret.tsx","../src/utils.ts","../src/GetUrlSecret.tsx","../src/DisplayUrl.tsx","../src/Toolbar.tsx","../src/types.ts","../src/Iframe.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n","import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","import {useEffect, useState} from 'react'\nimport {useClient} from 'sanity'\n\nimport {apiVersion, fetchSecretQuery, FetchSecretResponse, tag, UrlSecretId} from './isValidSecret'\nimport {SetError} from './types'\nimport {getExpiresAt, patchUrlSecret} from './utils'\n\nexport interface GetUrlSecretProps {\n urlSecretId: UrlSecretId\n urlSecret: string | null\n setUrlSecret: (secret: string | null) => void\n setError: SetError\n}\nexport function GetUrlSecret(props: GetUrlSecretProps) {\n const {urlSecretId, setUrlSecret, urlSecret, setError} = props\n const client = useClient({apiVersion})\n const [secretExpiresAt, setSecretExpiresAt] = useState<null | Date>(null)\n\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n\n useEffect(() => {\n if (urlSecret) return\n\n async function getSecret(signal: AbortSignal): Promise<void> {\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {signal, tag},\n )\n\n if (signal.aborted) return\n\n if (!data?.secret || !data?._updatedAt) {\n try {\n const newUpdatedAt = new Date()\n const newSecret = await patchUrlSecret(client, urlSecretId, signal)\n if (signal.aborted) return\n setUrlSecret(newSecret)\n setSecretExpiresAt(getExpiresAt(newUpdatedAt))\n } catch (err) {\n console.error(\n 'Failed to create a new preview secret. Ensure the `client` has a `token` specified that has `write` permissions.',\n err,\n )\n }\n return\n }\n\n if (data?.secret !== urlSecret) {\n setUrlSecret(data?.secret)\n setSecretExpiresAt(getExpiresAt(new Date(data?._updatedAt)))\n }\n }\n\n const abort = new AbortController()\n getSecret(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [client, setError, setUrlSecret, urlSecret, urlSecretId])\n\n useEffect(() => {\n if (!secretExpiresAt) return\n\n const timeout = setTimeout(\n () => {\n setUrlSecret(null)\n setSecretExpiresAt(null)\n },\n Math.max(0, secretExpiresAt.getTime() - new Date().getTime()),\n )\n // eslint-disable-next-line consistent-return\n return () => clearTimeout(timeout)\n }, [secretExpiresAt, setUrlSecret])\n\n return null\n}\n","import {Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\n\nexport function DisplayUrl({displayUrl}: {displayUrl: string}) {\n const truncatedUrl = useMemo(() => {\n const url = new URL(displayUrl)\n\n if (url.searchParams.has('secret')) {\n url.searchParams.delete('secret')\n url.searchParams.append('secret', '***')\n }\n\n return `${url.origin === location.origin ? '' : url.origin}${url.pathname}${url.search}`\n }, [displayUrl])\n\n return (\n <Text size={0} textOverflow=\"ellipsis\" title={displayUrl}>\n {truncatedUrl}\n </Text>\n )\n}\n","/* eslint-disable react/jsx-no-bind */\nimport {ClipboardIcon, LaunchIcon, MobileDeviceIcon, UndoIcon} from '@sanity/icons'\nimport {Box, Button, Card, Flex, Text, Tooltip, useToast} from '@sanity/ui'\nimport React, {useRef} from 'react'\nimport {useCopyToClipboard} from 'usehooks-ts'\n\nimport {DisplayUrl} from './DisplayUrl'\nimport {IframeSizeKey, type SizeProps} from './types'\n\nexport const sizes: SizeProps = {\n desktop: {\n width: '100%',\n height: '100%',\n },\n mobile: {\n width: 414,\n height: 746,\n },\n}\n\nexport const DEFAULT_SIZE = `desktop`\n\nexport interface ToolbarProps {\n displayUrl: string\n iframeSize: IframeSizeKey\n setIframeSize: (size: IframeSizeKey) => void\n showDisplayUrl: boolean\n reloading: boolean\n reloadButton: boolean\n handleReload: () => void\n}\nexport function Toolbar(props: ToolbarProps) {\n const {\n displayUrl,\n iframeSize,\n setIframeSize,\n reloading,\n showDisplayUrl,\n reloadButton,\n handleReload,\n } = props\n\n const input = useRef<HTMLTextAreaElement>(null)\n const {push: pushToast} = useToast()\n const [, copy] = useCopyToClipboard()\n\n return (\n <>\n <textarea\n style={{position: `absolute`, pointerEvents: `none`, opacity: 0}}\n ref={input}\n value={displayUrl}\n readOnly\n tabIndex={-1}\n />\n <Card padding={2} borderBottom>\n <Flex align=\"center\" gap={2}>\n <Flex align=\"center\" gap={1}>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {iframeSize === 'mobile' ? 'Exit mobile preview' : 'Preview mobile viewport'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n padding={2}\n mode={iframeSize === 'mobile' ? 'default' : 'ghost'}\n icon={MobileDeviceIcon}\n onClick={() => setIframeSize(iframeSize === 'mobile' ? 'desktop' : 'mobile')}\n />\n </Tooltip>\n </Flex>\n <Box flex={1}>\n {showDisplayUrl && displayUrl && <DisplayUrl displayUrl={displayUrl} />}\n </Box>\n <Flex align=\"center\" gap={1}>\n {reloadButton ? (\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n {reloading ? 'Reloading…' : 'Reload'}\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n mode=\"bleed\"\n fontSize={[1]}\n padding={2}\n icon={<UndoIcon style={{transform: 'rotate(90deg) scaleY(-1)'}} />}\n loading={reloading}\n aria-label=\"Reload\"\n onClick={() => handleReload()}\n />\n </Tooltip>\n ) : null}\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Copy URL\n </Text>\n }\n padding={2}\n >\n <Button\n mode=\"bleed\"\n disabled={!displayUrl}\n fontSize={[1]}\n icon={ClipboardIcon}\n padding={[2]}\n aria-label=\"Copy URL\"\n onClick={() => {\n if (!input?.current?.value) return\n\n copy(input.current.value)\n pushToast({\n closable: true,\n status: 'success',\n title: 'The URL is copied to the clipboard',\n })\n }}\n />\n </Tooltip>\n <Tooltip\n content={\n <Text size={1} style={{whiteSpace: 'nowrap'}}>\n Open URL in a new tab\n </Text>\n }\n padding={2}\n >\n <Button\n disabled={!displayUrl}\n fontSize={[1]}\n icon={LaunchIcon}\n mode=\"ghost\"\n paddingY={[2]}\n text=\"Open\"\n aria-label=\"Open URL in a new tab\"\n onClick={() => window.open(displayUrl)}\n />\n </Tooltip>\n </Flex>\n </Flex>\n </Card>\n </>\n )\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n","/* eslint-disable react/jsx-no-bind */\nimport {WarningOutlineIcon} from '@sanity/icons'\nimport {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotion} from '@sanity/ui'\nimport {AnimatePresence, motion, MotionConfig} from 'framer-motion'\nimport React, {forwardRef, useCallback, useDeferredValue, useEffect, useRef, useState} from 'react'\nimport {HTMLAttributeReferrerPolicy} from 'react'\nimport {SanityDocument} from 'sanity'\n\nimport {UrlResolver} from './defineUrlResolver'\nimport {GetUrlSecret} from './GetUrlSecret'\nimport {UrlSecretId} from './isValidSecret'\nimport {DEFAULT_SIZE, sizes, Toolbar} from './Toolbar'\nimport {IframeSizeKey, MissingSlug, SetError, type UrlState} from './types'\n\nexport type {UrlResolver, UrlSecretId}\n\nexport type IframeOptions = {\n urlSecretId?: UrlSecretId\n url: UrlState | UrlResolver\n defaultSize?: IframeSizeKey\n loader?: string | boolean\n showDisplayUrl?: boolean\n reload?: {\n revision?: boolean | number\n button?: boolean\n }\n attributes?: Partial<{\n allow: string\n referrerPolicy: HTMLAttributeReferrerPolicy | undefined\n sandbox: string\n onLoad: () => void\n }>\n}\n\nconst MotionFlex = motion(Flex)\n\nexport interface IframeProps {\n document: {\n displayed: SanityDocument\n }\n options: IframeOptions\n}\n\nexport function Iframe(props: IframeProps) {\n const [error, setError] = useState<unknown>(null)\n if (error) {\n throw error\n }\n\n const {document: sanityDocument, options} = props\n const {\n url,\n urlSecretId,\n defaultSize = DEFAULT_SIZE,\n reload,\n loader = 'Loading…',\n attributes = {},\n showDisplayUrl = true,\n } = options\n const [iframeSize, setIframeSize] = useState(sizes?.[defaultSize] ? defaultSize : DEFAULT_SIZE)\n\n // Workaround documents that initially appears to be an empty new document but just hasen't loaded yet\n const [workaroundEmptyDocument, setWorkaroundEmptyDocument] = useState(true)\n useEffect(() => {\n const timeout = setTimeout(() => setWorkaroundEmptyDocument(false), 1000)\n return () => clearTimeout(timeout)\n }, [])\n\n const prefersReducedMotion = usePrefersReducedMotion()\n const [urlState, setUrlState] = useState<UrlState>(() => (typeof url === 'function' ? '' : url))\n\n const [loading, setLoading] = useState(true)\n const [reloading, setReloading] = useState(false)\n\n const iframe = useRef<HTMLIFrameElement>(null)\n const {displayed} = sanityDocument\n\n const handleReload = useCallback(() => {\n if (!iframe?.current) {\n return\n }\n\n // Funky way to reload an iframe without CORS issues\n // eslint-disable-next-line no-self-assign\n iframe.current.src = iframe.current.src\n\n setReloading(true)\n }, [])\n\n const deferredRevision = useDeferredValue(displayed._rev)\n const displayUrl = typeof urlState === 'string' ? urlState : ''\n\n return (\n <MotionConfig transition={prefersReducedMotion ? {duration: 0} : undefined}>\n <Flex direction=\"column\" style={{height: `100%`}}>\n <Toolbar\n displayUrl={displayUrl}\n iframeSize={iframeSize}\n reloading={reloading}\n setIframeSize={setIframeSize}\n showDisplayUrl={showDisplayUrl}\n reloadButton={!!reload?.button}\n handleReload={handleReload}\n />\n {urlState === MissingSlug && !workaroundEmptyDocument ? (\n <MissingSlugScreen />\n ) : (\n <Card tone=\"transparent\" style={{height: `100%`}}>\n <Frame\n ref={iframe}\n loader={loader}\n loading={loading}\n reloading={reloading}\n iframeSize={iframeSize}\n setReloading={setReloading}\n setLoading={setLoading}\n displayUrl={displayUrl}\n attributes={attributes}\n />\n </Card>\n )}\n {typeof url === 'function' && (\n <AsyncUrl\n // We use the revision as a key, to force a re-render when the revision changes\n // This allows us to respond to changed props (maybe the url function itself changes)\n // But avoid calling async logic on every render accidentally\n key={deferredRevision}\n url={url}\n displayed={displayed}\n urlSecretId={urlSecretId}\n setDisplayUrl={setUrlState}\n setError={setError}\n />\n )}\n {displayUrl && (reload?.revision || reload?.revision === 0) && (\n <ReloadOnRevision\n revision={reload.revision}\n _rev={deferredRevision}\n handleReload={handleReload}\n />\n )}\n </Flex>\n </MotionConfig>\n )\n}\n\ninterface FrameProps extends Required<Pick<IframeOptions, 'loader' | 'attributes'>> {\n loader: string | boolean\n loading: boolean\n reloading: boolean\n setLoading: (loading: boolean) => void\n setReloading: (reloading: boolean) => void\n iframeSize: IframeSizeKey\n displayUrl: string\n}\nconst Frame = forwardRef(function Frame(\n props: FrameProps,\n iframe: React.ForwardedRef<HTMLIFrameElement>,\n) {\n const {loader, loading, setLoading, iframeSize, attributes, reloading, displayUrl, setReloading} =\n props\n\n function handleIframeLoad() {\n setLoading(false)\n setReloading(false)\n // Run onLoad from attributes\n if (attributes.onLoad && typeof attributes.onLoad === 'function') {\n attributes.onLoad()\n }\n }\n\n return (\n <Flex align=\"center\" justify=\"center\" style={{height: `100%`, position: `relative`}}>\n <AnimatePresence>\n {loader && loading && (\n <MotionFlex\n initial=\"initial\"\n animate=\"animate\"\n exit=\"exit\"\n variants={spinnerVariants}\n justify=\"center\"\n align=\"center\"\n style={{inset: `0`, position: `absolute`}}\n >\n <Flex\n style={{...sizes[iframeSize]}}\n justify=\"center\"\n align=\"center\"\n direction=\"column\"\n gap={4}\n >\n <Spinner muted />\n {loader && typeof loader === 'string' && (\n <Text muted size={1}>\n {loader}\n </Text>\n )}\n </Flex>\n </MotionFlex>\n )}\n </AnimatePresence>\n <motion.iframe\n ref={iframe}\n title=\"preview\"\n frameBorder=\"0\"\n style={{maxHeight: '100%'}}\n src={displayUrl}\n initial={['background', iframeSize]}\n variants={iframeVariants}\n animate={[\n loader && loading ? 'background' : 'active',\n reloading ? 'reloading' : 'idle',\n iframeSize,\n ]}\n {...attributes}\n onLoad={handleIframeLoad}\n />\n </Flex>\n )\n})\n\nconst spinnerVariants = {\n initial: {opacity: 1},\n animate: {opacity: [0, 0, 1]},\n exit: {opacity: [1, 0, 0]},\n}\n\nconst iframeVariants = {\n ...sizes,\n desktop: {\n ...sizes.desktop,\n boxShadow: '0 0 0 0px var(--card-shadow-outline-color)',\n },\n mobile: {\n ...sizes.mobile,\n boxShadow: '0 0 0 1px var(--card-shadow-outline-color)',\n },\n background: {\n opacity: 0,\n scale: 1,\n },\n idle: {\n scale: 1,\n },\n reloading: {\n scale: [1, 1, 1, 0.98],\n },\n active: {\n opacity: [0, 0, 1],\n scale: 1,\n },\n}\n\ninterface ReloadOnRevisionProps {\n _rev?: string\n revision: number | boolean\n handleReload: () => void\n}\nfunction ReloadOnRevision(props: ReloadOnRevisionProps) {\n const {revision, handleReload, _rev} = props\n const [initialRev] = useState(_rev)\n // Reload on new revisions\n // eslint-disable-next-line consistent-return\n useEffect(() => {\n if (_rev !== initialRev) {\n const timeout = setTimeout(handleReload, Number(revision === true ? 300 : revision))\n return () => clearTimeout(timeout)\n }\n }, [_rev, revision, handleReload, initialRev])\n\n return null\n}\n\ninterface AsyncUrlProps {\n displayed: SanityDocument\n url: UrlResolver\n urlSecretId?: UrlSecretId\n setDisplayUrl: (url: UrlState) => void\n setError: SetError\n}\nfunction AsyncUrl(props: AsyncUrlProps) {\n const {urlSecretId, setDisplayUrl, setError} = props\n // Snapshot values we only care about when the revision changes, done by changing the `key` prop\n const [displayed] = useState(props.displayed)\n const [url] = useState(() => props.url)\n const [urlSecret, setUrlSecret] = useState<null | string>(null)\n\n // Set initial URL and refresh on new revisions\n useEffect(() => {\n if (urlSecretId && !urlSecret) return\n\n const getUrl = async (signal: AbortSignal) => {\n const resolveUrl = await url(displayed, urlSecret, abort.signal)\n\n // Only update state if URL has changed\n if (!signal.aborted && resolveUrl) {\n setDisplayUrl(resolveUrl)\n }\n }\n\n const abort = new AbortController()\n getUrl(abort.signal).catch((error) => error.name !== 'AbortError' && setError(error))\n // eslint-disable-next-line consistent-return\n return () => abort.abort()\n }, [displayed, setDisplayUrl, setError, url, urlSecret, urlSecretId])\n\n if (urlSecretId) {\n return (\n <GetUrlSecret\n urlSecretId={urlSecretId}\n urlSecret={urlSecret}\n setUrlSecret={setUrlSecret}\n setError={setError}\n />\n )\n }\n\n return null\n}\n\nexport function MissingSlugScreen() {\n return (\n <Card height=\"fill\">\n <Flex align=\"center\" height=\"fill\" justify=\"center\" padding={4} sizing=\"border\">\n <Container width={0}>\n <Card padding={4} radius={2} shadow={1} tone=\"caution\">\n <Flex>\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack flex={1} marginLeft={3} space={3}>\n <Text as=\"h1\" size={1} weight=\"bold\">\n Missing slug\n </Text>\n <Text as=\"p\" muted size={1}>\n Add a slug to see the preview.\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Container>\n </Flex>\n </Card>\n )\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","getExpiresAt","_updatedAt","Date","getTime","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","GetUrlSecret","props","setUrlSecret","urlSecret","setError","useClient","secretExpiresAt","setSecretExpiresAt","useState","includes","TypeError","useEffect","getSecret","data","fetch","id","aborted","newUpdatedAt","err","console","error","abort","AbortController","catch","timeout","setTimeout","max","clearTimeout","DisplayUrl","_ref","displayUrl","truncatedUrl","useMemo","url","URL","searchParams","has","delete","append","origin","location","pathname","search","jsx","Text","size","textOverflow","title","children","sizes","desktop","width","height","mobile","DEFAULT_SIZE","Toolbar","iframeSize","setIframeSize","reloading","showDisplayUrl","reloadButton","handleReload","input","useRef","push","pushToast","useToast","copy","useCopyToClipboard","jsxs","Fragment","style","position","pointerEvents","opacity","ref","value","readOnly","tabIndex","Card","padding","borderBottom","Flex","align","gap","Tooltip","content","whiteSpace","Button","disabled","fontSize","mode","icon","MobileDeviceIcon","onClick","Box","flex","UndoIcon","transform","loading","ClipboardIcon","_a","current","closable","status","LaunchIcon","paddingY","text","window","open","MissingSlug","Symbol","MotionFlex","motion","Iframe","document","sanityDocument","options","defaultSize","reload","loader","attributes","workaroundEmptyDocument","setWorkaroundEmptyDocument","prefersReducedMotion","usePrefersReducedMotion","urlState","setUrlState","setLoading","setReloading","iframe","displayed","useCallback","src","deferredRevision","useDeferredValue","_rev","MotionConfig","transition","duration","direction","button","MissingSlugScreen","tone","Frame","AsyncUrl","setDisplayUrl","revision","ReloadOnRevision","forwardRef","handleIframeLoad","onLoad","justify","AnimatePresence","initial","animate","exit","variants","spinnerVariants","inset","Spinner","muted","frameBorder","maxHeight","iframeVariants","boxShadow","background","scale","idle","active","initialRev","Number","getUrl","resolveUrl","sizing","Container","radius","shadow","WarningOutlineIcon","Stack","marginLeft","space","as","weight"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-iframe-pane",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Display any URL in a View Pane, along with helpful buttons to Copy the URL or open in a new tab",
|
|
5
5
|
"homepage": "https://github.com/sanity-io/sanity-plugin-iframe-pane#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -25,26 +25,6 @@
|
|
|
25
25
|
"import": "./lib/index.js",
|
|
26
26
|
"default": "./lib/index.js"
|
|
27
27
|
},
|
|
28
|
-
"./is-valid-secret": {
|
|
29
|
-
"types": "./lib/is-valid-secret.d.ts",
|
|
30
|
-
"source": "./src/is-valid-secret.ts",
|
|
31
|
-
"require": "./lib/is-valid-secret.cjs",
|
|
32
|
-
"node": {
|
|
33
|
-
"import": "./lib/is-valid-secret.cjs.js"
|
|
34
|
-
},
|
|
35
|
-
"import": "./lib/is-valid-secret.js",
|
|
36
|
-
"default": "./lib/is-valid-secret.js"
|
|
37
|
-
},
|
|
38
|
-
"./preview-url": {
|
|
39
|
-
"types": "./lib/preview-url.d.ts",
|
|
40
|
-
"source": "./src/preview-url.ts",
|
|
41
|
-
"require": "./lib/preview-url.cjs",
|
|
42
|
-
"node": {
|
|
43
|
-
"import": "./lib/preview-url.cjs.js"
|
|
44
|
-
},
|
|
45
|
-
"import": "./lib/preview-url.js",
|
|
46
|
-
"default": "./lib/preview-url.js"
|
|
47
|
-
},
|
|
48
28
|
"./package.json": "./package.json"
|
|
49
29
|
},
|
|
50
30
|
"main": "./lib/index.cjs",
|
package/src/Iframe.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import {Box, Card, Container, Flex, Spinner, Stack, Text, usePrefersReducedMotio
|
|
|
4
4
|
import {AnimatePresence, motion, MotionConfig} from 'framer-motion'
|
|
5
5
|
import React, {forwardRef, useCallback, useDeferredValue, useEffect, useRef, useState} from 'react'
|
|
6
6
|
import {HTMLAttributeReferrerPolicy} from 'react'
|
|
7
|
-
import {
|
|
7
|
+
import {SanityDocument} from 'sanity'
|
|
8
8
|
|
|
9
9
|
import {UrlResolver} from './defineUrlResolver'
|
|
10
10
|
import {GetUrlSecret} from './GetUrlSecret'
|
|
@@ -36,7 +36,7 @@ const MotionFlex = motion(Flex)
|
|
|
36
36
|
|
|
37
37
|
export interface IframeProps {
|
|
38
38
|
document: {
|
|
39
|
-
displayed:
|
|
39
|
+
displayed: SanityDocument
|
|
40
40
|
}
|
|
41
41
|
options: IframeOptions
|
|
42
42
|
}
|
|
@@ -272,7 +272,7 @@ function ReloadOnRevision(props: ReloadOnRevisionProps) {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
interface AsyncUrlProps {
|
|
275
|
-
displayed:
|
|
275
|
+
displayed: SanityDocument
|
|
276
276
|
url: UrlResolver
|
|
277
277
|
urlSecretId?: UrlSecretId
|
|
278
278
|
setDisplayUrl: (url: UrlState) => void
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {SanityDocument} from 'sanity'
|
|
2
2
|
|
|
3
3
|
import {MissingSlug, UrlState} from './types'
|
|
4
4
|
|
|
5
5
|
export type UrlResolver = (
|
|
6
|
-
document:
|
|
6
|
+
document: SanityDocument,
|
|
7
7
|
urlSecret: string | null | undefined,
|
|
8
8
|
signal?: AbortSignal,
|
|
9
9
|
) => UrlState | Promise<UrlState>
|
package/src/previewUrl.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* other actions like "Review changes" and "Inspect"
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {definePlugin} from 'sanity'
|
|
6
|
+
import {definePlugin, SanityDocument} from 'sanity'
|
|
7
7
|
|
|
8
8
|
import {defineUrlResolver, DefineUrlResolverOptions} from './defineUrlResolver'
|
|
9
9
|
import {
|
|
@@ -49,7 +49,7 @@ export const previewUrl = definePlugin<ProductionUrlOptions>(
|
|
|
49
49
|
urlSecret = data?.secret ? data.secret : await patchUrlSecret(client, urlSecretId)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const url = urlResolver(document, urlSecret)
|
|
52
|
+
const url = urlResolver(document as SanityDocument, urlSecret)
|
|
53
53
|
if (url) {
|
|
54
54
|
return url === MissingSlug ? prev : url
|
|
55
55
|
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
var name = "sanity-plugin-iframe-pane";
|
|
2
|
-
const SECRET_TTL = 60 * 60;
|
|
3
|
-
const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
|
|
4
|
-
const tag = name;
|
|
5
|
-
const apiVersion = "2023-08-08";
|
|
6
|
-
async function isValidSecret(client, urlSecretId, urlSecret) {
|
|
7
|
-
if (!urlSecret) {
|
|
8
|
-
throw new TypeError("`urlSecret` is required");
|
|
9
|
-
}
|
|
10
|
-
if (!urlSecretId) {
|
|
11
|
-
throw new TypeError("`urlSecretId` is required");
|
|
12
|
-
}
|
|
13
|
-
if (!urlSecretId.includes(".")) {
|
|
14
|
-
throw new TypeError("`urlSecretId` must have a dot prefix, `".concat(urlSecretId, "` is not secure, add a prefix, for example `preview.").concat(urlSecretId, "` "));
|
|
15
|
-
}
|
|
16
|
-
if (!client) {
|
|
17
|
-
throw new TypeError("`client` is required");
|
|
18
|
-
}
|
|
19
|
-
if (!client.config().token) {
|
|
20
|
-
throw new TypeError("`client` must have a `token` specified");
|
|
21
|
-
}
|
|
22
|
-
const customClient = client.withConfig({
|
|
23
|
-
apiVersion,
|
|
24
|
-
useCdn: false,
|
|
25
|
-
perspective: "raw"
|
|
26
|
-
});
|
|
27
|
-
const data = await customClient.fetch(fetchSecretQuery, {
|
|
28
|
-
id: urlSecretId
|
|
29
|
-
}, {
|
|
30
|
-
tag
|
|
31
|
-
});
|
|
32
|
-
return (data == null ? void 0 : data.secret) === urlSecret;
|
|
33
|
-
}
|
|
34
|
-
export { SECRET_TTL, apiVersion, fetchSecretQuery, isValidSecret, tag };
|
|
35
|
-
//# sourceMappingURL=is-valid-secret-57fea7e5.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-valid-secret-57fea7e5.js","sources":["../../src/isValidSecret.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","isValidSecret","client","urlSecretId","urlSecret","TypeError","includes","config","token","customClient","withConfig","useCdn","perspective","data","fetch","id","secret"],"mappings":";AAKO,MAAMA,aAAa,EAAK,GAAA,EAAA;AAElB,MAAAC,gBAAA,GAAA,sEAAAC,MAAA,CAA0FF,UAAA,6BAAA;AAMhG,MAAMG,GAAM,GAAAC,IAAA;AAEZ,MAAMC,UAAa,GAAA,YAAA;AAgBJ,eAAAC,aAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,SACkB,EAAA;EAClB,IAAI,CAACA,SAAW,EAAA;IACR,MAAA,IAAIC,UAAU,yBAAyB,CAAA;EAC/C;EACA,IAAI,CAACF,WAAa,EAAA;IACV,MAAA,IAAIE,UAAU,2BAA2B,CAAA;EACjD;EACA,IAAI,CAACF,WAAA,CAAYG,QAAS,CAAA,GAAG,CAAG,EAAA;IAC9B,MAAM,IAAID,SAAA,2CAAAR,MAAA,CACqCM,WAAoE,0DAAAN,MAAA,CAAAM,WAAA,OAAA,CACnH;EACF;EACA,IAAI,CAACD,MAAQ,EAAA;IACL,MAAA,IAAIG,UAAU,sBAAsB,CAAA;EAC5C;EACA,IAAI,CAACH,MAAA,CAAOK,MAAO,CAAA,CAAA,CAAEC,KAAO,EAAA;IACpB,MAAA,IAAIH,UAAU,wCAAwC,CAAA;EAC9D;EAEM,MAAAI,YAAA,GAAeP,OAAOQ,UAAW,CAAA;IACrCV,UAAA;IACAW,MAAQ,EAAA,KAAA;IACRC,WAAa,EAAA;EAAA,CACd,CAAA;EACK,MAAAC,IAAA,GAAO,MAAMJ,YAAa,CAAAK,KAAA,CAC9BlB,gBAAA,EACA;IAACmB,IAAIZ;EAAW,CAAA,EAChB;IAACL;EAAG,CAAA,CACN;EAEA,OAAA,CAAOe,6BAAMG,MAAW,MAAAZ,SAAA;AAC1B;"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var name = "sanity-plugin-iframe-pane";
|
|
4
|
-
const SECRET_TTL = 60 * 60;
|
|
5
|
-
const fetchSecretQuery = /* groq */"*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ".concat(SECRET_TTL, "][0]{secret, _updatedAt}");
|
|
6
|
-
const tag = name;
|
|
7
|
-
const apiVersion = "2023-08-08";
|
|
8
|
-
async function isValidSecret(client, urlSecretId, urlSecret) {
|
|
9
|
-
if (!urlSecret) {
|
|
10
|
-
throw new TypeError("`urlSecret` is required");
|
|
11
|
-
}
|
|
12
|
-
if (!urlSecretId) {
|
|
13
|
-
throw new TypeError("`urlSecretId` is required");
|
|
14
|
-
}
|
|
15
|
-
if (!urlSecretId.includes(".")) {
|
|
16
|
-
throw new TypeError("`urlSecretId` must have a dot prefix, `".concat(urlSecretId, "` is not secure, add a prefix, for example `preview.").concat(urlSecretId, "` "));
|
|
17
|
-
}
|
|
18
|
-
if (!client) {
|
|
19
|
-
throw new TypeError("`client` is required");
|
|
20
|
-
}
|
|
21
|
-
if (!client.config().token) {
|
|
22
|
-
throw new TypeError("`client` must have a `token` specified");
|
|
23
|
-
}
|
|
24
|
-
const customClient = client.withConfig({
|
|
25
|
-
apiVersion,
|
|
26
|
-
useCdn: false,
|
|
27
|
-
perspective: "raw"
|
|
28
|
-
});
|
|
29
|
-
const data = await customClient.fetch(fetchSecretQuery, {
|
|
30
|
-
id: urlSecretId
|
|
31
|
-
}, {
|
|
32
|
-
tag
|
|
33
|
-
});
|
|
34
|
-
return (data == null ? void 0 : data.secret) === urlSecret;
|
|
35
|
-
}
|
|
36
|
-
exports.SECRET_TTL = SECRET_TTL;
|
|
37
|
-
exports.apiVersion = apiVersion;
|
|
38
|
-
exports.fetchSecretQuery = fetchSecretQuery;
|
|
39
|
-
exports.isValidSecret = isValidSecret;
|
|
40
|
-
exports.tag = tag;
|
|
41
|
-
//# sourceMappingURL=is-valid-secret-7b704c76.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-valid-secret-7b704c76.cjs","sources":["../../src/isValidSecret.tsx"],"sourcesContent":["import {name} from '../package.json'\n\nexport type UrlSecretId = `${string}.${string}`\n\n// updated within the hour, if it's older it'll create a new secret or return null\nexport const SECRET_TTL = 60 * 60\n\nexport const fetchSecretQuery = /* groq */ `*[_id == $id && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{secret, _updatedAt}`\nexport type FetchSecretResponse = {\n secret: string | null\n _updatedAt: string | null\n} | null\n\nexport const tag = name\n\nexport const apiVersion = '2023-08-08'\n\nexport type SanityClientLike = {\n config(): {token?: string}\n withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike\n fetch<\n R,\n Q = {\n [key: string]: any\n },\n >(\n query: string,\n params: Q,\n options: {tag?: string},\n ): Promise<R>\n}\nexport async function isValidSecret(\n client: SanityClientLike,\n urlSecretId: UrlSecretId,\n urlSecret: string,\n): Promise<boolean> {\n if (!urlSecret) {\n throw new TypeError('`urlSecret` is required')\n }\n if (!urlSecretId) {\n throw new TypeError('`urlSecretId` is required')\n }\n if (!urlSecretId.includes('.')) {\n throw new TypeError(\n `\\`urlSecretId\\` must have a dot prefix, \\`${urlSecretId}\\` is not secure, add a prefix, for example \\`preview.${urlSecretId}\\` `,\n )\n }\n if (!client) {\n throw new TypeError('`client` is required')\n }\n if (!client.config().token) {\n throw new TypeError('`client` must have a `token` specified')\n }\n\n const customClient = client.withConfig({\n apiVersion,\n useCdn: false,\n perspective: 'raw',\n })\n const data = await customClient.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n\n return data?.secret === urlSecret\n}\n"],"names":["SECRET_TTL","fetchSecretQuery","concat","tag","name","apiVersion","isValidSecret","client","urlSecretId","urlSecret","TypeError","includes","config","token","customClient","withConfig","useCdn","perspective","data","fetch","id","secret"],"mappings":";;;AAKO,MAAMA,aAAa,EAAK,GAAA,EAAA;AAElB,MAAAC,gBAAA,GAAA,sEAAAC,MAAA,CAA0FF,UAAA,6BAAA;AAMhG,MAAMG,GAAM,GAAAC,IAAA;AAEZ,MAAMC,UAAa,GAAA,YAAA;AAgBJ,eAAAC,aAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,SACkB,EAAA;EAClB,IAAI,CAACA,SAAW,EAAA;IACR,MAAA,IAAIC,UAAU,yBAAyB,CAAA;EAC/C;EACA,IAAI,CAACF,WAAa,EAAA;IACV,MAAA,IAAIE,UAAU,2BAA2B,CAAA;EACjD;EACA,IAAI,CAACF,WAAA,CAAYG,QAAS,CAAA,GAAG,CAAG,EAAA;IAC9B,MAAM,IAAID,SAAA,2CAAAR,MAAA,CACqCM,WAAoE,0DAAAN,MAAA,CAAAM,WAAA,OAAA,CACnH;EACF;EACA,IAAI,CAACD,MAAQ,EAAA;IACL,MAAA,IAAIG,UAAU,sBAAsB,CAAA;EAC5C;EACA,IAAI,CAACH,MAAA,CAAOK,MAAO,CAAA,CAAA,CAAEC,KAAO,EAAA;IACpB,MAAA,IAAIH,UAAU,wCAAwC,CAAA;EAC9D;EAEM,MAAAI,YAAA,GAAeP,OAAOQ,UAAW,CAAA;IACrCV,UAAA;IACAW,MAAQ,EAAA,KAAA;IACRC,WAAa,EAAA;EAAA,CACd,CAAA;EACK,MAAAC,IAAA,GAAO,MAAMJ,YAAa,CAAAK,KAAA,CAC9BlB,gBAAA,EACA;IAACmB,IAAIZ;EAAW,CAAA,EAChB;IAACL;EAAG,CAAA,CACN;EAEA,OAAA,CAAOe,6BAAMG,MAAW,MAAAZ,SAAA;AAC1B;;;;;"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { tag, SECRET_TTL } from './is-valid-secret-57fea7e5.js';
|
|
2
|
-
function getExpiresAt(_updatedAt) {
|
|
3
|
-
return new Date(_updatedAt.getTime() + 1e3 * SECRET_TTL);
|
|
4
|
-
}
|
|
5
|
-
function generateUrlSecret() {
|
|
6
|
-
if (typeof crypto !== "undefined") {
|
|
7
|
-
const array = new Uint8Array(16);
|
|
8
|
-
crypto.getRandomValues(array);
|
|
9
|
-
let key = "";
|
|
10
|
-
for (let i = 0; i < array.length; i++) {
|
|
11
|
-
key += array[i].toString(16).padStart(2, "0");
|
|
12
|
-
}
|
|
13
|
-
key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
|
|
14
|
-
return key;
|
|
15
|
-
}
|
|
16
|
-
return Math.random().toString(36).slice(2);
|
|
17
|
-
}
|
|
18
|
-
async function patchUrlSecret(client, urlSecretId, signal) {
|
|
19
|
-
const newSecret = generateUrlSecret();
|
|
20
|
-
const patch = client.patch(urlSecretId).set({
|
|
21
|
-
secret: newSecret
|
|
22
|
-
});
|
|
23
|
-
await client.transaction().createIfNotExists({
|
|
24
|
-
_id: urlSecretId,
|
|
25
|
-
_type: urlSecretId
|
|
26
|
-
}).patch(patch).commit({
|
|
27
|
-
tag,
|
|
28
|
-
signal
|
|
29
|
-
});
|
|
30
|
-
return newSecret;
|
|
31
|
-
}
|
|
32
|
-
const MissingSlug = Symbol("MissingSlug");
|
|
33
|
-
export { MissingSlug, getExpiresAt, patchUrlSecret };
|
|
34
|
-
//# sourceMappingURL=types-107599a1.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-107599a1.js","sources":["../../src/utils.ts","../../src/types.ts"],"sourcesContent":["import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n"],"names":["getExpiresAt","_updatedAt","Date","getTime","SECRET_TTL","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","tag","MissingSlug","Symbol"],"mappings":";AAIO,SAASA,aAAaC,UAAkB,EAAA;EAC7C,OAAO,IAAIC,IAAK,CAAAD,UAAA,CAAWE,OAAQ,CAAA,CAAA,GAAI,MAAOC,UAAU,CAAA;AAC1D;AAEA,SAASC,iBAAoBA,CAAA,EAAA;EAEvB,IAAA,OAAOC,WAAW,WAAa,EAAA;IAE3B,MAAAC,KAAA,GAAQ,IAAIC,UAAA,CAAW,EAAE,CAAA;IAC/BF,MAAA,CAAOG,gBAAgBF,KAAK,CAAA;IAG5B,IAAIG,GAAM,GAAA,EAAA;IACV,KAAA,IAASC,CAAI,GAAA,CAAA,EAAGA,CAAI,GAAAJ,KAAA,CAAMK,QAAQD,CAAK,EAAA,EAAA;MAE9BD,GAAA,IAAAH,KAAA,CAAMI,CAAC,CAAE,CAAAE,QAAA,CAAS,EAAE,CAAE,CAAAC,QAAA,CAAS,GAAG,GAAG,CAAA;IAC9C;IAGAJ,GAAA,GAAMK,IAAK,CAAAL,GAAG,CAAE,CAAAM,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,SAAS,EAAE,CAAA;IAEpE,OAAAN,GAAA;EACT;EAEA,OAAOO,KAAKC,MAAO,EAAA,CAAEL,SAAS,EAAE,CAAA,CAAEM,MAAM,CAAC,CAAA;AAC3C;AAEsB,eAAAC,cAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,MACiB,EAAA;EACjB,MAAMC,YAAYnB,iBAAkB,EAAA;EAC9B,MAAAoB,KAAA,GAAQJ,OAAOI,KAAM,CAAAH,WAAW,EAAEI,GAAI,CAAA;IAACC,MAAQ,EAAAH;EAAA,CAAU,CAAA;EAC/D,MAAMH,OACHO,WAAY,EAAA,CACZC,kBAAkB;IAACC,GAAA,EAAKR;IAAaS,KAAO,EAAAT;EAAY,CAAA,CAAA,CACxDG,MAAMA,KAAK,CAAA,CACXO,OAAO;IAACC,GAAA;IAAKV;GAAO,CAAA;EAChB,OAAAC,SAAA;AACT;AC5Ca,MAAAU,WAAA,GAAcC,OAAO,aAAa,CAAA;"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var isValidSecret = require('./is-valid-secret-7b704c76.cjs');
|
|
4
|
-
function getExpiresAt(_updatedAt) {
|
|
5
|
-
return new Date(_updatedAt.getTime() + 1e3 * isValidSecret.SECRET_TTL);
|
|
6
|
-
}
|
|
7
|
-
function generateUrlSecret() {
|
|
8
|
-
if (typeof crypto !== "undefined") {
|
|
9
|
-
const array = new Uint8Array(16);
|
|
10
|
-
crypto.getRandomValues(array);
|
|
11
|
-
let key = "";
|
|
12
|
-
for (let i = 0; i < array.length; i++) {
|
|
13
|
-
key += array[i].toString(16).padStart(2, "0");
|
|
14
|
-
}
|
|
15
|
-
key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, "");
|
|
16
|
-
return key;
|
|
17
|
-
}
|
|
18
|
-
return Math.random().toString(36).slice(2);
|
|
19
|
-
}
|
|
20
|
-
async function patchUrlSecret(client, urlSecretId, signal) {
|
|
21
|
-
const newSecret = generateUrlSecret();
|
|
22
|
-
const patch = client.patch(urlSecretId).set({
|
|
23
|
-
secret: newSecret
|
|
24
|
-
});
|
|
25
|
-
await client.transaction().createIfNotExists({
|
|
26
|
-
_id: urlSecretId,
|
|
27
|
-
_type: urlSecretId
|
|
28
|
-
}).patch(patch).commit({
|
|
29
|
-
tag: isValidSecret.tag,
|
|
30
|
-
signal
|
|
31
|
-
});
|
|
32
|
-
return newSecret;
|
|
33
|
-
}
|
|
34
|
-
const MissingSlug = Symbol("MissingSlug");
|
|
35
|
-
exports.MissingSlug = MissingSlug;
|
|
36
|
-
exports.getExpiresAt = getExpiresAt;
|
|
37
|
-
exports.patchUrlSecret = patchUrlSecret;
|
|
38
|
-
//# sourceMappingURL=types-4a29b6ac.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-4a29b6ac.cjs","sources":["../../src/utils.ts","../../src/types.ts"],"sourcesContent":["import type {SanityClient} from 'sanity'\n\nimport {SECRET_TTL, tag, UrlSecretId} from './isValidSecret'\n\nexport function getExpiresAt(_updatedAt: Date) {\n return new Date(_updatedAt.getTime() + 1000 * SECRET_TTL)\n}\n\nfunction generateUrlSecret() {\n // Try using WebCrypto if available\n if (typeof crypto !== 'undefined') {\n // Generate a random array of 16 bytes\n const array = new Uint8Array(16)\n crypto.getRandomValues(array)\n\n // Convert the array to a URL-safe string\n let key = ''\n for (let i = 0; i < array.length; i++) {\n // Convert each byte to a 2-digit hexadecimal number\n key += array[i].toString(16).padStart(2, '0')\n }\n\n // Replace '+' and '/' from base64url to '-' and '_'\n key = btoa(key).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]+$/, '')\n\n return key\n }\n // If not fallback to Math.random\n return Math.random().toString(36).slice(2)\n}\n\nexport async function patchUrlSecret(\n client: SanityClient,\n urlSecretId: UrlSecretId,\n signal?: AbortSignal,\n): Promise<string> {\n const newSecret = generateUrlSecret()\n const patch = client.patch(urlSecretId).set({secret: newSecret})\n await client\n .transaction()\n .createIfNotExists({_id: urlSecretId, _type: urlSecretId})\n .patch(patch)\n .commit({tag, signal})\n return newSecret\n}\n","export const MissingSlug = Symbol('MissingSlug')\n\nexport type UrlState = string | typeof MissingSlug\n\nexport type IframeSizeKey = keyof SizeProps\n\nexport type Size = 'desktop' | 'mobile'\n\nexport type SizeProps = {\n // eslint-disable-next-line no-unused-vars\n [key in Size]: {\n width: string | number\n height: string | number\n }\n}\n\nexport type SetError = (error: unknown) => void\n"],"names":["getExpiresAt","_updatedAt","Date","getTime","SECRET_TTL","generateUrlSecret","crypto","array","Uint8Array","getRandomValues","key","i","length","toString","padStart","btoa","replace","Math","random","slice","patchUrlSecret","client","urlSecretId","signal","newSecret","patch","set","secret","transaction","createIfNotExists","_id","_type","commit","tag","MissingSlug","Symbol"],"mappings":";;;AAIO,SAASA,aAAaC,UAAkB,EAAA;EAC7C,OAAO,IAAIC,IAAK,CAAAD,UAAA,CAAWE,OAAQ,CAAA,CAAA,GAAI,MAAOC,aAAAA,CAAAA,UAAU,CAAA;AAC1D;AAEA,SAASC,iBAAoBA,CAAA,EAAA;EAEvB,IAAA,OAAOC,WAAW,WAAa,EAAA;IAE3B,MAAAC,KAAA,GAAQ,IAAIC,UAAA,CAAW,EAAE,CAAA;IAC/BF,MAAA,CAAOG,gBAAgBF,KAAK,CAAA;IAG5B,IAAIG,GAAM,GAAA,EAAA;IACV,KAAA,IAASC,CAAI,GAAA,CAAA,EAAGA,CAAI,GAAAJ,KAAA,CAAMK,QAAQD,CAAK,EAAA,EAAA;MAE9BD,GAAA,IAAAH,KAAA,CAAMI,CAAC,CAAE,CAAAE,QAAA,CAAS,EAAE,CAAE,CAAAC,QAAA,CAAS,GAAG,GAAG,CAAA;IAC9C;IAGAJ,GAAA,GAAMK,IAAK,CAAAL,GAAG,CAAE,CAAAM,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,KAAO,EAAA,GAAG,CAAE,CAAAA,OAAA,CAAQ,SAAS,EAAE,CAAA;IAEpE,OAAAN,GAAA;EACT;EAEA,OAAOO,KAAKC,MAAO,EAAA,CAAEL,SAAS,EAAE,CAAA,CAAEM,MAAM,CAAC,CAAA;AAC3C;AAEsB,eAAAC,cAAAA,CACpBC,MACA,EAAAC,WAAA,EACAC,MACiB,EAAA;EACjB,MAAMC,YAAYnB,iBAAkB,EAAA;EAC9B,MAAAoB,KAAA,GAAQJ,OAAOI,KAAM,CAAAH,WAAW,EAAEI,GAAI,CAAA;IAACC,MAAQ,EAAAH;EAAA,CAAU,CAAA;EAC/D,MAAMH,OACHO,WAAY,EAAA,CACZC,kBAAkB;IAACC,GAAA,EAAKR;IAAaS,KAAO,EAAAT;EAAY,CAAA,CAAA,CACxDG,MAAMA,KAAK,CAAA,CACXO,OAAO;IAAAC,GAAA,EAACA,aAAA,CAAAA,GAAA;IAAKV;GAAO,CAAA;EAChB,OAAAC,SAAA;AACT;AC5Ca,MAAAU,WAAA,GAAcC,OAAO,aAAa,CAAA;;;"}
|
package/lib/is-valid-secret.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-valid-secret.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/lib/is-valid-secret.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export declare const apiVersion = '2023-08-08'
|
|
2
|
-
|
|
3
|
-
export declare const fetchSecretQuery: string
|
|
4
|
-
|
|
5
|
-
export declare type FetchSecretResponse = {
|
|
6
|
-
secret: string | null
|
|
7
|
-
_updatedAt: string | null
|
|
8
|
-
} | null
|
|
9
|
-
|
|
10
|
-
export declare function isValidSecret(
|
|
11
|
-
client: SanityClientLike,
|
|
12
|
-
urlSecretId: UrlSecretId,
|
|
13
|
-
urlSecret: string,
|
|
14
|
-
): Promise<boolean>
|
|
15
|
-
|
|
16
|
-
export declare type SanityClientLike = {
|
|
17
|
-
config(): {
|
|
18
|
-
token?: string
|
|
19
|
-
}
|
|
20
|
-
withConfig(config: {apiVersion?: string; useCdn?: boolean; perspective: 'raw'}): SanityClientLike
|
|
21
|
-
fetch<
|
|
22
|
-
R,
|
|
23
|
-
Q = {
|
|
24
|
-
[key: string]: any
|
|
25
|
-
},
|
|
26
|
-
>(
|
|
27
|
-
query: string,
|
|
28
|
-
params: Q,
|
|
29
|
-
options: {
|
|
30
|
-
tag?: string
|
|
31
|
-
},
|
|
32
|
-
): Promise<R>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export declare const SECRET_TTL: number
|
|
36
|
-
|
|
37
|
-
export declare const tag: string
|
|
38
|
-
|
|
39
|
-
export declare type UrlSecretId = `${string}.${string}`
|
|
40
|
-
|
|
41
|
-
export {}
|
package/lib/is-valid-secret.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-valid-secret.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/lib/preview-url.cjs
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
var sanity = require('sanity');
|
|
7
|
-
var types = require('./_chunks/types-4a29b6ac.cjs');
|
|
8
|
-
var isValidSecret = require('./_chunks/is-valid-secret-7b704c76.cjs');
|
|
9
|
-
function defineUrlResolver(options) {
|
|
10
|
-
const {
|
|
11
|
-
base,
|
|
12
|
-
requiresSlug = []
|
|
13
|
-
} = options;
|
|
14
|
-
return (document, urlSecret) => {
|
|
15
|
-
var _a;
|
|
16
|
-
const url = new URL(base, location.origin);
|
|
17
|
-
url.searchParams.set("type", document._type);
|
|
18
|
-
const slug = (_a = document == null ? void 0 : document.slug) == null ? void 0 : _a.current;
|
|
19
|
-
if (slug) {
|
|
20
|
-
url.searchParams.set("slug", slug);
|
|
21
|
-
} else if (requiresSlug.includes(document._type)) {
|
|
22
|
-
return types.MissingSlug;
|
|
23
|
-
}
|
|
24
|
-
if (urlSecret) {
|
|
25
|
-
url.searchParams.set("secret", urlSecret);
|
|
26
|
-
}
|
|
27
|
-
return url.toString();
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const previewUrl = sanity.definePlugin(_ref => {
|
|
31
|
-
let {
|
|
32
|
-
urlSecretId,
|
|
33
|
-
base,
|
|
34
|
-
matchTypes,
|
|
35
|
-
requiresSlug
|
|
36
|
-
} = _ref;
|
|
37
|
-
if (!base) {
|
|
38
|
-
throw new TypeError("`base` is required");
|
|
39
|
-
}
|
|
40
|
-
const urlResolver = defineUrlResolver({
|
|
41
|
-
base,
|
|
42
|
-
requiresSlug
|
|
43
|
-
});
|
|
44
|
-
return {
|
|
45
|
-
name: "previewUrl",
|
|
46
|
-
document: {
|
|
47
|
-
productionUrl: async (prev, _ref2) => {
|
|
48
|
-
let {
|
|
49
|
-
document,
|
|
50
|
-
getClient
|
|
51
|
-
} = _ref2;
|
|
52
|
-
if ((matchTypes == null ? void 0 : matchTypes.length) && !matchTypes.includes(document._type)) {
|
|
53
|
-
return prev;
|
|
54
|
-
}
|
|
55
|
-
let urlSecret = null;
|
|
56
|
-
if (urlSecretId) {
|
|
57
|
-
const client = getClient({
|
|
58
|
-
apiVersion: isValidSecret.apiVersion
|
|
59
|
-
});
|
|
60
|
-
const data = await client.fetch(isValidSecret.fetchSecretQuery, {
|
|
61
|
-
id: urlSecretId
|
|
62
|
-
}, {
|
|
63
|
-
tag: isValidSecret.tag
|
|
64
|
-
});
|
|
65
|
-
urlSecret = (data == null ? void 0 : data.secret) ? data.secret : await types.patchUrlSecret(client, urlSecretId);
|
|
66
|
-
}
|
|
67
|
-
const url = urlResolver(document, urlSecret);
|
|
68
|
-
if (url) {
|
|
69
|
-
return url === types.MissingSlug ? prev : url;
|
|
70
|
-
}
|
|
71
|
-
return prev;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
exports.previewUrl = previewUrl;
|
|
77
|
-
//# sourceMappingURL=preview-url.cjs.map
|
package/lib/preview-url.cjs.js
DELETED
package/lib/preview-url.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-url.cjs","sources":["../src/defineUrlResolver.tsx","../src/previewUrl.ts"],"sourcesContent":["import type {SanityDocumentLike} from 'sanity'\n\nimport {MissingSlug, UrlState} from './types'\n\nexport type UrlResolver = (\n document: SanityDocumentLike,\n urlSecret: string | null | undefined,\n signal?: AbortSignal,\n) => UrlState | Promise<UrlState>\n\nexport interface DefineUrlResolverOptions {\n base: string | URL\n requiresSlug?: string[]\n}\nexport function defineUrlResolver(options: DefineUrlResolverOptions): UrlResolver {\n const {base, requiresSlug = []} = options\n return (document, urlSecret) => {\n const url = new URL(base, location.origin)\n url.searchParams.set('type', document._type)\n const slug = (document?.slug as any)?.current\n if (slug) {\n url.searchParams.set('slug', slug)\n } else if (requiresSlug.includes(document._type)) {\n return MissingSlug\n }\n if (urlSecret) {\n url.searchParams.set('secret', urlSecret)\n }\n return url.toString()\n }\n}\n","/**\n * This plugin sets up the \"Open preview (CTRL + ALT + O)\" in the dropdown menu that hosts\n * other actions like \"Review changes\" and \"Inspect\"\n */\n\nimport {definePlugin} from 'sanity'\n\nimport {defineUrlResolver, DefineUrlResolverOptions} from './defineUrlResolver'\nimport {\n apiVersion,\n fetchSecretQuery,\n FetchSecretResponse,\n tag,\n type UrlSecretId,\n} from './isValidSecret'\nimport {MissingSlug} from './types'\nimport {patchUrlSecret} from './utils'\n\nexport type {DefineUrlResolverOptions, UrlSecretId}\n\nexport interface ProductionUrlOptions extends DefineUrlResolverOptions {\n matchTypes?: string[]\n urlSecretId?: UrlSecretId\n}\n\nexport const previewUrl = definePlugin<ProductionUrlOptions>(\n ({urlSecretId, base, matchTypes, requiresSlug}) => {\n if (!base) {\n throw new TypeError('`base` is required')\n }\n\n const urlResolver = defineUrlResolver({base, requiresSlug})\n return {\n name: 'previewUrl',\n document: {\n productionUrl: async (prev, {document, getClient}) => {\n if (matchTypes?.length && !matchTypes.includes(document._type)) {\n return prev\n }\n\n let urlSecret: string | null = null\n if (urlSecretId) {\n const client = getClient({apiVersion})\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n urlSecret = data?.secret ? data.secret : await patchUrlSecret(client, urlSecretId)\n }\n\n const url = urlResolver(document, urlSecret)\n if (url) {\n return url === MissingSlug ? prev : url\n }\n\n return prev\n },\n },\n }\n },\n)\n"],"names":["defineUrlResolver","options","base","requiresSlug","document","urlSecret","_a","url","URL","location","origin","searchParams","set","_type","slug","current","includes","MissingSlug","toString","previewUrl","definePlugin","_ref","urlSecretId","matchTypes","TypeError","urlResolver","name","productionUrl","prev","_ref2","getClient","length","client","apiVersion","data","fetch","fetchSecretQuery","id","tag","secret","patchUrlSecret"],"mappings":";;;;;;;;AAcO,SAASA,kBAAkBC,OAAgD,EAAA;EAChF,MAAM;IAACC,IAAA;IAAMC,YAAe,GAAA;GAAM,GAAAF,OAAA;EAC3B,OAAA,CAACG,UAAUC,SAAc,KAAA;IAhBlC,IAAAC,EAAA;IAiBI,MAAMC,GAAM,GAAA,IAAIC,GAAI,CAAAN,IAAA,EAAMO,SAASC,MAAM,CAAA;IACzCH,GAAA,CAAII,YAAa,CAAAC,GAAA,CAAI,MAAQ,EAAAR,QAAA,CAASS,KAAK,CAAA;IACrC,MAAAC,IAAA,GAAA,CAAQR,EAAU,GAAAF,QAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,QAAA,CAAAU,IAAA,KAAV,IAAwB,GAAA,KAAA,CAAA,GAAAR,EAAA,CAAAS,OAAA;IACtC,IAAID,IAAM,EAAA;MACJP,GAAA,CAAAI,YAAA,CAAaC,GAAI,CAAA,MAAA,EAAQE,IAAI,CAAA;IACxB,CAAA,MAAA,IAAAX,YAAA,CAAaa,QAAS,CAAAZ,QAAA,CAASS,KAAK,CAAG,EAAA;MACzC,OAAAI,iBAAA;IACT;IACA,IAAIZ,SAAW,EAAA;MACTE,GAAA,CAAAI,YAAA,CAAaC,GAAI,CAAA,QAAA,EAAUP,SAAS,CAAA;IAC1C;IACA,OAAOE,IAAIW,QAAS,EAAA;EAAA,CACtB;AACF;ACLO,MAAMC,UAAa,GAAAC,MAAA,CAAAA,YAAA,CACxBC,IAAA,IAAmD;EAAA,IAAlD;IAACC,WAAA;IAAapB,IAAM;IAAAqB,UAAA;IAAYpB;GAAkB,GAAAkB,IAAA;EACjD,IAAI,CAACnB,IAAM,EAAA;IACH,MAAA,IAAIsB,UAAU,oBAAoB,CAAA;EAC1C;EAEA,MAAMC,WAAc,GAAAzB,iBAAA,CAAkB;IAACE,IAAA;IAAMC;EAAa,CAAA,CAAA;EACnD,OAAA;IACLuB,IAAM,EAAA,YAAA;IACNtB,QAAU,EAAA;MACRuB,eAAe,MAAAA,CAAOC,IAAA,EAAAC,KAAA,KAAgC;QAAA,IAA1B;UAACzB,QAAA;UAAU0B;SAAe,GAAAD,KAAA;QACpD,IAAA,CAAIN,yCAAYQ,MAAU,KAAA,CAACR,WAAWP,QAAS,CAAAZ,QAAA,CAASS,KAAK,CAAG,EAAA;UACvD,OAAAe,IAAA;QACT;QAEA,IAAIvB,SAA2B,GAAA,IAAA;QAC/B,IAAIiB,WAAa,EAAA;UACf,MAAMU,MAAS,GAAAF,SAAA,CAAU;YAACG,UAAAA,EAAAA,aAAAA,CAAAA;UAAW,CAAA,CAAA;UAC/B,MAAAC,IAAA,GAAO,MAAMF,MAAO,CAAAG,KAAA,CACxBC,aAAA,CAAAA,gBAAA,EACA;YAACC,IAAIf;UAAW,CAAA,EAChB;YAAAgB,GAAA,EAACA;UAAG,CAAA,CACN;UACAjC,SAAA,GAAA,CAAY6B,6BAAMK,MAAS,IAAAL,IAAA,CAAKK,SAAS,MAAMC,KAAA,CAAAA,cAAA,CAAeR,QAAQV,WAAW,CAAA;QACnF;QAEM,MAAAf,GAAA,GAAMkB,WAAY,CAAArB,QAAA,EAAUC,SAAS,CAAA;QAC3C,IAAIE,GAAK,EAAA;UACA,OAAAA,GAAA,KAAQU,KAAAA,CAAAA,cAAcW,IAAO,GAAArB,GAAA;QACtC;QAEO,OAAAqB,IAAA;MACT;IACF;EAAA,CACF;AACF,CACF,CAAA;"}
|
package/lib/preview-url.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {Plugin as Plugin_2} from 'sanity'
|
|
2
|
-
|
|
3
|
-
export declare interface DefineUrlResolverOptions {
|
|
4
|
-
base: string | URL
|
|
5
|
-
requiresSlug?: string[]
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export declare const previewUrl: Plugin_2<ProductionUrlOptions>
|
|
9
|
-
|
|
10
|
-
export declare interface ProductionUrlOptions extends DefineUrlResolverOptions {
|
|
11
|
-
matchTypes?: string[]
|
|
12
|
-
urlSecretId?: UrlSecretId
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export declare type UrlSecretId = `${string}.${string}`
|
|
16
|
-
|
|
17
|
-
export {}
|
package/lib/preview-url.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { definePlugin } from 'sanity';
|
|
2
|
-
import { MissingSlug, patchUrlSecret } from './_chunks/types-107599a1.js';
|
|
3
|
-
import { apiVersion, fetchSecretQuery, tag } from './_chunks/is-valid-secret-57fea7e5.js';
|
|
4
|
-
function defineUrlResolver(options) {
|
|
5
|
-
const {
|
|
6
|
-
base,
|
|
7
|
-
requiresSlug = []
|
|
8
|
-
} = options;
|
|
9
|
-
return (document, urlSecret) => {
|
|
10
|
-
var _a;
|
|
11
|
-
const url = new URL(base, location.origin);
|
|
12
|
-
url.searchParams.set("type", document._type);
|
|
13
|
-
const slug = (_a = document == null ? void 0 : document.slug) == null ? void 0 : _a.current;
|
|
14
|
-
if (slug) {
|
|
15
|
-
url.searchParams.set("slug", slug);
|
|
16
|
-
} else if (requiresSlug.includes(document._type)) {
|
|
17
|
-
return MissingSlug;
|
|
18
|
-
}
|
|
19
|
-
if (urlSecret) {
|
|
20
|
-
url.searchParams.set("secret", urlSecret);
|
|
21
|
-
}
|
|
22
|
-
return url.toString();
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
const previewUrl = definePlugin(_ref => {
|
|
26
|
-
let {
|
|
27
|
-
urlSecretId,
|
|
28
|
-
base,
|
|
29
|
-
matchTypes,
|
|
30
|
-
requiresSlug
|
|
31
|
-
} = _ref;
|
|
32
|
-
if (!base) {
|
|
33
|
-
throw new TypeError("`base` is required");
|
|
34
|
-
}
|
|
35
|
-
const urlResolver = defineUrlResolver({
|
|
36
|
-
base,
|
|
37
|
-
requiresSlug
|
|
38
|
-
});
|
|
39
|
-
return {
|
|
40
|
-
name: "previewUrl",
|
|
41
|
-
document: {
|
|
42
|
-
productionUrl: async (prev, _ref2) => {
|
|
43
|
-
let {
|
|
44
|
-
document,
|
|
45
|
-
getClient
|
|
46
|
-
} = _ref2;
|
|
47
|
-
if ((matchTypes == null ? void 0 : matchTypes.length) && !matchTypes.includes(document._type)) {
|
|
48
|
-
return prev;
|
|
49
|
-
}
|
|
50
|
-
let urlSecret = null;
|
|
51
|
-
if (urlSecretId) {
|
|
52
|
-
const client = getClient({
|
|
53
|
-
apiVersion
|
|
54
|
-
});
|
|
55
|
-
const data = await client.fetch(fetchSecretQuery, {
|
|
56
|
-
id: urlSecretId
|
|
57
|
-
}, {
|
|
58
|
-
tag
|
|
59
|
-
});
|
|
60
|
-
urlSecret = (data == null ? void 0 : data.secret) ? data.secret : await patchUrlSecret(client, urlSecretId);
|
|
61
|
-
}
|
|
62
|
-
const url = urlResolver(document, urlSecret);
|
|
63
|
-
if (url) {
|
|
64
|
-
return url === MissingSlug ? prev : url;
|
|
65
|
-
}
|
|
66
|
-
return prev;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
export { previewUrl };
|
|
72
|
-
//# sourceMappingURL=preview-url.js.map
|
package/lib/preview-url.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-url.js","sources":["../src/defineUrlResolver.tsx","../src/previewUrl.ts"],"sourcesContent":["import type {SanityDocumentLike} from 'sanity'\n\nimport {MissingSlug, UrlState} from './types'\n\nexport type UrlResolver = (\n document: SanityDocumentLike,\n urlSecret: string | null | undefined,\n signal?: AbortSignal,\n) => UrlState | Promise<UrlState>\n\nexport interface DefineUrlResolverOptions {\n base: string | URL\n requiresSlug?: string[]\n}\nexport function defineUrlResolver(options: DefineUrlResolverOptions): UrlResolver {\n const {base, requiresSlug = []} = options\n return (document, urlSecret) => {\n const url = new URL(base, location.origin)\n url.searchParams.set('type', document._type)\n const slug = (document?.slug as any)?.current\n if (slug) {\n url.searchParams.set('slug', slug)\n } else if (requiresSlug.includes(document._type)) {\n return MissingSlug\n }\n if (urlSecret) {\n url.searchParams.set('secret', urlSecret)\n }\n return url.toString()\n }\n}\n","/**\n * This plugin sets up the \"Open preview (CTRL + ALT + O)\" in the dropdown menu that hosts\n * other actions like \"Review changes\" and \"Inspect\"\n */\n\nimport {definePlugin} from 'sanity'\n\nimport {defineUrlResolver, DefineUrlResolverOptions} from './defineUrlResolver'\nimport {\n apiVersion,\n fetchSecretQuery,\n FetchSecretResponse,\n tag,\n type UrlSecretId,\n} from './isValidSecret'\nimport {MissingSlug} from './types'\nimport {patchUrlSecret} from './utils'\n\nexport type {DefineUrlResolverOptions, UrlSecretId}\n\nexport interface ProductionUrlOptions extends DefineUrlResolverOptions {\n matchTypes?: string[]\n urlSecretId?: UrlSecretId\n}\n\nexport const previewUrl = definePlugin<ProductionUrlOptions>(\n ({urlSecretId, base, matchTypes, requiresSlug}) => {\n if (!base) {\n throw new TypeError('`base` is required')\n }\n\n const urlResolver = defineUrlResolver({base, requiresSlug})\n return {\n name: 'previewUrl',\n document: {\n productionUrl: async (prev, {document, getClient}) => {\n if (matchTypes?.length && !matchTypes.includes(document._type)) {\n return prev\n }\n\n let urlSecret: string | null = null\n if (urlSecretId) {\n const client = getClient({apiVersion})\n const data = await client.fetch<FetchSecretResponse>(\n fetchSecretQuery,\n {id: urlSecretId},\n {tag},\n )\n urlSecret = data?.secret ? data.secret : await patchUrlSecret(client, urlSecretId)\n }\n\n const url = urlResolver(document, urlSecret)\n if (url) {\n return url === MissingSlug ? prev : url\n }\n\n return prev\n },\n },\n }\n },\n)\n"],"names":["defineUrlResolver","options","base","requiresSlug","document","urlSecret","_a","url","URL","location","origin","searchParams","set","_type","slug","current","includes","MissingSlug","toString","previewUrl","definePlugin","_ref","urlSecretId","matchTypes","TypeError","urlResolver","name","productionUrl","prev","_ref2","getClient","length","client","apiVersion","data","fetch","fetchSecretQuery","id","tag","secret","patchUrlSecret"],"mappings":";;;AAcO,SAASA,kBAAkBC,OAAgD,EAAA;EAChF,MAAM;IAACC,IAAA;IAAMC,YAAe,GAAA;GAAM,GAAAF,OAAA;EAC3B,OAAA,CAACG,UAAUC,SAAc,KAAA;IAhBlC,IAAAC,EAAA;IAiBI,MAAMC,GAAM,GAAA,IAAIC,GAAI,CAAAN,IAAA,EAAMO,SAASC,MAAM,CAAA;IACzCH,GAAA,CAAII,YAAa,CAAAC,GAAA,CAAI,MAAQ,EAAAR,QAAA,CAASS,KAAK,CAAA;IACrC,MAAAC,IAAA,GAAA,CAAQR,EAAU,GAAAF,QAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAAA,QAAA,CAAAU,IAAA,KAAV,IAAwB,GAAA,KAAA,CAAA,GAAAR,EAAA,CAAAS,OAAA;IACtC,IAAID,IAAM,EAAA;MACJP,GAAA,CAAAI,YAAA,CAAaC,GAAI,CAAA,MAAA,EAAQE,IAAI,CAAA;IACxB,CAAA,MAAA,IAAAX,YAAA,CAAaa,QAAS,CAAAZ,QAAA,CAASS,KAAK,CAAG,EAAA;MACzC,OAAAI,WAAA;IACT;IACA,IAAIZ,SAAW,EAAA;MACTE,GAAA,CAAAI,YAAA,CAAaC,GAAI,CAAA,QAAA,EAAUP,SAAS,CAAA;IAC1C;IACA,OAAOE,IAAIW,QAAS,EAAA;EAAA,CACtB;AACF;ACLO,MAAMC,UAAa,GAAAC,YAAA,CACxBC,IAAA,IAAmD;EAAA,IAAlD;IAACC,WAAA;IAAapB,IAAM;IAAAqB,UAAA;IAAYpB;GAAkB,GAAAkB,IAAA;EACjD,IAAI,CAACnB,IAAM,EAAA;IACH,MAAA,IAAIsB,UAAU,oBAAoB,CAAA;EAC1C;EAEA,MAAMC,WAAc,GAAAzB,iBAAA,CAAkB;IAACE,IAAA;IAAMC;EAAa,CAAA,CAAA;EACnD,OAAA;IACLuB,IAAM,EAAA,YAAA;IACNtB,QAAU,EAAA;MACRuB,eAAe,MAAAA,CAAOC,IAAA,EAAAC,KAAA,KAAgC;QAAA,IAA1B;UAACzB,QAAA;UAAU0B;SAAe,GAAAD,KAAA;QACpD,IAAA,CAAIN,yCAAYQ,MAAU,KAAA,CAACR,WAAWP,QAAS,CAAAZ,QAAA,CAASS,KAAK,CAAG,EAAA;UACvD,OAAAe,IAAA;QACT;QAEA,IAAIvB,SAA2B,GAAA,IAAA;QAC/B,IAAIiB,WAAa,EAAA;UACf,MAAMU,MAAS,GAAAF,SAAA,CAAU;YAACG;UAAW,CAAA,CAAA;UAC/B,MAAAC,IAAA,GAAO,MAAMF,MAAO,CAAAG,KAAA,CACxBC,gBAAA,EACA;YAACC,IAAIf;UAAW,CAAA,EAChB;YAACgB;UAAG,CAAA,CACN;UACAjC,SAAA,GAAA,CAAY6B,6BAAMK,MAAS,IAAAL,IAAA,CAAKK,SAAS,MAAMC,cAAA,CAAeR,QAAQV,WAAW,CAAA;QACnF;QAEM,MAAAf,GAAA,GAAMkB,WAAY,CAAArB,QAAA,EAAUC,SAAS,CAAA;QAC3C,IAAIE,GAAK,EAAA;UACA,OAAAA,GAAA,KAAQU,cAAcW,IAAO,GAAArB,GAAA;QACtC;QAEO,OAAAqB,IAAA;MACT;IACF;EAAA,CACF;AACF,CACF,CAAA;"}
|
package/src/is-valid-secret.ts
DELETED
package/src/preview-url.ts
DELETED