next-sanity 12.3.4 → 12.3.5
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/RefreshOnFocus.js +2 -2
- package/dist/RefreshOnFocus.js.map +1 -1
- package/dist/RefreshOnInterval.js +14 -0
- package/dist/RefreshOnInterval.js.map +1 -0
- package/dist/RefreshOnMount.js +3 -3
- package/dist/RefreshOnMount.js.map +1 -1
- package/dist/RefreshOnReconnect.js +2 -2
- package/dist/RefreshOnReconnect.js.map +1 -1
- package/dist/live/client-components/index.d.ts +0 -3
- package/dist/live/client-components/index.d.ts.map +1 -1
- package/dist/live/client-components/index.js +16 -22
- package/dist/live/client-components/index.js.map +1 -1
- package/dist/live/conditions/react-server/index.js +1 -2
- package/dist/live/conditions/react-server/index.js.map +1 -1
- package/package.json +2 -2
package/dist/RefreshOnFocus.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRouter } from "next/navigation";
|
|
2
|
-
import { useEffect } from "react";
|
|
2
|
+
import { startTransition, useEffect } from "react";
|
|
3
3
|
const focusThrottleInterval = 5e3;
|
|
4
4
|
function RefreshOnFocus() {
|
|
5
5
|
const router = useRouter();
|
|
@@ -9,7 +9,7 @@ function RefreshOnFocus() {
|
|
|
9
9
|
const callback = () => {
|
|
10
10
|
const now = Date.now();
|
|
11
11
|
if (now > nextFocusRevalidatedAt && document.visibilityState !== "hidden") {
|
|
12
|
-
router.refresh();
|
|
12
|
+
startTransition(() => router.refresh());
|
|
13
13
|
nextFocusRevalidatedAt = now + focusThrottleInterval;
|
|
14
14
|
}
|
|
15
15
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RefreshOnFocus.js","names":[],"sources":["../src/live/client-components/RefreshOnFocus.tsx"],"sourcesContent":["import {useRouter} from 'next/navigation'\nimport {useEffect} from 'react'\n\nconst focusThrottleInterval = 5_000\n\nexport default function RefreshOnFocus(): null {\n const router = useRouter()\n\n useEffect(() => {\n const controller = new AbortController()\n let nextFocusRevalidatedAt = 0\n const callback = () => {\n const now = Date.now()\n if (now > nextFocusRevalidatedAt && document.visibilityState !== 'hidden') {\n router.refresh()\n nextFocusRevalidatedAt = now + focusThrottleInterval\n }\n }\n const {signal} = controller\n document.addEventListener('visibilitychange', callback, {passive: true, signal})\n window.addEventListener('focus', callback, {passive: true, signal})\n return () => controller.abort()\n }, [router])\n\n return null\n}\nRefreshOnFocus.displayName = 'RefreshOnFocus'\n"],"mappings":";;AAGA,MAAM,wBAAwB;AAE9B,SAAwB,iBAAuB;CAC7C,MAAM,SAAS,WAAW;AAE1B,iBAAgB;EACd,MAAM,aAAa,IAAI,iBAAiB;EACxC,IAAI,yBAAyB;EAC7B,MAAM,iBAAiB;GACrB,MAAM,MAAM,KAAK,KAAK;AACtB,OAAI,MAAM,0BAA0B,SAAS,oBAAoB,UAAU;AACzE,
|
|
1
|
+
{"version":3,"file":"RefreshOnFocus.js","names":[],"sources":["../src/live/client-components/RefreshOnFocus.tsx"],"sourcesContent":["import {useRouter} from 'next/navigation'\nimport {startTransition, useEffect} from 'react'\n\nconst focusThrottleInterval = 5_000\n\nexport default function RefreshOnFocus(): null {\n const router = useRouter()\n\n useEffect(() => {\n const controller = new AbortController()\n let nextFocusRevalidatedAt = 0\n const callback = () => {\n const now = Date.now()\n if (now > nextFocusRevalidatedAt && document.visibilityState !== 'hidden') {\n startTransition(() => router.refresh())\n nextFocusRevalidatedAt = now + focusThrottleInterval\n }\n }\n const {signal} = controller\n document.addEventListener('visibilitychange', callback, {passive: true, signal})\n window.addEventListener('focus', callback, {passive: true, signal})\n return () => controller.abort()\n }, [router])\n\n return null\n}\nRefreshOnFocus.displayName = 'RefreshOnFocus'\n"],"mappings":";;AAGA,MAAM,wBAAwB;AAE9B,SAAwB,iBAAuB;CAC7C,MAAM,SAAS,WAAW;AAE1B,iBAAgB;EACd,MAAM,aAAa,IAAI,iBAAiB;EACxC,IAAI,yBAAyB;EAC7B,MAAM,iBAAiB;GACrB,MAAM,MAAM,KAAK,KAAK;AACtB,OAAI,MAAM,0BAA0B,SAAS,oBAAoB,UAAU;AACzE,0BAAsB,OAAO,SAAS,CAAC;AACvC,6BAAyB,MAAM;;;EAGnC,MAAM,EAAC,WAAU;AACjB,WAAS,iBAAiB,oBAAoB,UAAU;GAAC,SAAS;GAAM;GAAO,CAAC;AAChF,SAAO,iBAAiB,SAAS,UAAU;GAAC,SAAS;GAAM;GAAO,CAAC;AACnE,eAAa,WAAW,OAAO;IAC9B,CAAC,OAAO,CAAC;AAEZ,QAAO;;AAET,eAAe,cAAc"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useRouter } from "next/navigation";
|
|
2
|
+
import { startTransition, useEffect } from "react";
|
|
3
|
+
function RefreshOnInterval(props) {
|
|
4
|
+
const router = useRouter();
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const interval = setInterval(() => startTransition(() => router.refresh()), props.interval);
|
|
7
|
+
return () => clearInterval(interval);
|
|
8
|
+
}, [router, props.interval]);
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
RefreshOnInterval.displayName = "RefreshOnInterval";
|
|
12
|
+
export { RefreshOnInterval as default };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=RefreshOnInterval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RefreshOnInterval.js","names":[],"sources":["../src/live/client-components/RefreshOnInterval.tsx"],"sourcesContent":["import {useRouter} from 'next/navigation'\nimport {startTransition, useEffect} from 'react'\n\nexport default function RefreshOnInterval(props: {interval: number}): null {\n const router = useRouter()\n\n useEffect(() => {\n const interval = setInterval(() => startTransition(() => router.refresh()), props.interval)\n return () => clearInterval(interval)\n }, [router, props.interval])\n\n return null\n}\nRefreshOnInterval.displayName = 'RefreshOnInterval'\n"],"mappings":";;AAGA,SAAwB,kBAAkB,OAAiC;CACzE,MAAM,SAAS,WAAW;AAE1B,iBAAgB;EACd,MAAM,WAAW,kBAAkB,sBAAsB,OAAO,SAAS,CAAC,EAAE,MAAM,SAAS;AAC3F,eAAa,cAAc,SAAS;IACnC,CAAC,QAAQ,MAAM,SAAS,CAAC;AAE5B,QAAO;;AAET,kBAAkB,cAAc"}
|
package/dist/RefreshOnMount.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRouter } from "next/navigation";
|
|
2
|
-
import { useEffect, useReducer } from "react";
|
|
2
|
+
import { startTransition, useEffect, useReducer } from "react";
|
|
3
3
|
/**
|
|
4
4
|
* Handles refreshing the page when the page is mounted,
|
|
5
5
|
* in case the content changes at a high enough frequency that by
|
|
@@ -10,10 +10,10 @@ function RefreshOnMount() {
|
|
|
10
10
|
const router = useRouter();
|
|
11
11
|
const [mounted, mount] = useReducer(() => true, false);
|
|
12
12
|
useEffect(() => {
|
|
13
|
-
if (!mounted) {
|
|
13
|
+
if (!mounted) startTransition(() => {
|
|
14
14
|
mount();
|
|
15
15
|
router.refresh();
|
|
16
|
-
}
|
|
16
|
+
});
|
|
17
17
|
}, [mounted, router]);
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RefreshOnMount.js","names":[],"sources":["../src/live/client-components/RefreshOnMount.tsx"],"sourcesContent":["/**\n * Handles refreshing the page when the page is mounted,\n * in case the content changes at a high enough frequency that by\n * the time the page started streaming, and the <SanityLive> component sets\n * up the EventSource connection, content might have changed.\n */\n\nimport {useRouter} from 'next/navigation'\nimport {useEffect, useReducer} from 'react'\n\nexport default function RefreshOnMount(): null {\n const router = useRouter()\n const [mounted, mount] = useReducer(() => true, false)\n\n useEffect(() => {\n if (!mounted) {\n mount()\n
|
|
1
|
+
{"version":3,"file":"RefreshOnMount.js","names":[],"sources":["../src/live/client-components/RefreshOnMount.tsx"],"sourcesContent":["/**\n * Handles refreshing the page when the page is mounted,\n * in case the content changes at a high enough frequency that by\n * the time the page started streaming, and the <SanityLive> component sets\n * up the EventSource connection, content might have changed.\n */\n\nimport {useRouter} from 'next/navigation'\nimport {useEffect, useReducer, startTransition} from 'react'\n\nexport default function RefreshOnMount(): null {\n const router = useRouter()\n const [mounted, mount] = useReducer(() => true, false)\n\n useEffect(() => {\n if (!mounted) {\n startTransition(() => {\n mount()\n router.refresh()\n })\n }\n }, [mounted, router])\n\n return null\n}\nRefreshOnMount.displayName = 'RefreshOnMount'\n"],"mappings":";;;;;;;;AAUA,SAAwB,iBAAuB;CAC7C,MAAM,SAAS,WAAW;CAC1B,MAAM,CAAC,SAAS,SAAS,iBAAiB,MAAM,MAAM;AAEtD,iBAAgB;AACd,MAAI,CAAC,QACH,uBAAsB;AACpB,UAAO;AACP,UAAO,SAAS;IAChB;IAEH,CAAC,SAAS,OAAO,CAAC;AAErB,QAAO;;AAET,eAAe,cAAc"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useRouter } from "next/navigation";
|
|
2
|
-
import { useEffect } from "react";
|
|
2
|
+
import { startTransition, useEffect } from "react";
|
|
3
3
|
function RefreshOnReconnect() {
|
|
4
4
|
const router = useRouter();
|
|
5
5
|
useEffect(() => {
|
|
6
6
|
const controller = new AbortController();
|
|
7
7
|
const { signal } = controller;
|
|
8
|
-
window.addEventListener("online", () => router.refresh(), {
|
|
8
|
+
window.addEventListener("online", () => startTransition(() => router.refresh()), {
|
|
9
9
|
passive: true,
|
|
10
10
|
signal
|
|
11
11
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RefreshOnReconnect.js","names":[],"sources":["../src/live/client-components/RefreshOnReconnect.tsx"],"sourcesContent":["import {useRouter} from 'next/navigation'\nimport {useEffect} from 'react'\n\nexport default function RefreshOnReconnect(): null {\n const router = useRouter()\n\n useEffect(() => {\n const controller = new AbortController()\n const {signal} = controller\n window.addEventListener('online', () => router.refresh(), {passive: true
|
|
1
|
+
{"version":3,"file":"RefreshOnReconnect.js","names":[],"sources":["../src/live/client-components/RefreshOnReconnect.tsx"],"sourcesContent":["import {useRouter} from 'next/navigation'\nimport {startTransition, useEffect} from 'react'\n\nexport default function RefreshOnReconnect(): null {\n const router = useRouter()\n\n useEffect(() => {\n const controller = new AbortController()\n const {signal} = controller\n window.addEventListener('online', () => startTransition(() => router.refresh()), {\n passive: true,\n signal,\n })\n return () => controller.abort()\n }, [router])\n\n return null\n}\nRefreshOnReconnect.displayName = 'RefreshOnReconnect'\n"],"mappings":";;AAGA,SAAwB,qBAA2B;CACjD,MAAM,SAAS,WAAW;AAE1B,iBAAgB;EACd,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,EAAC,WAAU;AACjB,SAAO,iBAAiB,gBAAgB,sBAAsB,OAAO,SAAS,CAAC,EAAE;GAC/E,SAAS;GACT;GACD,CAAC;AACF,eAAa,WAAW,OAAO;IAC9B,CAAC,OAAO,CAAC;AAEZ,QAAO;;AAET,mBAAmB,cAAc"}
|
|
@@ -26,9 +26,6 @@ interface SanityLiveProps extends Pick<InitializedClientConfig, "projectId" | "d
|
|
|
26
26
|
*/
|
|
27
27
|
waitFor?: "function";
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
30
|
-
* @public
|
|
31
|
-
*/
|
|
32
29
|
declare function SanityLive(props: SanityLiveProps): React.JSX.Element | null;
|
|
33
30
|
export { type SanityLiveProps, SanityLive as default };
|
|
34
31
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/live/client-components/SanityLive.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/live/client-components/SanityLive.tsx"],"mappings":";;AA2BA;;UAAiB,eAAA,SAAwB,IAAA,CACvC,uBAAA;EAUA,gBAAA;EACA,oBAAA,GAAuB,iBAAA;EACvB,cAAA;EACA,cAAA;EACA,kBAAA;EACA,UAAA;;;;;EAKA,OAAA,IAAW,KAAA;EACX,gBAAA;EACA,QAAA,IAAY,KAAA,EAAO,eAAA,EAAiB,gBAAA;EACpC,kBAAA,IAAsB,IAAA,EAAM,OAAA,OAAc,OAAA;;;;;;;;EAQ1C,OAAA;AAAA;AAAA,iBA+BO,UAAA,CAAW,KAAA,EAAO,eAAA,GAAkB,KAAA,CAAM,GAAA,CAAI,OAAA"}
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
import { d as setEnvironment, f as setPerspective } from "../../context.js";
|
|
3
3
|
import { t as isCorsOriginError } from "../../isCorsOriginError.js";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
|
-
import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { startTransition, 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
10
|
import dynamic from "next/dynamic";
|
|
11
|
-
const PresentationComlink = dynamic(() => import("../../PresentationComlink.js")
|
|
12
|
-
const RefreshOnMount = dynamic(() => import("../../RefreshOnMount.js")
|
|
13
|
-
const
|
|
14
|
-
const
|
|
11
|
+
const PresentationComlink = dynamic(() => import("../../PresentationComlink.js"));
|
|
12
|
+
const RefreshOnMount = dynamic(() => import("../../RefreshOnMount.js"));
|
|
13
|
+
const RefreshOnInterval = dynamic(() => import("../../RefreshOnInterval.js"));
|
|
14
|
+
const RefreshOnFocus = dynamic(() => import("../../RefreshOnFocus.js"));
|
|
15
|
+
const RefreshOnReconnect = dynamic(() => import("../../RefreshOnReconnect.js"));
|
|
15
16
|
function handleError(error) {
|
|
16
17
|
if (isCorsOriginError(error)) console.warn(`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.`, error.addOriginUrl && `Add it here:`, error.addOriginUrl?.toString());
|
|
17
18
|
else console.error(error);
|
|
@@ -20,9 +21,6 @@ function handleOnGoAway(event, intervalOnGoAway) {
|
|
|
20
21
|
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
22
|
else console.error("Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason:", event.reason);
|
|
22
23
|
}
|
|
23
|
-
/**
|
|
24
|
-
* @public
|
|
25
|
-
*/
|
|
26
24
|
function SanityLive(props) {
|
|
27
25
|
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;
|
|
28
26
|
const client = useMemo(() => createClient({
|
|
@@ -44,7 +42,7 @@ function SanityLive(props) {
|
|
|
44
42
|
token,
|
|
45
43
|
useProjectHostname
|
|
46
44
|
]);
|
|
47
|
-
const [
|
|
45
|
+
const [refreshOnInterval, setRefreshOnInterval] = useState(false);
|
|
48
46
|
/**
|
|
49
47
|
* 1. Handle Live Events and call revalidateTag or router.refresh when needed
|
|
50
48
|
*/
|
|
@@ -52,15 +50,17 @@ function SanityLive(props) {
|
|
|
52
50
|
const handleLiveEvent = useEffectEvent((event) => {
|
|
53
51
|
if (process.env.NODE_ENV !== "production" && event.type === "welcome") {
|
|
54
52
|
console.info("Sanity is live with", token ? "automatic revalidation for draft content changes as well as published content" : draftModeEnabled ? "automatic revalidation for only published content. Provide a `browserToken` to `defineLive` to support draft content outside of Presentation Tool." : "automatic revalidation of published content");
|
|
55
|
-
|
|
53
|
+
startTransition(() => setRefreshOnInterval(false));
|
|
56
54
|
} else if (event.type === "message") if (waitFor === "function") router.refresh();
|
|
57
55
|
else revalidateSyncTags$1(event.tags).then((result) => {
|
|
58
|
-
if (result === "refresh") router.refresh();
|
|
56
|
+
if (result === "refresh") startTransition(() => router.refresh());
|
|
59
57
|
});
|
|
60
|
-
else if (event.type === "restart" || event.type === "reconnect")
|
|
61
|
-
|
|
58
|
+
else if (event.type === "restart" || event.type === "reconnect") {
|
|
59
|
+
startTransition(() => setRefreshOnInterval(false));
|
|
60
|
+
startTransition(() => router.refresh());
|
|
61
|
+
} else if (event.type === "goaway") {
|
|
62
62
|
onGoAway(event, intervalOnGoAway);
|
|
63
|
-
|
|
63
|
+
startTransition(() => setRefreshOnInterval(intervalOnGoAway));
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
useEffect(() => {
|
|
@@ -139,14 +139,6 @@ function SanityLive(props) {
|
|
|
139
139
|
});
|
|
140
140
|
};
|
|
141
141
|
}, [draftModeEnabled]);
|
|
142
|
-
/**
|
|
143
|
-
* 6. Handle switching to long polling when needed
|
|
144
|
-
*/
|
|
145
|
-
useEffect(() => {
|
|
146
|
-
if (!longPollingInterval) return;
|
|
147
|
-
const interval = setInterval(() => router.refresh(), longPollingInterval);
|
|
148
|
-
return () => clearInterval(interval);
|
|
149
|
-
}, [longPollingInterval, router]);
|
|
150
142
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
143
|
draftModeEnabled && loadComlink && /* @__PURE__ */ jsx(PresentationComlink, {
|
|
152
144
|
projectId,
|
|
@@ -155,10 +147,12 @@ function SanityLive(props) {
|
|
|
155
147
|
draftModePerspective
|
|
156
148
|
}),
|
|
157
149
|
!draftModeEnabled && refreshOnMount && /* @__PURE__ */ jsx(RefreshOnMount, {}),
|
|
150
|
+
refreshOnInterval && Number.isFinite(refreshOnInterval) && refreshOnInterval > 0 && /* @__PURE__ */ jsx(RefreshOnInterval, { interval: refreshOnInterval }),
|
|
158
151
|
!draftModeEnabled && refreshOnFocus && /* @__PURE__ */ jsx(RefreshOnFocus, {}),
|
|
159
152
|
!draftModeEnabled && refreshOnReconnect && /* @__PURE__ */ jsx(RefreshOnReconnect, {})
|
|
160
153
|
] });
|
|
161
154
|
}
|
|
155
|
+
SanityLive.displayName = "SanityLiveClientComponent";
|
|
162
156
|
export { SanityLive as default };
|
|
163
157
|
|
|
164
158
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["defaultRevalidateSyncTags","revalidateSyncTags"],"sources":["../../../src/live/client-components/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 '#live/isCorsOriginError'\n\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":";;;;;;;;;;AAkBA,MAAM,sBAAsB,cAAc,OAAO,iCAA0B,EAAC,KAAK,OAAM,CAAC;AACxF,MAAM,iBAAiB,cAAc,OAAO,4BAAqB,EAAC,KAAK,OAAM,CAAC;AAC9E,MAAM,iBAAiB,cAAc,OAAO,4BAAqB,EAAC,KAAK,OAAM,CAAC;AAC9E,MAAM,qBAAqB,cAAc,OAAO,gCAAyB,EAAC,KAAK,OAAM,CAAC;AAwCtF,SAAS,YAAY,OAAgB;AACnC,KAAI,kBAAkB,MAAM,CAC1B,SAAQ,KACN,8EAA8E,OAAO,OAAO,yEAC5F,MAAM,gBAAgB,gBACtB,MAAM,cAAc,UAAU,CAC/B;KAED,SAAQ,MAAM,MAAM;;AAIxB,SAAS,eAAe,OAAwB,kBAAkC;AAChF,KAAI,iBACF,SAAQ,KACN,iFACA,mBAAmB,KACnB,4CACA,MAAM,OACP;KAED,SAAQ,MACN,mGACA,MAAM,OACP;;;;;AAOL,SAAgB,WAAW,OAAkD;CAC3E,MAAM,EACJ,WACA,SACA,SACA,YACA,oBACA,OACA,kBAEA,kBACA,sBACA,iBAAiB,OACjB,iBAAiB,mBACb,QACA,OAAO,WAAW,cAChB,OACA,OAAO,SAAS,OAAO,KAC7B,qBAAqB,MACrB,mBAAmB,KACnB,aAAa,oBACb,UAAU,aACV,WAAW,gBACX,oBAAA,uBAAqBA,oBACrB,YACE;CAEJ,MAAM,SAAS,cAEX,aAAa;EACX;EACA;EACA;EACA;EACA;EACA,2BAA2B;EAC3B;EACA,QAAQ;EACR;EACD,CAAC,EACJ;EAAC;EAAS;EAAY;EAAS;EAAW;EAAkB;EAAO;EAAmB,CACvF;CACD,MAAM,CAAC,qBAAqB,0BAA0B,SAAyB,MAAM;;;;CAKrF,MAAM,SAAS,WAAW;CAC1B,MAAM,kBAAkB,gBAAgB,UAAqB;AAC3D,MAAI,QAAQ,IAAI,aAAa,gBAAgB,MAAM,SAAS,WAAW;AAErE,WAAQ,KACN,uBACA,QACI,kFACA,mBACE,uJACA,8CACP;AAED,0BAAuB,MAAM;aACpB,MAAM,SAAS,UACxB,KAAI,YAAY,WAEd,QAAO,SAAS;MAEXC,sBAAmB,MAAM,KAAK,CAAC,MAAM,WAAW;AACnD,OAAI,WAAW,UAAW,QAAO,SAAS;IAC1C;WAEK,MAAM,SAAS,aAAa,MAAM,SAAS,YACpD,QAAO,SAAS;WACP,MAAM,SAAS,UAAU;AAClC,YAAS,OAAO,iBAAiB;AACjC,0BAAuB,iBAAiB;;GAE1C;AACF,iBAAgB;EACd,MAAM,eAAe,OAAO,KACzB,OAAO;GAAC,eAAe,CAAC,CAAC;GAAO,KAAK;GAAY;GAAQ,CAAC,CAC1D,UAAU;GACT,MAAM;GACN,QAAQ,QAAiB;AAEvB,YAAQ,IAAI;;GAEf,CAAC;AACJ,eAAa,aAAa,aAAa;IACtC;EAAC,OAAO;EAAM;EAAS;EAAY;EAAO;EAAQ,CAAC;;;;AAKtD,iBAAgB;AACd,MAAI,oBAAoB,qBACtB,gBAAe,qBAAqB;MAEpC,gBAAe,UAAU;IAE1B,CAAC,kBAAkB,qBAAqB,CAAC;CAE5C,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;;;;AAIrD,iBAAgB;AAEd,MAAI,qBAAqB,CAAE;AAI3B,MAAI,oBAAoB,OAAO;AAC7B,kBAAe,OAAO;AACtB;;AAIF,MAAI,kBAAkB;AACpB,kBAAe,SAAS;AACxB;;AAIF,iBAAe,UAAU;IAExB,CAAC,kBAAkB,MAAM,CAAC;;;;AAK7B,iBAAgB;AACd,MAAI,CAAC,qBAAqB,CAAE;EAC5B,MAAM,aAAa,IAAI,iBAAiB;EAExC,MAAM,UAAU,iBAAiB,eAAe,OAAO,EAAE,IAAM;AAC/D,SAAO,iBACL,YACC,EAAC,WAAiC;AACjC,OACE,QACA,OAAO,SAAS,YAChB,YAAY,QACZ,KAAK,WAAW,qBAChB,UAAU,QACV,KAAK,SAAS,gBACd;AACA,iBAAa,QAAQ;AACrB,mBAAe,sBAAsB,GAAG,wBAAwB,sBAAsB;AACtF,mBAAe,KAAK;AACpB,eAAW,OAAO;;KAGtB,EAAC,QAAQ,WAAW,QAAO,CAC5B;AACD,eAAa;AACX,gBAAa,QAAQ;AACrB,cAAW,OAAO;;IAEnB,EAAE,CAAC;;;;;CAMN,MAAM,0BAA0B,OAAkD,KAAA,EAAU;AAC5F,iBAAgB;AACd,MAAI,CAAC,iBAAkB;AACvB,eAAa,wBAAwB,QAAQ;AAC7C,eAAa;AACX,2BAAwB,UAAU,iBAAiB;AACjD,YAAQ,KAAK,iEAAiE;KAC9E;;IAEH,CAAC,iBAAiB,CAAC;;;;AAKtB,iBAAgB;AACd,MAAI,CAAC,oBAAqB;EAC1B,MAAM,WAAW,kBAAkB,OAAO,SAAS,EAAE,oBAAoB;AACzE,eAAa,cAAc,SAAS;IACnC,CAAC,qBAAqB,OAAO,CAAC;AAEjC,QACE,qBAAA,UAAA,EAAA,UAAA;EACG,oBAAoB,eACnB,oBAAC,qBAAD;GACa;GACF;GAES;GACI;GACtB,CAAA;EAEH,CAAC,oBAAoB,kBAAkB,oBAAC,gBAAD,EAAkB,CAAA;EACzD,CAAC,oBAAoB,kBAAkB,oBAAC,gBAAD,EAAkB,CAAA;EACzD,CAAC,oBAAoB,sBAAsB,oBAAC,oBAAD,EAAsB,CAAA;EACjE,EAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["defaultRevalidateSyncTags","revalidateSyncTags"],"sources":["../../../src/live/client-components/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, startTransition} from 'react'\n\nimport {isCorsOriginError} from '#live/isCorsOriginError'\n\nimport {setEnvironment, setPerspective} from '../hooks/context'\n\nconst PresentationComlink = dynamic(() => import('./PresentationComlink'))\nconst RefreshOnMount = dynamic(() => import('./RefreshOnMount'))\nconst RefreshOnInterval = dynamic(() => import('./RefreshOnInterval'))\nconst RefreshOnFocus = dynamic(() => import('./RefreshOnFocus'))\nconst RefreshOnReconnect = dynamic(() => import('./RefreshOnReconnect'))\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\nfunction 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 [refreshOnInterval, setRefreshOnInterval] = 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 startTransition(() => setRefreshOnInterval(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') startTransition(() => router.refresh())\n })\n }\n } else if (event.type === 'restart' || event.type === 'reconnect') {\n // Disable long polling when restart/reconnect event is received, this is a no-op if long polling is already disabled\n startTransition(() => setRefreshOnInterval(false))\n // @TODO add support for `onRestart` and `onReconnect` events so this can be customized\n startTransition(() => router.refresh())\n } else if (event.type === 'goaway') {\n onGoAway(event, intervalOnGoAway)\n startTransition(() => setRefreshOnInterval(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 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 {refreshOnInterval && Number.isFinite(refreshOnInterval) && refreshOnInterval > 0 && (\n <RefreshOnInterval interval={refreshOnInterval} />\n )}\n {!draftModeEnabled && refreshOnFocus && <RefreshOnFocus />}\n {!draftModeEnabled && refreshOnReconnect && <RefreshOnReconnect />}\n </>\n )\n}\n\nSanityLive.displayName = 'SanityLiveClientComponent'\n\nexport default SanityLive\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import "@sanity/client";
|
|
7
7
|
import SanityLiveClientComponent from "next-sanity/live/client-components";
|
|
8
8
|
import { PHASE_PRODUCTION_BUILD } from "next/constants";
|
|
9
|
-
import { preconnect
|
|
9
|
+
import { preconnect } from "react-dom";
|
|
10
10
|
/**
|
|
11
11
|
* @public
|
|
12
12
|
*/
|
|
@@ -68,7 +68,6 @@ function defineLive(config) {
|
|
|
68
68
|
const { isEnabled: isDraftModeEnabled } = await draftMode();
|
|
69
69
|
const { origin } = new URL(client.getUrl("", false));
|
|
70
70
|
preconnect(origin);
|
|
71
|
-
prefetchDNS(origin);
|
|
72
71
|
return /* @__PURE__ */ jsx(SanityLiveClientComponent, {
|
|
73
72
|
projectId,
|
|
74
73
|
dataset,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"sourcesContent":["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 {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport SanityLiveClientComponent from 'next-sanity/live/client-components'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {draftMode, cookies} from 'next/headers'\nimport {prefetchDNS, preconnect} from 'react-dom'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\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 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 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 return {\n sanityFetch,\n SanityLive,\n }\n}\n\nasync 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"],"mappings":";;;;;;;;;;;;AA6JA,SAAgB,WAAW,QAWzB;CACA,MAAM,EACJ,QAAQ,SACR,aACA,cACA,cACA,OAAO,eAAe,SACpB;AAEJ,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,oDAAoD;AAGtE,KAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,eAAe,gBAAgB,MAC3E,SAAQ,KACN,8LACD;AAGH,KAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,gBAAgB,iBAAiB,MAC7E,SAAQ,KACN,iXACD;CAGH,MAAM,SAAS,QAAQ,WAAW;EAAC,kBAAkB;EAAO,QAAQ;EAAM,CAAC;CAC3E,MAAM,EAAC,OAAO,kBAAiB,OAAO,QAAQ;CAC9C,MAAM,mBAAmB,OAAO,OAAO,QAAQ,CAAC,MAAM,cAAc;AAyGpE,QAAO;EACL,aAAA,eAxGyD,YAEzD,EACA,OACA,SAAS,EAAE,EACX,OAAO,QACP,OAAO,EAAE,EACT,aAAa,cACb,KACA,aAAa,OAAO,uBASnB;GACD,MAAM,QAAQ,WAAW,gBAAgB,qBAAqB,MAAM,WAAW,EAAE;GACjF,MAAM,cAAc,gBAAiB,MAAM,0BAA0B;GACrE,MAAM,SAAS,gBAAgB;GAC/B,MAAM,aACJ,cAAc,eAAe,KAAA,IACzB,aAAa,aACb,QAAQ,IAAI,aAAa,eACvB,QACA,KAAA;GACR,MAAM,eAAe,QAAQ,IAAI,kBAAkB;GACnD,MAAM,YAAY,UAAU,CAAC,eAAe,YAAY,KAAA;GAExD,MAAM,EAAC,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;IACzD,gBAAgB;IACH;IACb,OAAO;IACP,aAAa;IACb,MAAM;KAAC;KAAY,MAAM,CAAC,GAAG,MAAM,yBAAyB;KAAC;IAC7D;IACA;IACA,KAAK,CAAC,YAAY,kBAAkB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;IAC/D,CAAC;GAEF,MAAM,YAAY,CAAC,GAAG,MAAM,GAAI,UAAU,KAAK,QAAQ,UAAU,MAAM,IAAI,EAAE,CAAE;GAE/E,MAAM,EAAC,QAAQ,oBAAmB,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;IACxE,gBAAgB;IACH;IACb;IACA,OAAO,gBAAgB,eAAe,cAAc,cAAc;IAClE,MAAM;KAAC;KAAY,MAAM;KAAU;IACnC;IACA;IACA,KAAK;IACN,CAAC;AACF,UAAO;IAAC,MAAM;IAAQ,WAAW,mBAAmB;IAAM,MAAM;IAAU;;EAmD1E,YAAA,eAhD6E,WAAW,OAAO;GAC/F,MAAM,EACJ,gBACA,gBACA,oBACA,KACA,aAAa,KACb,SACA,UACA,kBACA,oBACA,YACE;GACJ,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,QAAQ;GACjB,MAAM,EAAC,WAAW,uBAAsB,MAAM,WAAW;GAGzD,MAAM,EAAC,WAAU,IAAI,IAAI,OAAO,OAAO,IAAI,MAAM,CAAC;AAClD,cAAW,OAAO;AAClB,eAAY,OAAO;AAEnB,UACE,oBAAC,2BAAD;IACa;IACF;IACA;IACG;IACQ;IACF;IACN;IACZ,OAAO,OAAO,iBAAiB,YAAY,qBAAqB,eAAe,KAAA;IAC/E,kBAAkB;IAClB,sBAAsB,MAAM,0BAA0B;IACtC;IACA;IACI;IACX;IACC;IACQ;IACE;IACX;IACT,CAAA;;EAOL;;AAGH,eAAe,2BAAuE;AACpF,SAAQ,MAAM,WAAW,EAAE,aACtB,MAAM,SAAS,EAAE,IAAI,sBAAsB,GAC1C,qBAAqB,MAAM,SAAS,EAAE,IAAI,sBAAsB,EAAE,OAAO,SAAS,GAClF,WACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"sourcesContent":["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 {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport SanityLiveClientComponent from 'next-sanity/live/client-components'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {draftMode, cookies} from 'next/headers'\nimport {preconnect} from 'react-dom'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\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 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 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 early, as the Sanity API is almost always on a different origin than the app\n const {origin} = new URL(client.getUrl('', false))\n preconnect(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 return {\n sanityFetch,\n SanityLive,\n }\n}\n\nasync 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"],"mappings":";;;;;;;;;;;;AA6JA,SAAgB,WAAW,QAWzB;CACA,MAAM,EACJ,QAAQ,SACR,aACA,cACA,cACA,OAAO,eAAe,SACpB;AAEJ,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,oDAAoD;AAGtE,KAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,eAAe,gBAAgB,MAC3E,SAAQ,KACN,8LACD;AAGH,KAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,gBAAgB,iBAAiB,MAC7E,SAAQ,KACN,iXACD;CAGH,MAAM,SAAS,QAAQ,WAAW;EAAC,kBAAkB;EAAO,QAAQ;EAAM,CAAC;CAC3E,MAAM,EAAC,OAAO,kBAAiB,OAAO,QAAQ;CAC9C,MAAM,mBAAmB,OAAO,OAAO,QAAQ,CAAC,MAAM,cAAc;AAwGpE,QAAO;EACL,aAAA,eAvGyD,YAEzD,EACA,OACA,SAAS,EAAE,EACX,OAAO,QACP,OAAO,EAAE,EACT,aAAa,cACb,KACA,aAAa,OAAO,uBASnB;GACD,MAAM,QAAQ,WAAW,gBAAgB,qBAAqB,MAAM,WAAW,EAAE;GACjF,MAAM,cAAc,gBAAiB,MAAM,0BAA0B;GACrE,MAAM,SAAS,gBAAgB;GAC/B,MAAM,aACJ,cAAc,eAAe,KAAA,IACzB,aAAa,aACb,QAAQ,IAAI,aAAa,eACvB,QACA,KAAA;GACR,MAAM,eAAe,QAAQ,IAAI,kBAAkB;GACnD,MAAM,YAAY,UAAU,CAAC,eAAe,YAAY,KAAA;GAExD,MAAM,EAAC,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;IACzD,gBAAgB;IACH;IACb,OAAO;IACP,aAAa;IACb,MAAM;KAAC;KAAY,MAAM,CAAC,GAAG,MAAM,yBAAyB;KAAC;IAC7D;IACA;IACA,KAAK,CAAC,YAAY,kBAAkB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;IAC/D,CAAC;GAEF,MAAM,YAAY,CAAC,GAAG,MAAM,GAAI,UAAU,KAAK,QAAQ,UAAU,MAAM,IAAI,EAAE,CAAE;GAE/E,MAAM,EAAC,QAAQ,oBAAmB,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;IACxE,gBAAgB;IACH;IACb;IACA,OAAO,gBAAgB,eAAe,cAAc,cAAc;IAClE,MAAM;KAAC;KAAY,MAAM;KAAU;IACnC;IACA;IACA,KAAK;IACN,CAAC;AACF,UAAO;IAAC,MAAM;IAAQ,WAAW,mBAAmB;IAAM,MAAM;IAAU;;EAkD1E,YAAA,eA/C6E,WAAW,OAAO;GAC/F,MAAM,EACJ,gBACA,gBACA,oBACA,KACA,aAAa,KACb,SACA,UACA,kBACA,oBACA,YACE;GACJ,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,QAAQ;GACjB,MAAM,EAAC,WAAW,uBAAsB,MAAM,WAAW;GAGzD,MAAM,EAAC,WAAU,IAAI,IAAI,OAAO,OAAO,IAAI,MAAM,CAAC;AAClD,cAAW,OAAO;AAElB,UACE,oBAAC,2BAAD;IACa;IACF;IACA;IACG;IACQ;IACF;IACN;IACZ,OAAO,OAAO,iBAAiB,YAAY,qBAAqB,eAAe,KAAA;IAC/E,kBAAkB;IAClB,sBAAsB,MAAM,0BAA0B;IACtC;IACA;IACI;IACX;IACC;IACQ;IACE;IACX;IACT,CAAA;;EAOL;;AAGH,eAAe,2BAAuE;AACpF,SAAQ,MAAM,WAAW,EAAE,aACtB,MAAM,SAAS,EAAE,IAAI,sBAAsB,GAC1C,qBAAqB,MAAM,SAAS,EAAE,IAAI,sBAAsB,EAAE,OAAO,SAAS,GAClF,WACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-sanity",
|
|
3
|
-
"version": "12.3.
|
|
3
|
+
"version": "12.3.5",
|
|
4
4
|
"description": "Sanity.io toolkit for Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"live",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"@vitejs/plugin-react": "^6.0.1",
|
|
79
79
|
"@vitest/coverage-v8": "^4.1.5",
|
|
80
80
|
"js-yaml": "^4.1.1",
|
|
81
|
-
"next": "16.3.0-canary.
|
|
81
|
+
"next": "16.3.0-canary.6",
|
|
82
82
|
"publint": "^0.3.18",
|
|
83
83
|
"react": "^19.2.5",
|
|
84
84
|
"react-dom": "^19.2.5",
|