next-sanity 13.0.0-cache-components.36 → 13.0.0-cache-components.38

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.
Files changed (48) hide show
  1. package/dist/NextStudio.js +17 -0
  2. package/dist/NextStudio.js.map +1 -1
  3. package/dist/NextStudioNoScript.js +2 -0
  4. package/dist/NextStudioNoScript.js.map +1 -1
  5. package/dist/RefreshOnMount.js +6 -0
  6. package/dist/RefreshOnMount.js.map +1 -1
  7. package/dist/SanityLive.js.map +1 -1
  8. package/dist/VisualEditing.js +41 -0
  9. package/dist/VisualEditing.js.map +1 -1
  10. package/dist/constants.js +3 -0
  11. package/dist/constants.js.map +1 -1
  12. package/dist/draft-mode/index.js +17 -0
  13. package/dist/draft-mode/index.js.map +1 -1
  14. package/dist/image/index.js +6 -0
  15. package/dist/image/index.js.map +1 -1
  16. package/dist/isCorsOriginError.js +1 -0
  17. package/dist/isCorsOriginError.js.map +1 -1
  18. package/dist/live/cache-life.js +32 -1
  19. package/dist/live/cache-life.js.map +1 -1
  20. package/dist/live/client-components/index.js +3 -0
  21. package/dist/live/client-components/index.js.map +1 -1
  22. package/dist/live/conditions/default/index.js +4 -0
  23. package/dist/live/conditions/default/index.js.map +1 -1
  24. package/dist/live/conditions/next-js/index.js +8 -1
  25. package/dist/live/conditions/next-js/index.js.map +1 -1
  26. package/dist/live/conditions/react-server/index.js +2 -1
  27. package/dist/live/conditions/react-server/index.js.map +1 -1
  28. package/dist/live/server-actions/index.default.js +6 -0
  29. package/dist/live/server-actions/index.default.js.map +1 -1
  30. package/dist/live/server-actions/index.next-js.js +6 -0
  31. package/dist/live/server-actions/index.next-js.js.map +1 -1
  32. package/dist/parseTags.d.ts +25 -3
  33. package/dist/parseTags.d.ts.map +1 -1
  34. package/dist/parseTags.js +21 -0
  35. package/dist/parseTags.js.map +1 -1
  36. package/dist/resolvePerspectiveFromCookies.js +25 -2
  37. package/dist/resolvePerspectiveFromCookies.js.map +1 -1
  38. package/dist/studio/client-component/index.js +7 -0
  39. package/dist/studio/client-component/index.js.map +1 -1
  40. package/dist/studio/index.js +40 -0
  41. package/dist/studio/index.js.map +1 -1
  42. package/dist/visual-editing/index.js +3 -0
  43. package/dist/visual-editing/index.js.map +1 -1
  44. package/dist/visual-editing/server-actions/index.js +6 -0
  45. package/dist/visual-editing/server-actions/index.js.map +1 -1
  46. package/dist/webhook/index.js +5 -0
  47. package/dist/webhook/index.js.map +1 -1
  48. package/package.json +18 -17
@@ -3,6 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useMemo, useSyncExternalStore } from "react";
4
4
  import { Studio } from "sanity";
5
5
  import { createHashHistory } from "history";
6
+ /** @internal */
6
7
  function createHashHistoryForStudio() {
7
8
  const history = createHashHistory();
8
9
  return {
@@ -40,10 +41,26 @@ function createHashHistoryForStudio() {
40
41
  }
41
42
  };
42
43
  }
44
+ /** @internal */
43
45
  function useIsMounted() {
44
46
  return useSyncExternalStore(emptySubscribe, () => true, () => false);
45
47
  }
46
48
  const emptySubscribe = () => () => {};
