next-sanity 12.3.0 → 12.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/NextStudio.js +17 -0
- package/dist/NextStudio.js.map +1 -1
- package/dist/NextStudioNoScript.js +2 -0
- package/dist/NextStudioNoScript.js.map +1 -1
- package/dist/PresentationComlink.js +1 -1
- package/dist/RefreshOnFocus.js +1 -1
- package/dist/RefreshOnMount.js +7 -1
- package/dist/RefreshOnMount.js.map +1 -1
- package/dist/RefreshOnReconnect.js +1 -1
- package/dist/SanityLiveStream.js +4 -0
- package/dist/SanityLiveStream.js.map +1 -1
- package/dist/VisualEditing.js +42 -1
- package/dist/VisualEditing.js.map +1 -1
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -1
- package/dist/draft-mode/index.js +19 -2
- package/dist/draft-mode/index.js.map +1 -1
- package/dist/hooks/index.js +53 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/image/index.d.ts +1 -1
- package/dist/image/index.js +7 -1
- package/dist/image/index.js.map +1 -1
- package/dist/isCorsOriginError.js +1 -0
- package/dist/isCorsOriginError.js.map +1 -1
- package/dist/live/client-components/live/index.js +24 -2
- package/dist/live/client-components/live/index.js.map +1 -1
- package/dist/live/client-components/live-stream/index.js +6 -1
- package/dist/live/client-components/live-stream/index.js.map +1 -1
- package/dist/live/server-actions/index.js +2 -2
- package/dist/live.js +9 -2
- package/dist/live.js.map +1 -1
- package/dist/live.server-only.js +3 -0
- package/dist/live.server-only.js.map +1 -1
- package/dist/studio/client-component/index.js +7 -0
- package/dist/studio/client-component/index.js.map +1 -1
- package/dist/studio/index.js +40 -0
- package/dist/studio/index.js.map +1 -1
- package/dist/utils.js +1 -0
- package/dist/utils.js.map +1 -1
- package/dist/visual-editing/client-component/index.js +7 -0
- package/dist/visual-editing/client-component/index.js.map +1 -1
- package/dist/visual-editing/index.js +3 -0
- package/dist/visual-editing/index.js.map +1 -1
- package/dist/visual-editing/server-actions/index.js +2 -2
- package/dist/webhook/index.d.ts +1 -1
- package/dist/webhook/index.js +5 -0
- package/dist/webhook/index.js.map +1 -1
- package/package.json +14 -13
package/dist/image/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import NextImage from "next/image";
|
|
2
|
+
import NextImage from "next/image.js";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
* @alpha
|
|
6
|
+
*/
|
|
4
7
|
const imageLoader = ({ src, width, quality }) => {
|
|
5
8
|
const url = new URL(src);
|
|
6
9
|
url.searchParams.set("auto", "format");
|
|
@@ -14,6 +17,9 @@ const imageLoader = ({ src, width, quality }) => {
|
|
|
14
17
|
if (quality) url.searchParams.set("q", quality.toString());
|
|
15
18
|
return url.href;
|
|
16
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* @alpha
|
|
22
|
+
*/
|
|
17
23
|
function Image(props) {
|
|
18
24
|
const { loader, src, ...rest } = props;
|
|
19
25
|
if (loader) throw new TypeError("The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.");
|
package/dist/image/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/image/imageLoader.ts","../../src/image/Image.tsx"],"sourcesContent":["import type {ImageLoader} from 'next/image'\n\n/**\n * @alpha\n */\nexport const imageLoader: ImageLoader = ({src, width, quality}) => {\n const url = new URL(src)\n url.searchParams.set('auto', 'format')\n if (!url.searchParams.has('fit')) {\n url.searchParams.set('fit', url.searchParams.has('h') ? 'min' : 'max')\n }\n if (url.searchParams.has('h') && url.searchParams.has('w')) {\n const originalHeight = parseInt(url.searchParams.get('h')!, 10)\n const originalWidth = parseInt(url.searchParams.get('w')!, 10)\n url.searchParams.set('h', Math.round((originalHeight / originalWidth) * width).toString())\n }\n url.searchParams.set('w', width.toString())\n if (quality) {\n url.searchParams.set('q', quality.toString())\n }\n return url.href\n}\n","import NextImage, {type ImageProps as NextImageProps} from 'next/image'\n\nimport {imageLoader} from './imageLoader'\n\n/**\n * @alpha\n */\nexport interface ImageProps extends Omit<NextImageProps, 'loader' | 'src'> {\n /**\n * The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.\n */\n loader?: never\n /**\n * Must be a string that is a valid URL to an image on the Sanity Image CDN.\n */\n src: string\n}\n\n/**\n * @alpha\n */\nexport function Image(props: ImageProps): React.JSX.Element {\n const {loader, src, ...rest} = props\n if (loader) {\n throw new TypeError(\n 'The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.',\n )\n }\n let srcUrl: URL\n try {\n srcUrl = new URL(src)\n if (props.height) {\n srcUrl.searchParams.set('h', `${props.height}`)\n }\n if (props.width) {\n srcUrl.searchParams.set('w', `${props.width}`)\n }\n } catch (err) {\n throw new TypeError('The `src` prop must be a valid URL to an image on the Sanity Image CDN.', {\n cause: err,\n })\n }\n return <NextImage {...rest} src={srcUrl.toString()} loader={imageLoader} />\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/image/imageLoader.ts","../../src/image/Image.tsx"],"sourcesContent":["import type {ImageLoader} from 'next/image'\n\n/**\n * @alpha\n */\nexport const imageLoader: ImageLoader = ({src, width, quality}) => {\n const url = new URL(src)\n url.searchParams.set('auto', 'format')\n if (!url.searchParams.has('fit')) {\n url.searchParams.set('fit', url.searchParams.has('h') ? 'min' : 'max')\n }\n if (url.searchParams.has('h') && url.searchParams.has('w')) {\n const originalHeight = parseInt(url.searchParams.get('h')!, 10)\n const originalWidth = parseInt(url.searchParams.get('w')!, 10)\n url.searchParams.set('h', Math.round((originalHeight / originalWidth) * width).toString())\n }\n url.searchParams.set('w', width.toString())\n if (quality) {\n url.searchParams.set('q', quality.toString())\n }\n return url.href\n}\n","import NextImage, {type ImageProps as NextImageProps} from 'next/image'\n\nimport {imageLoader} from './imageLoader'\n\n/**\n * @alpha\n */\nexport interface ImageProps extends Omit<NextImageProps, 'loader' | 'src'> {\n /**\n * The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.\n */\n loader?: never\n /**\n * Must be a string that is a valid URL to an image on the Sanity Image CDN.\n */\n src: string\n}\n\n/**\n * @alpha\n */\nexport function Image(props: ImageProps): React.JSX.Element {\n const {loader, src, ...rest} = props\n if (loader) {\n throw new TypeError(\n 'The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.',\n )\n }\n let srcUrl: URL\n try {\n srcUrl = new URL(src)\n if (props.height) {\n srcUrl.searchParams.set('h', `${props.height}`)\n }\n if (props.width) {\n srcUrl.searchParams.set('w', `${props.width}`)\n }\n } catch (err) {\n throw new TypeError('The `src` prop must be a valid URL to an image on the Sanity Image CDN.', {\n cause: err,\n })\n }\n return <NextImage {...rest} src={srcUrl.toString()} loader={imageLoader} />\n}\n"],"mappings":";;;;;;AAKA,MAAa,eAA4B,EAAC,KAAK,OAAO,cAAa;CACjE,MAAM,MAAM,IAAI,IAAI,IAAI;AACxB,KAAI,aAAa,IAAI,QAAQ,SAAS;AACtC,KAAI,CAAC,IAAI,aAAa,IAAI,MAAM,CAC9B,KAAI,aAAa,IAAI,OAAO,IAAI,aAAa,IAAI,IAAI,GAAG,QAAQ,MAAM;AAExE,KAAI,IAAI,aAAa,IAAI,IAAI,IAAI,IAAI,aAAa,IAAI,IAAI,EAAE;EAC1D,MAAM,iBAAiB,SAAS,IAAI,aAAa,IAAI,IAAI,EAAG,GAAG;EAC/D,MAAM,gBAAgB,SAAS,IAAI,aAAa,IAAI,IAAI,EAAG,GAAG;AAC9D,MAAI,aAAa,IAAI,KAAK,KAAK,MAAO,iBAAiB,gBAAiB,MAAM,CAAC,UAAU,CAAC;;AAE5F,KAAI,aAAa,IAAI,KAAK,MAAM,UAAU,CAAC;AAC3C,KAAI,QACF,KAAI,aAAa,IAAI,KAAK,QAAQ,UAAU,CAAC;AAE/C,QAAO,IAAI;;;;;ACCb,SAAgB,MAAM,OAAsC;CAC1D,MAAM,EAAC,QAAQ,KAAK,GAAG,SAAQ;AAC/B,KAAI,OACF,OAAM,IAAI,UACR,8GACD;CAEH,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,IAAI;AACrB,MAAI,MAAM,OACR,QAAO,aAAa,IAAI,KAAK,GAAG,MAAM,SAAS;AAEjD,MAAI,MAAM,MACR,QAAO,aAAa,IAAI,KAAK,GAAG,MAAM,QAAQ;UAEzC,KAAK;AACZ,QAAM,IAAI,UAAU,2EAA2E,EAC7F,OAAO,KACR,CAAC;;AAEJ,QAAO,oBAAC,WAAD;EAAW,GAAI;EAAM,KAAK,OAAO,UAAU;EAAE,QAAQ;EAAe,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isCorsOriginError.js","names":[],"sources":["../src/isCorsOriginError.ts"],"sourcesContent":["import type {CorsOriginError} from '@sanity/client'\n\n/** @public */\nexport function isCorsOriginError(error: unknown): error is CorsOriginError {\n return error instanceof Error && error.name === 'CorsOriginError'\n}\n\nexport type {CorsOriginError}\n"],"mappings":"AAGA,SAAgB,kBAAkB,OAA0C;AAC1E,QAAO,iBAAiB,SAAS,MAAM,SAAS"}
|
|
1
|
+
{"version":3,"file":"isCorsOriginError.js","names":[],"sources":["../src/isCorsOriginError.ts"],"sourcesContent":["import type {CorsOriginError} from '@sanity/client'\n\n/** @public */\nexport function isCorsOriginError(error: unknown): error is CorsOriginError {\n return error instanceof Error && error.name === 'CorsOriginError'\n}\n\nexport type {CorsOriginError}\n"],"mappings":";AAGA,SAAgB,kBAAkB,OAA0C;AAC1E,QAAO,iBAAiB,SAAS,MAAM,SAAS"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { d as setEnvironment, f as setPerspective } from "../../../context.js";
|
|
3
3
|
import { t as isCorsOriginError } from "../../../isCorsOriginError.js";
|
|
4
|
-
import { useRouter } from "next/navigation";
|
|
4
|
+
import { useRouter } from "next/navigation.js";
|
|
5
5
|
import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { isMaybePresentation, isMaybePreviewWindow } from "@sanity/presentation-comlink";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { createClient } from "@sanity/client";
|
|
9
9
|
import { revalidateSyncTags } from "next-sanity/live/server-actions";
|
|
10
|
-
import dynamic from "next/dynamic";
|
|
10
|
+
import dynamic from "next/dynamic.js";
|
|
11
11
|
const PresentationComlink = dynamic(() => import("../../../PresentationComlink.js"), { ssr: false });
|
|
12
12
|
const RefreshOnMount = dynamic(() => import("../../../RefreshOnMount.js"), { ssr: false });
|
|
13
13
|
const RefreshOnFocus = dynamic(() => import("../../../RefreshOnFocus.js"), { ssr: false });
|
|
@@ -20,6 +20,9 @@ function handleOnGoAway(event, intervalOnGoAway) {
|
|
|
20
20
|
if (intervalOnGoAway) console.warn("Sanity Live connection closed, switching to long polling set to a interval of", intervalOnGoAway / 1e3, "seconds and the server gave this reason:", event.reason);
|
|
21
21
|
else console.error("Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason:", event.reason);
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
23
26
|
function SanityLive(props) {
|
|
24
27
|
const { projectId, dataset, apiHost, apiVersion, useProjectHostname, token, requestTagPrefix, draftModeEnabled, draftModePerspective, refreshOnMount = false, refreshOnFocus = draftModeEnabled ? false : typeof window === "undefined" ? true : window.self === window.top, refreshOnReconnect = true, intervalOnGoAway = 3e4, requestTag = "next-loader.live", onError = handleError, onGoAway = handleOnGoAway, revalidateSyncTags: revalidateSyncTags$1 = revalidateSyncTags, waitFor } = props;
|
|
25
28
|
const client = useMemo(() => createClient({
|
|
@@ -42,6 +45,9 @@ function SanityLive(props) {
|
|
|
42
45
|
useProjectHostname
|
|
43
46
|
]);
|
|
44
47
|
const [longPollingInterval, setLongPollingInterval] = useState(false);
|
|
48
|
+
/**
|
|
49
|
+
* 1. Handle Live Events and call revalidateTag or router.refresh when needed
|
|
50
|
+
*/
|
|
45
51
|
const router = useRouter();
|
|
46
52
|
const handleLiveEvent = useEffectEvent((event) => {
|
|
47
53
|
if (process.env.NODE_ENV !== "production" && event.type === "welcome") {
|
|
@@ -76,11 +82,17 @@ function SanityLive(props) {
|
|
|
76
82
|
token,
|
|
77
83
|
waitFor
|
|
78
84
|
]);
|
|
85
|
+
/**
|
|
86
|
+
* 2. Notify what perspective we're in, when in Draft Mode
|
|
87
|
+
*/
|
|
79
88
|
useEffect(() => {
|
|
80
89
|
if (draftModeEnabled && draftModePerspective) setPerspective(draftModePerspective);
|
|
81
90
|
else setPerspective("unknown");
|
|
82
91
|
}, [draftModeEnabled, draftModePerspective]);
|
|
83
92
|
const [loadComlink, setLoadComlink] = useState(false);
|
|
93
|
+
/**
|
|
94
|
+
* 3. Notify what environment we're in, when in Draft Mode
|
|
95
|
+
*/
|
|
84
96
|
useEffect(() => {
|
|
85
97
|
if (isMaybePresentation()) return;
|
|
86
98
|
if (draftModeEnabled && token) {
|
|
@@ -93,6 +105,9 @@ function SanityLive(props) {
|
|
|
93
105
|
}
|
|
94
106
|
setEnvironment("unknown");
|
|
95
107
|
}, [draftModeEnabled, token]);
|
|
108
|
+
/**
|
|
109
|
+
* 4. If Presentation Tool is detected, load up the comlink and integrate with it
|
|
110
|
+
*/
|
|
96
111
|
useEffect(() => {
|
|
97
112
|
if (!isMaybePresentation()) return;
|
|
98
113
|
const controller = new AbortController();
|
|
@@ -110,6 +125,10 @@ function SanityLive(props) {
|
|
|
110
125
|
controller.abort();
|
|
111
126
|
};
|
|
112
127
|
}, []);
|
|
128
|
+
/**
|
|
129
|
+
* 5. Warn if draft mode is being disabled
|
|
130
|
+
* @TODO move logic into PresentationComlink, or maybe VisualEditing?
|
|
131
|
+
*/
|
|
113
132
|
const draftModeEnabledWarnRef = useRef(void 0);
|
|
114
133
|
useEffect(() => {
|
|
115
134
|
if (!draftModeEnabled) return;
|
|
@@ -120,6 +139,9 @@ function SanityLive(props) {
|
|
|
120
139
|
});
|
|
121
140
|
};
|
|
122
141
|
}, [draftModeEnabled]);
|
|
142
|
+
/**
|
|
143
|
+
* 6. Handle switching to long polling when needed
|
|
144
|
+
*/
|
|
123
145
|
useEffect(() => {
|
|
124
146
|
if (!longPollingInterval) return;
|
|
125
147
|
const interval = setInterval(() => router.refresh(), longPollingInterval);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["defaultRevalidateSyncTags","revalidateSyncTags"],"sources":["../../../../src/live/client-components/live/SanityLive.tsx"],"sourcesContent":["import {\n createClient,\n type ClientPerspective,\n type InitializedClientConfig,\n type LiveEvent,\n type LiveEventGoAway,\n type SyncTag,\n} from '@sanity/client'\nimport {isMaybePresentation, isMaybePreviewWindow} from '@sanity/presentation-comlink'\nimport {revalidateSyncTags as defaultRevalidateSyncTags} from 'next-sanity/live/server-actions'\nimport dynamic from 'next/dynamic'\nimport {useRouter} from 'next/navigation'\nimport {useEffect, useMemo, useRef, useState, useEffectEvent} from 'react'\n\nimport {isCorsOriginError} from '../../../isCorsOriginError'\nimport {setEnvironment, setPerspective} from '../../hooks/context'\n\nconst PresentationComlink = dynamic(() => import('./PresentationComlink'), {ssr: false})\nconst RefreshOnMount = dynamic(() => import('./RefreshOnMount'), {ssr: false})\nconst RefreshOnFocus = dynamic(() => import('./RefreshOnFocus'), {ssr: false})\nconst RefreshOnReconnect = dynamic(() => import('./RefreshOnReconnect'), {ssr: false})\n\n/**\n * @public\n */\nexport interface SanityLiveProps extends Pick<\n InitializedClientConfig,\n | 'projectId'\n | 'dataset'\n | 'apiHost'\n | 'apiVersion'\n | 'useProjectHostname'\n | 'token'\n | 'requestTagPrefix'\n> {\n // handleDraftModeAction: (secret: string) => Promise<void | string>\n draftModeEnabled: boolean\n draftModePerspective?: ClientPerspective\n refreshOnMount?: boolean\n refreshOnFocus?: boolean\n refreshOnReconnect?: boolean\n requestTag: string | undefined\n /**\n * Handle errors from the Live Events subscription.\n * By default it's reported using `console.error`, you can override this prop to handle it in your own way.\n */\n onError?: (error: unknown) => void\n intervalOnGoAway?: number | false\n onGoAway?: (event: LiveEventGoAway, intervalOnGoAway: number | false) => void\n revalidateSyncTags?: (tags: SyncTag[]) => Promise<void | 'refresh'>\n /**\n * Delays events until after a configured Sanity Function has processed them and called the callback endpoint.\n * When omitted, events are delivered immediately.\n *\n * @remarks\n * When set, any custom `revalidateSyncTags` will not be called — revalidation is handled by the Function instead.\n */\n waitFor?: 'function'\n}\n\nfunction handleError(error: unknown) {\n if (isCorsOriginError(error)) {\n console.warn(\n `Sanity Live is unable to connect to the Sanity API as the current origin - ${window.origin} - is not in the list of allowed CORS origins for this Sanity Project.`,\n error.addOriginUrl && `Add it here:`,\n error.addOriginUrl?.toString(),\n )\n } else {\n console.error(error)\n }\n}\n\nfunction handleOnGoAway(event: LiveEventGoAway, intervalOnGoAway: number | false) {\n if (intervalOnGoAway) {\n console.warn(\n 'Sanity Live connection closed, switching to long polling set to a interval of',\n intervalOnGoAway / 1000,\n 'seconds and the server gave this reason:',\n event.reason,\n )\n } else {\n console.error(\n 'Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason:',\n event.reason,\n )\n }\n}\n\n/**\n * @public\n */\nexport function SanityLive(props: SanityLiveProps): React.JSX.Element | null {\n const {\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n token,\n requestTagPrefix,\n // handleDraftModeAction,\n draftModeEnabled,\n draftModePerspective,\n refreshOnMount = false,\n refreshOnFocus = draftModeEnabled\n ? false\n : typeof window === 'undefined'\n ? true\n : window.self === window.top,\n refreshOnReconnect = true,\n intervalOnGoAway = 30_000,\n requestTag = 'next-loader.live',\n onError = handleError,\n onGoAway = handleOnGoAway,\n revalidateSyncTags = defaultRevalidateSyncTags,\n waitFor,\n } = props\n\n const client = useMemo(\n () =>\n createClient({\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n ignoreBrowserTokenWarning: true,\n token,\n useCdn: false,\n requestTagPrefix,\n }),\n [apiHost, apiVersion, dataset, projectId, requestTagPrefix, token, useProjectHostname],\n )\n const [longPollingInterval, setLongPollingInterval] = useState<number | false>(false)\n\n /**\n * 1. Handle Live Events and call revalidateTag or router.refresh when needed\n */\n const router = useRouter()\n const handleLiveEvent = useEffectEvent((event: LiveEvent) => {\n if (process.env.NODE_ENV !== 'production' && event.type === 'welcome') {\n // oxlint-disable-next-line no-console\n console.info(\n 'Sanity is live with',\n token\n ? 'automatic revalidation for draft content changes as well as published content'\n : draftModeEnabled\n ? 'automatic revalidation for only published content. Provide a `browserToken` to `defineLive` to support draft content outside of Presentation Tool.'\n : 'automatic revalidation of published content',\n )\n // Disable long polling when welcome event is received, this is a no-op if long polling is already disabled\n setLongPollingInterval(false)\n } else if (event.type === 'message') {\n if (waitFor === 'function') {\n // Cache is already revalidated by the Sanity Function, just refresh the router\n router.refresh()\n } else {\n void revalidateSyncTags(event.tags).then((result) => {\n if (result === 'refresh') router.refresh()\n })\n }\n } else if (event.type === 'restart' || event.type === 'reconnect') {\n router.refresh()\n } else if (event.type === 'goaway') {\n onGoAway(event, intervalOnGoAway)\n setLongPollingInterval(intervalOnGoAway)\n }\n })\n useEffect(() => {\n const subscription = client.live.events({includeDrafts: !!token, tag: requestTag, waitFor}).subscribe({\n next: handleLiveEvent,\n error: (err: unknown) => {\n // console.error('What?', err)\n onError(err)\n },\n })\n return () => subscription.unsubscribe()\n }, [client.live, onError, requestTag, token, waitFor])\n\n /**\n * 2. Notify what perspective we're in, when in Draft Mode\n */\n useEffect(() => {\n if (draftModeEnabled && draftModePerspective) {\n setPerspective(draftModePerspective)\n } else {\n setPerspective('unknown')\n }\n }, [draftModeEnabled, draftModePerspective])\n\n const [loadComlink, setLoadComlink] = useState(false)\n /**\n * 3. Notify what environment we're in, when in Draft Mode\n */\n useEffect(() => {\n // If we might be in Presentation Tool, then skip detecting here as it's handled later\n if (isMaybePresentation()) return\n\n // If we're definitely not in Presentation Tool, then we can set the environment as stand-alone live preview\n // if we have both a browser token, and draft mode is enabled\n if (draftModeEnabled && token) {\n setEnvironment('live')\n return\n }\n // If we're in draft mode, but don't have a browser token, then we're in static mode\n // which means that published content is still live, but draft changes likely need manual refresh\n if (draftModeEnabled) {\n setEnvironment('static')\n return\n }\n\n // Fallback to `unknown` otherwise, as we simply don't know how it's setup\n setEnvironment('unknown')\n return\n }, [draftModeEnabled, token])\n\n /**\n * 4. If Presentation Tool is detected, load up the comlink and integrate with it\n */\n useEffect(() => {\n if (!isMaybePresentation()) return\n const controller = new AbortController()\n // Wait for a while to see if Presentation Tool is detected, before assuming the env to be stand-alone live preview\n const timeout = setTimeout(() => setEnvironment('live'), 3_000)\n window.addEventListener(\n 'message',\n ({data}: MessageEvent<unknown>) => {\n if (\n data &&\n typeof data === 'object' &&\n 'domain' in data &&\n data.domain === 'sanity/channels' &&\n 'from' in data &&\n data.from === 'presentation'\n ) {\n clearTimeout(timeout)\n setEnvironment(isMaybePreviewWindow() ? 'presentation-window' : 'presentation-iframe')\n setLoadComlink(true)\n controller.abort()\n }\n },\n {signal: controller.signal},\n )\n return () => {\n clearTimeout(timeout)\n controller.abort()\n }\n }, [])\n\n /**\n * 5. Warn if draft mode is being disabled\n * @TODO move logic into PresentationComlink, or maybe VisualEditing?\n */\n const draftModeEnabledWarnRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n useEffect(() => {\n if (!draftModeEnabled) return\n clearTimeout(draftModeEnabledWarnRef.current)\n return () => {\n draftModeEnabledWarnRef.current = setTimeout(() => {\n console.warn('Sanity Live: Draft mode was enabled, but is now being disabled')\n })\n }\n }, [draftModeEnabled])\n\n /**\n * 6. Handle switching to long polling when needed\n */\n useEffect(() => {\n if (!longPollingInterval) return\n const interval = setInterval(() => router.refresh(), longPollingInterval)\n return () => clearInterval(interval)\n }, [longPollingInterval, router])\n\n return (\n <>\n {draftModeEnabled && loadComlink && (\n <PresentationComlink\n projectId={projectId!}\n dataset={dataset!}\n // handleDraftModeAction={handleDraftModeAction}\n draftModeEnabled={draftModeEnabled}\n draftModePerspective={draftModePerspective!}\n />\n )}\n {!draftModeEnabled && refreshOnMount && <RefreshOnMount />}\n {!draftModeEnabled && refreshOnFocus && <RefreshOnFocus />}\n {!draftModeEnabled && refreshOnReconnect && <RefreshOnReconnect />}\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["defaultRevalidateSyncTags","revalidateSyncTags"],"sources":["../../../../src/live/client-components/live/SanityLive.tsx"],"sourcesContent":["import {\n createClient,\n type ClientPerspective,\n type InitializedClientConfig,\n type LiveEvent,\n type LiveEventGoAway,\n type SyncTag,\n} from '@sanity/client'\nimport {isMaybePresentation, isMaybePreviewWindow} from '@sanity/presentation-comlink'\nimport {revalidateSyncTags as defaultRevalidateSyncTags} from 'next-sanity/live/server-actions'\nimport dynamic from 'next/dynamic'\nimport {useRouter} from 'next/navigation'\nimport {useEffect, useMemo, useRef, useState, useEffectEvent} from 'react'\n\nimport {isCorsOriginError} from '../../../isCorsOriginError'\nimport {setEnvironment, setPerspective} from '../../hooks/context'\n\nconst PresentationComlink = dynamic(() => import('./PresentationComlink'), {ssr: false})\nconst RefreshOnMount = dynamic(() => import('./RefreshOnMount'), {ssr: false})\nconst RefreshOnFocus = dynamic(() => import('./RefreshOnFocus'), {ssr: false})\nconst RefreshOnReconnect = dynamic(() => import('./RefreshOnReconnect'), {ssr: false})\n\n/**\n * @public\n */\nexport interface SanityLiveProps extends Pick<\n InitializedClientConfig,\n | 'projectId'\n | 'dataset'\n | 'apiHost'\n | 'apiVersion'\n | 'useProjectHostname'\n | 'token'\n | 'requestTagPrefix'\n> {\n // handleDraftModeAction: (secret: string) => Promise<void | string>\n draftModeEnabled: boolean\n draftModePerspective?: ClientPerspective\n refreshOnMount?: boolean\n refreshOnFocus?: boolean\n refreshOnReconnect?: boolean\n requestTag: string | undefined\n /**\n * Handle errors from the Live Events subscription.\n * By default it's reported using `console.error`, you can override this prop to handle it in your own way.\n */\n onError?: (error: unknown) => void\n intervalOnGoAway?: number | false\n onGoAway?: (event: LiveEventGoAway, intervalOnGoAway: number | false) => void\n revalidateSyncTags?: (tags: SyncTag[]) => Promise<void | 'refresh'>\n /**\n * Delays events until after a configured Sanity Function has processed them and called the callback endpoint.\n * When omitted, events are delivered immediately.\n *\n * @remarks\n * When set, any custom `revalidateSyncTags` will not be called — revalidation is handled by the Function instead.\n */\n waitFor?: 'function'\n}\n\nfunction handleError(error: unknown) {\n if (isCorsOriginError(error)) {\n console.warn(\n `Sanity Live is unable to connect to the Sanity API as the current origin - ${window.origin} - is not in the list of allowed CORS origins for this Sanity Project.`,\n error.addOriginUrl && `Add it here:`,\n error.addOriginUrl?.toString(),\n )\n } else {\n console.error(error)\n }\n}\n\nfunction handleOnGoAway(event: LiveEventGoAway, intervalOnGoAway: number | false) {\n if (intervalOnGoAway) {\n console.warn(\n 'Sanity Live connection closed, switching to long polling set to a interval of',\n intervalOnGoAway / 1000,\n 'seconds and the server gave this reason:',\n event.reason,\n )\n } else {\n console.error(\n 'Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason:',\n event.reason,\n )\n }\n}\n\n/**\n * @public\n */\nexport function SanityLive(props: SanityLiveProps): React.JSX.Element | null {\n const {\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n token,\n requestTagPrefix,\n // handleDraftModeAction,\n draftModeEnabled,\n draftModePerspective,\n refreshOnMount = false,\n refreshOnFocus = draftModeEnabled\n ? false\n : typeof window === 'undefined'\n ? true\n : window.self === window.top,\n refreshOnReconnect = true,\n intervalOnGoAway = 30_000,\n requestTag = 'next-loader.live',\n onError = handleError,\n onGoAway = handleOnGoAway,\n revalidateSyncTags = defaultRevalidateSyncTags,\n waitFor,\n } = props\n\n const client = useMemo(\n () =>\n createClient({\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n ignoreBrowserTokenWarning: true,\n token,\n useCdn: false,\n requestTagPrefix,\n }),\n [apiHost, apiVersion, dataset, projectId, requestTagPrefix, token, useProjectHostname],\n )\n const [longPollingInterval, setLongPollingInterval] = useState<number | false>(false)\n\n /**\n * 1. Handle Live Events and call revalidateTag or router.refresh when needed\n */\n const router = useRouter()\n const handleLiveEvent = useEffectEvent((event: LiveEvent) => {\n if (process.env.NODE_ENV !== 'production' && event.type === 'welcome') {\n // oxlint-disable-next-line no-console\n console.info(\n 'Sanity is live with',\n token\n ? 'automatic revalidation for draft content changes as well as published content'\n : draftModeEnabled\n ? 'automatic revalidation for only published content. Provide a `browserToken` to `defineLive` to support draft content outside of Presentation Tool.'\n : 'automatic revalidation of published content',\n )\n // Disable long polling when welcome event is received, this is a no-op if long polling is already disabled\n setLongPollingInterval(false)\n } else if (event.type === 'message') {\n if (waitFor === 'function') {\n // Cache is already revalidated by the Sanity Function, just refresh the router\n router.refresh()\n } else {\n void revalidateSyncTags(event.tags).then((result) => {\n if (result === 'refresh') router.refresh()\n })\n }\n } else if (event.type === 'restart' || event.type === 'reconnect') {\n router.refresh()\n } else if (event.type === 'goaway') {\n onGoAway(event, intervalOnGoAway)\n setLongPollingInterval(intervalOnGoAway)\n }\n })\n useEffect(() => {\n const subscription = client.live\n .events({includeDrafts: !!token, tag: requestTag, waitFor})\n .subscribe({\n next: handleLiveEvent,\n error: (err: unknown) => {\n // console.error('What?', err)\n onError(err)\n },\n })\n return () => subscription.unsubscribe()\n }, [client.live, onError, requestTag, token, waitFor])\n\n /**\n * 2. Notify what perspective we're in, when in Draft Mode\n */\n useEffect(() => {\n if (draftModeEnabled && draftModePerspective) {\n setPerspective(draftModePerspective)\n } else {\n setPerspective('unknown')\n }\n }, [draftModeEnabled, draftModePerspective])\n\n const [loadComlink, setLoadComlink] = useState(false)\n /**\n * 3. Notify what environment we're in, when in Draft Mode\n */\n useEffect(() => {\n // If we might be in Presentation Tool, then skip detecting here as it's handled later\n if (isMaybePresentation()) return\n\n // If we're definitely not in Presentation Tool, then we can set the environment as stand-alone live preview\n // if we have both a browser token, and draft mode is enabled\n if (draftModeEnabled && token) {\n setEnvironment('live')\n return\n }\n // If we're in draft mode, but don't have a browser token, then we're in static mode\n // which means that published content is still live, but draft changes likely need manual refresh\n if (draftModeEnabled) {\n setEnvironment('static')\n return\n }\n\n // Fallback to `unknown` otherwise, as we simply don't know how it's setup\n setEnvironment('unknown')\n return\n }, [draftModeEnabled, token])\n\n /**\n * 4. If Presentation Tool is detected, load up the comlink and integrate with it\n */\n useEffect(() => {\n if (!isMaybePresentation()) return\n const controller = new AbortController()\n // Wait for a while to see if Presentation Tool is detected, before assuming the env to be stand-alone live preview\n const timeout = setTimeout(() => setEnvironment('live'), 3_000)\n window.addEventListener(\n 'message',\n ({data}: MessageEvent<unknown>) => {\n if (\n data &&\n typeof data === 'object' &&\n 'domain' in data &&\n data.domain === 'sanity/channels' &&\n 'from' in data &&\n data.from === 'presentation'\n ) {\n clearTimeout(timeout)\n setEnvironment(isMaybePreviewWindow() ? 'presentation-window' : 'presentation-iframe')\n setLoadComlink(true)\n controller.abort()\n }\n },\n {signal: controller.signal},\n )\n return () => {\n clearTimeout(timeout)\n controller.abort()\n }\n }, [])\n\n /**\n * 5. Warn if draft mode is being disabled\n * @TODO move logic into PresentationComlink, or maybe VisualEditing?\n */\n const draftModeEnabledWarnRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n useEffect(() => {\n if (!draftModeEnabled) return\n clearTimeout(draftModeEnabledWarnRef.current)\n return () => {\n draftModeEnabledWarnRef.current = setTimeout(() => {\n console.warn('Sanity Live: Draft mode was enabled, but is now being disabled')\n })\n }\n }, [draftModeEnabled])\n\n /**\n * 6. Handle switching to long polling when needed\n */\n useEffect(() => {\n if (!longPollingInterval) return\n const interval = setInterval(() => router.refresh(), longPollingInterval)\n return () => clearInterval(interval)\n }, [longPollingInterval, router])\n\n return (\n <>\n {draftModeEnabled && loadComlink && (\n <PresentationComlink\n projectId={projectId!}\n dataset={dataset!}\n // handleDraftModeAction={handleDraftModeAction}\n draftModeEnabled={draftModeEnabled}\n draftModePerspective={draftModePerspective!}\n />\n )}\n {!draftModeEnabled && refreshOnMount && <RefreshOnMount />}\n {!draftModeEnabled && refreshOnFocus && <RefreshOnFocus />}\n {!draftModeEnabled && refreshOnReconnect && <RefreshOnReconnect />}\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import dynamic from "next/dynamic";
|
|
3
|
+
import dynamic from "next/dynamic.js";
|
|
4
|
+
/**
|
|
5
|
+
* This file works around a new restriction in Next v15 where server components are not allowed
|
|
6
|
+
* to use dynamic(() => import('...), {ssr: false})
|
|
7
|
+
* only Client Components can set ssr: false.
|
|
8
|
+
*/
|
|
4
9
|
const SanityLiveStreamClientComponent = dynamic(() => import("../../../SanityLiveStream.js"), { ssr: false });
|
|
5
10
|
function SanityLiveStreamLazyClientComponent(props) {
|
|
6
11
|
return /* @__PURE__ */ jsx(SanityLiveStreamClientComponent, { ...props });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/client-components/live-stream/SanityLiveStreamLazy.tsx"],"sourcesContent":["/**\n * This file works around a new restriction in Next v15 where server components are not allowed\n * to use dynamic(() => import('...), {ssr: false})\n * only Client Components can set ssr: false.\n */\n\nimport dynamic from 'next/dynamic'\n\nimport type {SanityLiveStreamProps} from './SanityLiveStream'\n\nconst SanityLiveStreamClientComponent = dynamic(() => import('./SanityLiveStream'), {ssr: false})\n\nexport function SanityLiveStreamLazyClientComponent(props: SanityLiveStreamProps): React.ReactNode {\n return <SanityLiveStreamClientComponent {...props} />\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/client-components/live-stream/SanityLiveStreamLazy.tsx"],"sourcesContent":["/**\n * This file works around a new restriction in Next v15 where server components are not allowed\n * to use dynamic(() => import('...), {ssr: false})\n * only Client Components can set ssr: false.\n */\n\nimport dynamic from 'next/dynamic'\n\nimport type {SanityLiveStreamProps} from './SanityLiveStream'\n\nconst SanityLiveStreamClientComponent = dynamic(() => import('./SanityLiveStream'), {ssr: false})\n\nexport function SanityLiveStreamLazyClientComponent(props: SanityLiveStreamProps): React.ReactNode {\n return <SanityLiveStreamClientComponent {...props} />\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,kCAAkC,cAAc,OAAO,iCAAuB,EAAC,KAAK,OAAM,CAAC;AAEjG,SAAgB,oCAAoC,OAA+C;AACjG,QAAO,oBAAC,iCAAD,EAAiC,GAAI,OAAS,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import { t as sanitizePerspective } from "../../utils.js";
|
|
3
3
|
import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
|
|
4
|
-
import { cookies, draftMode } from "next/headers";
|
|
5
|
-
import { revalidateTag } from "next/cache";
|
|
4
|
+
import { cookies, draftMode } from "next/headers.js";
|
|
5
|
+
import { revalidateTag } from "next/cache.js";
|
|
6
6
|
async function revalidateSyncTags(tags) {
|
|
7
7
|
revalidateTag("sanity:fetch-sync-tags", "max");
|
|
8
8
|
for (const _tag of tags) {
|
package/dist/live.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { t as isCorsOriginError } from "./isCorsOriginError.js";
|
|
2
2
|
import { t as sanitizePerspective } from "./utils.js";
|
|
3
3
|
import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
|
|
4
|
-
import { cookies, draftMode } from "next/headers";
|
|
4
|
+
import { cookies, draftMode } from "next/headers.js";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import "@sanity/client";
|
|
6
7
|
import SanityLiveClientComponent from "next-sanity/live/client-components/live";
|
|
7
8
|
import SanityLiveStreamClientComponent from "next-sanity/live/client-components/live-stream";
|
|
8
|
-
import { PHASE_PRODUCTION_BUILD } from "next/constants";
|
|
9
|
+
import { PHASE_PRODUCTION_BUILD } from "next/constants.js";
|
|
9
10
|
import { preconnect, prefetchDNS } from "react-dom";
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
10
14
|
async function resolveCookiePerspective() {
|
|
11
15
|
return (await draftMode()).isEnabled ? (await cookies()).has(perspectiveCookieName) ? sanitizePerspective((await cookies()).get(perspectiveCookieName)?.value, "drafts") : "drafts" : "published";
|
|
12
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
13
20
|
function defineLive(config) {
|
|
14
21
|
const { client: _client, serverToken, browserToken, fetchOptions, stega: stegaEnabled = true } = config;
|
|
15
22
|
if (!_client) throw new Error("`client` is required for `defineLive` to function");
|
package/dist/live.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.js","names":[],"sources":["../src/live/resolveCookiePerspective.ts","../src/live/defineLive.tsx"],"sourcesContent":["import type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {cookies, draftMode} from 'next/headers'\n\nimport {sanitizePerspective} from './utils'\n\n/**\n * @internal\n */\nexport async function resolveCookiePerspective(): Promise<Exclude<ClientPerspective, 'raw'>> {\n return (await draftMode()).isEnabled\n ? (await cookies()).has(perspectiveCookieName)\n ? sanitizePerspective((await cookies()).get(perspectiveCookieName)?.value, 'drafts')\n : 'drafts'\n : 'published'\n}\n","import {\n type ClientPerspective,\n type ClientReturn,\n type ContentSourceMap,\n type LiveEventGoAway,\n type QueryParams,\n type SanityClient,\n type SyncTag,\n} from '@sanity/client'\nimport SanityLiveClientComponent from 'next-sanity/live/client-components/live'\nimport SanityLiveStreamClientComponent from 'next-sanity/live/client-components/live-stream'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {draftMode} from 'next/headers'\nimport {prefetchDNS, preconnect} from 'react-dom'\n\nimport {resolveCookiePerspective} from './resolveCookiePerspective'\n\n/**\n * @public\n */\nexport type DefinedSanityFetchType = <const QueryString extends string>(options: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n /**\n * Add custom `next.tags` to the underlying fetch request.\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnexttags\n * This can be used in conjunction with custom fallback revalidation strategies, as well as with custom Server Actions that mutate data and want to render with fresh data right away (faster than the Live Event latency).\n * @defaultValue `['sanity']`\n */\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n stega?: boolean\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.fetch'\n */\n requestTag?: string\n}) => Promise<{\n data: ClientReturn<QueryString>\n sourceMap: ContentSourceMap | null\n tags: string[]\n}>\n\n/**\n * @public\n */\nexport type DefinedSanityLiveStreamType = <const QueryString extends string>(props: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n /**\n * Add custom `next.tags` to the underlying fetch request.\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnexttags\n * This can be used in conjunction with custom fallback revalidation strategies, as well as with custom Server Actions that mutate data and want to render with fresh data right away (faster than the Live Event latency).\n * @defaultValue `['sanity']`\n */\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n stega?: boolean\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.live-stream.fetch'\n */\n requestTag?: string\n children: (result: {\n data: ClientReturn<QueryString>\n sourceMap: ContentSourceMap | null\n tags: string[]\n }) => Promise<Awaited<React.ReactNode>>\n}) => React.ReactNode\n\n/**\n * @public\n */\nexport interface DefinedSanityLiveProps {\n /**\n * Automatic refresh of RSC when the component <SanityLive /> is mounted.\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `true`\n */\n refreshOnMount?: boolean\n /**\n * Automatically refresh when window gets focused\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `false` if draftMode().isEnabled, otherwise `true` if not inside an iframe\n */\n refreshOnFocus?: boolean\n /**\n * Automatically refresh when the browser regains a network connection (via navigator.onLine)\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `true`\n */\n refreshOnReconnect?: boolean\n /**\n * Automatically refresh on an interval when the Live Event API emits a `goaway` event, which indicates that the connection is rejected or closed.\n * This typically happens if the connection limit is reached, or if the connection is idle for too long.\n * To disable this long polling fallback behavior set `intervalOnGoAway` to `false` or `0`.\n * You can also use `onGoAway` to handle the `goaway` event in your own way, and read the reason why the event was emitted.\n * @defaultValue `30_000` 30 seconds interval\n */\n intervalOnGoAway?: number | false\n\n /**\n * Delays events until after a Sanity Function has processed them and called the callback endpoint.\n * When omitted, events are delivered immediately.\n */\n waitFor?: 'function'\n\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.live'\n */\n requestTag?: string\n\n /**\n * Handle errors from the Live Events subscription.\n * By default it's reported using `console.error`, you can override this prop to handle it in your own way.\n */\n onError?: (error: unknown) => void\n\n /**\n * Handle the `goaway` event if the connection is rejected/closed.\n * `event.reason` will be a string of why the event was emitted, for example `'connection limit reached'`.\n * When this happens the `<SanityLive />` will fallback to long polling with a default interval of 30 seconds, providing your own `onGoAway` handler does not change this behavior.\n * If you want to disable long polling set `intervalOnGoAway` to `false` or `0`.\n */\n onGoAway?: (event: LiveEventGoAway, intervalOnGoAway: number | false) => void\n\n /**\n * Override how cache tags are invalidated, you need to pass a server action here.\n * You can also pass a `use client` function here, and have `router.refresh()` be called if the promise resolves to `'refresh'`.\n */\n revalidateSyncTags?: (tags: SyncTag[]) => Promise<void | 'refresh'>\n}\n\n/**\n * @public\n */\nexport interface DefineSanityLiveOptions {\n /**\n * Required for `sanityFetch` and `SanityLive` to work\n */\n client: SanityClient\n /**\n * Optional. If provided then the token needs to have permissions to query documents with `drafts.` prefixes in order for `perspective: 'drafts'` to work.\n * This token is not shared with the browser.\n */\n serverToken?: string | false\n /**\n * Optional. This token is shared with the browser, and should only have access to query published documents.\n * It is used to setup a `Live Draft Content` EventSource connection, and enables live previewing drafts stand-alone, outside of Presentation Tool.\n */\n browserToken?: string | false\n /**\n * Fetch options used by `sanityFetch`\n * @deprecated this option is removed in the next major version, use `export const revalidate` on the `page.tsx` or `layout.tsx` instead\n */\n fetchOptions?: {\n /**\n * Optional, enables time based revalidation in addition to the EventSource connection.\n * @defaultValue `false`\n */\n revalidate?: number | false\n }\n /**\n * Optional. Include stega encoding when draft mode is enabled.\n * @defaultValue `true`\n */\n stega?: boolean\n}\n\n/**\n * @public\n */\nexport function defineLive(config: DefineSanityLiveOptions): {\n /**\n * Use this function to fetch data from Sanity in your React Server Components.\n * @public\n */\n sanityFetch: DefinedSanityFetchType\n /**\n * Render this in your root layout.tsx to make your page revalidate on new content live, automatically.\n * @public\n */\n SanityLive: React.ComponentType<DefinedSanityLiveProps>\n /**\n * @alpha experimental, it may change or even be removed at any time\n */\n SanityLiveStream: DefinedSanityLiveStreamType\n} {\n const {\n client: _client,\n serverToken,\n browserToken,\n fetchOptions,\n stega: stegaEnabled = true,\n } = config\n\n if (!_client) {\n throw new Error('`client` is required for `defineLive` to function')\n }\n\n if (process.env.NODE_ENV !== 'production' && !serverToken && serverToken !== false) {\n console.warn(\n 'No `serverToken` provided to `defineLive`. This means that only published content will be fetched and respond to live events. You can silence this warning by setting `serverToken: false`.',\n )\n }\n\n if (process.env.NODE_ENV !== 'production' && !browserToken && browserToken !== false) {\n console.warn(\n 'No `browserToken` provided to `defineLive`. This means that live previewing drafts will only work when using the Presentation Tool in your Sanity Studio. To support live previewing drafts stand-alone, provide a `browserToken`. It is shared with the browser so it should only have Viewer rights or lower. You can silence this warning by setting `browserToken: false`.',\n )\n }\n\n const client = _client.withConfig({allowReconfigure: false, useCdn: false})\n const {token: originalToken} = client.config()\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedSanityFetchType = async function sanityFetch<\n const QueryString extends string,\n >({\n query,\n params = {},\n stega: _stega,\n tags = [],\n perspective: _perspective,\n tag,\n requestTag = tag ?? 'next-loader.fetch',\n }: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n stega?: boolean\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n tag?: string\n requestTag?: string\n }) {\n const stega = _stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled)\n const perspective = _perspective ?? (await resolveCookiePerspective())\n const useCdn = perspective === 'published'\n const revalidate =\n fetchOptions?.revalidate !== undefined\n ? fetchOptions.revalidate\n : process.env.NODE_ENV === 'production'\n ? false\n : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n\n const {syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective: perspective as ClientPerspective,\n stega: false,\n returnQuery: false,\n next: {revalidate, tags: [...tags, 'sanity:fetch-sync-tags']},\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `sanity:${tag}`) || [])]\n\n const {result, resultSourceMap} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective: perspective as ClientPerspective,\n stega,\n token: perspective !== 'published' && serverToken ? serverToken : originalToken,\n next: {revalidate, tags: cacheTags},\n useCdn,\n cacheMode,\n tag: requestTag,\n })\n return {data: result, sourceMap: resultSourceMap || null, tags: cacheTags}\n }\n\n const SanityLive: React.ComponentType<DefinedSanityLiveProps> = async function SanityLive(props) {\n const {\n refreshOnMount,\n refreshOnFocus,\n refreshOnReconnect,\n tag,\n requestTag = tag,\n onError,\n onGoAway,\n intervalOnGoAway,\n revalidateSyncTags,\n waitFor,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n const {isEnabled: isDraftModeEnabled} = await draftMode()\n\n // Preconnect to the Live Event API origin, or at least prefetch the DNS if preconenct is not supported\n const {origin} = new URL(client.getUrl('', false))\n preconnect(origin)\n prefetchDNS(origin)\n\n return (\n <SanityLiveClientComponent\n projectId={projectId}\n dataset={dataset}\n apiHost={apiHost}\n apiVersion={apiVersion}\n useProjectHostname={useProjectHostname}\n requestTagPrefix={requestTagPrefix}\n requestTag={requestTag}\n token={typeof browserToken === 'string' && isDraftModeEnabled ? browserToken : undefined}\n draftModeEnabled={isDraftModeEnabled}\n draftModePerspective={await resolveCookiePerspective()}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n onError={onError}\n onGoAway={onGoAway}\n intervalOnGoAway={intervalOnGoAway}\n revalidateSyncTags={revalidateSyncTags}\n waitFor={waitFor}\n />\n )\n }\n\n const SanityLiveStream: DefinedSanityLiveStreamType = async function SanityLiveStream(props) {\n const {\n query,\n params,\n perspective: _perspective,\n stega: _stega,\n tags,\n children,\n tag,\n requestTag = tag ?? 'next-loader.live-stream.fetch',\n } = props\n const {\n data,\n sourceMap,\n tags: cacheTags,\n } = await sanityFetch({\n query,\n params,\n tags,\n perspective: _perspective,\n stega: _stega,\n requestTag,\n })\n const {isEnabled: isDraftModeEnabled} = await draftMode()\n\n if (isDraftModeEnabled) {\n const stega = _stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled)\n const perspective = _perspective ?? (await resolveCookiePerspective())\n const {projectId, dataset} = client.config()\n return (\n <SanityLiveStreamClientComponent\n projectId={projectId}\n dataset={dataset}\n query={query}\n params={await params}\n perspective={perspective}\n stega={stega}\n initial={children({data, sourceMap, tags: cacheTags})}\n // oxlint-disable-next-line react/no-children-prop\n children={\n // oxlint-disable-next-line no-unsafe-type-assertion\n children as unknown as any\n }\n />\n )\n }\n\n return children({data, sourceMap, tags: cacheTags})\n }\n\n return {\n sanityFetch,\n SanityLive,\n SanityLiveStream,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"live.js","names":[],"sources":["../src/live/resolveCookiePerspective.ts","../src/live/defineLive.tsx"],"sourcesContent":["import type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {cookies, draftMode} from 'next/headers'\n\nimport {sanitizePerspective} from './utils'\n\n/**\n * @internal\n */\nexport async function resolveCookiePerspective(): Promise<Exclude<ClientPerspective, 'raw'>> {\n return (await draftMode()).isEnabled\n ? (await cookies()).has(perspectiveCookieName)\n ? sanitizePerspective((await cookies()).get(perspectiveCookieName)?.value, 'drafts')\n : 'drafts'\n : 'published'\n}\n","import {\n type ClientPerspective,\n type ClientReturn,\n type ContentSourceMap,\n type LiveEventGoAway,\n type QueryParams,\n type SanityClient,\n type SyncTag,\n} from '@sanity/client'\nimport SanityLiveClientComponent from 'next-sanity/live/client-components/live'\nimport SanityLiveStreamClientComponent from 'next-sanity/live/client-components/live-stream'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {draftMode} from 'next/headers'\nimport {prefetchDNS, preconnect} from 'react-dom'\n\nimport {resolveCookiePerspective} from './resolveCookiePerspective'\n\n/**\n * @public\n */\nexport type DefinedSanityFetchType = <const QueryString extends string>(options: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n /**\n * Add custom `next.tags` to the underlying fetch request.\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnexttags\n * This can be used in conjunction with custom fallback revalidation strategies, as well as with custom Server Actions that mutate data and want to render with fresh data right away (faster than the Live Event latency).\n * @defaultValue `['sanity']`\n */\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n stega?: boolean\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.fetch'\n */\n requestTag?: string\n}) => Promise<{\n data: ClientReturn<QueryString>\n sourceMap: ContentSourceMap | null\n tags: string[]\n}>\n\n/**\n * @public\n */\nexport type DefinedSanityLiveStreamType = <const QueryString extends string>(props: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n /**\n * Add custom `next.tags` to the underlying fetch request.\n * @see https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnexttags\n * This can be used in conjunction with custom fallback revalidation strategies, as well as with custom Server Actions that mutate data and want to render with fresh data right away (faster than the Live Event latency).\n * @defaultValue `['sanity']`\n */\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n stega?: boolean\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.live-stream.fetch'\n */\n requestTag?: string\n children: (result: {\n data: ClientReturn<QueryString>\n sourceMap: ContentSourceMap | null\n tags: string[]\n }) => Promise<Awaited<React.ReactNode>>\n}) => React.ReactNode\n\n/**\n * @public\n */\nexport interface DefinedSanityLiveProps {\n /**\n * Automatic refresh of RSC when the component <SanityLive /> is mounted.\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `true`\n */\n refreshOnMount?: boolean\n /**\n * Automatically refresh when window gets focused\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `false` if draftMode().isEnabled, otherwise `true` if not inside an iframe\n */\n refreshOnFocus?: boolean\n /**\n * Automatically refresh when the browser regains a network connection (via navigator.onLine)\n * Note that this is different from revalidation, which is based on tags and causes `sanityFetch` calls to be re-fetched.\n * @defaultValue `true`\n */\n refreshOnReconnect?: boolean\n /**\n * Automatically refresh on an interval when the Live Event API emits a `goaway` event, which indicates that the connection is rejected or closed.\n * This typically happens if the connection limit is reached, or if the connection is idle for too long.\n * To disable this long polling fallback behavior set `intervalOnGoAway` to `false` or `0`.\n * You can also use `onGoAway` to handle the `goaway` event in your own way, and read the reason why the event was emitted.\n * @defaultValue `30_000` 30 seconds interval\n */\n intervalOnGoAway?: number | false\n\n /**\n * Delays events until after a Sanity Function has processed them and called the callback endpoint.\n * When omitted, events are delivered immediately.\n */\n waitFor?: 'function'\n\n /**\n * @deprecated use `requestTag` instead\n */\n tag?: never\n\n /**\n * This request tag is used to identify the request when viewing request logs from your Sanity Content Lake.\n * @see https://www.sanity.io/docs/reference-api-request-tags\n * @defaultValue 'next-loader.live'\n */\n requestTag?: string\n\n /**\n * Handle errors from the Live Events subscription.\n * By default it's reported using `console.error`, you can override this prop to handle it in your own way.\n */\n onError?: (error: unknown) => void\n\n /**\n * Handle the `goaway` event if the connection is rejected/closed.\n * `event.reason` will be a string of why the event was emitted, for example `'connection limit reached'`.\n * When this happens the `<SanityLive />` will fallback to long polling with a default interval of 30 seconds, providing your own `onGoAway` handler does not change this behavior.\n * If you want to disable long polling set `intervalOnGoAway` to `false` or `0`.\n */\n onGoAway?: (event: LiveEventGoAway, intervalOnGoAway: number | false) => void\n\n /**\n * Override how cache tags are invalidated, you need to pass a server action here.\n * You can also pass a `use client` function here, and have `router.refresh()` be called if the promise resolves to `'refresh'`.\n */\n revalidateSyncTags?: (tags: SyncTag[]) => Promise<void | 'refresh'>\n}\n\n/**\n * @public\n */\nexport interface DefineSanityLiveOptions {\n /**\n * Required for `sanityFetch` and `SanityLive` to work\n */\n client: SanityClient\n /**\n * Optional. If provided then the token needs to have permissions to query documents with `drafts.` prefixes in order for `perspective: 'drafts'` to work.\n * This token is not shared with the browser.\n */\n serverToken?: string | false\n /**\n * Optional. This token is shared with the browser, and should only have access to query published documents.\n * It is used to setup a `Live Draft Content` EventSource connection, and enables live previewing drafts stand-alone, outside of Presentation Tool.\n */\n browserToken?: string | false\n /**\n * Fetch options used by `sanityFetch`\n * @deprecated this option is removed in the next major version, use `export const revalidate` on the `page.tsx` or `layout.tsx` instead\n */\n fetchOptions?: {\n /**\n * Optional, enables time based revalidation in addition to the EventSource connection.\n * @defaultValue `false`\n */\n revalidate?: number | false\n }\n /**\n * Optional. Include stega encoding when draft mode is enabled.\n * @defaultValue `true`\n */\n stega?: boolean\n}\n\n/**\n * @public\n */\nexport function defineLive(config: DefineSanityLiveOptions): {\n /**\n * Use this function to fetch data from Sanity in your React Server Components.\n * @public\n */\n sanityFetch: DefinedSanityFetchType\n /**\n * Render this in your root layout.tsx to make your page revalidate on new content live, automatically.\n * @public\n */\n SanityLive: React.ComponentType<DefinedSanityLiveProps>\n /**\n * @alpha experimental, it may change or even be removed at any time\n */\n SanityLiveStream: DefinedSanityLiveStreamType\n} {\n const {\n client: _client,\n serverToken,\n browserToken,\n fetchOptions,\n stega: stegaEnabled = true,\n } = config\n\n if (!_client) {\n throw new Error('`client` is required for `defineLive` to function')\n }\n\n if (process.env.NODE_ENV !== 'production' && !serverToken && serverToken !== false) {\n console.warn(\n 'No `serverToken` provided to `defineLive`. This means that only published content will be fetched and respond to live events. You can silence this warning by setting `serverToken: false`.',\n )\n }\n\n if (process.env.NODE_ENV !== 'production' && !browserToken && browserToken !== false) {\n console.warn(\n 'No `browserToken` provided to `defineLive`. This means that live previewing drafts will only work when using the Presentation Tool in your Sanity Studio. To support live previewing drafts stand-alone, provide a `browserToken`. It is shared with the browser so it should only have Viewer rights or lower. You can silence this warning by setting `browserToken: false`.',\n )\n }\n\n const client = _client.withConfig({allowReconfigure: false, useCdn: false})\n const {token: originalToken} = client.config()\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedSanityFetchType = async function sanityFetch<\n const QueryString extends string,\n >({\n query,\n params = {},\n stega: _stega,\n tags = [],\n perspective: _perspective,\n tag,\n requestTag = tag ?? 'next-loader.fetch',\n }: {\n query: QueryString\n params?: QueryParams | Promise<QueryParams>\n stega?: boolean\n tags?: string[]\n perspective?: Exclude<ClientPerspective, 'raw'>\n tag?: string\n requestTag?: string\n }) {\n const stega = _stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled)\n const perspective = _perspective ?? (await resolveCookiePerspective())\n const useCdn = perspective === 'published'\n const revalidate =\n fetchOptions?.revalidate !== undefined\n ? fetchOptions.revalidate\n : process.env.NODE_ENV === 'production'\n ? false\n : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n\n const {syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective: perspective as ClientPerspective,\n stega: false,\n returnQuery: false,\n next: {revalidate, tags: [...tags, 'sanity:fetch-sync-tags']},\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `sanity:${tag}`) || [])]\n\n const {result, resultSourceMap} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective: perspective as ClientPerspective,\n stega,\n token: perspective !== 'published' && serverToken ? serverToken : originalToken,\n next: {revalidate, tags: cacheTags},\n useCdn,\n cacheMode,\n tag: requestTag,\n })\n return {data: result, sourceMap: resultSourceMap || null, tags: cacheTags}\n }\n\n const SanityLive: React.ComponentType<DefinedSanityLiveProps> = async function SanityLive(props) {\n const {\n refreshOnMount,\n refreshOnFocus,\n refreshOnReconnect,\n tag,\n requestTag = tag,\n onError,\n onGoAway,\n intervalOnGoAway,\n revalidateSyncTags,\n waitFor,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n const {isEnabled: isDraftModeEnabled} = await draftMode()\n\n // Preconnect to the Live Event API origin, or at least prefetch the DNS if preconenct is not supported\n const {origin} = new URL(client.getUrl('', false))\n preconnect(origin)\n prefetchDNS(origin)\n\n return (\n <SanityLiveClientComponent\n projectId={projectId}\n dataset={dataset}\n apiHost={apiHost}\n apiVersion={apiVersion}\n useProjectHostname={useProjectHostname}\n requestTagPrefix={requestTagPrefix}\n requestTag={requestTag}\n token={typeof browserToken === 'string' && isDraftModeEnabled ? browserToken : undefined}\n draftModeEnabled={isDraftModeEnabled}\n draftModePerspective={await resolveCookiePerspective()}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n onError={onError}\n onGoAway={onGoAway}\n intervalOnGoAway={intervalOnGoAway}\n revalidateSyncTags={revalidateSyncTags}\n waitFor={waitFor}\n />\n )\n }\n\n const SanityLiveStream: DefinedSanityLiveStreamType = async function SanityLiveStream(props) {\n const {\n query,\n params,\n perspective: _perspective,\n stega: _stega,\n tags,\n children,\n tag,\n requestTag = tag ?? 'next-loader.live-stream.fetch',\n } = props\n const {\n data,\n sourceMap,\n tags: cacheTags,\n } = await sanityFetch({\n query,\n params,\n tags,\n perspective: _perspective,\n stega: _stega,\n requestTag,\n })\n const {isEnabled: isDraftModeEnabled} = await draftMode()\n\n if (isDraftModeEnabled) {\n const stega = _stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled)\n const perspective = _perspective ?? (await resolveCookiePerspective())\n const {projectId, dataset} = client.config()\n return (\n <SanityLiveStreamClientComponent\n projectId={projectId}\n dataset={dataset}\n query={query}\n params={await params}\n perspective={perspective}\n stega={stega}\n initial={children({data, sourceMap, tags: cacheTags})}\n // oxlint-disable-next-line react/no-children-prop\n children={\n // oxlint-disable-next-line no-unsafe-type-assertion\n children as unknown as any\n }\n />\n )\n }\n\n return children({data, sourceMap, tags: cacheTags})\n }\n\n return {\n sanityFetch,\n SanityLive,\n SanityLiveStream,\n }\n}\n"],"mappings":"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"}
|
package/dist/live.server-only.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.server-only.js","names":[],"sources":["../src/live.server-only.ts"],"sourcesContent":["import type {\n DefineSanityLiveOptions,\n DefinedSanityFetchType,\n DefinedSanityLiveProps,\n DefinedSanityLiveStreamType,\n} from './live/defineLive'\n\n/**\n * @public\n */\nexport function defineLive(_config: DefineSanityLiveOptions): {\n sanityFetch: DefinedSanityFetchType\n SanityLive: React.ComponentType<DefinedSanityLiveProps>\n SanityLiveStream: DefinedSanityLiveStreamType\n} {\n throw new Error('defineLive can only be used in React Server Components')\n}\n\n/**\n * @public\n */\nexport type {\n DefineSanityLiveOptions,\n DefinedSanityFetchType,\n DefinedSanityLiveProps,\n DefinedSanityLiveStreamType,\n}\n\n// @TODO deprecate, so that we can simplify this branching and just use `import 'server-only'` instead\nexport {isCorsOriginError} from './isCorsOriginError'\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"live.server-only.js","names":[],"sources":["../src/live.server-only.ts"],"sourcesContent":["import type {\n DefineSanityLiveOptions,\n DefinedSanityFetchType,\n DefinedSanityLiveProps,\n DefinedSanityLiveStreamType,\n} from './live/defineLive'\n\n/**\n * @public\n */\nexport function defineLive(_config: DefineSanityLiveOptions): {\n sanityFetch: DefinedSanityFetchType\n SanityLive: React.ComponentType<DefinedSanityLiveProps>\n SanityLiveStream: DefinedSanityLiveStreamType\n} {\n throw new Error('defineLive can only be used in React Server Components')\n}\n\n/**\n * @public\n */\nexport type {\n DefineSanityLiveOptions,\n DefinedSanityFetchType,\n DefinedSanityLiveProps,\n DefinedSanityLiveStreamType,\n}\n\n// @TODO deprecate, so that we can simplify this branching and just use `import 'server-only'` instead\nexport {isCorsOriginError} from './isCorsOriginError'\n"],"mappings":";;;;AAUA,SAAgB,WAAW,SAIzB;AACA,OAAM,IAAI,MAAM,yDAAyD"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Suspense, lazy } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),
|
|
7
|
+
* or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)
|
|
8
|
+
* we could use `dynamic(() => import('...), {ssr: false})` here.
|
|
9
|
+
* Since we can't, we need to use a lazy import and Suspense ourself.
|
|
10
|
+
*/
|
|
4
11
|
const NextStudioClientComponent = lazy(() => import("../../NextStudio.js"));
|
|
5
12
|
function NextStudioLazyClientComponent(props) {
|
|
6
13
|
return /* @__PURE__ */ jsx(Suspense, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/studio/client-component/NextStudioLazy.tsx"],"sourcesContent":["/**\n *\n * If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),\n * or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)\n * we could use `dynamic(() => import('...), {ssr: false})` here.\n * Since we can't, we need to use a lazy import and Suspense ourself.\n */\n\nimport {lazy, Suspense} from 'react'\n\nimport type {NextStudioProps} from './NextStudio'\n\nconst NextStudioClientComponent = lazy(() => import('./NextStudio'))\n\nexport function NextStudioLazyClientComponent(props: NextStudioProps): React.ReactNode {\n return (\n <Suspense fallback={null}>\n <NextStudioClientComponent {...props} />\n </Suspense>\n )\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/studio/client-component/NextStudioLazy.tsx"],"sourcesContent":["/**\n *\n * If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),\n * or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)\n * we could use `dynamic(() => import('...), {ssr: false})` here.\n * Since we can't, we need to use a lazy import and Suspense ourself.\n */\n\nimport {lazy, Suspense} from 'react'\n\nimport type {NextStudioProps} from './NextStudio'\n\nconst NextStudioClientComponent = lazy(() => import('./NextStudio'))\n\nexport function NextStudioLazyClientComponent(props: NextStudioProps): React.ReactNode {\n return (\n <Suspense fallback={null}>\n <NextStudioClientComponent {...props} />\n </Suspense>\n )\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAM,4BAA4B,WAAW,OAAO,uBAAgB;AAEpE,SAAgB,8BAA8B,OAAyC;AACrF,QACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,2BAAD,EAA2B,GAAI,OAAS,CAAA;EAC/B,CAAA"}
|
package/dist/studio/index.js
CHANGED
|
@@ -2,15 +2,55 @@ import { n as NextStudioLayout, t as NextStudioNoScript } from "../NextStudioNoS
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { preloadModule } from "react-dom";
|
|
4
4
|
import { NextStudio } from "next-sanity/studio/client-component";
|
|
5
|
+
/**
|
|
6
|
+
* In router segments (`/app/studio/[[...index]]/page.tsx`):
|
|
7
|
+
* ```tsx
|
|
8
|
+
* // If you don't want to change any defaults you can just re-export the viewport config directly:
|
|
9
|
+
* export {viewport} from 'next-sanity/studio'
|
|
10
|
+
*
|
|
11
|
+
* // To customize the viewport config, spread it on the export:
|
|
12
|
+
* import {viewport as studioViewport} from 'next-sanity/studio'
|
|
13
|
+
* import type { Viewport } from 'next'
|
|
14
|
+
*
|
|
15
|
+
* export const viewport: Viewport = {
|
|
16
|
+
* ...studioViewport,
|
|
17
|
+
* // Overrides the viewport to resize behavior
|
|
18
|
+
* interactiveWidget: 'resizes-content'
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
5
23
|
const viewport = {
|
|
6
24
|
width: "device-width",
|
|
7
25
|
initialScale: 1,
|
|
8
26
|
viewportFit: "cover"
|
|
9
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* In router segments (`/app/studio/[[...index]]/page.tsx`):
|
|
30
|
+
* ```tsx
|
|
31
|
+
* // If you don't want to change any defaults you can just re-export the metadata directly:
|
|
32
|
+
* export {metadata} from 'next-sanity/studio'
|
|
33
|
+
*
|
|
34
|
+
* // To customize the metadata, spread it on the export:
|
|
35
|
+
* import {metadata as studioMetadata} from 'next-sanity/studio'
|
|
36
|
+
* import type { Metadata } from 'next'
|
|
37
|
+
*
|
|
38
|
+
* export const metadata: Metadata = {
|
|
39
|
+
* ...studioMetadata,
|
|
40
|
+
* // Set another title
|
|
41
|
+
* title: 'My Studio',
|
|
42
|
+
* })
|
|
43
|
+
* ```
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
10
46
|
const metadata = {
|
|
11
47
|
referrer: "same-origin",
|
|
12
48
|
robots: "noindex"
|
|
13
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* Loads the bridge script the same way Sanity Studio does:
|
|
52
|
+
* https://github.com/sanity-io/sanity/blob/bd5b1acb5015baaddd8d96c2abd1eaf579b3c904/packages/sanity/src/_internal/cli/server/renderDocument.tsx#L124-L139
|
|
53
|
+
*/
|
|
14
54
|
const bridgeScript = "https://core.sanity-cdn.com/bridge.js";
|
|
15
55
|
function NextStudioWithBridge(props) {
|
|
16
56
|
preloadModule(bridgeScript, { as: "script" });
|
package/dist/studio/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/studio/head.tsx","../../src/studio/NextStudioWithBridge.tsx"],"sourcesContent":["import type {Metadata, Viewport} from 'next'\n\n/**\n * In router segments (`/app/studio/[[...index]]/page.tsx`):\n * ```tsx\n * // If you don't want to change any defaults you can just re-export the viewport config directly:\n * export {viewport} from 'next-sanity/studio'\n *\n * // To customize the viewport config, spread it on the export:\n * import {viewport as studioViewport} from 'next-sanity/studio'\n * import type { Viewport } from 'next'\n *\n * export const viewport: Viewport = {\n * ...studioViewport,\n * // Overrides the viewport to resize behavior\n * interactiveWidget: 'resizes-content'\n * })\n * ```\n * @public\n */\nexport const viewport = {\n width: 'device-width' as const,\n initialScale: 1 as const,\n // Studio implements display cutouts CSS (The iPhone Notch ™ ) and needs `viewport-fit=covered` for it to work correctly\n viewportFit: 'cover',\n} satisfies Viewport\n\n/**\n * In router segments (`/app/studio/[[...index]]/page.tsx`):\n * ```tsx\n * // If you don't want to change any defaults you can just re-export the metadata directly:\n * export {metadata} from 'next-sanity/studio'\n *\n * // To customize the metadata, spread it on the export:\n * import {metadata as studioMetadata} from 'next-sanity/studio'\n * import type { Metadata } from 'next'\n *\n * export const metadata: Metadata = {\n * ...studioMetadata,\n * // Set another title\n * title: 'My Studio',\n * })\n * ```\n * @public\n */\nexport const metadata = {\n referrer: 'same-origin' as const,\n robots: 'noindex' as const,\n} satisfies Metadata\n","import {NextStudio, type NextStudioProps} from 'next-sanity/studio/client-component'\nimport {preloadModule} from 'react-dom'\n\n/**\n * Loads the bridge script the same way Sanity Studio does:\n * https://github.com/sanity-io/sanity/blob/bd5b1acb5015baaddd8d96c2abd1eaf579b3c904/packages/sanity/src/_internal/cli/server/renderDocument.tsx#L124-L139\n */\n\nconst bridgeScript = 'https://core.sanity-cdn.com/bridge.js'\n\nexport function NextStudioWithBridge(props: NextStudioProps): React.JSX.Element {\n preloadModule(bridgeScript, {as: 'script'})\n\n return (\n <>\n <script src={bridgeScript} async type=\"module\" data-sanity-core />\n <NextStudio {...props} />\n </>\n )\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/studio/head.tsx","../../src/studio/NextStudioWithBridge.tsx"],"sourcesContent":["import type {Metadata, Viewport} from 'next'\n\n/**\n * In router segments (`/app/studio/[[...index]]/page.tsx`):\n * ```tsx\n * // If you don't want to change any defaults you can just re-export the viewport config directly:\n * export {viewport} from 'next-sanity/studio'\n *\n * // To customize the viewport config, spread it on the export:\n * import {viewport as studioViewport} from 'next-sanity/studio'\n * import type { Viewport } from 'next'\n *\n * export const viewport: Viewport = {\n * ...studioViewport,\n * // Overrides the viewport to resize behavior\n * interactiveWidget: 'resizes-content'\n * })\n * ```\n * @public\n */\nexport const viewport = {\n width: 'device-width' as const,\n initialScale: 1 as const,\n // Studio implements display cutouts CSS (The iPhone Notch ™ ) and needs `viewport-fit=covered` for it to work correctly\n viewportFit: 'cover',\n} satisfies Viewport\n\n/**\n * In router segments (`/app/studio/[[...index]]/page.tsx`):\n * ```tsx\n * // If you don't want to change any defaults you can just re-export the metadata directly:\n * export {metadata} from 'next-sanity/studio'\n *\n * // To customize the metadata, spread it on the export:\n * import {metadata as studioMetadata} from 'next-sanity/studio'\n * import type { Metadata } from 'next'\n *\n * export const metadata: Metadata = {\n * ...studioMetadata,\n * // Set another title\n * title: 'My Studio',\n * })\n * ```\n * @public\n */\nexport const metadata = {\n referrer: 'same-origin' as const,\n robots: 'noindex' as const,\n} satisfies Metadata\n","import {NextStudio, type NextStudioProps} from 'next-sanity/studio/client-component'\nimport {preloadModule} from 'react-dom'\n\n/**\n * Loads the bridge script the same way Sanity Studio does:\n * https://github.com/sanity-io/sanity/blob/bd5b1acb5015baaddd8d96c2abd1eaf579b3c904/packages/sanity/src/_internal/cli/server/renderDocument.tsx#L124-L139\n */\n\nconst bridgeScript = 'https://core.sanity-cdn.com/bridge.js'\n\nexport function NextStudioWithBridge(props: NextStudioProps): React.JSX.Element {\n preloadModule(bridgeScript, {as: 'script'})\n\n return (\n <>\n <script src={bridgeScript} async type=\"module\" data-sanity-core />\n <NextStudio {...props} />\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,WAAW;CACtB,OAAO;CACP,cAAc;CAEd,aAAa;CACd;;;;;;;;;;;;;;;;;;;AAoBD,MAAa,WAAW;CACtB,UAAU;CACV,QAAQ;CACT;;;;;ACxCD,MAAM,eAAe;AAErB,SAAgB,qBAAqB,OAA2C;AAC9E,eAAc,cAAc,EAAC,IAAI,UAAS,CAAC;AAE3C,QACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,UAAD;EAAQ,KAAK;EAAc,OAAA;EAAM,MAAK;EAAS,oBAAA;EAAmB,CAAA,EAClE,oBAAC,YAAD,EAAY,GAAI,OAAS,CAAA,CACxB,EAAA,CAAA"}
|
package/dist/utils.js
CHANGED
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../src/live/utils.ts"],"sourcesContent":["import {validateApiPerspective, type ClientPerspective} from '@sanity/client'\n\n/** @internal */\nexport function sanitizePerspective(\n _perspective: unknown,\n fallback: 'drafts' | 'published',\n): Exclude<ClientPerspective, 'raw'> {\n const perspective =\n typeof _perspective === 'string' && _perspective.includes(',')\n ? _perspective.split(',')\n : _perspective\n try {\n validateApiPerspective(perspective)\n return perspective === 'raw' ? fallback : perspective\n } catch (err) {\n console.warn(`Invalid perspective:`, _perspective, perspective, err)\n return fallback\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../src/live/utils.ts"],"sourcesContent":["import {validateApiPerspective, type ClientPerspective} from '@sanity/client'\n\n/** @internal */\nexport function sanitizePerspective(\n _perspective: unknown,\n fallback: 'drafts' | 'published',\n): Exclude<ClientPerspective, 'raw'> {\n const perspective =\n typeof _perspective === 'string' && _perspective.includes(',')\n ? _perspective.split(',')\n : _perspective\n try {\n validateApiPerspective(perspective)\n return perspective === 'raw' ? fallback : perspective\n } catch (err) {\n console.warn(`Invalid perspective:`, _perspective, perspective, err)\n return fallback\n }\n}\n"],"mappings":";;AAGA,SAAgB,oBACd,cACA,UACmC;CACnC,MAAM,cACJ,OAAO,iBAAiB,YAAY,aAAa,SAAS,IAAI,GAC1D,aAAa,MAAM,IAAI,GACvB;AACN,KAAI;AACF,yBAAuB,YAAY;AACnC,SAAO,gBAAgB,QAAQ,WAAW;UACnC,KAAK;AACZ,UAAQ,KAAK,wBAAwB,cAAc,aAAa,IAAI;AACpE,SAAO"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Suspense, lazy } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),
|
|
7
|
+
* or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)
|
|
8
|
+
* we could use `dynamic(() => import('...), {ssr: false})` here.
|
|
9
|
+
* Since we can't, we need to use a lazy import and Suspense ourself.
|
|
10
|
+
*/
|
|
4
11
|
const VisualEditingClientComponent = lazy(() => import("../../VisualEditing.js"));
|
|
5
12
|
function VisualEditingLazyClientComponent(props) {
|
|
6
13
|
return /* @__PURE__ */ jsx(Suspense, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/visual-editing/client-component/VisualEditingLazy.tsx"],"sourcesContent":["/**\n *\n * If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),\n * or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)\n * we could use `dynamic(() => import('...), {ssr: false})` here.\n * Since we can't, we need to use a lazy import and Suspense ourself.\n */\n\nimport {lazy, Suspense} from 'react'\n\nimport type {VisualEditingProps} from './VisualEditing'\n\nconst VisualEditingClientComponent = lazy(() => import('./VisualEditing'))\n\nexport function VisualEditingLazyClientComponent(props: VisualEditingProps): React.ReactNode {\n return (\n <Suspense fallback={null}>\n <VisualEditingClientComponent {...props} />\n </Suspense>\n )\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/visual-editing/client-component/VisualEditingLazy.tsx"],"sourcesContent":["/**\n *\n * If pages router supported `next/dynamic` imports (it wants `next/dynamic.js`),\n * or if turbopack in app router allowed `next/dynamic.js` (it doesn't yet)\n * we could use `dynamic(() => import('...), {ssr: false})` here.\n * Since we can't, we need to use a lazy import and Suspense ourself.\n */\n\nimport {lazy, Suspense} from 'react'\n\nimport type {VisualEditingProps} from './VisualEditing'\n\nconst VisualEditingClientComponent = lazy(() => import('./VisualEditing'))\n\nexport function VisualEditingLazyClientComponent(props: VisualEditingProps): React.ReactNode {\n return (\n <Suspense fallback={null}>\n <VisualEditingClientComponent {...props} />\n </Suspense>\n )\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAM,+BAA+B,WAAW,OAAO,0BAAmB;AAE1E,SAAgB,iCAAiC,OAA4C;AAC3F,QACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,8BAAD,EAA8B,GAAI,OAAS,CAAA;EAClC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/visual-editing/VisualEditing.tsx"],"sourcesContent":["import type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\nimport VisualEditingComponent from 'next-sanity/visual-editing/client-component'\n\n/**\n * @public\n */\nexport function VisualEditing(props: VisualEditingProps): React.ReactElement {\n let autoBasePath: string | undefined\n if (typeof props.basePath !== 'string') {\n try {\n autoBasePath = process.env['__NEXT_ROUTER_BASEPATH']\n if (autoBasePath) {\n // oxlint-disable-next-line no-console\n console.log(\n `Detected next basePath as ${JSON.stringify(autoBasePath)} by reading \"process.env.__NEXT_ROUTER_BASEPATH\". If this is incorrect then you can set it manually with the basePath prop on the <VisualEditing /> component.`,\n )\n }\n } catch (err) {\n console.error('Failed detecting basePath', err)\n }\n }\n let autoTrailingSlash: boolean | undefined\n if (typeof props.trailingSlash !== 'boolean') {\n try {\n autoTrailingSlash = Boolean(process.env['__NEXT_TRAILING_SLASH'])\n if (autoTrailingSlash) {\n // oxlint-disable-next-line no-console\n console.log(\n `Detected next trailingSlash as ${JSON.stringify(autoTrailingSlash)} by reading \"process.env.__NEXT_TRAILING_SLASH\". If this is incorrect then you can set it manually with the trailingSlash prop on the <VisualEditing /> component.`,\n )\n }\n } catch (err) {\n console.error('Failed detecting trailingSlash', err)\n }\n }\n return (\n <VisualEditingComponent\n {...props}\n basePath={props.basePath ?? autoBasePath}\n trailingSlash={props.trailingSlash ?? autoTrailingSlash}\n />\n )\n}\n\nexport type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/visual-editing/VisualEditing.tsx"],"sourcesContent":["import type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\nimport VisualEditingComponent from 'next-sanity/visual-editing/client-component'\n\n/**\n * @public\n */\nexport function VisualEditing(props: VisualEditingProps): React.ReactElement {\n let autoBasePath: string | undefined\n if (typeof props.basePath !== 'string') {\n try {\n autoBasePath = process.env['__NEXT_ROUTER_BASEPATH']\n if (autoBasePath) {\n // oxlint-disable-next-line no-console\n console.log(\n `Detected next basePath as ${JSON.stringify(autoBasePath)} by reading \"process.env.__NEXT_ROUTER_BASEPATH\". If this is incorrect then you can set it manually with the basePath prop on the <VisualEditing /> component.`,\n )\n }\n } catch (err) {\n console.error('Failed detecting basePath', err)\n }\n }\n let autoTrailingSlash: boolean | undefined\n if (typeof props.trailingSlash !== 'boolean') {\n try {\n autoTrailingSlash = Boolean(process.env['__NEXT_TRAILING_SLASH'])\n if (autoTrailingSlash) {\n // oxlint-disable-next-line no-console\n console.log(\n `Detected next trailingSlash as ${JSON.stringify(autoTrailingSlash)} by reading \"process.env.__NEXT_TRAILING_SLASH\". If this is incorrect then you can set it manually with the trailingSlash prop on the <VisualEditing /> component.`,\n )\n }\n } catch (err) {\n console.error('Failed detecting trailingSlash', err)\n }\n }\n return (\n <VisualEditingComponent\n {...props}\n basePath={props.basePath ?? autoBasePath}\n trailingSlash={props.trailingSlash ?? autoTrailingSlash}\n />\n )\n}\n\nexport type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\n"],"mappings":";;;;;AAMA,SAAgB,cAAc,OAA+C;CAC3E,IAAI;AACJ,KAAI,OAAO,MAAM,aAAa,SAC5B,KAAI;AACF,iBAAe,QAAQ,IAAI;AAC3B,MAAI,aAEF,SAAQ,IACN,6BAA6B,KAAK,UAAU,aAAa,CAAC,gKAC3D;UAEI,KAAK;AACZ,UAAQ,MAAM,6BAA6B,IAAI;;CAGnD,IAAI;AACJ,KAAI,OAAO,MAAM,kBAAkB,UACjC,KAAI;AACF,sBAAoB,QAAQ,QAAQ,IAAI,yBAAyB;AACjE,MAAI,kBAEF,SAAQ,IACN,kCAAkC,KAAK,UAAU,kBAAkB,CAAC,oKACrE;UAEI,KAAK;AACZ,UAAQ,MAAM,kCAAkC,IAAI;;AAGxD,QACE,oBAAC,wBAAD;EACE,GAAI;EACJ,UAAU,MAAM,YAAY;EAC5B,eAAe,MAAM,iBAAiB;EACtC,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use server";
|
|
2
|
-
import { draftMode } from "next/headers";
|
|
3
|
-
import { revalidatePath } from "next/cache";
|
|
2
|
+
import { draftMode } from "next/headers.js";
|
|
3
|
+
import { revalidatePath } from "next/cache.js";
|
|
4
4
|
async function revalidateRootLayout() {
|
|
5
5
|
if (!(await draftMode()).isEnabled) {
|
|
6
6
|
console.warn("Skipped revalidatePath request because draft mode is not enabled");
|
package/dist/webhook/index.d.ts
CHANGED
package/dist/webhook/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { SIGNATURE_HEADER_NAME, isValidSignature } from "@sanity/webhook";
|
|
2
|
+
/**
|
|
3
|
+
* Handles parsing the body JSON, and validating its signature. Also waits for Content Lake eventual consistency so you can run your queries
|
|
4
|
+
* without worrying about getting stale data.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
2
7
|
async function parseBody(req, secret, waitForContentLakeEventualConsistency = true) {
|
|
3
8
|
const signature = req.headers.get(SIGNATURE_HEADER_NAME);
|
|
4
9
|
if (!signature) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/webhook/index.ts"],"sourcesContent":["import {isValidSignature, SIGNATURE_HEADER_NAME} from '@sanity/webhook'\nimport type {NextRequest} from 'next/server'\n\n/** @public */\nexport type ParsedBody<T> = {\n /**\n * If a secret is given then it returns a boolean. If no secret is provided then no validation is done on the signature, and it'll return `null`\n */\n isValidSignature: boolean | null\n body: T | null\n}\n\n/** @public */\ninterface SanityDocument {\n _id: string\n _type: string\n _createdAt: string\n _updatedAt: string\n _rev: string\n [key: string]: unknown\n}\n\n/**\n * Handles parsing the body JSON, and validating its signature. Also waits for Content Lake eventual consistency so you can run your queries\n * without worrying about getting stale data.\n * @public\n */\nexport async function parseBody<Body = SanityDocument>(\n req: NextRequest,\n secret?: string,\n waitForContentLakeEventualConsistency = true,\n): Promise<ParsedBody<Body>> {\n const signature = req.headers.get(SIGNATURE_HEADER_NAME)\n if (!signature) {\n console.error('Missing signature header')\n return {body: null, isValidSignature: null}\n }\n\n const body = await req.text()\n const validSignature = secret ? await isValidSignature(body, signature, secret.trim()) : null\n\n if (validSignature !== false && waitForContentLakeEventualConsistency) {\n await new Promise((resolve) => setTimeout(resolve, 3000))\n }\n\n return {\n body: body.trim() ? JSON.parse(body) : null,\n isValidSignature: validSignature,\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/webhook/index.ts"],"sourcesContent":["import {isValidSignature, SIGNATURE_HEADER_NAME} from '@sanity/webhook'\nimport type {NextRequest} from 'next/server'\n\n/** @public */\nexport type ParsedBody<T> = {\n /**\n * If a secret is given then it returns a boolean. If no secret is provided then no validation is done on the signature, and it'll return `null`\n */\n isValidSignature: boolean | null\n body: T | null\n}\n\n/** @public */\ninterface SanityDocument {\n _id: string\n _type: string\n _createdAt: string\n _updatedAt: string\n _rev: string\n [key: string]: unknown\n}\n\n/**\n * Handles parsing the body JSON, and validating its signature. Also waits for Content Lake eventual consistency so you can run your queries\n * without worrying about getting stale data.\n * @public\n */\nexport async function parseBody<Body = SanityDocument>(\n req: NextRequest,\n secret?: string,\n waitForContentLakeEventualConsistency = true,\n): Promise<ParsedBody<Body>> {\n const signature = req.headers.get(SIGNATURE_HEADER_NAME)\n if (!signature) {\n console.error('Missing signature header')\n return {body: null, isValidSignature: null}\n }\n\n const body = await req.text()\n const validSignature = secret ? await isValidSignature(body, signature, secret.trim()) : null\n\n if (validSignature !== false && waitForContentLakeEventualConsistency) {\n await new Promise((resolve) => setTimeout(resolve, 3000))\n }\n\n return {\n body: body.trim() ? JSON.parse(body) : null,\n isValidSignature: validSignature,\n }\n}\n"],"mappings":";;;;;;AA2BA,eAAsB,UACpB,KACA,QACA,wCAAwC,MACb;CAC3B,MAAM,YAAY,IAAI,QAAQ,IAAI,sBAAsB;AACxD,KAAI,CAAC,WAAW;AACd,UAAQ,MAAM,2BAA2B;AACzC,SAAO;GAAC,MAAM;GAAM,kBAAkB;GAAK;;CAG7C,MAAM,OAAO,MAAM,IAAI,MAAM;CAC7B,MAAM,iBAAiB,SAAS,MAAM,iBAAiB,MAAM,WAAW,OAAO,MAAM,CAAC,GAAG;AAEzF,KAAI,mBAAmB,SAAS,sCAC9B,OAAM,IAAI,SAAS,YAAY,WAAW,SAAS,IAAK,CAAC;AAG3D,QAAO;EACL,MAAM,KAAK,MAAM,GAAG,KAAK,MAAM,KAAK,GAAG;EACvC,kBAAkB;EACnB"}
|