UNPKG

next-sanity

Version:
180 lines (179 loc) 7.21 kB
"use client"; import { isCorsOriginError } from "../../isCorsOriginError.js"; import { sanitizePerspective } from "../../utils.js"; import { PUBLISHED_SYNC_TAG_PREFIX } from "../../constants.js"; import { setEnvironment, setPerspective } from "../../context.js"; import { createClient } from "@sanity/client"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useRef, useState } from "react"; import { isMaybePresentation, isMaybePreviewWindow } from "@sanity/presentation-comlink"; import { useEffectEvent } from "use-effect-event"; import dynamic from "next/dynamic"; const PresentationComlink = dynamic(() => import("../../PresentationComlink.js"), { ssr: false }); const RefreshOnMount = dynamic(() => import("../../RefreshOnMount.js"), { ssr: false }); const RefreshOnFocus = dynamic(() => import("../../RefreshOnFocus.js"), { ssr: false }); const RefreshOnReconnect = dynamic(() => import("../../RefreshOnReconnect.js"), { ssr: false }); function handleError(error) { 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()); else console.error(error); } function handleOnGoAway(event, intervalOnGoAway) { 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); else console.error("Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason:", event.reason); } function SanityLive(props) { const { config, draftModeEnabled, 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, resolveDraftModePerspective } = props; const { projectId, dataset, apiHost, apiVersion, useProjectHostname, token, requestTagPrefix } = config; const client = useMemo(() => createClient({ projectId, dataset, apiHost, apiVersion, useProjectHostname, ignoreBrowserTokenWarning: true, token, useCdn: false, requestTagPrefix }), [ apiHost, apiVersion, dataset, projectId, requestTagPrefix, token, useProjectHostname ]); const [longPollingInterval, setLongPollingInterval] = useState(false); const [resolvedInitialPerspective, setResolvedInitialPerspective] = useState(false); const router = useRouter(); const handleLiveEvent = useEffectEvent((event) => { if (process.env.NODE_ENV !== "production" && event.type === "welcome") { 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"); setLongPollingInterval(false); } else if (event.type === "message") revalidateSyncTags(event.tags.map((tag) => `${PUBLISHED_SYNC_TAG_PREFIX}${tag}`)).then((result) => { if (result === "refresh") router.refresh(); }); else if (event.type === "restart" || event.type === "reconnect") router.refresh(); else if (event.type === "goaway") { onGoAway(event, intervalOnGoAway); setLongPollingInterval(intervalOnGoAway); } }); useEffect(() => { const subscription = client.live.events({ tag: requestTag }).subscribe({ next: handleLiveEvent, error: (err) => { onError(err); } }); return () => subscription.unsubscribe(); }, [ client.live, onError, requestTag, token ]); const handleLiveDraftEvent = useEffectEvent((event) => { if (event.type === "message") router.refresh(); }); useEffect(() => { if (!token) return; const subscription = client.live.events({ includeDrafts: !!token, tag: requestTag }).subscribe({ next: handleLiveDraftEvent, error: (err) => { onError(err); } }); return () => subscription.unsubscribe(); }, [ client.live, onError, requestTag, token ]); useEffect(() => { if (resolvedInitialPerspective) return void 0; if (!draftModeEnabled) { setResolvedInitialPerspective(true); setPerspective("unknown"); return; } const controller = new AbortController(); resolveDraftModePerspective().then((perspective) => { if (controller.signal.aborted) return; setResolvedInitialPerspective(true); setPerspective(sanitizePerspective(perspective, "drafts")); }).catch((err) => { if (controller.signal.aborted) return; console.error("Failed to resolve draft mode perspective", err); setResolvedInitialPerspective(true); setPerspective("unknown"); }); return () => controller.abort(); }, [ draftModeEnabled, resolveDraftModePerspective, resolvedInitialPerspective ]); const [loadComlink, setLoadComlink] = useState(false); useEffect(() => { if (isMaybePresentation()) return; if (draftModeEnabled && token) { setEnvironment("live"); return; } if (draftModeEnabled) { setEnvironment("static"); return; } setEnvironment("unknown"); }, [draftModeEnabled, token]); useEffect(() => { if (!isMaybePresentation()) return; const controller = new AbortController(); const timeout = setTimeout(() => setEnvironment("live"), 3e3); window.addEventListener("message", ({ data }) => { if (data && typeof data === "object" && "domain" in data && data.domain === "sanity/channels" && "from" in data && data.from === "presentation") { clearTimeout(timeout); setEnvironment(isMaybePreviewWindow() ? "presentation-window" : "presentation-iframe"); setLoadComlink(true); controller.abort(); } }, { signal: controller.signal }); return () => { clearTimeout(timeout); controller.abort(); }; }, []); const draftModeEnabledWarnRef = useRef(void 0); useEffect(() => { if (!draftModeEnabled) return; clearTimeout(draftModeEnabledWarnRef.current); return () => { draftModeEnabledWarnRef.current = setTimeout(() => { console.warn("Sanity Live: Draft mode was enabled, but is now being disabled"); }); }; }, [draftModeEnabled]); useEffect(() => { if (!longPollingInterval) return; const interval = setInterval(() => router.refresh(), longPollingInterval); return () => clearInterval(interval); }, [longPollingInterval, router]); return /* @__PURE__ */ jsxs(Fragment, { children: [ draftModeEnabled && loadComlink && resolvedInitialPerspective && /* @__PURE__ */ jsx(PresentationComlink, { projectId, dataset, draftModeEnabled }), !draftModeEnabled && refreshOnMount && /* @__PURE__ */ jsx(RefreshOnMount, {}), !draftModeEnabled && refreshOnFocus && /* @__PURE__ */ jsx(RefreshOnFocus, {}), !draftModeEnabled && refreshOnReconnect && /* @__PURE__ */ jsx(RefreshOnReconnect, {}) ] }); } export { SanityLive as default }; //# sourceMappingURL=live.js.map