49
+ /**
50
+ * Override how the Studio renders by passing children.
51
+ * This is useful for advanced use cases where you're using StudioProvider and StudioLayout instead of Studio:
52
+ * ```
53
+ * import {StudioProvider, StudioLayout} from 'sanity'
54
+ * import {NextStudio} from 'next-sanity/studio'
55
+ * <NextStudio config={config}>
56
+ * <StudioProvider config={config}>
57
+ * <CustomComponentThatUsesContextFromStudioProvider />
58
+ * <StudioLayout />
59
+ * </StudioProvider>
60
+ * </NextStudio>
61
+ * ```
62
+ * @public
63
+ */
47
64
  function NextStudioComponent({ children, config, unstable__noScript = true, scheme, history, ...props }) {
48
65
  const isMounted = useIsMounted();
49
66
  const unstableHistory = useMemo(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"NextStudio.js","names":[],"sources":["../src/studio/client-component/createHashHistoryForStudio.ts","../src/studio/client-component/useIsMounted.ts","../src/studio/client-component/NextStudio.tsx"],"sourcesContent":["// oxlint-disable unbound-method\nimport {createHashHistory, type History, type Listener} from 'history'\n\n/** @internal */\nexport function createHashHistoryForStudio(): History {\n const history = createHashHistory()\n return {\n get action() {\n return history.action\n },\n get location() {\n return history.location\n },\n get createHref() {\n return history.createHref\n },\n get push() {\n return history.push\n },\n get replace() {\n return history.replace\n },\n get go() {\n return history.go\n },\n get back() {\n return history.back\n },\n get forward() {\n return history.forward\n },\n get block() {\n return history.block\n },\n // Overriding listen to workaround a problem where native history provides history.listen(location => void), but the npm package is history.listen(({action, location}) => void)\n listen(listener: Listener) {\n // return history.listen(({ action, location }) => {\n return history.listen(({location}) => {\n // console.debug('history.listen', action, location)\n // @ts-expect-error -- working around a bug? in studio\n listener(location)\n })\n },\n }\n}\n","import {useSyncExternalStore} from 'react'\n\n/** @internal */\nexport function useIsMounted(): boolean {\n return useSyncExternalStore(\n emptySubscribe,\n () => true,\n () => false,\n )\n}\nconst emptySubscribe = () => () => {}\n","import {useMemo} from 'react'\nimport {Studio, type StudioProps} from 'sanity'\n\nimport {NextStudioLayout} from '../NextStudioLayout'\nimport {NextStudioNoScript} from '../NextStudioNoScript'\nimport {createHashHistoryForStudio} from './createHashHistoryForStudio'\nimport {useIsMounted} from './useIsMounted'\n\n/** @public */\nexport interface NextStudioProps extends StudioProps {\n children?: React.ReactNode\n /**\n * Render the <noscript> tag\n * @defaultValue true\n * @alpha\n */\n unstable__noScript?: boolean\n /**\n * The 'hash' option is new feature that is not yet stable for production, but is available for testing and its API won't change in a breaking way.\n * If 'hash' doesn't work for you, or if you want to use a memory based history, you can use the `unstable_history` prop instead.\n * @alpha\n * @defaultValue 'browser'\n */\n history?: 'browser' | 'hash'\n}\n/**\n * Override how the Studio renders by passing children.\n * This is useful for advanced use cases where you're using StudioProvider and StudioLayout instead of Studio:\n * ```\n * import {StudioProvider, StudioLayout} from 'sanity'\n * import {NextStudio} from 'next-sanity/studio'\n * <NextStudio config={config}>\n * <StudioProvider config={config}>\n * <CustomComponentThatUsesContextFromStudioProvider />\n * <StudioLayout />\n * </StudioProvider>\n * </NextStudio>\n * ```\n * @public\n */\nexport default function NextStudioComponent({\n children,\n config,\n unstable__noScript = true,\n scheme,\n history,\n ...props\n}: NextStudioProps): React.JSX.Element {\n const isMounted = useIsMounted()\n const unstableHistory = useMemo<typeof props.unstable_history>(() => {\n if (props.unstable_history && history) {\n throw new Error('Cannot use both `unstable_history` and `history` props at the same time')\n }\n\n if (isMounted && history === 'hash') {\n return createHashHistoryForStudio()\n }\n return props.unstable_history\n }, [history, isMounted, props.unstable_history])\n\n return (\n <>\n {unstable__noScript && <NextStudioNoScript />}\n <NextStudioLayout>\n {history === 'hash' && !isMounted\n ? null\n : children || (\n <Studio\n config={config}\n scheme={scheme}\n unstable_globalStyles\n {...props}\n unstable_history={unstableHistory}\n />\n )}\n </NextStudioLayout>\n </>\n )\n}\n"],"mappings":";;;;;AAIA,SAAgB,6BAAsC;CACpD,MAAM,UAAU,mBAAmB;AACnC,QAAO;EACL,IAAI,SAAS;AACX,UAAO,QAAQ;;EAEjB,IAAI,WAAW;AACb,UAAO,QAAQ;;EAEjB,IAAI,aAAa;AACf,UAAO,QAAQ;;EAEjB,IAAI,OAAO;AACT,UAAO,QAAQ;;EAEjB,IAAI,UAAU;AACZ,UAAO,QAAQ;;EAEjB,IAAI,KAAK;AACP,UAAO,QAAQ;;EAEjB,IAAI,OAAO;AACT,UAAO,QAAQ;;EAEjB,IAAI,UAAU;AACZ,UAAO,QAAQ;;EAEjB,IAAI,QAAQ;AACV,UAAO,QAAQ;;EAGjB,OAAO,UAAoB;AAEzB,UAAO,QAAQ,QAAQ,EAAC,eAAc;AAGpC,aAAS,SAAS;KAClB;;EAEL;;ACxCH,SAAgB,eAAwB;AACtC,QAAO,qBACL,sBACM,YACA,MACP;;AAEH,MAAM,6BAA6B;AC8BnC,SAAwB,oBAAoB,EAC1C,UACA,QACA,qBAAqB,MACrB,QACA,SACA,GAAG,SACkC;CACrC,MAAM,YAAY,cAAc;CAChC,MAAM,kBAAkB,cAA6C;AACnE,MAAI,MAAM,oBAAoB,QAC5B,OAAM,IAAI,MAAM,0EAA0E;AAG5F,MAAI,aAAa,YAAY,OAC3B,QAAO,4BAA4B;AAErC,SAAO,MAAM;IACZ;EAAC;EAAS;EAAW,MAAM;EAAiB,CAAC;AAEhD,QACE,qBAAA,UAAA,EAAA,UAAA,CACG,sBAAsB,oBAAC,oBAAA,EAAA,CAAqB,EAC7C,oBAAC,kBAAA,EAAA,UACE,YAAY,UAAU,CAAC,YACpB,OACA,YACE,oBAAC,QAAA;EACS;EACA;EACR,uBAAA;EACA,GAAI;EACJ,kBAAkB;GAClB,EAAA,CAES,CAAA,EAAA,CAClB"}
1
+ {"version":3,"file":"NextStudio.js","names":[],"sources":["../src/studio/client-component/createHashHistoryForStudio.ts","../src/studio/client-component/useIsMounted.ts","../src/studio/client-component/NextStudio.tsx"],"sourcesContent":["// oxlint-disable unbound-method\nimport {createHashHistory, type History, type Listener} from 'history'\n\n/** @internal */\nexport function createHashHistoryForStudio(): History {\n const history = createHashHistory()\n return {\n get action() {\n return history.action\n },\n get location() {\n return history.location\n },\n get createHref() {\n return history.createHref\n },\n get push() {\n return history.push\n },\n get replace() {\n return history.replace\n },\n get go() {\n return history.go\n },\n get back() {\n return history.back\n },\n get forward() {\n return history.forward\n },\n get block() {\n return history.block\n },\n // Overriding listen to workaround a problem where native history provides history.listen(location => void), but the npm package is history.listen(({action, location}) => void)\n listen(listener: Listener) {\n // return history.listen(({ action, location }) => {\n return history.listen(({location}) => {\n // console.debug('history.listen', action, location)\n // @ts-expect-error -- working around a bug? in studio\n listener(location)\n })\n },\n }\n}\n","import {useSyncExternalStore} from 'react'\n\n/** @internal */\nexport function useIsMounted(): boolean {\n return useSyncExternalStore(\n emptySubscribe,\n () => true,\n () => false,\n )\n}\nconst emptySubscribe = () => () => {}\n","import {useMemo} from 'react'\nimport {Studio, type StudioProps} from 'sanity'\n\nimport {NextStudioLayout} from '../NextStudioLayout'\nimport {NextStudioNoScript} from '../NextStudioNoScript'\nimport {createHashHistoryForStudio} from './createHashHistoryForStudio'\nimport {useIsMounted} from './useIsMounted'\n\n/** @public */\nexport interface NextStudioProps extends StudioProps {\n children?: React.ReactNode\n /**\n * Render the <noscript> tag\n * @defaultValue true\n * @alpha\n */\n unstable__noScript?: boolean\n /**\n * The 'hash' option is new feature that is not yet stable for production, but is available for testing and its API won't change in a breaking way.\n * If 'hash' doesn't work for you, or if you want to use a memory based history, you can use the `unstable_history` prop instead.\n * @alpha\n * @defaultValue 'browser'\n */\n history?: 'browser' | 'hash'\n}\n/**\n * Override how the Studio renders by passing children.\n * This is useful for advanced use cases where you're using StudioProvider and StudioLayout instead of Studio:\n * ```\n * import {StudioProvider, StudioLayout} from 'sanity'\n * import {NextStudio} from 'next-sanity/studio'\n * <NextStudio config={config}>\n * <StudioProvider config={config}>\n * <CustomComponentThatUsesContextFromStudioProvider />\n * <StudioLayout />\n * </StudioProvider>\n * </NextStudio>\n * ```\n * @public\n */\nexport default function NextStudioComponent({\n children,\n config,\n unstable__noScript = true,\n scheme,\n history,\n ...props\n}: NextStudioProps): React.JSX.Element {\n const isMounted = useIsMounted()\n const unstableHistory = useMemo<typeof props.unstable_history>(() => {\n if (props.unstable_history && history) {\n throw new Error('Cannot use both `unstable_history` and `history` props at the same time')\n }\n\n if (isMounted && history === 'hash') {\n return createHashHistoryForStudio()\n }\n return props.unstable_history\n }, [history, isMounted, props.unstable_history])\n\n return (\n <>\n {unstable__noScript && <NextStudioNoScript />}\n <NextStudioLayout>\n {history === 'hash' && !isMounted\n ? null\n : children || (\n <Studio\n config={config}\n scheme={scheme}\n unstable_globalStyles\n {...props}\n unstable_history={unstableHistory}\n />\n )}\n </NextStudioLayout>\n </>\n )\n}\n"],"mappings":";;;;;;AAIA,SAAgB,6BAAsC;CACpD,MAAM,UAAU,mBAAmB;AACnC,QAAO;EACL,IAAI,SAAS;AACX,UAAO,QAAQ;;EAEjB,IAAI,WAAW;AACb,UAAO,QAAQ;;EAEjB,IAAI,aAAa;AACf,UAAO,QAAQ;;EAEjB,IAAI,OAAO;AACT,UAAO,QAAQ;;EAEjB,IAAI,UAAU;AACZ,UAAO,QAAQ;;EAEjB,IAAI,KAAK;AACP,UAAO,QAAQ;;EAEjB,IAAI,OAAO;AACT,UAAO,QAAQ;;EAEjB,IAAI,UAAU;AACZ,UAAO,QAAQ;;EAEjB,IAAI,QAAQ;AACV,UAAO,QAAQ;;EAGjB,OAAO,UAAoB;AAEzB,UAAO,QAAQ,QAAQ,EAAC,eAAc;AAGpC,aAAS,SAAS;KAClB;;EAEL;;;ACxCH,SAAgB,eAAwB;AACtC,QAAO,qBACL,sBACM,YACA,MACP;;AAEH,MAAM,6BAA6B;;;;;;;;;;;;;;;;AC8BnC,SAAwB,oBAAoB,EAC1C,UACA,QACA,qBAAqB,MACrB,QACA,SACA,GAAG,SACkC;CACrC,MAAM,YAAY,cAAc;CAChC,MAAM,kBAAkB,cAA6C;AACnE,MAAI,MAAM,oBAAoB,QAC5B,OAAM,IAAI,MAAM,0EAA0E;AAG5F,MAAI,aAAa,YAAY,OAC3B,QAAO,4BAA4B;AAErC,SAAO,MAAM;IACZ;EAAC;EAAS;EAAW,MAAM;EAAiB,CAAC;AAEhD,QACE,qBAAA,UAAA,EAAA,UAAA,CACG,sBAAsB,oBAAC,oBAAD,EAAsB,CAAA,EAC7C,oBAAC,kBAAD,EAAA,UACG,YAAY,UAAU,CAAC,YACpB,OACA,YACE,oBAAC,QAAD;EACU;EACA;EACR,uBAAA;EACA,GAAI;EACJ,kBAAkB;EAClB,CAAA,EAES,CAAA,CAClB,EAAA,CAAA"}
@@ -6,6 +6,7 @@ const style = {
6
6
  WebkitFontSmoothing: "antialiased",
7
7
  overflow: "auto"
8
8
  };
9
+ /** @public */
9
10
  const NextStudioLayout = ({ children }) => {
10
11
  return /* @__PURE__ */ jsx("div", {
11
12
  id: "sanity",
@@ -33,6 +34,7 @@ const styles = {
33
34
  fontFamily: "helvetica, arial, sans-serif"
34
35
  }
35
36
  };
37
+ /** @internal */
36
38
  const NextStudioNoScript = () => /* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("div", {
37
39
  style: styles.outer,
38
40
  children: /* @__PURE__ */ jsxs("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"NextStudioNoScript.js","names":[],"sources":["../src/studio/NextStudioLayout.tsx","../src/studio/NextStudioNoScript.tsx"],"sourcesContent":["/** @public */\nexport interface NextStudioLayoutProps {\n children: React.ReactNode\n}\n\nconst style = {\n height: '100vh',\n maxHeight: '100dvh',\n overscrollBehavior: 'none',\n WebkitFontSmoothing: 'antialiased',\n overflow: 'auto',\n} satisfies React.CSSProperties\n\n/** @public */\nexport const NextStudioLayout = ({children}: NextStudioLayoutProps): React.JSX.Element => {\n return (\n <div id=\"sanity\" data-ui=\"NextStudioLayout\" style={style}>\n {children}\n </div>\n )\n}\n","const styles: Record<'outer' | 'inner', React.CSSProperties> = {\n outer: {\n position: 'absolute',\n top: 0,\n right: 0,\n left: 0,\n bottom: 0,\n background: '#fff',\n zIndex: 1,\n },\n inner: {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n textAlign: 'center',\n fontFamily: 'helvetica, arial, sans-serif',\n },\n}\n\n/** @internal */\nexport const NextStudioNoScript = (): React.JSX.Element => (\n <noscript>\n <div style={styles.outer}>\n <div style={styles.inner}>\n <h1>JavaScript disabled</h1>\n <p>\n Please <a href=\"https://www.enable-javascript.com/\">enable JavaScript</a> in your browser\n and reload the page to proceed.\n </p>\n </div>\n </div>\n </noscript>\n)\n"],"mappings":";AAKA,MAAM,QAAQ;CACZ,QAAQ;CACR,WAAW;CACX,oBAAoB;CACpB,qBAAqB;CACrB,UAAU;CACX;AAGD,MAAa,oBAAoB,EAAC,eAAwD;AACxF,QACE,oBAAC,OAAA;EAAI,IAAG;EAAS,WAAQ;EAA0B;EAChD;GACG;;AClBV,MAAM,SAAyD;CAC7D,OAAO;EACL,UAAU;EACV,KAAK;EACL,OAAO;EACP,MAAM;EACN,QAAQ;EACR,YAAY;EACZ,QAAQ;EACT;CACD,OAAO;EACL,UAAU;EACV,KAAK;EACL,MAAM;EACN,WAAW;EACX,WAAW;EACX,YAAY;EACb;CACF;AAGD,MAAa,2BACX,oBAAC,YAAA,EAAA,UACC,oBAAC,OAAA;CAAI,OAAO,OAAO;WACjB,qBAAC,OAAA;EAAI,OAAO,OAAO;aACjB,oBAAC,MAAA,EAAA,UAAG,uBAAA,CAAwB,EAC5B,qBAAC,KAAA,EAAA,UAAA;GAAE;GACM,oBAAC,KAAA;IAAE,MAAK;cAAqC;KAAqB;;MAEvE,CAAA;GACA;EACF,EAAA,CACG"}
1
+ {"version":3,"file":"NextStudioNoScript.js","names":[],"sources":["../src/studio/NextStudioLayout.tsx","../src/studio/NextStudioNoScript.tsx"],"sourcesContent":["/** @public */\nexport interface NextStudioLayoutProps {\n children: React.ReactNode\n}\n\nconst style = {\n height: '100vh',\n maxHeight: '100dvh',\n overscrollBehavior: 'none',\n WebkitFontSmoothing: 'antialiased',\n overflow: 'auto',\n} satisfies React.CSSProperties\n\n/** @public */\nexport const NextStudioLayout = ({children}: NextStudioLayoutProps): React.JSX.Element => {\n return (\n <div id=\"sanity\" data-ui=\"NextStudioLayout\" style={style}>\n {children}\n </div>\n )\n}\n","const styles: Record<'outer' | 'inner', React.CSSProperties> = {\n outer: {\n position: 'absolute',\n top: 0,\n right: 0,\n left: 0,\n bottom: 0,\n background: '#fff',\n zIndex: 1,\n },\n inner: {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n textAlign: 'center',\n fontFamily: 'helvetica, arial, sans-serif',\n },\n}\n\n/** @internal */\nexport const NextStudioNoScript = (): React.JSX.Element => (\n <noscript>\n <div style={styles.outer}>\n <div style={styles.inner}>\n <h1>JavaScript disabled</h1>\n <p>\n Please <a href=\"https://www.enable-javascript.com/\">enable JavaScript</a> in your browser\n and reload the page to proceed.\n </p>\n </div>\n </div>\n </noscript>\n)\n"],"mappings":";AAKA,MAAM,QAAQ;CACZ,QAAQ;CACR,WAAW;CACX,oBAAoB;CACpB,qBAAqB;CACrB,UAAU;CACX;;AAGD,MAAa,oBAAoB,EAAC,eAAwD;AACxF,QACE,oBAAC,OAAD;EAAK,IAAG;EAAS,WAAQ;EAA0B;EAChD;EACG,CAAA;;AClBV,MAAM,SAAyD;CAC7D,OAAO;EACL,UAAU;EACV,KAAK;EACL,OAAO;EACP,MAAM;EACN,QAAQ;EACR,YAAY;EACZ,QAAQ;EACT;CACD,OAAO;EACL,UAAU;EACV,KAAK;EACL,MAAM;EACN,WAAW;EACX,WAAW;EACX,YAAY;EACb;CACF;;AAGD,MAAa,2BACX,oBAAC,YAAD,EAAA,UACE,oBAAC,OAAD;CAAK,OAAO,OAAO;WACjB,qBAAC,OAAD;EAAK,OAAO,OAAO;YAAnB,CACE,oBAAC,MAAD,EAAA,UAAI,uBAAwB,CAAA,EAC5B,qBAAC,KAAD,EAAA,UAAA;GAAG;GACM,oBAAC,KAAD;IAAG,MAAK;cAAqC;IAAqB,CAAA;;GAEvE,EAAA,CAAA,CACA;;CACF,CAAA,EACG,CAAA"}
@@ -1,5 +1,11 @@
1
1
  import { useRouter } from "next/navigation";
2
2
  import { startTransition, useEffect, useReducer } from "react";
3
+ /**
4
+ * Handles refreshing the page when the page is mounted,
5
+ * in case the content changes at a high enough frequency that by
6
+ * the time the page started streaming, and the <SanityLive> component sets
7
+ * up the EventSource connection, content might have changed.
8
+ */
3
9
  function RefreshOnMount() {
4
10
  const router = useRouter();
5
11
  const [mounted, mount] = useReducer(() => true, false);
@@ -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, 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
+ {"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 +1 @@
1
- {"version":3,"file":"SanityLive.js","names":[],"sources":["../src/live/client-components/SanityLive.tsx"],"sourcesContent":["import {createClient, type InitializedClientConfig, type LiveEvent} from '@sanity/client'\nimport dynamic from 'next/dynamic'\nimport {useRouter} from 'next/navigation'\nimport {startTransition, useEffect, useEffectEvent, useMemo, useState} from 'react'\n\nimport {cacheTagPrefixes} from '#live/constants'\nimport {isCorsOriginError} from '#live/isCorsOriginError'\nimport type {\n SanityLiveAction,\n SanityLiveActionContext,\n SanityLiveOnError,\n SanityLiveOnGoaway,\n SanityLiveOnReconnect,\n SanityLiveOnRestart,\n SanityLiveOnWelcome,\n} from '#live/types'\n\nconst RefreshOnFocus = dynamic(() => import('./RefreshOnFocus'))\nconst RefreshOnMount = dynamic(() => import('./RefreshOnMount'))\nconst RefreshOnInterval = dynamic(() => import('./RefreshOnInterval'))\nconst RefreshOnReconnect = dynamic(() => import('./RefreshOnReconnect'))\n\ninterface SanityClientConfig extends Pick<\n InitializedClientConfig,\n | 'projectId'\n | 'dataset'\n | 'apiHost'\n | 'apiVersion'\n | 'useProjectHostname'\n | 'token'\n | 'requestTagPrefix'\n> {}\n\nexport interface SanityLiveProps {\n config: SanityClientConfig\n includeDrafts?: boolean\n requestTag: string\n\n action: SanityLiveAction\n onError: SanityLiveOnError | false | undefined\n onWelcome: SanityLiveOnWelcome | false | undefined\n onReconnect: SanityLiveOnReconnect | false | undefined\n onRestart: SanityLiveOnRestart | false | undefined\n onGoAway: SanityLiveOnGoaway | false | undefined\n\n refreshOnMount?: boolean\n refreshOnFocus?: boolean\n refreshOnReconnect?: boolean\n}\n\nfunction SanityLive(props: SanityLiveProps): React.JSX.Element | null {\n const {\n config,\n includeDrafts = false,\n action,\n onError,\n onWelcome = handleWelcome,\n onReconnect,\n onRestart,\n onGoAway = handleGoaway,\n refreshOnMount = false,\n refreshOnFocus = false,\n refreshOnReconnect = true,\n requestTag,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, token, requestTagPrefix} =\n config\n const actionContext = {includeDrafts} satisfies SanityLiveActionContext\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\n const [refreshOnInterval, setRefreshOnInterval] = useState<number | false>(false)\n\n const [error, setError] = useState<unknown>(null)\n if (error) {\n // Throw during render to bubble up to the nearest <ErrorBoundary>, if `onError` is provided we won't rethrow\n throw error\n }\n const handleError = useEffectEvent((error: unknown) => {\n if (onError) {\n void onError(error, actionContext)\n } else {\n setError(\n isCorsOriginError(error)\n ? new Error(\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.${error.addOriginUrl ? ` Add it here: ${error.addOriginUrl}` : ''}`,\n {cause: error},\n )\n : error,\n )\n }\n })\n\n const router = useRouter()\n const handleLiveEvent = useEffectEvent((event: LiveEvent) => {\n switch (event.type) {\n case 'welcome': {\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\n if (onWelcome) {\n startTransition(() => onWelcome(event, actionContext))\n }\n break\n }\n case 'message': {\n startTransition(() =>\n action(\n event.tags.map(\n (tag) =>\n `${includeDrafts ? cacheTagPrefixes.drafts : cacheTagPrefixes.published}${tag}`,\n ),\n ).then((result) => {\n if (result === 'refresh') {\n startTransition(() => router.refresh())\n }\n }),\n )\n break\n }\n case 'restart': {\n // Disable long polling when restart event is received, this is a no-op if long polling is already disabled\n startTransition(() => setRefreshOnInterval(false))\n\n if (onRestart) {\n startTransition(() => onRestart(event, actionContext))\n }\n break\n }\n case 'reconnect': {\n // Disable long polling when reconnect event is received, this is a no-op if long polling is already disabled\n startTransition(() => setRefreshOnInterval(false))\n\n if (onReconnect) {\n startTransition(() => onReconnect(event, actionContext))\n }\n break\n }\n case 'goaway': {\n if (onGoAway) {\n startTransition(() =>\n onGoAway(event, actionContext, (interval) =>\n startTransition(() => setRefreshOnInterval(interval)),\n ),\n )\n } else if (!onGoAway) {\n handleError(\n new Error(\n `Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason: ${event.reason}`,\n {cause: event},\n ),\n )\n }\n break\n }\n default:\n handleError(new Error(`Unknown live event type`, {cause: event}))\n break\n }\n })\n useEffect(() => {\n const subscription = client.live\n .events({includeDrafts, tag: requestTag})\n .subscribe({next: handleLiveEvent, error: handleError})\n return () => subscription.unsubscribe()\n }, [client.live, requestTag, includeDrafts])\n\n return (\n <>\n {refreshOnFocus && <RefreshOnFocus />}\n {refreshOnInterval && Number.isFinite(refreshOnInterval) && refreshOnInterval > 0 && (\n <RefreshOnInterval interval={refreshOnInterval} />\n )}\n {refreshOnMount && <RefreshOnMount />}\n {refreshOnReconnect && <RefreshOnReconnect />}\n </>\n )\n}\n\nSanityLive.displayName = 'SanityLiveClientComponent'\n\nexport default SanityLive\n\nconst handleWelcome: SanityLiveOnWelcome = (_, {includeDrafts}) => {\n // oxlint-disable-next-line no-console\n console.info(\n `<SanityLive${includeDrafts ? ' includeDrafts' : ''}> is connected and listening for live events to ${includeDrafts ? 'all content including drafts and version documents in content releases' : 'published content'}`,\n )\n}\n\nconst handleGoaway: SanityLiveOnGoaway = (event, {includeDrafts}, setLongPollingInterval) => {\n const interval = 30_000\n console.warn(\n `<SanityLive${includeDrafts ? ' includeDrafts' : ''}> connection is closed after receiving a 'goaway' event, the server gave this reason:`,\n event.reason,\n `Content will now be refreshed every ${interval / 1_000} seconds`,\n )\n setLongPollingInterval(interval)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SanityLive.js","names":[],"sources":["../src/live/client-components/SanityLive.tsx"],"sourcesContent":["import {createClient, type InitializedClientConfig, type LiveEvent} from '@sanity/client'\nimport dynamic from 'next/dynamic'\nimport {useRouter} from 'next/navigation'\nimport {startTransition, useEffect, useEffectEvent, useMemo, useState} from 'react'\n\nimport {cacheTagPrefixes} from '#live/constants'\nimport {isCorsOriginError} from '#live/isCorsOriginError'\nimport type {\n SanityLiveAction,\n SanityLiveActionContext,\n SanityLiveOnError,\n SanityLiveOnGoaway,\n SanityLiveOnReconnect,\n SanityLiveOnRestart,\n SanityLiveOnWelcome,\n} from '#live/types'\n\nconst RefreshOnFocus = dynamic(() => import('./RefreshOnFocus'))\nconst RefreshOnMount = dynamic(() => import('./RefreshOnMount'))\nconst RefreshOnInterval = dynamic(() => import('./RefreshOnInterval'))\nconst RefreshOnReconnect = dynamic(() => import('./RefreshOnReconnect'))\n\ninterface SanityClientConfig extends Pick<\n InitializedClientConfig,\n | 'projectId'\n | 'dataset'\n | 'apiHost'\n | 'apiVersion'\n | 'useProjectHostname'\n | 'token'\n | 'requestTagPrefix'\n> {}\n\nexport interface SanityLiveProps {\n config: SanityClientConfig\n includeDrafts?: boolean\n requestTag: string\n\n action: SanityLiveAction\n onError: SanityLiveOnError | false | undefined\n onWelcome: SanityLiveOnWelcome | false | undefined\n onReconnect: SanityLiveOnReconnect | false | undefined\n onRestart: SanityLiveOnRestart | false | undefined\n onGoAway: SanityLiveOnGoaway | false | undefined\n\n refreshOnMount?: boolean\n refreshOnFocus?: boolean\n refreshOnReconnect?: boolean\n}\n\nfunction SanityLive(props: SanityLiveProps): React.JSX.Element | null {\n const {\n config,\n includeDrafts = false,\n action,\n onError,\n onWelcome = handleWelcome,\n onReconnect,\n onRestart,\n onGoAway = handleGoaway,\n refreshOnMount = false,\n refreshOnFocus = false,\n refreshOnReconnect = true,\n requestTag,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, token, requestTagPrefix} =\n config\n const actionContext = {includeDrafts} satisfies SanityLiveActionContext\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\n const [refreshOnInterval, setRefreshOnInterval] = useState<number | false>(false)\n\n const [error, setError] = useState<unknown>(null)\n if (error) {\n // Throw during render to bubble up to the nearest <ErrorBoundary>, if `onError` is provided we won't rethrow\n throw error\n }\n const handleError = useEffectEvent((error: unknown) => {\n if (onError) {\n void onError(error, actionContext)\n } else {\n setError(\n isCorsOriginError(error)\n ? new Error(\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.${error.addOriginUrl ? ` Add it here: ${error.addOriginUrl}` : ''}`,\n {cause: error},\n )\n : error,\n )\n }\n })\n\n const router = useRouter()\n const handleLiveEvent = useEffectEvent((event: LiveEvent) => {\n switch (event.type) {\n case 'welcome': {\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\n if (onWelcome) {\n startTransition(() => onWelcome(event, actionContext))\n }\n break\n }\n case 'message': {\n startTransition(() =>\n action(\n event.tags.map(\n (tag) =>\n `${includeDrafts ? cacheTagPrefixes.drafts : cacheTagPrefixes.published}${tag}`,\n ),\n ).then((result) => {\n if (result === 'refresh') {\n startTransition(() => router.refresh())\n }\n }),\n )\n break\n }\n case 'restart': {\n // Disable long polling when restart event is received, this is a no-op if long polling is already disabled\n startTransition(() => setRefreshOnInterval(false))\n\n if (onRestart) {\n startTransition(() => onRestart(event, actionContext))\n }\n break\n }\n case 'reconnect': {\n // Disable long polling when reconnect event is received, this is a no-op if long polling is already disabled\n startTransition(() => setRefreshOnInterval(false))\n\n if (onReconnect) {\n startTransition(() => onReconnect(event, actionContext))\n }\n break\n }\n case 'goaway': {\n if (onGoAway) {\n startTransition(() =>\n onGoAway(event, actionContext, (interval) =>\n startTransition(() => setRefreshOnInterval(interval)),\n ),\n )\n } else if (!onGoAway) {\n handleError(\n new Error(\n `Sanity Live connection closed, automatic revalidation is disabled, the server gave this reason: ${event.reason}`,\n {cause: event},\n ),\n )\n }\n break\n }\n default:\n handleError(new Error(`Unknown live event type`, {cause: event}))\n break\n }\n })\n useEffect(() => {\n const subscription = client.live\n .events({includeDrafts, tag: requestTag})\n .subscribe({next: handleLiveEvent, error: handleError})\n return () => subscription.unsubscribe()\n }, [client.live, requestTag, includeDrafts])\n\n return (\n <>\n {refreshOnFocus && <RefreshOnFocus />}\n {refreshOnInterval && Number.isFinite(refreshOnInterval) && refreshOnInterval > 0 && (\n <RefreshOnInterval interval={refreshOnInterval} />\n )}\n {refreshOnMount && <RefreshOnMount />}\n {refreshOnReconnect && <RefreshOnReconnect />}\n </>\n )\n}\n\nSanityLive.displayName = 'SanityLiveClientComponent'\n\nexport default SanityLive\n\nconst handleWelcome: SanityLiveOnWelcome = (_, {includeDrafts}) => {\n // oxlint-disable-next-line no-console\n console.info(\n `<SanityLive${includeDrafts ? ' includeDrafts' : ''}> is connected and listening for live events to ${includeDrafts ? 'all content including drafts and version documents in content releases' : 'published content'}`,\n )\n}\n\nconst handleGoaway: SanityLiveOnGoaway = (event, {includeDrafts}, setLongPollingInterval) => {\n const interval = 30_000\n console.warn(\n `<SanityLive${includeDrafts ? ' includeDrafts' : ''}> connection is closed after receiving a 'goaway' event, the server gave this reason:`,\n event.reason,\n `Content will now be refreshed every ${interval / 1_000} seconds`,\n )\n setLongPollingInterval(interval)\n}\n"],"mappings":"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"}
@@ -3,11 +3,25 @@ import { VisualEditing as VisualEditing$1 } from "@sanity/visual-editing/react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
5
  import { actionRefresh } from "next-sanity/visual-editing/server-actions";
6
+ /**
7
+ * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/path-has-prefix.ts#L10-L17
8
+ * Checks if a given path starts with a given prefix. It ensures it matches
9
+ * exactly without containing extra chars. e.g. prefix /docs should replace
10
+ * for /docs, /docs/, /docs/a but not /docsss
11
+ * @param path The path to check.
12
+ * @param prefix The prefix to check against.
13
+ */
6
14
  function pathHasPrefix(path, prefix) {
7
15
  if (typeof path !== "string") return false;
8
16
  const { pathname } = parsePath(path);
9
17
  return pathname === prefix || pathname.startsWith(`${prefix}/`);
10
18
  }
19
+ /**
20
+ * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/parse-path.ts#L6-L22
21
+ * Given a path this function will find the pathname, query and hash and return
22
+ * them. This is useful to parse full paths on the client side.
23
+ * @param path A path to parse e.g. /foo/bar?id=1#hash
24
+ */
11
25
  function parsePath(path) {
12
26
  const hashIndex = path.indexOf("#");
13
27
  const queryIndex = path.indexOf("?");
@@ -23,18 +37,37 @@ function parsePath(path) {
23
37
  hash: ""
24
38
  };
25
39
  }
40
+ /**
41
+ * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/add-path-prefix.ts#L3C1-L14C2
42
+ * Adds the provided prefix to the given path. It first ensures that the path
43
+ * is indeed starting with a slash.
44
+ */
26
45
  function addPathPrefix(path, prefix) {
27
46
  if (!path.startsWith("/") || !prefix) return path;
28
47
  if (path === "/" && prefix) return prefix;
29
48
  const { pathname, query, hash } = parsePath(path);
30
49
  return `${prefix}${pathname}${query}${hash}`;
31
50
  }
51
+ /**
52
+ * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/remove-path-prefix.ts#L3-L39
53
+ * Given a path and a prefix it will remove the prefix when it exists in the
54
+ * given path. It ensures it matches exactly without containing extra chars
55
+ * and if the prefix is not there it will be noop.
56
+ *
57
+ * @param path The path to remove the prefix from.
58
+ * @param prefix The prefix to be removed.
59
+ */
32
60
  function removePathPrefix(path, prefix) {
33
61
  if (!pathHasPrefix(path, prefix)) return path;
34
62
  const withoutPrefix = path.slice(prefix.length);
35
63
  if (withoutPrefix.startsWith("/")) return withoutPrefix;
36
64
  return `/${withoutPrefix}`;
37
65
  }
66
+ /**
67
+ * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/client/normalize-trailing-slash.ts#L16
68
+ * Normalizes the trailing slash of a path according to the `trailingSlash` option
69
+ * in `next.config.js`.
70
+ */
38
71
  const normalizePathTrailingSlash = (path, trailingSlash) => {
39
72
  const { pathname, query, hash } = parsePath(path);
40
73
  if (trailingSlash) {
@@ -43,6 +76,14 @@ const normalizePathTrailingSlash = (path, trailingSlash) => {
43
76
  }
44
77
  return `${removeTrailingSlash(pathname)}${query}${hash}`;
45
78
  };
79
+ /**
80
+ * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/shared/lib/router/utils/remove-trailing-slash.ts#L8
81
+ * Removes the trailing slash for a given route or page path. Preserves the
82
+ * root page. Examples:
83
+ * - `/foo/bar/` -> `/foo/bar`
84
+ * - `/foo/bar` -> `/foo/bar`
85
+ * - `/` -> `/`
86
+ */
46
87
  function removeTrailingSlash(route) {
47
88
  return route.replace(/\/$/, "") || "/";
48
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VisualEditing.js","names":["VisualEditingComponent"],"sources":["../src/visual-editing/client-component/utils.ts","../src/visual-editing/client-component/VisualEditing.tsx"],"sourcesContent":["/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/path-has-prefix.ts#L10-L17\n * Checks if a given path starts with a given prefix. It ensures it matches\n * exactly without containing extra chars. e.g. prefix /docs should replace\n * for /docs, /docs/, /docs/a but not /docsss\n * @param path The path to check.\n * @param prefix The prefix to check against.\n */\nfunction pathHasPrefix(path: string, prefix: string): boolean {\n if (typeof path !== 'string') {\n return false\n }\n\n const {pathname} = parsePath(path)\n return pathname === prefix || pathname.startsWith(`${prefix}/`)\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/parse-path.ts#L6-L22\n * Given a path this function will find the pathname, query and hash and return\n * them. This is useful to parse full paths on the client side.\n * @param path A path to parse e.g. /foo/bar?id=1#hash\n */\nfunction parsePath(path: string): {\n pathname: string\n query: string\n hash: string\n} {\n const hashIndex = path.indexOf('#')\n const queryIndex = path.indexOf('?')\n const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex)\n\n if (hasQuery || hashIndex > -1) {\n return {\n pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),\n query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : '',\n hash: hashIndex > -1 ? path.slice(hashIndex) : '',\n }\n }\n\n return {pathname: path, query: '', hash: ''}\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/add-path-prefix.ts#L3C1-L14C2\n * Adds the provided prefix to the given path. It first ensures that the path\n * is indeed starting with a slash.\n */\nexport function addPathPrefix(path: string, prefix?: string): string {\n if (!path.startsWith('/') || !prefix) {\n return path\n }\n // If the path is exactly '/' then return just the prefix\n if (path === '/' && prefix) {\n return prefix\n }\n\n const {pathname, query, hash} = parsePath(path)\n return `${prefix}${pathname}${query}${hash}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/remove-path-prefix.ts#L3-L39\n * Given a path and a prefix it will remove the prefix when it exists in the\n * given path. It ensures it matches exactly without containing extra chars\n * and if the prefix is not there it will be noop.\n *\n * @param path The path to remove the prefix from.\n * @param prefix The prefix to be removed.\n */\nexport function removePathPrefix(path: string, prefix: string): string {\n // If the path doesn't start with the prefix we can return it as is. This\n // protects us from situations where the prefix is a substring of the path\n // prefix such as:\n //\n // For prefix: /blog\n //\n // /blog -> true\n // /blog/ -> true\n // /blog/1 -> true\n // /blogging -> false\n // /blogging/ -> false\n // /blogging/1 -> false\n if (!pathHasPrefix(path, prefix)) {\n return path\n }\n\n // Remove the prefix from the path via slicing.\n const withoutPrefix = path.slice(prefix.length)\n\n // If the path without the prefix starts with a `/` we can return it as is.\n if (withoutPrefix.startsWith('/')) {\n return withoutPrefix\n }\n\n // If the path without the prefix doesn't start with a `/` we need to add it\n // back to the path to make sure it's a valid path.\n return `/${withoutPrefix}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/client/normalize-trailing-slash.ts#L16\n * Normalizes the trailing slash of a path according to the `trailingSlash` option\n * in `next.config.js`.\n */\nexport const normalizePathTrailingSlash = (path: string, trailingSlash: boolean): string => {\n const {pathname, query, hash} = parsePath(path)\n if (trailingSlash) {\n if (pathname.endsWith('/')) {\n return `${pathname}${query}${hash}`\n }\n return `${pathname}/${query}${hash}`\n }\n\n return `${removeTrailingSlash(pathname)}${query}${hash}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/shared/lib/router/utils/remove-trailing-slash.ts#L8\n * Removes the trailing slash for a given route or page path. Preserves the\n * root page. Examples:\n * - `/foo/bar/` -> `/foo/bar`\n * - `/foo/bar` -> `/foo/bar`\n * - `/` -> `/`\n */\nfunction removeTrailingSlash(route: string) {\n return route.replace(/\\/$/, '') || '/'\n}\n","import {\n type HistoryAdapter,\n type HistoryAdapterNavigate,\n type HistoryRefresh,\n VisualEditing as VisualEditingComponent,\n type VisualEditingOptions,\n} from '@sanity/visual-editing/react'\nimport {actionRefresh} from 'next-sanity/visual-editing/server-actions'\nimport {usePathname, useRouter, useSearchParams} from 'next/navigation'\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react'\n\nimport {addPathPrefix, normalizePathTrailingSlash, removePathPrefix} from './utils'\n\n/**\n * @public\n */\nexport interface VisualEditingProps extends Omit<VisualEditingOptions, 'history'> {\n /**\n * @deprecated The histoy adapter is already implemented\n */\n history?: never\n /**\n * If next.config.ts is configured with a basePath we try to configure it automatically,\n * you can disable this by setting basePath to ''.\n * @example basePath=\"/my-custom-base-path\"\n * @alpha experimental and may change without notice\n * @defaultValue process.env.__NEXT_ROUTER_BASEPATH || ''\n */\n basePath?: string\n /**\n * If next.config.ts is configured with a `trailingSlash` we try to detect it automatically,\n * it can be controlled manually by passing a boolean.\n * @example trailingSlash={true}\n * @alpha experimental and may change without notice\n * @defaultValue Boolean(process.env.__NEXT_TRAILING_SLASH)\n */\n trailingSlash?: boolean\n}\n\nexport default function VisualEditing(props: VisualEditingProps): React.JSX.Element | null {\n const {\n basePath = '',\n plugins,\n components,\n refresh,\n trailingSlash = false,\n zIndex,\n onPerspectiveChange,\n } = props\n\n const router = useRouter()\n const routerRef = useRef(router)\n const [navigate, setNavigate] = useState<HistoryAdapterNavigate | undefined>()\n\n useEffect(() => {\n routerRef.current = router\n }, [router])\n\n const history = useMemo<HistoryAdapter>(\n () => ({\n subscribe: (_navigate) => {\n setNavigate(() => _navigate)\n return () => setNavigate(undefined)\n },\n update: (update) => {\n switch (update.type) {\n case 'push':\n return routerRef.current.push(removePathPrefix(update.url, basePath))\n case 'pop':\n return routerRef.current.back()\n case 'replace':\n return routerRef.current.replace(removePathPrefix(update.url, basePath))\n default:\n throw new Error(`Unknown update type`, {cause: update})\n }\n },\n }),\n [basePath],\n )\n\n const pathname = usePathname()\n const searchParams = useSearchParams()\n useEffect(() => {\n if (navigate) {\n navigate({\n type: 'push',\n url: normalizePathTrailingSlash(\n addPathPrefix(\n `${pathname}${searchParams?.size ? `?${searchParams.toString()}` : ''}`,\n basePath,\n ),\n trailingSlash,\n ),\n })\n }\n }, [basePath, navigate, pathname, searchParams, trailingSlash])\n\n const handleRefresh = useCallback((payload: HistoryRefresh): false | Promise<void> => {\n switch (payload.source) {\n case 'manual':\n return actionRefresh(payload)\n case 'mutation': {\n if (payload.livePreviewEnabled) {\n // oxlint-disable-next-line no-console\n console.debug(\n 'Live preview is setup, mutation is skipped assuming its handled by the live preview',\n )\n return false\n }\n return actionRefresh(payload)\n }\n default:\n throw new Error('Unknown refresh source', {cause: payload})\n }\n }, [])\n\n return (\n <VisualEditingComponent\n plugins={plugins}\n components={components}\n history={history}\n portal\n refresh={refresh ?? handleRefresh}\n onPerspectiveChange={onPerspectiveChange}\n zIndex={zIndex}\n />\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VisualEditing.js","names":["VisualEditingComponent"],"sources":["../src/visual-editing/client-component/utils.ts","../src/visual-editing/client-component/VisualEditing.tsx"],"sourcesContent":["/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/path-has-prefix.ts#L10-L17\n * Checks if a given path starts with a given prefix. It ensures it matches\n * exactly without containing extra chars. e.g. prefix /docs should replace\n * for /docs, /docs/, /docs/a but not /docsss\n * @param path The path to check.\n * @param prefix The prefix to check against.\n */\nfunction pathHasPrefix(path: string, prefix: string): boolean {\n if (typeof path !== 'string') {\n return false\n }\n\n const {pathname} = parsePath(path)\n return pathname === prefix || pathname.startsWith(`${prefix}/`)\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/parse-path.ts#L6-L22\n * Given a path this function will find the pathname, query and hash and return\n * them. This is useful to parse full paths on the client side.\n * @param path A path to parse e.g. /foo/bar?id=1#hash\n */\nfunction parsePath(path: string): {\n pathname: string\n query: string\n hash: string\n} {\n const hashIndex = path.indexOf('#')\n const queryIndex = path.indexOf('?')\n const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex)\n\n if (hasQuery || hashIndex > -1) {\n return {\n pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),\n query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : '',\n hash: hashIndex > -1 ? path.slice(hashIndex) : '',\n }\n }\n\n return {pathname: path, query: '', hash: ''}\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/add-path-prefix.ts#L3C1-L14C2\n * Adds the provided prefix to the given path. It first ensures that the path\n * is indeed starting with a slash.\n */\nexport function addPathPrefix(path: string, prefix?: string): string {\n if (!path.startsWith('/') || !prefix) {\n return path\n }\n // If the path is exactly '/' then return just the prefix\n if (path === '/' && prefix) {\n return prefix\n }\n\n const {pathname, query, hash} = parsePath(path)\n return `${prefix}${pathname}${query}${hash}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/5469e6427b54ab7e9876d4c85b47f9c3afdc5c1f/packages/next/src/shared/lib/router/utils/remove-path-prefix.ts#L3-L39\n * Given a path and a prefix it will remove the prefix when it exists in the\n * given path. It ensures it matches exactly without containing extra chars\n * and if the prefix is not there it will be noop.\n *\n * @param path The path to remove the prefix from.\n * @param prefix The prefix to be removed.\n */\nexport function removePathPrefix(path: string, prefix: string): string {\n // If the path doesn't start with the prefix we can return it as is. This\n // protects us from situations where the prefix is a substring of the path\n // prefix such as:\n //\n // For prefix: /blog\n //\n // /blog -> true\n // /blog/ -> true\n // /blog/1 -> true\n // /blogging -> false\n // /blogging/ -> false\n // /blogging/1 -> false\n if (!pathHasPrefix(path, prefix)) {\n return path\n }\n\n // Remove the prefix from the path via slicing.\n const withoutPrefix = path.slice(prefix.length)\n\n // If the path without the prefix starts with a `/` we can return it as is.\n if (withoutPrefix.startsWith('/')) {\n return withoutPrefix\n }\n\n // If the path without the prefix doesn't start with a `/` we need to add it\n // back to the path to make sure it's a valid path.\n return `/${withoutPrefix}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/client/normalize-trailing-slash.ts#L16\n * Normalizes the trailing slash of a path according to the `trailingSlash` option\n * in `next.config.js`.\n */\nexport const normalizePathTrailingSlash = (path: string, trailingSlash: boolean): string => {\n const {pathname, query, hash} = parsePath(path)\n if (trailingSlash) {\n if (pathname.endsWith('/')) {\n return `${pathname}${query}${hash}`\n }\n return `${pathname}/${query}${hash}`\n }\n\n return `${removeTrailingSlash(pathname)}${query}${hash}`\n}\n\n/**\n * From: https://github.com/vercel/next.js/blob/dfe7fc03e2268e7cb765dce6a89e02c831c922d5/packages/next/src/shared/lib/router/utils/remove-trailing-slash.ts#L8\n * Removes the trailing slash for a given route or page path. Preserves the\n * root page. Examples:\n * - `/foo/bar/` -> `/foo/bar`\n * - `/foo/bar` -> `/foo/bar`\n * - `/` -> `/`\n */\nfunction removeTrailingSlash(route: string) {\n return route.replace(/\\/$/, '') || '/'\n}\n","import {\n type HistoryAdapter,\n type HistoryAdapterNavigate,\n type HistoryRefresh,\n VisualEditing as VisualEditingComponent,\n type VisualEditingOptions,\n} from '@sanity/visual-editing/react'\nimport {actionRefresh} from 'next-sanity/visual-editing/server-actions'\nimport {usePathname, useRouter, useSearchParams} from 'next/navigation'\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react'\n\nimport {addPathPrefix, normalizePathTrailingSlash, removePathPrefix} from './utils'\n\n/**\n * @public\n */\nexport interface VisualEditingProps extends Omit<VisualEditingOptions, 'history'> {\n /**\n * @deprecated The histoy adapter is already implemented\n */\n history?: never\n /**\n * If next.config.ts is configured with a basePath we try to configure it automatically,\n * you can disable this by setting basePath to ''.\n * @example basePath=\"/my-custom-base-path\"\n * @alpha experimental and may change without notice\n * @defaultValue process.env.__NEXT_ROUTER_BASEPATH || ''\n */\n basePath?: string\n /**\n * If next.config.ts is configured with a `trailingSlash` we try to detect it automatically,\n * it can be controlled manually by passing a boolean.\n * @example trailingSlash={true}\n * @alpha experimental and may change without notice\n * @defaultValue Boolean(process.env.__NEXT_TRAILING_SLASH)\n */\n trailingSlash?: boolean\n}\n\nexport default function VisualEditing(props: VisualEditingProps): React.JSX.Element | null {\n const {\n basePath = '',\n plugins,\n components,\n refresh,\n trailingSlash = false,\n zIndex,\n onPerspectiveChange,\n } = props\n\n const router = useRouter()\n const routerRef = useRef(router)\n const [navigate, setNavigate] = useState<HistoryAdapterNavigate | undefined>()\n\n useEffect(() => {\n routerRef.current = router\n }, [router])\n\n const history = useMemo<HistoryAdapter>(\n () => ({\n subscribe: (_navigate) => {\n setNavigate(() => _navigate)\n return () => setNavigate(undefined)\n },\n update: (update) => {\n switch (update.type) {\n case 'push':\n return routerRef.current.push(removePathPrefix(update.url, basePath))\n case 'pop':\n return routerRef.current.back()\n case 'replace':\n return routerRef.current.replace(removePathPrefix(update.url, basePath))\n default:\n throw new Error(`Unknown update type`, {cause: update})\n }\n },\n }),\n [basePath],\n )\n\n const pathname = usePathname()\n const searchParams = useSearchParams()\n useEffect(() => {\n if (navigate) {\n navigate({\n type: 'push',\n url: normalizePathTrailingSlash(\n addPathPrefix(\n `${pathname}${searchParams?.size ? `?${searchParams.toString()}` : ''}`,\n basePath,\n ),\n trailingSlash,\n ),\n })\n }\n }, [basePath, navigate, pathname, searchParams, trailingSlash])\n\n const handleRefresh = useCallback((payload: HistoryRefresh): false | Promise<void> => {\n switch (payload.source) {\n case 'manual':\n return actionRefresh(payload)\n case 'mutation': {\n if (payload.livePreviewEnabled) {\n // oxlint-disable-next-line no-console\n console.debug(\n 'Live preview is setup, mutation is skipped assuming its handled by the live preview',\n )\n return false\n }\n return actionRefresh(payload)\n }\n default:\n throw new Error('Unknown refresh source', {cause: payload})\n }\n }, [])\n\n return (\n <VisualEditingComponent\n plugins={plugins}\n components={components}\n history={history}\n portal\n refresh={refresh ?? handleRefresh}\n onPerspectiveChange={onPerspectiveChange}\n zIndex={zIndex}\n />\n )\n}\n"],"mappings":"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"}
package/dist/constants.js CHANGED
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short
3
+ */
1
4
  const revalidate = 31536e3;
2
5
  const cacheTagPrefixes = {
3
6
  published: "sanity:",
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":[],"sources":["../src/live/shared/constants.ts"],"sourcesContent":["import type {CacheTagPrefixes} from './types'\n\n/**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short\n */\nexport const revalidate = 31_536_000 // 365 days\n\nexport const cacheTagPrefixes = {\n published: 'sanity:',\n drafts: 'sanity-drafts:',\n} satisfies CacheTagPrefixes\n"],"mappings":"AAKA,MAAa,aAAa;AAE1B,MAAa,mBAAmB;CAC9B,WAAW;CACX,QAAQ;CACT"}
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../src/live/shared/constants.ts"],"sourcesContent":["import type {CacheTagPrefixes} from './types'\n\n/**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short\n */\nexport const revalidate = 31_536_000 // 365 days\n\nexport const cacheTagPrefixes = {\n published: 'sanity:',\n drafts: 'sanity-drafts:',\n} satisfies CacheTagPrefixes\n"],"mappings":";;;AAKA,MAAa,aAAa;AAE1B,MAAa,mBAAmB;CAC9B,WAAW;CACX,QAAQ;CACT"}
@@ -2,6 +2,23 @@ import { validatePreviewUrl } from "@sanity/preview-url-secret";
2
2
  import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
3
3
  import { cookies, draftMode } from "next/headers";
4
4
  import { redirect } from "next/navigation";
5
+ /**
6
+ * Sets up an API route for enabling draft mode, can be paired with the `previewUrl.previewMode.enable` in `sanity/presentation`.
7
+ * Can also be used with `sanity-plugin-iframe-pane`.
8
+ * @example
9
+ * ```ts
10
+ * // src/app/api/draft-mode/enable/route.ts
11
+ *
12
+ * import { defineEnableDraftMode } from "next-sanity/draft-mode";
13
+ * import { client } from "@/sanity/lib/client";
14
+ *
15
+ * export const { GET } = defineEnableDraftMode({
16
+ * client: client.withConfig({ token: process.env.SANITY_API_READ_TOKEN }),
17
+ * });
18
+ * ```
19
+ *
20
+ * @public
21
+ */
5
22
  function defineEnableDraftMode(options) {
6
23
  const { client } = options;
7
24
  return { GET: async (request) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/draft-mode/define-enable-draft-mode.ts"],"sourcesContent":["import type {SanityClient} from '@sanity/client'\nimport {validatePreviewUrl} from '@sanity/preview-url-secret'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {cookies, draftMode} from 'next/headers'\nimport {redirect} from 'next/navigation'\n\n/**\n * @public\n */\nexport interface DefineEnableDraftModeOptions {\n client: SanityClient\n /**\n * Force secure cookies in development mode.\n * Enable this when using Next.js --experimental-https flag.\n * This option has no effect in production (cookies are always secure).\n * @defaultValue false\n */\n secureDevMode?: boolean\n}\n\n/**\n * @public\n */\nexport interface EnableDraftMode {\n GET: (request: Request) => Promise<Response>\n}\n\n/**\n * Sets up an API route for enabling draft mode, can be paired with the `previewUrl.previewMode.enable` in `sanity/presentation`.\n * Can also be used with `sanity-plugin-iframe-pane`.\n * @example\n * ```ts\n * // src/app/api/draft-mode/enable/route.ts\n *\n * import { defineEnableDraftMode } from \"next-sanity/draft-mode\";\n * import { client } from \"@/sanity/lib/client\";\n *\n * export const { GET } = defineEnableDraftMode({\n * client: client.withConfig({ token: process.env.SANITY_API_READ_TOKEN }),\n * });\n * ```\n *\n * @public\n */\nexport function defineEnableDraftMode(options: DefineEnableDraftModeOptions): EnableDraftMode {\n const {client} = options\n return {\n GET: async (request: Request) => {\n // @TODO check if already in draft mode at a much earlier stage, and skip validation\n\n const {\n isValid,\n redirectTo = '/',\n studioPreviewPerspective,\n } = await validatePreviewUrl(client, request.url)\n if (!isValid) {\n return new Response('Invalid secret', {status: 401})\n }\n\n const draftModeStore = await draftMode()\n\n // Let's enable draft mode if it's not already enabled\n if (!draftModeStore.isEnabled) {\n draftModeStore.enable()\n }\n\n const isProduction = process.env.NODE_ENV === 'production'\n\n // We can't auto-detect HTTPS in dev due to Next.js limitations,\n // so we need an explicit option\n const isSecure = isProduction || (options.secureDevMode ?? false)\n\n // Override cookie header for draft mode for usage in live-preview\n // https://github.com/vercel/next.js/issues/49927\n const cookieStore = await cookies()\n const cookie = cookieStore.get('__prerender_bypass')!\n cookieStore.set({\n name: '__prerender_bypass',\n value: cookie?.value,\n httpOnly: true,\n path: '/',\n secure: isSecure,\n sameSite: isSecure ? 'none' : 'lax',\n })\n\n if (studioPreviewPerspective) {\n cookieStore.set({\n name: perspectiveCookieName,\n value: studioPreviewPerspective,\n httpOnly: true,\n path: '/',\n secure: isSecure,\n sameSite: isSecure ? 'none' : 'lax',\n })\n }\n\n // the `redirect` function throws, and eventually returns a Promise<Response>. TSC doesn't \"see\" that so we have to tell it\n return redirect(redirectTo) as Promise<Response>\n },\n }\n}\n"],"mappings":";;;;AA4CA,SAAgB,sBAAsB,SAAwD;CAC5F,MAAM,EAAC,WAAU;AACjB,QAAO,EACL,KAAK,OAAO,YAAqB;EAG/B,MAAM,EACJ,SACA,aAAa,KACb,6BACE,MAAM,mBAAmB,QAAQ,QAAQ,IAAI;AACjD,MAAI,CAAC,QACH,QAAO,IAAI,SAAS,kBAAkB,EAAC,QAAQ,KAAI,CAAC;EAGtD,MAAM,iBAAiB,MAAM,WAAW;AAGxC,MAAI,CAAC,eAAe,UAClB,gBAAe,QAAQ;EAOzB,MAAM,WAJe,QAAQ,IAAI,aAAa,iBAIZ,QAAQ,iBAAiB;EAI3D,MAAM,cAAc,MAAM,SAAS;EACnC,MAAM,SAAS,YAAY,IAAI,qBAAqB;AACpD,cAAY,IAAI;GACd,MAAM;GACN,OAAO,QAAQ;GACf,UAAU;GACV,MAAM;GACN,QAAQ;GACR,UAAU,WAAW,SAAS;GAC/B,CAAC;AAEF,MAAI,yBACF,aAAY,IAAI;GACd,MAAM;GACN,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,UAAU,WAAW,SAAS;GAC/B,CAAC;AAIJ,SAAO,SAAS,WAAW;IAE9B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/draft-mode/define-enable-draft-mode.ts"],"sourcesContent":["import type {SanityClient} from '@sanity/client'\nimport {validatePreviewUrl} from '@sanity/preview-url-secret'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {cookies, draftMode} from 'next/headers'\nimport {redirect} from 'next/navigation'\n\n/**\n * @public\n */\nexport interface DefineEnableDraftModeOptions {\n client: SanityClient\n /**\n * Force secure cookies in development mode.\n * Enable this when using Next.js --experimental-https flag.\n * This option has no effect in production (cookies are always secure).\n * @defaultValue false\n */\n secureDevMode?: boolean\n}\n\n/**\n * @public\n */\nexport interface EnableDraftMode {\n GET: (request: Request) => Promise<Response>\n}\n\n/**\n * Sets up an API route for enabling draft mode, can be paired with the `previewUrl.previewMode.enable` in `sanity/presentation`.\n * Can also be used with `sanity-plugin-iframe-pane`.\n * @example\n * ```ts\n * // src/app/api/draft-mode/enable/route.ts\n *\n * import { defineEnableDraftMode } from \"next-sanity/draft-mode\";\n * import { client } from \"@/sanity/lib/client\";\n *\n * export const { GET } = defineEnableDraftMode({\n * client: client.withConfig({ token: process.env.SANITY_API_READ_TOKEN }),\n * });\n * ```\n *\n * @public\n */\nexport function defineEnableDraftMode(options: DefineEnableDraftModeOptions): EnableDraftMode {\n const {client} = options\n return {\n GET: async (request: Request) => {\n // @TODO check if already in draft mode at a much earlier stage, and skip validation\n\n const {\n isValid,\n redirectTo = '/',\n studioPreviewPerspective,\n } = await validatePreviewUrl(client, request.url)\n if (!isValid) {\n return new Response('Invalid secret', {status: 401})\n }\n\n const draftModeStore = await draftMode()\n\n // Let's enable draft mode if it's not already enabled\n if (!draftModeStore.isEnabled) {\n draftModeStore.enable()\n }\n\n const isProduction = process.env.NODE_ENV === 'production'\n\n // We can't auto-detect HTTPS in dev due to Next.js limitations,\n // so we need an explicit option\n const isSecure = isProduction || (options.secureDevMode ?? false)\n\n // Override cookie header for draft mode for usage in live-preview\n // https://github.com/vercel/next.js/issues/49927\n const cookieStore = await cookies()\n const cookie = cookieStore.get('__prerender_bypass')!\n cookieStore.set({\n name: '__prerender_bypass',\n value: cookie?.value,\n httpOnly: true,\n path: '/',\n secure: isSecure,\n sameSite: isSecure ? 'none' : 'lax',\n })\n\n if (studioPreviewPerspective) {\n cookieStore.set({\n name: perspectiveCookieName,\n value: studioPreviewPerspective,\n httpOnly: true,\n path: '/',\n secure: isSecure,\n sameSite: isSecure ? 'none' : 'lax',\n })\n }\n\n // the `redirect` function throws, and eventually returns a Promise<Response>. TSC doesn't \"see\" that so we have to tell it\n return redirect(redirectTo) as Promise<Response>\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,sBAAsB,SAAwD;CAC5F,MAAM,EAAC,WAAU;AACjB,QAAO,EACL,KAAK,OAAO,YAAqB;EAG/B,MAAM,EACJ,SACA,aAAa,KACb,6BACE,MAAM,mBAAmB,QAAQ,QAAQ,IAAI;AACjD,MAAI,CAAC,QACH,QAAO,IAAI,SAAS,kBAAkB,EAAC,QAAQ,KAAI,CAAC;EAGtD,MAAM,iBAAiB,MAAM,WAAW;AAGxC,MAAI,CAAC,eAAe,UAClB,gBAAe,QAAQ;EAOzB,MAAM,WAJe,QAAQ,IAAI,aAAa,iBAIZ,QAAQ,iBAAiB;EAI3D,MAAM,cAAc,MAAM,SAAS;EACnC,MAAM,SAAS,YAAY,IAAI,qBAAqB;AACpD,cAAY,IAAI;GACd,MAAM;GACN,OAAO,QAAQ;GACf,UAAU;GACV,MAAM;GACN,QAAQ;GACR,UAAU,WAAW,SAAS;GAC/B,CAAC;AAEF,MAAI,yBACF,aAAY,IAAI;GACd,MAAM;GACN,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,UAAU,WAAW,SAAS;GAC/B,CAAC;AAIJ,SAAO,SAAS,WAAW;IAE9B"}
@@ -1,6 +1,9 @@
1
1
  "use client";
2
2
  import NextImage from "next/image";
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.");
@@ -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":";;;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,WAAA;EAAU,GAAI;EAAM,KAAK,OAAO,UAAU;EAAE,QAAQ;GAAe"}
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,3 +1,4 @@
1
+ /** @public */
1
2
  function isCorsOriginError(error) {
2
3
  return error instanceof Error && error.name === "CorsOriginError";
3
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"isCorsOriginError.js","names":[],"sources":["../src/live/shared/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/live/shared/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,4 +1,35 @@
1
- const sanity = { revalidate: 31536e3 };
1
+ /**
2
+ * For usage with `cacheComponents: true`, and `defineLive`:
3
+ * ```ts
4
+ * // next.config.ts
5
+ *
6
+ * import type {NextConfig} from 'next'
7
+ * import {sanity} from 'next-sanity/cache-life'
8
+ *
9
+ * const nextConfig: NextConfig = {
10
+ * cacheComponents: true,
11
+ * cacheLife: {
12
+ * sanity
13
+ * }
14
+ * }
15
+ *
16
+ * export default nextConfig
17
+ * ```
18
+ *
19
+ * ```ts
20
+ *
21
+ * async function sanityFetch() {
22
+ * 'use cache'
23
+ * cacheLife('sanity')
24
+ * const {data} = await fetch({query, params})
25
+ * return data
26
+ * }
27
+ */
28
+ const sanity = {
29
+ /**
30
+ * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short
31
+ */
32
+ revalidate: 31536e3 };
2
33
  export { sanity };
3
34
 
4
35
  //# sourceMappingURL=cache-life.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache-life.js","names":[],"sources":["../../src/live/cache-life.ts"],"sourcesContent":["import {revalidate} from '#live/constants'\n\n/**\n * For usage with `cacheComponents: true`, and `defineLive`:\n * ```ts\n * // next.config.ts\n *\n * import type {NextConfig} from 'next'\n * import {sanity} from 'next-sanity/cache-life'\n *\n * const nextConfig: NextConfig = {\n * cacheComponents: true,\n * cacheLife: {\n * sanity\n * }\n * }\n *\n * export default nextConfig\n * ```\n *\n * ```ts\n *\n * async function sanityFetch() {\n * 'use cache'\n * cacheLife('sanity')\n * const {data} = await fetch({query, params})\n * return data\n * }\n */\nexport const sanity = {\n /**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short\n */\n revalidate: 31_536_000, // 365 days\n} as const satisfies {\n /**\n * This cache may be stale on clients for ... seconds before checking with the server.\n */\n stale?: number\n /**\n * If the server receives a new request after ... seconds, start revalidating new values in the background.\n */\n revalidate?: typeof revalidate\n /**\n * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n */\n expire?: number\n}\n"],"mappings":"AA6BA,MAAa,SAAS,EAIpB,YAAY,SACb"}
1
+ {"version":3,"file":"cache-life.js","names":[],"sources":["../../src/live/cache-life.ts"],"sourcesContent":["import {revalidate} from '#live/constants'\n\n/**\n * For usage with `cacheComponents: true`, and `defineLive`:\n * ```ts\n * // next.config.ts\n *\n * import type {NextConfig} from 'next'\n * import {sanity} from 'next-sanity/cache-life'\n *\n * const nextConfig: NextConfig = {\n * cacheComponents: true,\n * cacheLife: {\n * sanity\n * }\n * }\n *\n * export default nextConfig\n * ```\n *\n * ```ts\n *\n * async function sanityFetch() {\n * 'use cache'\n * cacheLife('sanity')\n * const {data} = await fetch({query, params})\n * return data\n * }\n */\nexport const sanity = {\n /**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short\n */\n revalidate: 31_536_000, // 365 days\n} as const satisfies {\n /**\n * This cache may be stale on clients for ... seconds before checking with the server.\n */\n stale?: number\n /**\n * If the server receives a new request after ... seconds, start revalidating new values in the background.\n */\n revalidate?: typeof revalidate\n /**\n * If this entry has no traffic for ... seconds it will expire. The next request will recompute it.\n */\n expire?: number\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,SAAS;;;;AAIpB,YAAY,SACb"}
@@ -1,5 +1,8 @@
1
1
  "use client";
2
2
  import dynamic from "next/dynamic";
3
+ /**
4
+ * @alpha CAUTION: this is an internal component and does not follow semver. Using it directly is at your own risk.
5
+ */
3
6
  const SanityLive = dynamic(() => import("../../SanityLive.js"), { ssr: false });
4
7
  export { SanityLive };
5
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/live/client-components/index.ts"],"sourcesContent":["'use client'\n\nimport dynamic from 'next/dynamic'\n\nimport type {SanityLiveProps} from './SanityLive'\n/**\n * @alpha CAUTION: this is an internal component and does not follow semver. Using it directly is at your own risk.\n */\nexport const SanityLive: React.ComponentType<SanityLiveProps> = dynamic(\n () => import('./SanityLive'),\n {ssr: false},\n)\n"],"mappings":";;AAQA,MAAa,aAAmD,cACxD,OAAO,wBACb,EAAC,KAAK,OAAM,CACb"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/live/client-components/index.ts"],"sourcesContent":["'use client'\n\nimport dynamic from 'next/dynamic'\n\nimport type {SanityLiveProps} from './SanityLive'\n/**\n * @alpha CAUTION: this is an internal component and does not follow semver. Using it directly is at your own risk.\n */\nexport const SanityLive: React.ComponentType<SanityLiveProps> = dynamic(\n () => import('./SanityLive'),\n {ssr: false},\n)\n"],"mappings":";;;;;AAQA,MAAa,aAAmD,cACxD,OAAO,wBACb,EAAC,KAAK,OAAM,CACb"}
@@ -3,6 +3,10 @@ import { t as parseTags } from "../../../parseTags.js";
3
3
  function defineLive(_config) {
4
4
  throw new Error(`defineLive can't be imported by a client component`);
5
5
  }
6
+ /**
7
+ * Resolves the perspective from the cookie that is set by `import { defineEnableDraftMode } from "next-sanity/draft-mode"`
8
+ * @public
9
+ */
6
10
  const resolvePerspectiveFromCookies = () => {
7
11
  throw new Error(`resolvePerspectiveFromCookies can't be imported by a client component`);
8
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/conditions/default/index.ts"],"sourcesContent":["// This is the fallback export condition for `import 'next-sanity/live'`,\n// it should have the same type definitions as the other conditions so that userland don't have to worry about setting the right\n// `customCondition` in their `tsconfig.json` in order to get accurate typings.\n// The implementation here though should all throw errors, as importing this file means userland made a mistake and somehow a client component is\n// trying to pull in something it shouldn't.\n\nimport type {ResolvePerspectiveFromCookies} from '#live/resolvePerspectiveFromCookies'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport {isCorsOriginError} from '#live/isCorsOriginError'\nexport {parseTags} from '#live/parseTags'\n\n/**\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(_config: DefineLiveOptions): never {\n throw new Error(`defineLive can't be imported by a client component`)\n}\n\n/**\n * Resolves the perspective from the cookie that is set by `import { defineEnableDraftMode } from \"next-sanity/draft-mode\"`\n * @public\n */\nexport const resolvePerspectiveFromCookies: ResolvePerspectiveFromCookies = () => {\n throw new Error(`resolvePerspectiveFromCookies can't be imported by a client component`)\n}\n\nexport type {PerspectiveType as LivePerspective} from '#live/types'\n"],"mappings":";;AA6BA,SAAgB,WAAW,SAAmC;AAC5D,OAAM,IAAI,MAAM,qDAAqD;;AAOvE,MAAa,sCAAqE;AAChF,OAAM,IAAI,MAAM,wEAAwE"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/live/conditions/default/index.ts"],"sourcesContent":["// This is the fallback export condition for `import 'next-sanity/live'`,\n// it should have the same type definitions as the other conditions so that userland don't have to worry about setting the right\n// `customCondition` in their `tsconfig.json` in order to get accurate typings.\n// The implementation here though should all throw errors, as importing this file means userland made a mistake and somehow a client component is\n// trying to pull in something it shouldn't.\n\nimport type {ResolvePerspectiveFromCookies} from '#live/resolvePerspectiveFromCookies'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport {isCorsOriginError} from '#live/isCorsOriginError'\nexport {parseTags} from '#live/parseTags'\n\n/**\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(_config: DefineLiveOptions): never {\n throw new Error(`defineLive can't be imported by a client component`)\n}\n\n/**\n * Resolves the perspective from the cookie that is set by `import { defineEnableDraftMode } from \"next-sanity/draft-mode\"`\n * @public\n */\nexport const resolvePerspectiveFromCookies: ResolvePerspectiveFromCookies = () => {\n throw new Error(`resolvePerspectiveFromCookies can't be imported by a client component`)\n}\n\nexport type {PerspectiveType as LivePerspective} from '#live/types'\n"],"mappings":";;AA6BA,SAAgB,WAAW,SAAmC;AAC5D,OAAM,IAAI,MAAM,qDAAqD;;;;;;AAOvE,MAAa,sCAAqE;AAChF,OAAM,IAAI,MAAM,wEAAwE"}
@@ -1,7 +1,7 @@
1
1
  import { t as isCorsOriginError } from "../../../isCorsOriginError.js";
2
2
  import { n as revalidate, t as cacheTagPrefixes } from "../../../constants.js";
3
- import { t as parseTags } from "../../../parseTags.js";
4
3
  import { n as validateStrictFetchOptions, r as validateStrictSanityLiveProps, t as resolvePerspectiveFromCookies } from "../../../resolvePerspectiveFromCookies.js";
4
+ import { t as parseTags } from "../../../parseTags.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { SanityLive } from "next-sanity/live/client-components";
7
7
  import { actionRefresh, actionUpdateTags } from "next-sanity/live/server-actions";
@@ -40,7 +40,14 @@ function defineLive(config) {
40
40
  token: perspective === "published" ? originalToken : serverToken || originalToken
41
41
  });
42
42
  const tags = [...customCacheTags, ...(syncTags || []).map((tag) => `${cacheTagPrefix}${tag}`)];
43
+ /**
44
+ * The tags used here, are expired later on in the `expireTags` Server Action with the `expireTag` function from `next/cache`
45
+ */
43
46
  cacheTag(...tags);
47
+ /**
48
+ * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short,
49
+ * userland can still set a shorter revalidate time by calling `cacheLife` themselves.
50
+ */
44
51
  cacheLife({ revalidate });
45
52
  return {
46
53
  data: result,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/next-js/defineLive.tsx"],"sourcesContent":["import {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {actionRefresh, actionUpdateTags} from 'next-sanity/live/server-actions'\nimport {cacheLife, cacheTag} from 'next/cache'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {preconnect} from 'react-dom'\n\nimport {cacheTagPrefixes, revalidate} from '#live/constants'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions) {\n const {client: _client, serverToken, browserToken, strict = false} = 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: true})\n const {token: originalToken, perspective: originalPerspective = 'published'} = client.config()\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective: _perspective,\n stega: _stega,\n tags: customCacheTags = [],\n requestTag = 'next-loader.fetch.cache-components',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const perspective = _perspective ?? originalPerspective\n const stega = _stega ?? false\n const useCdn = perspective === 'published'\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n\n const cacheTagPrefix =\n perspective === 'published' ? cacheTagPrefixes.published : cacheTagPrefixes.drafts\n const {result, resultSourceMap, syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n returnQuery: false,\n perspective,\n useCdn,\n stega,\n cacheMode,\n tag: requestTag,\n token: perspective === 'published' ? originalToken : serverToken || originalToken, // @TODO can pass undefined instead of config.token here?\n })\n const tags = [...customCacheTags, ...(syncTags || []).map((tag) => `${cacheTagPrefix}${tag}`)]\n /**\n * The tags used here, are expired later on in the `expireTags` Server Action with the `expireTag` function from `next/cache`\n */\n cacheTag(...tags)\n /**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short,\n * userland can still set a shorter revalidate time by calling `cacheLife` themselves.\n */\n cacheLife({revalidate})\n\n return {data: result, sourceMap: resultSourceMap || null, tags}\n }\n\n const SanityLive: React.ComponentType<DefinedLiveProps> = function SanityLive(props) {\n if (strict) {\n validateStrictSanityLiveProps(props)\n }\n const {\n includeDrafts = false,\n action = actionUpdateTags,\n onReconnect = actionRefresh,\n onRestart = actionRefresh,\n\n onWelcome,\n onError,\n onGoAway,\n\n refreshOnMount = false,\n refreshOnFocus = false,\n refreshOnReconnect = false,\n requestTag = 'next-loader.live.cache-components',\n } = props\n\n const shouldIncludeDrafts = typeof browserToken === 'string' && includeDrafts\n\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\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 config={{\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n requestTagPrefix,\n token: shouldIncludeDrafts ? browserToken : undefined,\n }}\n includeDrafts={shouldIncludeDrafts}\n action={action}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onWelcome={onWelcome}\n onError={onError}\n onGoAway={onGoAway}\n requestTag={requestTag}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {\n sanityFetch: sanityFetch,\n SanityLive: SanityLive,\n }\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,WAAW,QAA2B;CACpD,MAAM,EAAC,QAAQ,SAAS,aAAa,cAAc,SAAS,UAAS;AAErE,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;EAAK,CAAC;CAC1E,MAAM,EAAC,OAAO,eAAe,aAAa,sBAAsB,gBAAe,OAAO,QAAQ;CAE9F,MAAM,cAAgC,eAAe,YAAY,EAC/D,OACA,SAAS,EAAE,EACX,aAAa,cACb,OAAO,QACP,MAAM,kBAAkB,EAAE,EAC1B,aAAa,wCACZ;AACD,MAAI,OACF,4BAA2B;GAAC,aAAa;GAAc,OAAO;GAAO,CAAC;EAExE,MAAM,cAAc,gBAAgB;EACpC,MAAM,QAAQ,UAAU;EACxB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,eAAe,QAAQ,IAAI,kBAAkB;EACnD,MAAM,YAAY,UAAU,CAAC,eAAe,YAAY,KAAA;EAExD,MAAM,iBACJ,gBAAgB,cAAc,iBAAiB,YAAY,iBAAiB;EAC9E,MAAM,EAAC,QAAQ,iBAAiB,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;GAClF,gBAAgB;GAChB,aAAa;GACb;GACA;GACA;GACA;GACA,KAAK;GACL,OAAO,gBAAgB,cAAc,gBAAgB,eAAe;GACrE,CAAC;EACF,MAAM,OAAO,CAAC,GAAG,iBAAiB,IAAI,YAAY,EAAE,EAAE,KAAK,QAAQ,GAAG,iBAAiB,MAAM,CAAC;AAI9F,WAAS,GAAG,KAAK;AAKjB,YAAU,EAAC,YAAW,CAAC;AAEvB,SAAO;GAAC,MAAM;GAAQ,WAAW,mBAAmB;GAAM;GAAK;;CAGjE,MAAMA,eAAoD,SAASA,aAAW,OAAO;AACnF,MAAI,OACF,+BAA8B,MAAM;EAEtC,MAAM,EACJ,gBAAgB,OAChB,SAAS,kBACT,cAAc,eACd,YAAY,eAEZ,WACA,SACA,UAEA,iBAAiB,OACjB,iBAAiB,OACjB,qBAAqB,OACrB,aAAa,wCACX;EAEJ,MAAM,sBAAsB,OAAO,iBAAiB,YAAY;EAEhE,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,QAAQ;EAGjB,MAAM,EAAC,WAAU,IAAI,IAAI,OAAO,OAAO,IAAI,MAAM,CAAC;AAClD,aAAW,OAAO;AAElB,SACE,oBAACC,YAAAA;GACC,QAAQ;IACN;IACA;IACA;IACA;IACA;IACA;IACA,OAAO,sBAAsB,eAAe,KAAA;IAC7C;GACD,eAAe;GACP;GACK;GACF;GACA;GACF;GACC;GACE;GACI;GACA;GACI;IACpB;;AAGN,cAAW,cAAc;AAEzB,QAAO;EACQ;EACb,YAAYD;EACb"}
1
+ {"version":3,"file":"index.js","names":["SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/next-js/defineLive.tsx"],"sourcesContent":["import {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {actionRefresh, actionUpdateTags} from 'next-sanity/live/server-actions'\nimport {cacheLife, cacheTag} from 'next/cache'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {preconnect} from 'react-dom'\n\nimport {cacheTagPrefixes, revalidate} from '#live/constants'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions) {\n const {client: _client, serverToken, browserToken, strict = false} = 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: true})\n const {token: originalToken, perspective: originalPerspective = 'published'} = client.config()\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective: _perspective,\n stega: _stega,\n tags: customCacheTags = [],\n requestTag = 'next-loader.fetch.cache-components',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const perspective = _perspective ?? originalPerspective\n const stega = _stega ?? false\n const useCdn = perspective === 'published'\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n\n const cacheTagPrefix =\n perspective === 'published' ? cacheTagPrefixes.published : cacheTagPrefixes.drafts\n const {result, resultSourceMap, syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n returnQuery: false,\n perspective,\n useCdn,\n stega,\n cacheMode,\n tag: requestTag,\n token: perspective === 'published' ? originalToken : serverToken || originalToken, // @TODO can pass undefined instead of config.token here?\n })\n const tags = [...customCacheTags, ...(syncTags || []).map((tag) => `${cacheTagPrefix}${tag}`)]\n /**\n * The tags used here, are expired later on in the `expireTags` Server Action with the `expireTag` function from `next/cache`\n */\n cacheTag(...tags)\n /**\n * Sanity Live handles on-demand revalidation, so the default 15min time based revalidation is too short,\n * userland can still set a shorter revalidate time by calling `cacheLife` themselves.\n */\n cacheLife({revalidate})\n\n return {data: result, sourceMap: resultSourceMap || null, tags}\n }\n\n const SanityLive: React.ComponentType<DefinedLiveProps> = function SanityLive(props) {\n if (strict) {\n validateStrictSanityLiveProps(props)\n }\n const {\n includeDrafts = false,\n action = actionUpdateTags,\n onReconnect = actionRefresh,\n onRestart = actionRefresh,\n\n onWelcome,\n onError,\n onGoAway,\n\n refreshOnMount = false,\n refreshOnFocus = false,\n refreshOnReconnect = false,\n requestTag = 'next-loader.live.cache-components',\n } = props\n\n const shouldIncludeDrafts = typeof browserToken === 'string' && includeDrafts\n\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\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 config={{\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n requestTagPrefix,\n token: shouldIncludeDrafts ? browserToken : undefined,\n }}\n includeDrafts={shouldIncludeDrafts}\n action={action}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onWelcome={onWelcome}\n onError={onError}\n onGoAway={onGoAway}\n requestTag={requestTag}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {\n sanityFetch: sanityFetch,\n SanityLive: SanityLive,\n }\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,WAAW,QAA2B;CACpD,MAAM,EAAC,QAAQ,SAAS,aAAa,cAAc,SAAS,UAAS;AAErE,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;EAAK,CAAC;CAC1E,MAAM,EAAC,OAAO,eAAe,aAAa,sBAAsB,gBAAe,OAAO,QAAQ;CAE9F,MAAM,cAAgC,eAAe,YAAY,EAC/D,OACA,SAAS,EAAE,EACX,aAAa,cACb,OAAO,QACP,MAAM,kBAAkB,EAAE,EAC1B,aAAa,wCACZ;AACD,MAAI,OACF,4BAA2B;GAAC,aAAa;GAAc,OAAO;GAAO,CAAC;EAExE,MAAM,cAAc,gBAAgB;EACpC,MAAM,QAAQ,UAAU;EACxB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,eAAe,QAAQ,IAAI,kBAAkB;EACnD,MAAM,YAAY,UAAU,CAAC,eAAe,YAAY,KAAA;EAExD,MAAM,iBACJ,gBAAgB,cAAc,iBAAiB,YAAY,iBAAiB;EAC9E,MAAM,EAAC,QAAQ,iBAAiB,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;GAClF,gBAAgB;GAChB,aAAa;GACb;GACA;GACA;GACA;GACA,KAAK;GACL,OAAO,gBAAgB,cAAc,gBAAgB,eAAe;GACrE,CAAC;EACF,MAAM,OAAO,CAAC,GAAG,iBAAiB,IAAI,YAAY,EAAE,EAAE,KAAK,QAAQ,GAAG,iBAAiB,MAAM,CAAC;;;;AAI9F,WAAS,GAAG,KAAK;;;;;AAKjB,YAAU,EAAC,YAAW,CAAC;AAEvB,SAAO;GAAC,MAAM;GAAQ,WAAW,mBAAmB;GAAM;GAAK;;CAGjE,MAAMA,eAAoD,SAASA,aAAW,OAAO;AACnF,MAAI,OACF,+BAA8B,MAAM;EAEtC,MAAM,EACJ,gBAAgB,OAChB,SAAS,kBACT,cAAc,eACd,YAAY,eAEZ,WACA,SACA,UAEA,iBAAiB,OACjB,iBAAiB,OACjB,qBAAqB,OACrB,aAAa,wCACX;EAEJ,MAAM,sBAAsB,OAAO,iBAAiB,YAAY;EAEhE,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,QAAQ;EAGjB,MAAM,EAAC,WAAU,IAAI,IAAI,OAAO,OAAO,IAAI,MAAM,CAAC;AAClD,aAAW,OAAO;AAElB,SACE,oBAACC,YAAD;GACE,QAAQ;IACN;IACA;IACA;IACA;IACA;IACA;IACA,OAAO,sBAAsB,eAAe,KAAA;IAC7C;GACD,eAAe;GACP;GACK;GACF;GACA;GACF;GACC;GACE;GACI;GACA;GACI;GACpB,CAAA;;AAGN,cAAW,cAAc;AAEzB,QAAO;EACQ;EACb,YAAYD;EACb"}
@@ -1,11 +1,12 @@
1
1
  import { t as isCorsOriginError } from "../../../isCorsOriginError.js";
2
2
  import { t as cacheTagPrefixes } from "../../../constants.js";
3
- import { t as parseTags } from "../../../parseTags.js";
4
3
  import { n as validateStrictFetchOptions, r as validateStrictSanityLiveProps, t as resolvePerspectiveFromCookies } from "../../../resolvePerspectiveFromCookies.js";
4
+ import { t as parseTags } from "../../../parseTags.js";
5
5
  import { t as sanitizePerspective } from "../../../sanitizePerspective.js";
6
6
  import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
7
7
  import { cookies, draftMode } from "next/headers";
8
8
  import { jsx } from "react/jsx-runtime";
9
+ import "@sanity/client";
9
10
  import { SanityLive } from "next-sanity/live/client-components";
10
11
  import { actionRefresh, actionUpdateTags } from "next-sanity/live/server-actions";
11
12
  import { PHASE_PRODUCTION_BUILD } from "next/constants";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"sourcesContent":["import {type ClientPerspective, type QueryParams} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {actionRefresh, actionUpdateTags} from 'next-sanity/live/server-actions'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {cookies, draftMode} from 'next/headers'\nimport {preconnect} from 'react-dom'\n\nimport {cacheTagPrefixes} from '#live/constants'\nimport {sanitizePerspective} from '#live/sanitizePerspective'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions) {\n const {\n client: _client,\n serverToken,\n browserToken,\n stega: stegaEnabled = true,\n strict = false,\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, perspective: originalPerspective = 'published'} = client.config()\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedFetchType = 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 if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const stega = strict\n ? _stega!\n : (_stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled))\n const perspective = strict\n ? _perspective!\n : (_perspective ??\n (await resolveCookiePerspective(\n originalPerspective === 'raw' ? 'published' : originalPerspective,\n )))\n const useCdn = perspective === 'published'\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n const revalidate = false\n const cacheTagPrefix =\n perspective === 'published' ? cacheTagPrefixes.published : cacheTagPrefixes.drafts\n\n // fetch the tags first, with revalidate to 1s to ensure we get the latest tags, eventually\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: {\n revalidate,\n tags: [...tags, 'fetch-sync-tags'].map((tag) => `${cacheTagPrefix}${tag}`),\n },\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `${cacheTagPrefix}${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<DefinedLiveProps> = async function SanityLive(props) {\n if (strict) {\n validateStrictSanityLiveProps(props)\n }\n const {\n includeDrafts = (await draftMode()).isEnabled,\n action = actionUpdateTags,\n onReconnect = actionRefresh,\n onRestart = actionRefresh,\n\n onWelcome = false,\n onError = false,\n onGoAway = false,\n\n refreshOnMount,\n refreshOnFocus,\n refreshOnReconnect,\n requestTag = 'next-loader.live',\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n const shouldIncludeDrafts = typeof browserToken === 'string' && includeDrafts\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 config={{\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n requestTagPrefix,\n token: shouldIncludeDrafts ? browserToken : undefined,\n }}\n includeDrafts={shouldIncludeDrafts}\n action={action}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onWelcome={onWelcome}\n onError={onError}\n onGoAway={onGoAway}\n requestTag={requestTag}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {\n sanityFetch,\n SanityLive,\n }\n}\n\nasync function resolveCookiePerspective(\n fallback: Exclude<ClientPerspective, 'raw'>,\n): 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 : fallback\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"sourcesContent":["import {type ClientPerspective, type QueryParams} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {actionRefresh, actionUpdateTags} from 'next-sanity/live/server-actions'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {cookies, draftMode} from 'next/headers'\nimport {preconnect} from 'react-dom'\n\nimport {cacheTagPrefixes} from '#live/constants'\nimport {sanitizePerspective} from '#live/sanitizePerspective'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions & {strict?: false}): {\n sanityFetch: DefinedFetchType\n SanityLive: React.ComponentType<DefinedLiveProps>\n}\nexport function defineLive(config: DefineLiveOptions) {\n const {\n client: _client,\n serverToken,\n browserToken,\n stega: stegaEnabled = true,\n strict = false,\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, perspective: originalPerspective = 'published'} = client.config()\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedFetchType = 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 if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const stega = strict\n ? _stega!\n : (_stega ?? (stegaEnabled && studioUrlDefined && (await draftMode()).isEnabled))\n const perspective = strict\n ? _perspective!\n : (_perspective ??\n (await resolveCookiePerspective(\n originalPerspective === 'raw' ? 'published' : originalPerspective,\n )))\n const useCdn = perspective === 'published'\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn && !isBuildPhase ? 'noStale' : undefined\n const revalidate = false\n const cacheTagPrefix =\n perspective === 'published' ? cacheTagPrefixes.published : cacheTagPrefixes.drafts\n\n // fetch the tags first, with revalidate to 1s to ensure we get the latest tags, eventually\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: {\n revalidate,\n tags: [...tags, 'fetch-sync-tags'].map((tag) => `${cacheTagPrefix}${tag}`),\n },\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `${cacheTagPrefix}${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<DefinedLiveProps> = async function SanityLive(props) {\n if (strict) {\n validateStrictSanityLiveProps(props)\n }\n const {\n includeDrafts = (await draftMode()).isEnabled,\n action = actionUpdateTags,\n onReconnect = actionRefresh,\n onRestart = actionRefresh,\n\n onWelcome = false,\n onError = false,\n onGoAway = false,\n\n refreshOnMount,\n refreshOnFocus,\n refreshOnReconnect,\n requestTag = 'next-loader.live',\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n const shouldIncludeDrafts = typeof browserToken === 'string' && includeDrafts\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 config={{\n projectId,\n dataset,\n apiHost,\n apiVersion,\n useProjectHostname,\n requestTagPrefix,\n token: shouldIncludeDrafts ? browserToken : undefined,\n }}\n includeDrafts={shouldIncludeDrafts}\n action={action}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onWelcome={onWelcome}\n onError={onError}\n onGoAway={onGoAway}\n requestTag={requestTag}\n refreshOnMount={refreshOnMount}\n refreshOnFocus={refreshOnFocus}\n refreshOnReconnect={refreshOnReconnect}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {\n sanityFetch,\n SanityLive,\n }\n}\n\nasync function resolveCookiePerspective(\n fallback: Exclude<ClientPerspective, 'raw'>,\n): 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 : fallback\n}\n"],"mappings":"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"}
@@ -2,6 +2,9 @@
2
2
  import { t as parseTags } from "../../parseTags.js";
3
3
  import { draftMode } from "next/headers";
4
4
  import { refresh, revalidateTag, updateTag } from "next/cache";
5
+ /**
6
+ * Used by `<SanityLive action={actionRevalidateTags} />`
7
+ */
5
8
  async function actionUpdateTags(unsafeTags) {
6
9
  const { tags, prefixType } = parseTags(unsafeTags);
7
10
  if ((await draftMode()).isEnabled) {
@@ -13,6 +16,9 @@ async function actionUpdateTags(unsafeTags) {
13
16
  revalidateTag("sanity:fetch-sync-tags", "max");
14
17
  console.log(`<SanityLive ${prefixType === "drafts" ? "includeDrafts " : ""}/> updated tags: ${tags.join(", ")} and revalidated tag: "sanity:fetch-sync-tags" with cache profile "max"`);
15
18
  }
19
+ /**
20
+ * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`
21
+ */
16
22
  async function actionRefresh() {
17
23
  refresh();
18
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.default.js","names":[],"sources":["../../../src/live/server-actions/index.default.ts"],"sourcesContent":["'use server'\n\nimport {refresh, revalidateTag, updateTag} from 'next/cache'\nimport {draftMode} from 'next/headers'\n\nimport {parseTags} from '#live/parseTags'\n\n/**\n * Used by `<SanityLive action={actionRevalidateTags} />`\n */\nexport async function actionUpdateTags(unsafeTags: unknown): Promise<void> {\n const {tags, prefixType} = parseTags(unsafeTags)\n if ((await draftMode()).isEnabled) {\n console.warn(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> action called in draft mode, cache is bypassed in draft mode so the refresh() function is called instead of updateTag()`,\n {tags},\n )\n refresh()\n return undefined\n }\n for (const tag of tags) {\n updateTag(tag)\n }\n revalidateTag('sanity:fetch-sync-tags', 'max')\n // oxlint-disable-next-line no-console\n console.log(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> updated tags: ${tags.join(', ')} and revalidated tag: \"sanity:fetch-sync-tags\" with cache profile \"max\"`,\n )\n}\n\n/**\n * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`\n */\nexport async function actionRefresh(): Promise<void> {\n refresh()\n}\n"],"mappings":";;;;AAUA,eAAsB,iBAAiB,YAAoC;CACzE,MAAM,EAAC,MAAM,eAAc,UAAU,WAAW;AAChD,MAAK,MAAM,WAAW,EAAE,WAAW;AACjC,UAAQ,KACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,6HAC/D,EAAC,MAAK,CACP;AACD,WAAS;AACT;;AAEF,MAAK,MAAM,OAAO,KAChB,WAAU,IAAI;AAEhB,eAAc,0BAA0B,MAAM;AAE9C,SAAQ,IACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,mBAAmB,KAAK,KAAK,KAAK,CAAC,yEACnG;;AAMH,eAAsB,gBAA+B;AACnD,UAAS"}
1
+ {"version":3,"file":"index.default.js","names":[],"sources":["../../../src/live/server-actions/index.default.ts"],"sourcesContent":["'use server'\n\nimport {refresh, revalidateTag, updateTag} from 'next/cache'\nimport {draftMode} from 'next/headers'\n\nimport {parseTags} from '#live/parseTags'\n\n/**\n * Used by `<SanityLive action={actionRevalidateTags} />`\n */\nexport async function actionUpdateTags(unsafeTags: unknown): Promise<void> {\n const {tags, prefixType} = parseTags(unsafeTags)\n if ((await draftMode()).isEnabled) {\n console.warn(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> action called in draft mode, cache is bypassed in draft mode so the refresh() function is called instead of updateTag()`,\n {tags},\n )\n refresh()\n return undefined\n }\n for (const tag of tags) {\n updateTag(tag)\n }\n revalidateTag('sanity:fetch-sync-tags', 'max')\n // oxlint-disable-next-line no-console\n console.log(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> updated tags: ${tags.join(', ')} and revalidated tag: \"sanity:fetch-sync-tags\" with cache profile \"max\"`,\n )\n}\n\n/**\n * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`\n */\nexport async function actionRefresh(): Promise<void> {\n refresh()\n}\n"],"mappings":";;;;;;;AAUA,eAAsB,iBAAiB,YAAoC;CACzE,MAAM,EAAC,MAAM,eAAc,UAAU,WAAW;AAChD,MAAK,MAAM,WAAW,EAAE,WAAW;AACjC,UAAQ,KACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,6HAC/D,EAAC,MAAK,CACP;AACD,WAAS;AACT;;AAEF,MAAK,MAAM,OAAO,KAChB,WAAU,IAAI;AAEhB,eAAc,0BAA0B,MAAM;AAE9C,SAAQ,IACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,mBAAmB,KAAK,KAAK,KAAK,CAAC,yEACnG;;;;;AAMH,eAAsB,gBAA+B;AACnD,UAAS"}
@@ -2,6 +2,9 @@
2
2
  import { t as parseTags } from "../../parseTags.js";
3
3
  import { draftMode } from "next/headers";
4
4
  import { refresh, updateTag } from "next/cache";
5
+ /**
6
+ * Used by `<SanityLive action={actionRevalidateTags} />`
7
+ */
5
8
  async function actionUpdateTags(unsafeTags) {
6
9
  const { tags, prefixType } = parseTags(unsafeTags);
7
10
  if ((await draftMode()).isEnabled) {
@@ -12,6 +15,9 @@ async function actionUpdateTags(unsafeTags) {
12
15
  for (const tag of tags) updateTag(tag);
13
16
  console.log(`<SanityLive ${prefixType === "drafts" ? "includeDrafts " : ""}/> updated tags: ${tags.join(", ")}`);
14
17
  }
18
+ /**
19
+ * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`
20
+ */
15
21
  async function actionRefresh() {
16
22
  refresh();
17
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.next-js.js","names":[],"sources":["../../../src/live/server-actions/index.next-js.ts"],"sourcesContent":["'use server'\n\nimport {refresh, updateTag} from 'next/cache'\nimport {draftMode} from 'next/headers'\n\nimport {parseTags} from '#live/parseTags'\n\n/**\n * Used by `<SanityLive action={actionRevalidateTags} />`\n */\nexport async function actionUpdateTags(unsafeTags: unknown): Promise<void> {\n const {tags, prefixType} = parseTags(unsafeTags)\n if ((await draftMode()).isEnabled) {\n console.warn(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> action called in draft mode, cache is bypassed in draft mode so the refresh() function is called instead of updateTag()`,\n {tags},\n )\n refresh()\n return undefined\n }\n for (const tag of tags) {\n updateTag(tag)\n }\n // oxlint-disable-next-line no-console\n console.log(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> updated tags: ${tags.join(', ')}`,\n )\n}\n\n/**\n * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`\n */\nexport async function actionRefresh(): Promise<void> {\n refresh()\n}\n"],"mappings":";;;;AAUA,eAAsB,iBAAiB,YAAoC;CACzE,MAAM,EAAC,MAAM,eAAc,UAAU,WAAW;AAChD,MAAK,MAAM,WAAW,EAAE,WAAW;AACjC,UAAQ,KACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,6HAC/D,EAAC,MAAK,CACP;AACD,WAAS;AACT;;AAEF,MAAK,MAAM,OAAO,KAChB,WAAU,IAAI;AAGhB,SAAQ,IACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,mBAAmB,KAAK,KAAK,KAAK,GAClG;;AAMH,eAAsB,gBAA+B;AACnD,UAAS"}
1
+ {"version":3,"file":"index.next-js.js","names":[],"sources":["../../../src/live/server-actions/index.next-js.ts"],"sourcesContent":["'use server'\n\nimport {refresh, updateTag} from 'next/cache'\nimport {draftMode} from 'next/headers'\n\nimport {parseTags} from '#live/parseTags'\n\n/**\n * Used by `<SanityLive action={actionRevalidateTags} />`\n */\nexport async function actionUpdateTags(unsafeTags: unknown): Promise<void> {\n const {tags, prefixType} = parseTags(unsafeTags)\n if ((await draftMode()).isEnabled) {\n console.warn(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> action called in draft mode, cache is bypassed in draft mode so the refresh() function is called instead of updateTag()`,\n {tags},\n )\n refresh()\n return undefined\n }\n for (const tag of tags) {\n updateTag(tag)\n }\n // oxlint-disable-next-line no-console\n console.log(\n `<SanityLive ${prefixType === 'drafts' ? 'includeDrafts ' : ''}/> updated tags: ${tags.join(', ')}`,\n )\n}\n\n/**\n * Used by `<SanityLive onReconnect={actionRefresh} onRestart={actionRefresh} />`\n */\nexport async function actionRefresh(): Promise<void> {\n refresh()\n}\n"],"mappings":";;;;;;;AAUA,eAAsB,iBAAiB,YAAoC;CACzE,MAAM,EAAC,MAAM,eAAc,UAAU,WAAW;AAChD,MAAK,MAAM,WAAW,EAAE,WAAW;AACjC,UAAQ,KACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,6HAC/D,EAAC,MAAK,CACP;AACD,WAAS;AACT;;AAEF,MAAK,MAAM,OAAO,KAChB,WAAU,IAAI;AAGhB,SAAQ,IACN,eAAe,eAAe,WAAW,mBAAmB,GAAG,mBAAmB,KAAK,KAAK,KAAK,GAClG;;;;;AAMH,eAAsB,gBAA+B;AACnD,UAAS"}
@@ -1,5 +1,8 @@
1
1
  import { cookies } from "next/headers";
2
2
  import { ClientPerspective, SyncTag } from "@sanity/client";
3
+ /**
4
+ * @deprecated - refactor to exporting the same function instead
5
+ */
3
6
  type ResolvePerspectiveFromCookies = (options: {
4
7
  /**
5
8
  * You must await the cookies() function from next/headers
@@ -14,14 +17,33 @@ type ResolvePerspectiveFromCookies = (options: {
14
17
  cookies: Awaited<ReturnType<typeof cookies>>;
15
18
  }) => Promise<Exclude<ClientPerspective, "raw">>;
16
19
  /**
17
- * Resolves the perspective from the cookie that is set by `import { defineEnableDraftMode } from "next-sanity/draft-mode"`
20
+ * Reads the active draft-mode perspective from the cookie set by
21
+ * {@link "next-sanity/draft-mode".defineEnableDraftMode | `defineEnableDraftMode`}, falling back to `'drafts'`
22
+ * when the cookie is missing or contains an invalid value.
23
+ *
24
+ * This helper is intended for use with Next.js Cache Components (`cacheComponents: true`),
25
+ * where `cookies()` and `draftMode()` cannot be called inside `'use cache'` boundaries.
26
+ * Resolve the perspective once outside the cache boundary and pass it in as a prop / cache key.
27
+ *
28
+ * The caller is responsible for awaiting `cookies()` from `next/headers` and passing the
29
+ * resulting cookie store as the `cookies` option — this keeps the helper free of dynamic APIs
30
+ * so it can be invoked from anywhere a `ReadonlyRequestCookies` instance is available.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import {cookies} from 'next/headers'
35
+ * import {resolvePerspectiveFromCookies} from 'next-sanity/live'
36
+ *
37
+ * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})
38
+ * ```
39
+ *
18
40
  * @public
19
41
  */
20
- declare const resolvePerspectiveFromCookies: ({
42
+ declare function resolvePerspectiveFromCookies({
21
43
  cookies: jar
22
44
  }: {
23
45
  cookies: Awaited<ReturnType<typeof cookies>>;
24
- }) => Promise<Exclude<ClientPerspective, "raw">>;
46
+ }): Promise<Exclude<ClientPerspective, "raw">>;
25
47
  declare const cacheTagPrefixes: {
26
48
  published: string;
27
49
  drafts: string;
@@ -1 +1 @@
1
- {"version":3,"file":"parseTags.d.ts","names":[],"sources":["../src/live/shared/resolvePerspectiveFromCookies.ts","../src/live/shared/constants.ts","../src/live/shared/parseTags.ts"],"mappings":";;KAMY,6BAAA,IAAiC,OAAA;EAA7C;;;;;;;;;;EAWE,OAAA,EAAS,OAAA,CAAQ,UAAA,QAAkB,OAAA;AAAA,MAC/B,OAAA,CAAQ,OAAA,CAAQ,iBAAA;;;;;cAMT,6BAAA;EACX,OAAA,EAAS;AAAA;EAET,OAAA,EAAS,OAAA,CAAQ,UAAA,QAAkB,OAAA;AAAA,MACjC,OAAA,CAAQ,OAAA,CAAQ,iBAAA;AAAA,cCrBP,gBAAA;EACX,SAAA;EACA,MAAA;AAAA;AAAA,UCLQ,mBAAA;EACR,IAAA,YAAgB,gBAAA,CAAiB,SAAA,GAAY,OAAA;EAC7C,MAAA,SAAe,gBAAA,CAAiB,SAAA;EAChC,UAAA;AAAA;AAAA,UAEQ,eAAA;EACR,IAAA,YAAgB,gBAAA,CAAiB,MAAA,GAAS,OAAA;EAC1C,MAAA,SAAe,gBAAA,CAAiB,MAAA;EAChC,UAAA;AAAA;AAAA,KAEG,UAAA,GAAa,mBAAA,GAAsB,eAAA;;;;;;;;;;;;AFUxC;;;;;;;;;;iBEagB,SAAA,CAAU,UAAA,YAAsB,UAAA"}
1
+ {"version":3,"file":"parseTags.d.ts","names":[],"sources":["../src/live/shared/resolvePerspectiveFromCookies.ts","../src/live/shared/constants.ts","../src/live/shared/parseTags.ts"],"mappings":";;;AASA;;KAAY,6BAAA,IAAiC,OAAA;;;;;;;;;;;EAW3C,OAAA,EAAS,OAAA,CAAQ,UAAA,QAAkB,OAAA;AAAA,MAC/B,OAAA,CAAQ,OAAA,CAAQ,iBAAA;;;;;;;AAyBtB;;;;;;;;;;;;;;;;;iBAAsB,6BAAA,CAAA;EACpB,OAAA,EAAS;AAAA;EAET,OAAA,EAAS,OAAA,CAAQ,UAAA,QAAkB,OAAA;AAAA,IACjC,OAAA,CAAQ,OAAA,CAAQ,iBAAA;AAAA,cC3CP,gBAAA;EACX,SAAA;EACA,MAAA;AAAA;AAAA,UCLQ,mBAAA;EACR,IAAA,YAAgB,gBAAA,CAAiB,SAAA,GAAY,OAAA;EAC7C,MAAA,SAAe,gBAAA,CAAiB,SAAA;EAChC,UAAA;AAAA;AAAA,UAEQ,eAAA;EACR,IAAA,YAAgB,gBAAA,CAAiB,MAAA,GAAS,OAAA;EAC1C,MAAA,SAAe,gBAAA,CAAiB,MAAA;EAChC,UAAA;AAAA;AAAA,KAEG,UAAA,GAAa,mBAAA,GAAsB,eAAA;;;;;;;;;;;;AFgCxC;;;;;;;;;;iBETgB,SAAA,CAAU,UAAA,YAAsB,UAAA"}
package/dist/parseTags.js CHANGED
@@ -1,4 +1,25 @@
1
1
  import { t as cacheTagPrefixes } from "./constants.js";
2
+ /**
3
+ * Prefixes live event tags according to the conventions used by `defineLive().sanityFetch()`
4
+ * so that they can be used with `import {updateTag} from 'next/cache'`.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import {updateTag} from 'next/cache'
9
+ * import {parseTags} from 'next-sanity/live'
10
+ * import {SanityLive} from '#sanity/live
11
+ *
12
+ * <SanityLive
13
+ * action={async (event, context) => {
14
+ * 'use server'
15
+ *
16
+ * for (const tag of parseTags(event.tags, context)) {
17
+ * updateTag(tag)
18
+ * }
19
+ * }}
20
+ * />
21
+ * ```
22
+ */
2
23
  function parseTags(unsafeTags) {
3
24
  if (!Array.isArray(unsafeTags)) throw new TypeError("tags must be an array", { cause: { unsafeTags } });
4
25
  if (unsafeTags.length === 0) throw new TypeError("tags must be an non-empty array", { cause: { unsafeTags } });
@@ -1 +1 @@
1
- {"version":3,"file":"parseTags.js","names":[],"sources":["../src/live/shared/parseTags.ts"],"sourcesContent":["import type {SyncTag} from '@sanity/client'\n\nimport {cacheTagPrefixes} from './constants'\n\ninterface ParsedPublishedTags {\n tags: `${typeof cacheTagPrefixes.published}${SyncTag}`[]\n prefix: typeof cacheTagPrefixes.published\n prefixType: 'published'\n}\ninterface ParsedDraftTags {\n tags: `${typeof cacheTagPrefixes.drafts}${SyncTag}`[]\n prefix: typeof cacheTagPrefixes.drafts\n prefixType: 'drafts'\n}\ntype ParsedTags = ParsedPublishedTags | ParsedDraftTags\n\n/**\n * Prefixes live event tags according to the conventions used by `defineLive().sanityFetch()`\n * so that they can be used with `import {updateTag} from 'next/cache'`.\n *\n * @example\n * ```tsx\n * import {updateTag} from 'next/cache'\n * import {parseTags} from 'next-sanity/live'\n * import {SanityLive} from '#sanity/live\n *\n * <SanityLive\n * action={async (event, context) => {\n * 'use server'\n *\n * for (const tag of parseTags(event.tags, context)) {\n * updateTag(tag)\n * }\n * }}\n * />\n * ```\n */\nexport function parseTags(unsafeTags: unknown): ParsedTags {\n if (!Array.isArray(unsafeTags)) {\n throw new TypeError('tags must be an array', {cause: {unsafeTags}})\n }\n if (unsafeTags.length === 0) {\n throw new TypeError('tags must be an non-empty array', {cause: {unsafeTags}})\n }\n if (unsafeTags.some((tag) => typeof tag !== 'string')) {\n throw new TypeError('tags must be an array of strings', {cause: {unsafeTags}})\n }\n if (unsafeTags.some((tag) => tag.startsWith(cacheTagPrefixes.published))) {\n const prefixType = 'published'\n const tags: ParsedPublishedTags['tags'] = []\n // oxlint-disable-next-line no-unsafe-type-assertion\n for (const tag of unsafeTags as string[]) {\n if (tag.startsWith(cacheTagPrefixes.drafts)) {\n throw new TypeError('cannot mix published and drafts tags', {cause: {tag, unsafeTags}})\n }\n if (!tag.startsWith(cacheTagPrefixes.published)) {\n throw new TypeError('tag must start with a valid prefix', {cause: {tag}})\n }\n // oxlint-disable-next-line no-unsafe-type-assertion\n tags.push(tag as `${typeof cacheTagPrefixes.published}${SyncTag}`)\n }\n return {tags, prefix: cacheTagPrefixes.published, prefixType}\n } else if (unsafeTags.some((tag) => tag.startsWith(cacheTagPrefixes.drafts))) {\n const prefixType = 'drafts'\n const tags: ParsedDraftTags['tags'] = []\n // oxlint-disable-next-line no-unsafe-type-assertion\n for (const tag of unsafeTags as string[]) {\n if (tag.startsWith(cacheTagPrefixes.published)) {\n throw new TypeError('cannot mix published and drafts tags', {cause: {tag, unsafeTags}})\n }\n if (!tag.startsWith(cacheTagPrefixes.drafts)) {\n throw new TypeError('tag must start with a valid prefix', {cause: {tag}})\n }\n // oxlint-disable-next-line no-unsafe-type-assertion\n tags.push(tag as `${typeof cacheTagPrefixes.drafts}${SyncTag}`)\n }\n return {tags, prefix: cacheTagPrefixes.drafts, prefixType}\n }\n\n throw new Error('Failed to parse tags, no valid prefix found', {cause: {unsafeTags}})\n}\n"],"mappings":";AAqCA,SAAgB,UAAU,YAAiC;AACzD,KAAI,CAAC,MAAM,QAAQ,WAAW,CAC5B,OAAM,IAAI,UAAU,yBAAyB,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAErE,KAAI,WAAW,WAAW,EACxB,OAAM,IAAI,UAAU,mCAAmC,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAE/E,KAAI,WAAW,MAAM,QAAQ,OAAO,QAAQ,SAAS,CACnD,OAAM,IAAI,UAAU,oCAAoC,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAEhF,KAAI,WAAW,MAAM,QAAQ,IAAI,WAAW,iBAAiB,UAAU,CAAC,EAAE;EACxE,MAAM,aAAa;EACnB,MAAM,OAAoC,EAAE;AAE5C,OAAK,MAAM,OAAO,YAAwB;AACxC,OAAI,IAAI,WAAW,iBAAiB,OAAO,CACzC,OAAM,IAAI,UAAU,wCAAwC,EAAC,OAAO;IAAC;IAAK;IAAW,EAAC,CAAC;AAEzF,OAAI,CAAC,IAAI,WAAW,iBAAiB,UAAU,CAC7C,OAAM,IAAI,UAAU,sCAAsC,EAAC,OAAO,EAAC,KAAI,EAAC,CAAC;AAG3E,QAAK,KAAK,IAAwD;;AAEpE,SAAO;GAAC;GAAM,QAAQ,iBAAiB;GAAW;GAAW;YACpD,WAAW,MAAM,QAAQ,IAAI,WAAW,iBAAiB,OAAO,CAAC,EAAE;EAC5E,MAAM,aAAa;EACnB,MAAM,OAAgC,EAAE;AAExC,OAAK,MAAM,OAAO,YAAwB;AACxC,OAAI,IAAI,WAAW,iBAAiB,UAAU,CAC5C,OAAM,IAAI,UAAU,wCAAwC,EAAC,OAAO;IAAC;IAAK;IAAW,EAAC,CAAC;AAEzF,OAAI,CAAC,IAAI,WAAW,iBAAiB,OAAO,CAC1C,OAAM,IAAI,UAAU,sCAAsC,EAAC,OAAO,EAAC,KAAI,EAAC,CAAC;AAG3E,QAAK,KAAK,IAAqD;;AAEjE,SAAO;GAAC;GAAM,QAAQ,iBAAiB;GAAQ;GAAW;;AAG5D,OAAM,IAAI,MAAM,+CAA+C,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC"}
1
+ {"version":3,"file":"parseTags.js","names":[],"sources":["../src/live/shared/parseTags.ts"],"sourcesContent":["import type {SyncTag} from '@sanity/client'\n\nimport {cacheTagPrefixes} from './constants'\n\ninterface ParsedPublishedTags {\n tags: `${typeof cacheTagPrefixes.published}${SyncTag}`[]\n prefix: typeof cacheTagPrefixes.published\n prefixType: 'published'\n}\ninterface ParsedDraftTags {\n tags: `${typeof cacheTagPrefixes.drafts}${SyncTag}`[]\n prefix: typeof cacheTagPrefixes.drafts\n prefixType: 'drafts'\n}\ntype ParsedTags = ParsedPublishedTags | ParsedDraftTags\n\n/**\n * Prefixes live event tags according to the conventions used by `defineLive().sanityFetch()`\n * so that they can be used with `import {updateTag} from 'next/cache'`.\n *\n * @example\n * ```tsx\n * import {updateTag} from 'next/cache'\n * import {parseTags} from 'next-sanity/live'\n * import {SanityLive} from '#sanity/live\n *\n * <SanityLive\n * action={async (event, context) => {\n * 'use server'\n *\n * for (const tag of parseTags(event.tags, context)) {\n * updateTag(tag)\n * }\n * }}\n * />\n * ```\n */\nexport function parseTags(unsafeTags: unknown): ParsedTags {\n if (!Array.isArray(unsafeTags)) {\n throw new TypeError('tags must be an array', {cause: {unsafeTags}})\n }\n if (unsafeTags.length === 0) {\n throw new TypeError('tags must be an non-empty array', {cause: {unsafeTags}})\n }\n if (unsafeTags.some((tag) => typeof tag !== 'string')) {\n throw new TypeError('tags must be an array of strings', {cause: {unsafeTags}})\n }\n if (unsafeTags.some((tag) => tag.startsWith(cacheTagPrefixes.published))) {\n const prefixType = 'published'\n const tags: ParsedPublishedTags['tags'] = []\n // oxlint-disable-next-line no-unsafe-type-assertion\n for (const tag of unsafeTags as string[]) {\n if (tag.startsWith(cacheTagPrefixes.drafts)) {\n throw new TypeError('cannot mix published and drafts tags', {cause: {tag, unsafeTags}})\n }\n if (!tag.startsWith(cacheTagPrefixes.published)) {\n throw new TypeError('tag must start with a valid prefix', {cause: {tag}})\n }\n // oxlint-disable-next-line no-unsafe-type-assertion\n tags.push(tag as `${typeof cacheTagPrefixes.published}${SyncTag}`)\n }\n return {tags, prefix: cacheTagPrefixes.published, prefixType}\n } else if (unsafeTags.some((tag) => tag.startsWith(cacheTagPrefixes.drafts))) {\n const prefixType = 'drafts'\n const tags: ParsedDraftTags['tags'] = []\n // oxlint-disable-next-line no-unsafe-type-assertion\n for (const tag of unsafeTags as string[]) {\n if (tag.startsWith(cacheTagPrefixes.published)) {\n throw new TypeError('cannot mix published and drafts tags', {cause: {tag, unsafeTags}})\n }\n if (!tag.startsWith(cacheTagPrefixes.drafts)) {\n throw new TypeError('tag must start with a valid prefix', {cause: {tag}})\n }\n // oxlint-disable-next-line no-unsafe-type-assertion\n tags.push(tag as `${typeof cacheTagPrefixes.drafts}${SyncTag}`)\n }\n return {tags, prefix: cacheTagPrefixes.drafts, prefixType}\n }\n\n throw new Error('Failed to parse tags, no valid prefix found', {cause: {unsafeTags}})\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,UAAU,YAAiC;AACzD,KAAI,CAAC,MAAM,QAAQ,WAAW,CAC5B,OAAM,IAAI,UAAU,yBAAyB,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAErE,KAAI,WAAW,WAAW,EACxB,OAAM,IAAI,UAAU,mCAAmC,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAE/E,KAAI,WAAW,MAAM,QAAQ,OAAO,QAAQ,SAAS,CACnD,OAAM,IAAI,UAAU,oCAAoC,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC;AAEhF,KAAI,WAAW,MAAM,QAAQ,IAAI,WAAW,iBAAiB,UAAU,CAAC,EAAE;EACxE,MAAM,aAAa;EACnB,MAAM,OAAoC,EAAE;AAE5C,OAAK,MAAM,OAAO,YAAwB;AACxC,OAAI,IAAI,WAAW,iBAAiB,OAAO,CACzC,OAAM,IAAI,UAAU,wCAAwC,EAAC,OAAO;IAAC;IAAK;IAAW,EAAC,CAAC;AAEzF,OAAI,CAAC,IAAI,WAAW,iBAAiB,UAAU,CAC7C,OAAM,IAAI,UAAU,sCAAsC,EAAC,OAAO,EAAC,KAAI,EAAC,CAAC;AAG3E,QAAK,KAAK,IAAwD;;AAEpE,SAAO;GAAC;GAAM,QAAQ,iBAAiB;GAAW;GAAW;YACpD,WAAW,MAAM,QAAQ,IAAI,WAAW,iBAAiB,OAAO,CAAC,EAAE;EAC5E,MAAM,aAAa;EACnB,MAAM,OAAgC,EAAE;AAExC,OAAK,MAAM,OAAO,YAAwB;AACxC,OAAI,IAAI,WAAW,iBAAiB,UAAU,CAC5C,OAAM,IAAI,UAAU,wCAAwC,EAAC,OAAO;IAAC;IAAK;IAAW,EAAC,CAAC;AAEzF,OAAI,CAAC,IAAI,WAAW,iBAAiB,OAAO,CAC1C,OAAM,IAAI,UAAU,sCAAsC,EAAC,OAAO,EAAC,KAAI,EAAC,CAAC;AAG3E,QAAK,KAAK,IAAqD;;AAEjE,SAAO;GAAC;GAAM,QAAQ,iBAAiB;GAAQ;GAAW;;AAG5D,OAAM,IAAI,MAAM,+CAA+C,EAAC,OAAO,EAAC,YAAW,EAAC,CAAC"}
@@ -8,9 +8,32 @@ function validateStrictFetchOptions(options) {
8
8
  if (typeof options.perspective === "undefined" || options.perspective === null) throw new Error(`sanityFetch() requires an explicit \`perspective\` option when \`strict: true\` is set on \`defineLive\`.\n\nMore information: ${generateHelpUrl("next-sanity-fetch-strict")}`, { cause: options });
9
9
  if (typeof options.stega !== "boolean") throw new Error(`sanityFetch() requires an explicit \`stega\` option (true or false) when \`strict: true\` is set on \`defineLive\`.\n\nMore information: ${generateHelpUrl("next-sanity-fetch-strict")}`, { cause: options });
10
10
  }
11
- const resolvePerspectiveFromCookies = async function resolvePerspectiveFromCookies({ cookies: jar }) {
11
+ /**
12
+ * Reads the active draft-mode perspective from the cookie set by
13
+ * {@link "next-sanity/draft-mode".defineEnableDraftMode | `defineEnableDraftMode`}, falling back to `'drafts'`
14
+ * when the cookie is missing or contains an invalid value.
15
+ *
16
+ * This helper is intended for use with Next.js Cache Components (`cacheComponents: true`),
17
+ * where `cookies()` and `draftMode()` cannot be called inside `'use cache'` boundaries.
18
+ * Resolve the perspective once outside the cache boundary and pass it in as a prop / cache key.
19
+ *
20
+ * The caller is responsible for awaiting `cookies()` from `next/headers` and passing the
21
+ * resulting cookie store as the `cookies` option — this keeps the helper free of dynamic APIs
22
+ * so it can be invoked from anywhere a `ReadonlyRequestCookies` instance is available.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import {cookies} from 'next/headers'
27
+ * import {resolvePerspectiveFromCookies} from 'next-sanity/live'
28
+ *
29
+ * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+ async function resolvePerspectiveFromCookies({ cookies: jar }) {
12
35
  return jar.has(perspectiveCookieName) ? sanitizePerspective(jar.get(perspectiveCookieName)?.value, "drafts") : "drafts";
13
- };
36
+ }
14
37
  export { validateStrictFetchOptions as n, validateStrictSanityLiveProps as r, resolvePerspectiveFromCookies as t };
15
38
 
16
39
  //# sourceMappingURL=resolvePerspectiveFromCookies.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolvePerspectiveFromCookies.js","names":[],"sources":["../src/live/shared/strictValidation.ts","../src/live/shared/resolvePerspectiveFromCookies.ts"],"sourcesContent":["import {generateHelpUrl} from '@sanity/generate-help-url'\n\nexport function validateStrictSanityLiveProps(props: {includeDrafts?: unknown}): void {\n if (typeof props.includeDrafts !== 'boolean') {\n throw new Error(\n `<SanityLive> requires an explicit \\`includeDrafts\\` prop (true or false) when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-live-strict')}`,\n {cause: props},\n )\n }\n}\n\nexport function validateStrictFetchOptions(options: {\n perspective?: unknown\n stega?: unknown\n}): void {\n if (typeof options.perspective === 'undefined' || options.perspective === null) {\n throw new Error(\n `sanityFetch() requires an explicit \\`perspective\\` option when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-fetch-strict')}`,\n {cause: options},\n )\n }\n if (typeof options.stega !== 'boolean') {\n throw new Error(\n `sanityFetch() requires an explicit \\`stega\\` option (true or false) when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-fetch-strict')}`,\n {cause: options},\n )\n }\n}\n","import type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport type {cookies} from 'next/headers'\n\nimport {sanitizePerspective} from './sanitizePerspective'\n\nexport type ResolvePerspectiveFromCookies = (options: {\n /**\n * You must await the cookies() function from next/headers\n * and pass it here.\n * Example:\n * ```ts\n * import { cookies } from 'next/headers'\n *\n * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})\n * ```\n */\n cookies: Awaited<ReturnType<typeof cookies>>\n}) => Promise<Exclude<ClientPerspective, 'raw'>>\n\n/**\n * Resolves the perspective from the cookie that is set by `import { defineEnableDraftMode } from \"next-sanity/draft-mode\"`\n * @public\n */\nexport const resolvePerspectiveFromCookies = async function resolvePerspectiveFromCookies({\n cookies: jar,\n}: {\n cookies: Awaited<ReturnType<typeof cookies>>\n}): Promise<Exclude<ClientPerspective, 'raw'>> {\n return jar.has(perspectiveCookieName)\n ? sanitizePerspective(jar.get(perspectiveCookieName)?.value, 'drafts')\n : 'drafts'\n}\n"],"mappings":";;;AAEA,SAAgB,8BAA8B,OAAwC;AACpF,KAAI,OAAO,MAAM,kBAAkB,UACjC,OAAM,IAAI,MACR,iJAAiJ,gBAAgB,0BAA0B,IAC3L,EAAC,OAAO,OAAM,CACf;;AAIL,SAAgB,2BAA2B,SAGlC;AACP,KAAI,OAAO,QAAQ,gBAAgB,eAAe,QAAQ,gBAAgB,KACxE,OAAM,IAAI,MACR,kIAAkI,gBAAgB,2BAA2B,IAC7K,EAAC,OAAO,SAAQ,CACjB;AAEH,KAAI,OAAO,QAAQ,UAAU,UAC3B,OAAM,IAAI,MACR,4IAA4I,gBAAgB,2BAA2B,IACvL,EAAC,OAAO,SAAQ,CACjB;;ACDL,MAAa,gCAAgC,eAAe,8BAA8B,EACxF,SAAS,OAGoC;AAC7C,QAAO,IAAI,IAAI,sBAAsB,GACjC,oBAAoB,IAAI,IAAI,sBAAsB,EAAE,OAAO,SAAS,GACpE"}
1
+ {"version":3,"file":"resolvePerspectiveFromCookies.js","names":[],"sources":["../src/live/shared/strictValidation.ts","../src/live/shared/resolvePerspectiveFromCookies.ts"],"sourcesContent":["import {generateHelpUrl} from '@sanity/generate-help-url'\n\nexport function validateStrictSanityLiveProps(props: {includeDrafts?: unknown}): void {\n if (typeof props.includeDrafts !== 'boolean') {\n throw new Error(\n `<SanityLive> requires an explicit \\`includeDrafts\\` prop (true or false) when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-live-strict')}`,\n {cause: props},\n )\n }\n}\n\nexport function validateStrictFetchOptions(options: {\n perspective?: unknown\n stega?: unknown\n}): void {\n if (typeof options.perspective === 'undefined' || options.perspective === null) {\n throw new Error(\n `sanityFetch() requires an explicit \\`perspective\\` option when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-fetch-strict')}`,\n {cause: options},\n )\n }\n if (typeof options.stega !== 'boolean') {\n throw new Error(\n `sanityFetch() requires an explicit \\`stega\\` option (true or false) when \\`strict: true\\` is set on \\`defineLive\\`.\\n\\nMore information: ${generateHelpUrl('next-sanity-fetch-strict')}`,\n {cause: options},\n )\n }\n}\n","import type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport type {cookies} from 'next/headers'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\n\n/**\n * @deprecated - refactor to exporting the same function instead\n */\nexport type ResolvePerspectiveFromCookies = (options: {\n /**\n * You must await the cookies() function from next/headers\n * and pass it here.\n * Example:\n * ```ts\n * import { cookies } from 'next/headers'\n *\n * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})\n * ```\n */\n cookies: Awaited<ReturnType<typeof cookies>>\n}) => Promise<Exclude<ClientPerspective, 'raw'>>\n\n/**\n * Reads the active draft-mode perspective from the cookie set by\n * {@link \"next-sanity/draft-mode\".defineEnableDraftMode | `defineEnableDraftMode`}, falling back to `'drafts'`\n * when the cookie is missing or contains an invalid value.\n *\n * This helper is intended for use with Next.js Cache Components (`cacheComponents: true`),\n * where `cookies()` and `draftMode()` cannot be called inside `'use cache'` boundaries.\n * Resolve the perspective once outside the cache boundary and pass it in as a prop / cache key.\n *\n * The caller is responsible for awaiting `cookies()` from `next/headers` and passing the\n * resulting cookie store as the `cookies` option — this keeps the helper free of dynamic APIs\n * so it can be invoked from anywhere a `ReadonlyRequestCookies` instance is available.\n *\n * @example\n * ```ts\n * import {cookies} from 'next/headers'\n * import {resolvePerspectiveFromCookies} from 'next-sanity/live'\n *\n * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})\n * ```\n *\n * @public\n */\nexport async function resolvePerspectiveFromCookies({\n cookies: jar,\n}: {\n cookies: Awaited<ReturnType<typeof cookies>>\n}): Promise<Exclude<ClientPerspective, 'raw'>> {\n return jar.has(perspectiveCookieName)\n ? sanitizePerspective(jar.get(perspectiveCookieName)?.value, 'drafts')\n : 'drafts'\n}\n"],"mappings":";;;AAEA,SAAgB,8BAA8B,OAAwC;AACpF,KAAI,OAAO,MAAM,kBAAkB,UACjC,OAAM,IAAI,MACR,iJAAiJ,gBAAgB,0BAA0B,IAC3L,EAAC,OAAO,OAAM,CACf;;AAIL,SAAgB,2BAA2B,SAGlC;AACP,KAAI,OAAO,QAAQ,gBAAgB,eAAe,QAAQ,gBAAgB,KACxE,OAAM,IAAI,MACR,kIAAkI,gBAAgB,2BAA2B,IAC7K,EAAC,OAAO,SAAQ,CACjB;AAEH,KAAI,OAAO,QAAQ,UAAU,UAC3B,OAAM,IAAI,MACR,4IAA4I,gBAAgB,2BAA2B,IACvL,EAAC,OAAO,SAAQ,CACjB;;;;;;;;;;;;;;;;;;;;;;;;;ACqBL,eAAsB,8BAA8B,EAClD,SAAS,OAGoC;AAC7C,QAAO,IAAI,IAAI,sBAAsB,GACjC,oBAAoB,IAAI,IAAI,sBAAsB,EAAE,OAAO,SAAS,GACpE"}
@@ -1,6 +1,13 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { Suspense, lazy } from "react";
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":";;;AAYA,MAAM,4BAA4B,WAAW,OAAO,uBAAgB;AAEpE,SAAgB,8BAA8B,OAAyC;AACrF,QACE,oBAAC,UAAA;EAAS,UAAU;YAClB,oBAAC,2BAAA,EAA0B,GAAI,OAAA,CAAS;GAC/B"}
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"}
@@ -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" });
@@ -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":";;;;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,UAAA;EAAO,KAAK;EAAc,OAAA;EAAM,MAAK;EAAS,oBAAA;GAAmB,EAClE,oBAAC,YAAA,EAAW,GAAI,OAAA,CAAS,CAAA,EAAA,CACxB"}
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"}
@@ -1,6 +1,9 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { VisualEditing as VisualEditing$1 } from "next-sanity/visual-editing/client-component";
3
3
  import { actionPerspectiveChange } from "next-sanity/visual-editing/server-actions";
4
+ /**
5
+ * @public
6
+ */
4
7
  function VisualEditing(props) {
5
8
  let autoBasePath;
6
9
  if (typeof props.basePath !== "string") try {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["VisualEditingComponent"],"sources":["../../src/visual-editing/VisualEditing.tsx"],"sourcesContent":["import type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\nimport {VisualEditing as VisualEditingComponent} from 'next-sanity/visual-editing/client-component'\nimport {actionPerspectiveChange} from 'next-sanity/visual-editing/server-actions'\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 onPerspectiveChange={actionPerspectiveChange}\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":";;;AAOA,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,oBAACA,iBAAAA;EACC,qBAAqB;EACrB,GAAI;EACJ,UAAU,MAAM,YAAY;EAC5B,eAAe,MAAM,iBAAiB;GACtC"}
1
+ {"version":3,"file":"index.js","names":["VisualEditingComponent"],"sources":["../../src/visual-editing/VisualEditing.tsx"],"sourcesContent":["import type {VisualEditingProps} from 'next-sanity/visual-editing/client-component'\nimport {VisualEditing as VisualEditingComponent} from 'next-sanity/visual-editing/client-component'\nimport {actionPerspectiveChange} from 'next-sanity/visual-editing/server-actions'\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 onPerspectiveChange={actionPerspectiveChange}\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":";;;;;;AAOA,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,oBAACA,iBAAD;EACE,qBAAqB;EACrB,GAAI;EACJ,UAAU,MAAM,YAAY;EAC5B,eAAe,MAAM,iBAAiB;EACtC,CAAA"}
@@ -3,9 +3,15 @@ import { t as sanitizePerspective } from "../../sanitizePerspective.js";
3
3
  import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
4
4
  import { cookies } from "next/headers";
5
5
  import { refresh } from "next/cache";
6
+ /**
7
+ * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.
8
+ */
6
9
  async function actionRefresh(_payload) {
7
10
  refresh();
8
11
  }
12
+ /**
13
+ * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.
14
+ */
9
15
  async function actionPerspectiveChange(perspective) {
10
16
  const sanitizedPerspective = sanitizePerspective(perspective, "drafts");
11
17
  if (!sanitizedPerspective || Array.isArray(sanitizedPerspective) && sanitizedPerspective.length === 0) throw new Error(`Invalid perspective`, { cause: perspective });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/visual-editing/server-actions/index.ts"],"sourcesContent":["'use server'\n\nimport type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport type {HistoryRefresh} from '@sanity/visual-editing/react'\nimport {refresh} from 'next/cache'\nimport {cookies} from 'next/headers'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\n\n/**\n * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.\n */\nexport async function actionRefresh(_payload: HistoryRefresh): Promise<void> {\n refresh()\n}\n\n/**\n * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.\n */\nexport async function actionPerspectiveChange(perspective: ClientPerspective): Promise<void> {\n const sanitizedPerspective = sanitizePerspective(perspective, 'drafts')\n if (\n !sanitizedPerspective ||\n (Array.isArray(sanitizedPerspective) && sanitizedPerspective.length === 0)\n ) {\n throw new Error(`Invalid perspective`, {cause: perspective})\n }\n\n const nextPerspective = Array.isArray(sanitizedPerspective)\n ? sanitizedPerspective.join(',')\n : sanitizedPerspective\n const jar = await cookies()\n if (\n nextPerspective === jar.get(perspectiveCookieName)?.value &&\n process.env.NODE_ENV !== 'production'\n ) {\n // oxlint-disable-next-line no-console\n console.debug('actionPerspectiveChange', 'Perspective is the same, skipping', nextPerspective)\n return\n }\n jar.set(perspectiveCookieName, nextPerspective, {\n httpOnly: true,\n path: '/',\n secure: true,\n sameSite: 'none',\n })\n\n refresh()\n}\n"],"mappings":";;;;;AAaA,eAAsB,cAAc,UAAyC;AAC3E,UAAS;;AAMX,eAAsB,wBAAwB,aAA+C;CAC3F,MAAM,uBAAuB,oBAAoB,aAAa,SAAS;AACvE,KACE,CAAC,wBACA,MAAM,QAAQ,qBAAqB,IAAI,qBAAqB,WAAW,EAExE,OAAM,IAAI,MAAM,uBAAuB,EAAC,OAAO,aAAY,CAAC;CAG9D,MAAM,kBAAkB,MAAM,QAAQ,qBAAqB,GACvD,qBAAqB,KAAK,IAAI,GAC9B;CACJ,MAAM,MAAM,MAAM,SAAS;AAC3B,KACE,oBAAoB,IAAI,IAAI,sBAAsB,EAAE,SACpD,QAAQ,IAAI,aAAa,cACzB;AAEA,UAAQ,MAAM,2BAA2B,qCAAqC,gBAAgB;AAC9F;;AAEF,KAAI,IAAI,uBAAuB,iBAAiB;EAC9C,UAAU;EACV,MAAM;EACN,QAAQ;EACR,UAAU;EACX,CAAC;AAEF,UAAS"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/visual-editing/server-actions/index.ts"],"sourcesContent":["'use server'\n\nimport type {ClientPerspective} from '@sanity/client'\nimport {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport type {HistoryRefresh} from '@sanity/visual-editing/react'\nimport {refresh} from 'next/cache'\nimport {cookies} from 'next/headers'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\n\n/**\n * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.\n */\nexport async function actionRefresh(_payload: HistoryRefresh): Promise<void> {\n refresh()\n}\n\n/**\n * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.\n */\nexport async function actionPerspectiveChange(perspective: ClientPerspective): Promise<void> {\n const sanitizedPerspective = sanitizePerspective(perspective, 'drafts')\n if (\n !sanitizedPerspective ||\n (Array.isArray(sanitizedPerspective) && sanitizedPerspective.length === 0)\n ) {\n throw new Error(`Invalid perspective`, {cause: perspective})\n }\n\n const nextPerspective = Array.isArray(sanitizedPerspective)\n ? sanitizedPerspective.join(',')\n : sanitizedPerspective\n const jar = await cookies()\n if (\n nextPerspective === jar.get(perspectiveCookieName)?.value &&\n process.env.NODE_ENV !== 'production'\n ) {\n // oxlint-disable-next-line no-console\n console.debug('actionPerspectiveChange', 'Perspective is the same, skipping', nextPerspective)\n return\n }\n jar.set(perspectiveCookieName, nextPerspective, {\n httpOnly: true,\n path: '/',\n secure: true,\n sameSite: 'none',\n })\n\n refresh()\n}\n"],"mappings":";;;;;;;;AAaA,eAAsB,cAAc,UAAyC;AAC3E,UAAS;;;;;AAMX,eAAsB,wBAAwB,aAA+C;CAC3F,MAAM,uBAAuB,oBAAoB,aAAa,SAAS;AACvE,KACE,CAAC,wBACA,MAAM,QAAQ,qBAAqB,IAAI,qBAAqB,WAAW,EAExE,OAAM,IAAI,MAAM,uBAAuB,EAAC,OAAO,aAAY,CAAC;CAG9D,MAAM,kBAAkB,MAAM,QAAQ,qBAAqB,GACvD,qBAAqB,KAAK,IAAI,GAC9B;CACJ,MAAM,MAAM,MAAM,SAAS;AAC3B,KACE,oBAAoB,IAAI,IAAI,sBAAsB,EAAE,SACpD,QAAQ,IAAI,aAAa,cACzB;AAEA,UAAQ,MAAM,2BAA2B,qCAAqC,gBAAgB;AAC9F;;AAEF,KAAI,IAAI,uBAAuB,iBAAiB;EAC9C,UAAU;EACV,MAAM;EACN,QAAQ;EACR,UAAU;EACX,CAAC;AAEF,UAAS"}
@@ -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":";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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-sanity",
3
- "version": "13.0.0-cache-components.36",
3
+ "version": "13.0.0-cache-components.38",
4
4
  "description": "Sanity.io toolkit for Next.js",
5
5
  "keywords": [
6
6
  "live",
@@ -62,43 +62,44 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@portabletext/react": "^6.0.3",
65
- "@sanity/client": "^7.20.0",
65
+ "@sanity/client": "^7.22.0",
66
66
  "@sanity/comlink": "^4.0.1",
67
67
  "@sanity/generate-help-url": "^4.0.0",
68
68
  "@sanity/presentation-comlink": "^2.0.1",
69
- "@sanity/preview-url-secret": "^4.0.4",
70
- "@sanity/visual-editing": "^5.3.3",
69
+ "@sanity/preview-url-secret": "^4.0.5",
70
+ "@sanity/visual-editing": "^5.3.4",
71
71
  "@sanity/webhook": "^4.0.4",
72
72
  "dequal": "^2.0.3",
73
- "groq": "^5.18.0",
73
+ "groq": "^5.23.0",
74
74
  "history": "^5.3.0"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@sanity/tsconfig": "^2.1.0",
78
78
  "@types/js-yaml": "^4.0.9",
79
- "@types/node": "^24.12.0",
79
+ "@types/node": "^24.12.2",
80
80
  "@types/react": "^19.2.14",
81
81
  "@types/react-dom": "^19.2.3",
82
- "@vitejs/plugin-react": "^5.2.0",
83
- "@vitest/coverage-v8": "^4.1.0",
82
+ "@vitejs/plugin-react": "^6.0.1",
83
+ "@vitest/coverage-v8": "^4.1.5",
84
84
  "js-yaml": "^4.1.1",
85
- "next": "16.2.1-canary.10",
85
+ "next": "16.3.0-canary.9",
86
86
  "publint": "^0.3.18",
87
- "react": "^19.2.4",
88
- "react-dom": "^19.2.4",
89
- "styled-components": "^6.3.12",
90
- "tsdown": "0.20.3",
91
- "typedoc": "^0.28.17",
87
+ "react": "^19.2.5",
88
+ "react-dom": "^19.2.5",
89
+ "styled-components": "^6.4.1",
90
+ "tsdown": "^0.21.10",
91
+ "typedoc": "^0.28.19",
92
92
  "typescript": "5.9.3",
93
- "vitest": "^4.1.0",
93
+ "vite": "^8.0.10",
94
+ "vitest": "^4.1.5",
94
95
  "vitest-package-exports": "^1.2.0"
95
96
  },
96
97
  "peerDependencies": {
97
- "@sanity/client": "^7.20.0",
98
+ "@sanity/client": "^7.22.0",
98
99
  "next": "^16.0.0-0",
99
100
  "react": "^19.2.3",
100
101
  "react-dom": "^19.2.3",
101
- "sanity": "^5.18.0",
102
+ "sanity": "^5.23.0",
102
103
  "styled-components": "^6.1"
103
104
  },
104
105
  "engines": {