next-sanity 13.1.7 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/VisualEditing.js +2 -1
  2. package/dist/VisualEditing.js.map +1 -1
  3. package/dist/draft-mode/index.js +19 -2
  4. package/dist/draft-mode/index.js.map +1 -1
  5. package/dist/index.d.ts +9 -1
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +10 -1
  8. package/dist/index.js.map +1 -0
  9. package/dist/live/conditions/default/index.d.ts +77 -5
  10. package/dist/live/conditions/default/index.d.ts.map +1 -1
  11. package/dist/live/conditions/default/index.js +70 -1
  12. package/dist/live/conditions/default/index.js.map +1 -1
  13. package/dist/live/conditions/next-js/index.d.ts +10 -5
  14. package/dist/live/conditions/next-js/index.d.ts.map +1 -1
  15. package/dist/live/conditions/next-js/index.js +4 -3
  16. package/dist/live/conditions/next-js/index.js.map +1 -1
  17. package/dist/live/conditions/react-server/index.d.ts +10 -5
  18. package/dist/live/conditions/react-server/index.d.ts.map +1 -1
  19. package/dist/live/conditions/react-server/index.js +9 -3
  20. package/dist/live/conditions/react-server/index.js.map +1 -1
  21. package/dist/parseTags.d.ts +70 -1
  22. package/dist/parseTags.d.ts.map +1 -1
  23. package/dist/{resolvePerspectiveFromCookies.js → resolveVariantFromCookies.js} +73 -4
  24. package/dist/resolveVariantFromCookies.js.map +1 -0
  25. package/dist/sanitizeVariant.js +37 -0
  26. package/dist/sanitizeVariant.js.map +1 -0
  27. package/dist/types.d.ts +25 -0
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/visual-editing/index.d.ts.map +1 -1
  30. package/dist/visual-editing/index.js +2 -1
  31. package/dist/visual-editing/index.js.map +1 -1
  32. package/dist/visual-editing/server-actions/index.d.ts +5 -1
  33. package/dist/visual-editing/server-actions/index.d.ts.map +1 -1
  34. package/dist/visual-editing/server-actions/index.js +36 -3
  35. package/dist/visual-editing/server-actions/index.js.map +1 -1
  36. package/package.json +4 -4
  37. package/dist/resolvePerspectiveFromCookies.js.map +0 -1
  38. package/dist/sanitizePerspective.js +0 -14
  39. package/dist/sanitizePerspective.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["sanityCacheLife","SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/next-js/defineLive.tsx"],"sourcesContent":["import {sanity as sanityCacheLife} from 'next-sanity/live/cache-life'\nimport {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {revalidateSyncTagsAction} from 'next-sanity/live/server-actions'\nimport {cacheLife, cacheTag} from 'next/cache'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\n\nimport {cacheTagPrefix, defaultApiHost} from '#live/constants'\nimport {preconnect} from '#live/preconnect'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\n/**\n * Set up Sanity Live for Cache Components. `defineLive` returns `sanityFetch`\n * and `<SanityLive />`, which connect your Sanity client to the Live Content API\n * so cached pages can update in response to fine-grained content changes.\n *\n * With `strict: true`, `perspective` and `stega` become required\n * `sanityFetch` options, and `includeDrafts` becomes required on\n * `<SanityLive />`. Resolve dynamic values from `draftMode()` and `cookies()`\n * outside `'use cache'` boundaries, then pass them into cached components.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * // sanity/live.ts\n * import {cookies, draftMode} from 'next/headers'\n * import {createClient} from 'next-sanity'\n * import {\n * defineLive,\n * resolvePerspectiveFromCookies,\n * type LivePerspective,\n * } from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * strict: true,\n * })\n *\n * export interface DynamicFetchOptions {\n * perspective: LivePerspective\n * stega: boolean\n * }\n *\n * // Resolve dynamic values outside 'use cache' boundaries.\n * export async function getDynamicFetchOptions(): Promise<DynamicFetchOptions> {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (!isDraftMode) {\n * return {perspective: 'published', stega: false}\n * }\n *\n * const jar = await cookies()\n * const perspective = await resolvePerspectiveFromCookies({cookies: jar})\n * return {perspective: perspective ?? 'drafts', stega: true}\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {draftMode} from 'next/headers'\n *\n * import {SanityLive} from '@/sanity/live'\n *\n * export default async function RootLayout({children}: {children: React.ReactNode}) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive includeDrafts={isDraftMode} />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {draftMode} from 'next/headers'\n * import {Suspense} from 'react'\n * import {defineQuery} from 'next-sanity'\n *\n * import {\n * getDynamicFetchOptions,\n * sanityFetch,\n * type DynamicFetchOptions,\n * } from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (isDraftMode) {\n * return (\n * <Suspense fallback={<div>Loading...</div>}>\n * <DynamicPage params={props.params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await props.params\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage(props: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await props.params\n * const {perspective, stega} = await getDynamicFetchOptions()\n *\n * return <CachedPage slug={slug} perspective={perspective} stega={stega} />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * stega,\n * }: {slug: string} & DynamicFetchOptions) {\n * 'use cache'\n *\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * perspective,\n * stega,\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\n/**\n * Set up Sanity Live. `defineLive` returns `sanityFetch` and `<SanityLive />`,\n * which connect your Sanity client to the Live Content API so pages can serve\n * cached content and update in response to fine-grained content changes.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * import {createClient} from 'next-sanity'\n * import {defineLive} from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * })\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {SanityLive} from '@/sanity/live'\n *\n * export default function RootLayout({children}: {children: React.ReactNode}) {\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {defineQuery} from 'next-sanity'\n * import {sanityFetch} from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {slug} = await props.params\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\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 === 'development' && !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 === 'development' && !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({\n allowReconfigure: false,\n useCdn: true,\n perspective: 'published',\n stega: false,\n })\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective,\n stega,\n tags: customCacheTags = [],\n requestTag = 'next-loader.fetch.cache-components',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective, stega})\n }\n\n const useCdn = perspective ? perspective === 'published' : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn !== false && !isBuildPhase ? 'noStale' : undefined\n const token =\n ((perspective && perspective !== 'published') || stega) && serverToken\n ? serverToken\n : undefined\n\n const {result, resultSourceMap, syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n stega,\n returnQuery: false,\n useCdn,\n cacheMode,\n tag: requestTag,\n token,\n })\n const tags = [...customCacheTags, ...(syncTags || []).map((tag) => `${cacheTagPrefix}${tag}`)]\n /**\n * The tags used here, are expired later on in the `action` Server Action given to `<SanityLive />` with the `revalidateTag` function from `next/cache`,\n * or by a route handler that userland sets up.\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(sanityCacheLife)\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: _includeDrafts = false,\n requestTag = 'next-loader.live.cache-components',\n waitFor,\n\n action,\n onError,\n onWelcome,\n onReconnect,\n onRestart,\n onGoAway,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n\n const includeDrafts = typeof browserToken === 'string' && !!browserToken && _includeDrafts\n const shouldWaitFor = waitFor === 'function' && !includeDrafts ? waitFor : undefined\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 preconnect(client)\n\n return (\n <SanityLiveClientComponent\n config={{\n projectId,\n dataset,\n apiHost: apiHost === defaultApiHost ? undefined : apiHost,\n apiVersion,\n useProjectHostname: useProjectHostname ? undefined : useProjectHostname,\n requestTagPrefix,\n token: includeDrafts ? browserToken : undefined,\n }}\n includeDrafts={includeDrafts ? true : undefined}\n requestTag={requestTag}\n waitFor={shouldWaitFor}\n action={\n action ??\n (shouldWaitFor === 'function' || includeDrafts ? 'refresh' : revalidateSyncTagsAction)\n }\n onError={onError}\n onWelcome={onWelcome}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onGoAway={onGoAway}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {sanityFetch, SanityLive}\n}\n"],"mappings":";;;;;;;;;;AA+PA,SAAgB,WAAW,QAA2B;CACpD,MAAM,EAAC,QAAQ,SAAS,aAAa,cAAc,SAAS,UAAS;CAErE,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,mDAAmD;CAGrE,IAAI,QAAQ,IAAI,aAAa,iBAAiB,CAAC,eAAe,gBAAgB,OAC5E,QAAQ,KACN,6LACF;CAGF,IAAI,QAAQ,IAAI,aAAa,iBAAiB,CAAC,gBAAgB,iBAAiB,OAC9E,QAAQ,KACN,gXACF;CAGF,MAAM,SAAS,QAAQ,WAAW;EAChC,kBAAkB;EAClB,QAAQ;EACR,aAAa;EACb,OAAO;CACT,CAAC;CAED,MAAM,cAAgC,eAAe,YAAY,EAC/D,OACA,SAAS,CAAC,GACV,aACA,OACA,MAAM,kBAAkB,CAAC,GACzB,aAAa,wCACZ;EACD,IAAI,QACF,2BAA2B;GAAC;GAAa;EAAK,CAAC;EAGjD,MAAM,SAAS,cAAc,gBAAgB,cAAc,KAAA;EAC3D,MAAM,eAAe,QAAQ,IAAI,kBAAkB;EACnD,MAAM,YAAY,WAAW,SAAS,CAAC,eAAe,YAAY,KAAA;EAClE,MAAM,SACF,eAAe,gBAAgB,eAAgB,UAAU,cACvD,cACA,KAAA;EAEN,MAAM,EAAC,QAAQ,iBAAiB,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;GAClF,gBAAgB;GAChB;GACA;GACA,aAAa;GACb;GACA;GACA,KAAK;GACL;EACF,CAAC;EACD,MAAM,OAAO,CAAC,GAAG,iBAAiB,IAAI,YAAY,CAAC,EAAA,CAAG,KAAK,QAAQ,GAAG,iBAAiB,KAAK,CAAC;;;;;EAK7F,SAAS,GAAG,IAAI;;;;;EAKhB,UAAUA,MAAe;EAEzB,OAAO;GAAC,MAAM;GAAQ,WAAW,mBAAmB;GAAM;EAAI;CAChE;CAEA,MAAMC,eAAoD,SAASA,aAAW,OAAO;EACnF,IAAI,QACF,8BAA8B,KAAK;EAErC,MAAM,EACJ,eAAe,iBAAiB,OAChC,aAAa,qCACb,SAEA,QACA,SACA,WACA,aACA,WACA,aACE;EACJ,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,OAAO;EAEhB,MAAM,gBAAgB,OAAO,iBAAiB,YAAY,CAAC,CAAC,gBAAgB;EAC5E,MAAM,gBAAgB,YAAY,cAAc,CAAC,gBAAgB,UAAU,KAAA;EAG3E,WAAW,MAAM;EAEjB,OACE,oBAACC,YAAD;GACE,QAAQ;IACN;IACA;IACA,SAAS,YAAA,0BAA6B,KAAA,IAAY;IAClD;IACA,oBAAoB,qBAAqB,KAAA,IAAY;IACrD;IACA,OAAO,gBAAgB,eAAe,KAAA;GACxC;GACA,eAAe,gBAAgB,OAAO,KAAA;GAC1B;GACZ,SAAS;GACT,QACE,WACC,kBAAkB,cAAc,gBAAgB,YAAY;GAEtD;GACE;GACE;GACF;GACD;EACX,CAAA;CAEL;CACA,aAAW,cAAc;CAEzB,OAAO;EAAC;EAAa,YAAA;CAAU;AACjC"}
1
+ {"version":3,"file":"index.js","names":["sanityCacheLife","SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/next-js/defineLive.tsx"],"sourcesContent":["import {sanity as sanityCacheLife} from 'next-sanity/live/cache-life'\nimport {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {revalidateSyncTagsAction} from 'next-sanity/live/server-actions'\nimport {cacheLife, cacheTag} from 'next/cache'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\n\nimport {cacheTagPrefix, defaultApiHost} from '#live/constants'\nimport {preconnect} from '#live/preconnect'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\n/**\n * Set up Sanity Live for Cache Components. `defineLive` returns `sanityFetch`\n * and `<SanityLive />`, which connect your Sanity client to the Live Content API\n * so cached pages can update in response to fine-grained content changes.\n *\n * With `strict: true`, `perspective` and `stega` become required\n * `sanityFetch` options, and `includeDrafts` becomes required on\n * `<SanityLive />`. Resolve dynamic values from `draftMode()` and `cookies()`\n * outside `'use cache'` boundaries, then pass them into cached components.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * // sanity/live.ts\n * import {cookies, draftMode} from 'next/headers'\n * import {createClient} from 'next-sanity'\n * import {\n * defineLive,\n * resolvePerspectiveFromCookies,\n * resolveVariantFromCookies,\n * type LivePerspective,\n * } from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * strict: true,\n * })\n *\n * export interface DynamicFetchOptions {\n * perspective: LivePerspective\n * variant?: string\n * stega: boolean\n * }\n *\n * // Resolve dynamic values outside 'use cache' boundaries.\n * export async function getDynamicFetchOptions(): Promise<DynamicFetchOptions> {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (!isDraftMode) {\n * return {perspective: 'published', stega: false}\n * }\n *\n * const jar = await cookies()\n * const perspective = await resolvePerspectiveFromCookies({cookies: jar})\n * const variant = await resolveVariantFromCookies({cookies: jar})\n * return {perspective: perspective ?? 'drafts', variant, stega: true}\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {draftMode} from 'next/headers'\n *\n * import {SanityLive} from '@/sanity/live'\n *\n * export default async function RootLayout({children}: {children: React.ReactNode}) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive includeDrafts={isDraftMode} />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {draftMode} from 'next/headers'\n * import {Suspense} from 'react'\n * import {defineQuery} from 'next-sanity'\n *\n * import {\n * getDynamicFetchOptions,\n * sanityFetch,\n * type DynamicFetchOptions,\n * } from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (isDraftMode) {\n * return (\n * <Suspense fallback={<div>Loading...</div>}>\n * <DynamicPage params={props.params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await props.params\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage(props: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await props.params\n * const {perspective, variant, stega} = await getDynamicFetchOptions()\n *\n * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega={stega} />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * variant,\n * stega,\n * }: {slug: string} & DynamicFetchOptions) {\n * 'use cache'\n *\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * perspective,\n * variant,\n * stega,\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\n/**\n * Set up Sanity Live. `defineLive` returns `sanityFetch` and `<SanityLive />`,\n * which connect your Sanity client to the Live Content API so pages can serve\n * cached content and update in response to fine-grained content changes.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * import {createClient} from 'next-sanity'\n * import {defineLive} from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * })\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {SanityLive} from '@/sanity/live'\n *\n * export default function RootLayout({children}: {children: React.ReactNode}) {\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {defineQuery} from 'next-sanity'\n * import {sanityFetch} from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {slug} = await props.params\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\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 === 'development' && !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 === 'development' && !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({\n allowReconfigure: false,\n useCdn: true,\n perspective: 'published',\n stega: false,\n })\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective,\n variant,\n stega,\n tags: customCacheTags = [],\n requestTag = 'next-loader.fetch.cache-components',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective, stega})\n }\n\n const useCdn = perspective ? perspective === 'published' : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn !== false && !isBuildPhase ? 'noStale' : undefined\n const token =\n ((perspective && perspective !== 'published') || stega) && serverToken\n ? serverToken\n : undefined\n\n const {result, resultSourceMap, syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n variant,\n stega,\n returnQuery: false,\n useCdn,\n cacheMode,\n tag: requestTag,\n token,\n })\n const tags = [...customCacheTags, ...(syncTags || []).map((tag) => `${cacheTagPrefix}${tag}`)]\n /**\n * The tags used here, are expired later on in the `action` Server Action given to `<SanityLive />` with the `revalidateTag` function from `next/cache`,\n * or by a route handler that userland sets up.\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(sanityCacheLife)\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: _includeDrafts = false,\n requestTag = 'next-loader.live.cache-components',\n waitFor,\n\n action,\n onError,\n onWelcome,\n onReconnect,\n onRestart,\n onGoAway,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n\n const includeDrafts = typeof browserToken === 'string' && !!browserToken && _includeDrafts\n const shouldWaitFor = waitFor === 'function' && !includeDrafts ? waitFor : undefined\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 preconnect(client)\n\n return (\n <SanityLiveClientComponent\n config={{\n projectId,\n dataset,\n apiHost: apiHost === defaultApiHost ? undefined : apiHost,\n apiVersion,\n useProjectHostname: useProjectHostname ? undefined : useProjectHostname,\n requestTagPrefix,\n token: includeDrafts ? browserToken : undefined,\n }}\n includeDrafts={includeDrafts ? true : undefined}\n requestTag={requestTag}\n waitFor={shouldWaitFor}\n action={\n action ??\n (shouldWaitFor === 'function' || includeDrafts ? 'refresh' : revalidateSyncTagsAction)\n }\n onError={onError}\n onWelcome={onWelcome}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onGoAway={onGoAway}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {sanityFetch, SanityLive}\n}\n"],"mappings":";;;;;;;;;;AAoQA,SAAgB,WAAW,QAA2B;CACpD,MAAM,EAAC,QAAQ,SAAS,aAAa,cAAc,SAAS,UAAS;CAErE,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,mDAAmD;CAGrE,IAAI,QAAQ,IAAI,aAAa,iBAAiB,CAAC,eAAe,gBAAgB,OAC5E,QAAQ,KACN,6LACF;CAGF,IAAI,QAAQ,IAAI,aAAa,iBAAiB,CAAC,gBAAgB,iBAAiB,OAC9E,QAAQ,KACN,gXACF;CAGF,MAAM,SAAS,QAAQ,WAAW;EAChC,kBAAkB;EAClB,QAAQ;EACR,aAAa;EACb,OAAO;CACT,CAAC;CAED,MAAM,cAAgC,eAAe,YAAY,EAC/D,OACA,SAAS,CAAC,GACV,aACA,SACA,OACA,MAAM,kBAAkB,CAAC,GACzB,aAAa,wCACZ;EACD,IAAI,QACF,2BAA2B;GAAC;GAAa;EAAK,CAAC;EAGjD,MAAM,SAAS,cAAc,gBAAgB,cAAc,KAAA;EAC3D,MAAM,eAAe,QAAQ,IAAI,kBAAkB;EACnD,MAAM,YAAY,WAAW,SAAS,CAAC,eAAe,YAAY,KAAA;EAClE,MAAM,SACF,eAAe,gBAAgB,eAAgB,UAAU,cACvD,cACA,KAAA;EAEN,MAAM,EAAC,QAAQ,iBAAiB,aAAY,MAAM,OAAO,MAAM,OAAO,MAAM,QAAQ;GAClF,gBAAgB;GAChB;GACA;GACA;GACA,aAAa;GACb;GACA;GACA,KAAK;GACL;EACF,CAAC;EACD,MAAM,OAAO,CAAC,GAAG,iBAAiB,IAAI,YAAY,CAAC,EAAA,CAAG,KAAK,QAAQ,GAAG,iBAAiB,KAAK,CAAC;;;;;EAK7F,SAAS,GAAG,IAAI;;;;;EAKhB,UAAUA,MAAe;EAEzB,OAAO;GAAC,MAAM;GAAQ,WAAW,mBAAmB;GAAM;EAAI;CAChE;CAEA,MAAMC,eAAoD,SAASA,aAAW,OAAO;EACnF,IAAI,QACF,8BAA8B,KAAK;EAErC,MAAM,EACJ,eAAe,iBAAiB,OAChC,aAAa,qCACb,SAEA,QACA,SACA,WACA,aACA,WACA,aACE;EACJ,MAAM,EAAC,WAAW,SAAS,SAAS,YAAY,oBAAoB,qBAClE,OAAO,OAAO;EAEhB,MAAM,gBAAgB,OAAO,iBAAiB,YAAY,CAAC,CAAC,gBAAgB;EAC5E,MAAM,gBAAgB,YAAY,cAAc,CAAC,gBAAgB,UAAU,KAAA;EAG3E,WAAW,MAAM;EAEjB,OACE,oBAACC,YAAD;GACE,QAAQ;IACN;IACA;IACA,SAAS,YAAA,0BAA6B,KAAA,IAAY;IAClD;IACA,oBAAoB,qBAAqB,KAAA,IAAY;IACrD;IACA,OAAO,gBAAgB,eAAe,KAAA;GACxC;GACA,eAAe,gBAAgB,OAAO,KAAA;GAC1B;GACZ,SAAS;GACT,QACE,WACC,kBAAkB,cAAc,gBAAgB,YAAY;GAEtD;GACE;GACE;GACF;GACD;EACX,CAAA;CAEL;CACA,aAAW,cAAc;CAEzB,OAAO;EAAC;EAAa,YAAA;CAAU;AACjC"}
@@ -1,6 +1,6 @@
1
1
  import { t as isCorsOriginError } from "../../../isCorsOriginError.js";
2
2
  import { c as SanityLiveOnError, d as SanityLiveOnRestart, f as SanityLiveOnWelcome, i as LivePerspective, l as SanityLiveOnGoaway, m as StrictDefinedLiveProps, n as DefinedFetchType, o as SanityLiveAction, p as StrictDefinedFetchType, r as DefinedLiveProps, s as SanityLiveContext, t as DefineLiveOptions, u as SanityLiveOnReconnect } from "../../../types.js";
3
- import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../parseTags.js";
3
+ import { n as resolveVariantFromCookies, r as resolvePerspectiveFromCookies, t as parseTags } from "../../../parseTags.js";
4
4
  /**
5
5
  * Set up Sanity Live for Cache Components. `defineLive` returns `sanityFetch`
6
6
  * and `<SanityLive />`, which connect your Sanity client to the Live Content API
@@ -22,6 +22,7 @@ import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../par
22
22
  * import {
23
23
  * defineLive,
24
24
  * resolvePerspectiveFromCookies,
25
+ * resolveVariantFromCookies,
25
26
  * type LivePerspective,
26
27
  * } from 'next-sanity/live'
27
28
  *
@@ -42,6 +43,7 @@ import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../par
42
43
  *
43
44
  * export interface DynamicFetchOptions {
44
45
  * perspective: LivePerspective
46
+ * variant?: string
45
47
  * stega: boolean
46
48
  * }
47
49
  *
@@ -54,7 +56,8 @@ import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../par
54
56
  *
55
57
  * const jar = await cookies()
56
58
  * const perspective = await resolvePerspectiveFromCookies({cookies: jar})
57
- * return {perspective: perspective ?? 'drafts', stega: true}
59
+ * const variant = await resolveVariantFromCookies({cookies: jar})
60
+ * return {perspective: perspective ?? 'drafts', variant, stega: true}
58
61
  * }
59
62
  * ```
60
63
  *
@@ -125,14 +128,15 @@ import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../par
125
128
  *
126
129
  * async function DynamicPage(props: Pick<PageProps<'/[slug]'>, 'params'>) {
127
130
  * const {slug} = await props.params
128
- * const {perspective, stega} = await getDynamicFetchOptions()
131
+ * const {perspective, variant, stega} = await getDynamicFetchOptions()
129
132
  *
130
- * return <CachedPage slug={slug} perspective={perspective} stega={stega} />
133
+ * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega={stega} />
131
134
  * }
132
135
  *
133
136
  * async function CachedPage({
134
137
  * slug,
135
138
  * perspective,
139
+ * variant,
136
140
  * stega,
137
141
  * }: {slug: string} & DynamicFetchOptions) {
138
142
  * 'use cache'
@@ -141,6 +145,7 @@ import { n as resolvePerspectiveFromCookies, t as parseTags } from "../../../par
141
145
  * query: POST_QUERY,
142
146
  * params: {slug},
143
147
  * perspective,
148
+ * variant,
144
149
  * stega,
145
150
  * })
146
151
  *
@@ -243,5 +248,5 @@ declare function defineLive(config: DefineLiveOptions & {
243
248
  sanityFetch: DefinedFetchType;
244
249
  SanityLive: React.ComponentType<DefinedLiveProps>;
245
250
  };
246
- export { type DefineLiveOptions, type DefinedFetchType, type DefinedLiveProps, type LivePerspective, type SanityLiveAction, type SanityLiveContext, type SanityLiveOnError, type SanityLiveOnGoaway, type SanityLiveOnReconnect, type SanityLiveOnRestart, type SanityLiveOnWelcome, type StrictDefinedFetchType, type StrictDefinedLiveProps, defineLive, isCorsOriginError, parseTags, resolvePerspectiveFromCookies };
251
+ export { type DefineLiveOptions, type DefinedFetchType, type DefinedLiveProps, type LivePerspective, type SanityLiveAction, type SanityLiveContext, type SanityLiveOnError, type SanityLiveOnGoaway, type SanityLiveOnReconnect, type SanityLiveOnRestart, type SanityLiveOnWelcome, type StrictDefinedFetchType, type StrictDefinedLiveProps, defineLive, isCorsOriginError, parseTags, resolvePerspectiveFromCookies, resolveVariantFromCookies };
247
252
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuKgB,WAAW,QAAQ;EAAqB;;EACtD,aAAa;EACb,YAAY,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmFlB,WAAW,QAAQ;EAAqB;;EACtD,aAAa;EACb,YAAY,MAAM,cAAc"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6KgB,WAAW,QAAQ;EAAqB;;EACtD,aAAa;EACb,YAAY,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmFlB,WAAW,QAAQ;EAAqB;;EACtD,aAAa;EACb,YAAY,MAAM,cAAc"}
@@ -1,6 +1,6 @@
1
1
  import "../../../constants.js";
2
2
  import { t as isCorsOriginError } from "../../../isCorsOriginError.js";
3
- import { i as preconnect, n as validateStrictFetchOptions, r as validateStrictSanityLiveProps, t as resolvePerspectiveFromCookies } from "../../../resolvePerspectiveFromCookies.js";
3
+ import { a as preconnect, i as validateStrictSanityLiveProps, n as resolvePerspectiveFromCookies, r as validateStrictFetchOptions, t as resolveVariantFromCookies } from "../../../resolveVariantFromCookies.js";
4
4
  import { t as parseTags } from "../../../parseTags.js";
5
5
  import { cookies, draftMode } from "next/headers";
6
6
  import { jsx } from "react/jsx-runtime";
@@ -19,13 +19,14 @@ function defineLive(config) {
19
19
  stega: false
20
20
  });
21
21
  const studioUrlDefined = typeof client.config().stega.studioUrl !== "undefined";
22
- const sanityFetch = async function sanityFetch({ query, params = {}, perspective: _perspective, stega: _stega, tags = [], requestTag = "next-loader.fetch" }) {
22
+ const sanityFetch = async function sanityFetch({ query, params = {}, perspective: _perspective, variant: _variant, stega: _stega, tags = [], requestTag = "next-loader.fetch" }) {
23
23
  if (strict) validateStrictFetchOptions({
24
24
  perspective: _perspective,
25
25
  stega: _stega
26
26
  });
27
27
  const stega = strict ? _stega : _stega ?? (serverToken && studioUrlDefined ? (await draftMode()).isEnabled : false);
28
28
  const perspective = strict ? _perspective : _perspective ?? (serverToken ? await resolveCookiePerspective() : void 0);
29
+ const variant = strict ? _variant : _variant ?? (serverToken && typeof _perspective === "undefined" ? await resolveCookieVariant() : void 0);
29
30
  const useCdn = perspective ? perspective === "published" : void 0;
30
31
  const isBuildPhase = process.env["NEXT_PHASE"] === PHASE_PRODUCTION_BUILD;
31
32
  const cacheMode = useCdn !== false && !isBuildPhase ? "noStale" : void 0;
@@ -33,6 +34,7 @@ function defineLive(config) {
33
34
  const { syncTags } = await client.fetch(query, await params, {
34
35
  filterResponse: false,
35
36
  perspective,
37
+ variant,
36
38
  stega: false,
37
39
  resultSourceMap: false,
38
40
  returnQuery: false,
@@ -45,6 +47,7 @@ function defineLive(config) {
45
47
  const { result, resultSourceMap } = await client.fetch(query, await params, {
46
48
  filterResponse: false,
47
49
  perspective,
50
+ variant,
48
51
  stega,
49
52
  next: {
50
53
  revalidate: false,
@@ -98,6 +101,9 @@ function defineLive(config) {
98
101
  async function resolveCookiePerspective() {
99
102
  return (await draftMode()).isEnabled ? await resolvePerspectiveFromCookies({ cookies: await cookies() }) : void 0;
100
103
  }
101
- export { defineLive, isCorsOriginError, parseTags, resolvePerspectiveFromCookies };
104
+ async function resolveCookieVariant() {
105
+ return (await draftMode()).isEnabled ? await resolveVariantFromCookies({ cookies: await cookies() }) : void 0;
106
+ }
107
+ export { defineLive, isCorsOriginError, parseTags, resolvePerspectiveFromCookies, resolveVariantFromCookies };
102
108
 
103
109
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["SanityLive","SanityLiveClientComponent"],"sources":["../../../../src/live/conditions/react-server/defineLive.tsx"],"sourcesContent":["import {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {revalidateSyncTagsAction} from 'next-sanity/live/server-actions'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {cookies, draftMode} from 'next/headers'\n\nimport {cacheTagPrefix, defaultApiHost} from '#live/constants'\nimport {preconnect} from '#live/preconnect'\nimport {resolvePerspectiveFromCookies} from '#live/resolvePerspectiveFromCookies'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n LivePerspective,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\n/**\n * Set up Sanity Live for Cache Components. `defineLive` returns `sanityFetch`\n * and `<SanityLive />`, which connect your Sanity client to the Live Content API\n * so cached pages can update in response to fine-grained content changes.\n *\n * With `strict: true`, `perspective` and `stega` become required\n * `sanityFetch` options, and `includeDrafts` becomes required on\n * `<SanityLive />`. Resolve dynamic values from `draftMode()` and `cookies()`\n * outside `'use cache'` boundaries, then pass them into cached components.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * // sanity/live.ts\n * import {cookies, draftMode} from 'next/headers'\n * import {createClient} from 'next-sanity'\n * import {\n * defineLive,\n * resolvePerspectiveFromCookies,\n * type LivePerspective,\n * } from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * strict: true,\n * })\n *\n * export interface DynamicFetchOptions {\n * perspective: LivePerspective\n * stega: boolean\n * }\n *\n * // Resolve dynamic values outside 'use cache' boundaries.\n * export async function getDynamicFetchOptions(): Promise<DynamicFetchOptions> {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (!isDraftMode) {\n * return {perspective: 'published', stega: false}\n * }\n *\n * const jar = await cookies()\n * const perspective = await resolvePerspectiveFromCookies({cookies: jar})\n * return {perspective: perspective ?? 'drafts', stega: true}\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {draftMode} from 'next/headers'\n *\n * import {SanityLive} from '@/sanity/live'\n *\n * export default async function RootLayout({children}: {children: React.ReactNode}) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive includeDrafts={isDraftMode} />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {draftMode} from 'next/headers'\n * import {Suspense} from 'react'\n * import {defineQuery} from 'next-sanity'\n *\n * import {\n * getDynamicFetchOptions,\n * sanityFetch,\n * type DynamicFetchOptions,\n * } from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (isDraftMode) {\n * return (\n * <Suspense fallback={<div>Loading...</div>}>\n * <DynamicPage params={props.params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await props.params\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage(props: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await props.params\n * const {perspective, stega} = await getDynamicFetchOptions()\n *\n * return <CachedPage slug={slug} perspective={perspective} stega={stega} />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * stega,\n * }: {slug: string} & DynamicFetchOptions) {\n * 'use cache'\n *\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * perspective,\n * stega,\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\n/**\n * Set up Sanity Live. `defineLive` returns `sanityFetch` and `<SanityLive />`,\n * which connect your Sanity client to the Live Content API so pages can serve\n * cached content and update in response to fine-grained content changes.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * import {createClient} from 'next-sanity'\n * import {defineLive} from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * })\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {SanityLive} from '@/sanity/live'\n *\n * export default function RootLayout({children}: {children: React.ReactNode}) {\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {defineQuery} from 'next-sanity'\n * import {sanityFetch} from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {slug} = await props.params\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\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 === 'development' && !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 === 'development' && !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({\n allowReconfigure: false,\n useCdn: true,\n perspective: 'published',\n stega: false,\n })\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective: _perspective,\n stega: _stega,\n tags = [],\n requestTag = 'next-loader.fetch',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const stega = strict\n ? _stega\n : (_stega ?? (serverToken && studioUrlDefined ? (await draftMode()).isEnabled : false))\n const perspective = strict\n ? _perspective\n : (_perspective ?? (serverToken ? await resolveCookiePerspective() : undefined))\n const useCdn = perspective ? perspective === 'published' : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn !== false && !isBuildPhase ? 'noStale' : undefined\n const token =\n ((perspective && perspective !== 'published') || stega) && serverToken\n ? serverToken\n : undefined\n\n // 1. Fetch the tags first, with an uncached request, but that does not count towards the Sanity API quota\n const {syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n stega: false,\n resultSourceMap: false,\n returnQuery: false,\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n token,\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `${cacheTagPrefix}${tag}`) || [])]\n\n // 2. Then fetch the data, using the fetch cache with specified tags\n const {result, resultSourceMap} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n stega,\n next: {revalidate: false, tags: cacheTags},\n useCdn,\n cacheMode,\n tag: requestTag,\n token,\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: _includeDrafts,\n requestTag = 'next-loader.live',\n waitFor,\n\n action,\n onError,\n onWelcome,\n onReconnect,\n onRestart,\n onGoAway,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n\n const includeDrafts =\n typeof browserToken === 'string' &&\n !!browserToken &&\n (_includeDrafts ?? (await draftMode()).isEnabled)\n const shouldWaitFor = waitFor === 'function' && !includeDrafts ? waitFor : undefined\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 preconnect(client)\n\n return (\n <SanityLiveClientComponent\n config={{\n projectId,\n dataset,\n apiHost: apiHost === defaultApiHost ? undefined : apiHost,\n apiVersion,\n useProjectHostname: useProjectHostname ? undefined : useProjectHostname,\n requestTagPrefix,\n token: includeDrafts ? browserToken : undefined,\n }}\n includeDrafts={includeDrafts ? true : undefined}\n requestTag={requestTag}\n waitFor={shouldWaitFor}\n action={\n action ??\n (shouldWaitFor === 'function' || includeDrafts ? 'refresh' : revalidateSyncTagsAction)\n }\n onError={onError}\n onWelcome={onWelcome}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onGoAway={onGoAway}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {sanityFetch, SanityLive}\n}\n\nasync function resolveCookiePerspective(): Promise<LivePerspective | undefined> {\n return (await draftMode()).isEnabled\n ? await resolvePerspectiveFromCookies({cookies: await cookies()})\n : undefined\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 {SanityLive as SanityLiveClientComponent} from 'next-sanity/live/client-components'\nimport {revalidateSyncTagsAction} from 'next-sanity/live/server-actions'\nimport {PHASE_PRODUCTION_BUILD} from 'next/constants'\nimport {cookies, draftMode} from 'next/headers'\n\nimport {cacheTagPrefix, defaultApiHost} from '#live/constants'\nimport {preconnect} from '#live/preconnect'\nimport {resolvePerspectiveFromCookies} from '#live/resolvePerspectiveFromCookies'\nimport {resolveVariantFromCookies} from '#live/resolveVariantFromCookies'\nimport {validateStrictFetchOptions, validateStrictSanityLiveProps} from '#live/strictValidation'\nimport type {\n DefinedFetchType,\n DefinedLiveProps,\n DefineLiveOptions,\n LivePerspective,\n StrictDefinedFetchType,\n StrictDefinedLiveProps,\n} from '#live/types'\n\n/**\n * Set up Sanity Live for Cache Components. `defineLive` returns `sanityFetch`\n * and `<SanityLive />`, which connect your Sanity client to the Live Content API\n * so cached pages can update in response to fine-grained content changes.\n *\n * With `strict: true`, `perspective` and `stega` become required\n * `sanityFetch` options, and `includeDrafts` becomes required on\n * `<SanityLive />`. Resolve dynamic values from `draftMode()` and `cookies()`\n * outside `'use cache'` boundaries, then pass them into cached components.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * // sanity/live.ts\n * import {cookies, draftMode} from 'next/headers'\n * import {createClient} from 'next-sanity'\n * import {\n * defineLive,\n * resolvePerspectiveFromCookies,\n * resolveVariantFromCookies,\n * type LivePerspective,\n * } from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * strict: true,\n * })\n *\n * export interface DynamicFetchOptions {\n * perspective: LivePerspective\n * variant?: string\n * stega: boolean\n * }\n *\n * // Resolve dynamic values outside 'use cache' boundaries.\n * export async function getDynamicFetchOptions(): Promise<DynamicFetchOptions> {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (!isDraftMode) {\n * return {perspective: 'published', stega: false}\n * }\n *\n * const jar = await cookies()\n * const perspective = await resolvePerspectiveFromCookies({cookies: jar})\n * const variant = await resolveVariantFromCookies({cookies: jar})\n * return {perspective: perspective ?? 'drafts', variant, stega: true}\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {draftMode} from 'next/headers'\n *\n * import {SanityLive} from '@/sanity/live'\n *\n * export default async function RootLayout({children}: {children: React.ReactNode}) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive includeDrafts={isDraftMode} />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {draftMode} from 'next/headers'\n * import {Suspense} from 'react'\n * import {defineQuery} from 'next-sanity'\n *\n * import {\n * getDynamicFetchOptions,\n * sanityFetch,\n * type DynamicFetchOptions,\n * } from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n * if (isDraftMode) {\n * return (\n * <Suspense fallback={<div>Loading...</div>}>\n * <DynamicPage params={props.params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await props.params\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage(props: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await props.params\n * const {perspective, variant, stega} = await getDynamicFetchOptions()\n *\n * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega={stega} />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * variant,\n * stega,\n * }: {slug: string} & DynamicFetchOptions) {\n * 'use cache'\n *\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * perspective,\n * variant,\n * stega,\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\n */\nexport function defineLive(config: DefineLiveOptions & {strict: true}): {\n sanityFetch: StrictDefinedFetchType\n SanityLive: React.ComponentType<StrictDefinedLiveProps>\n}\n/**\n * Set up Sanity Live. `defineLive` returns `sanityFetch` and `<SanityLive />`,\n * which connect your Sanity client to the Live Content API so pages can serve\n * cached content and update in response to fine-grained content changes.\n *\n * @see [Live Content API](https://www.sanity.io/docs/content-lake/live-content-api)\n * @see [Sanity Live](https://www.sanity.io/live)\n *\n * @example\n * ```tsx\n * import {createClient} from 'next-sanity'\n * import {defineLive} from 'next-sanity/live'\n *\n * const client = createClient({\n * projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n * dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,\n * useCdn: true,\n * perspective: 'published',\n * })\n * const token = process.env.SANITY_API_READ_TOKEN\n *\n * export const {sanityFetch, SanityLive} = defineLive({\n * client,\n * browserToken: token,\n * serverToken: token,\n * })\n * ```\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import {SanityLive} from '@/sanity/live'\n *\n * export default function RootLayout({children}: {children: React.ReactNode}) {\n * return (\n * <html lang=\"en\">\n * <body>\n * {children}\n * <SanityLive />\n * </body>\n * </html>\n * )\n * }\n * ```\n *\n * @example\n * ```tsx\n * // app/[slug]/page.tsx\n * import {defineQuery} from 'next-sanity'\n * import {sanityFetch} from '@/sanity/live'\n *\n * const POSTS_SLUGS_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current]{\"slug\": slug.current}\n * `)\n * const POST_QUERY = defineQuery(`\n * *[_type == \"post\" && slug.current == $slug][0]\n * `)\n *\n * export async function generateStaticParams() {\n * const {data} = await sanityFetch({\n * query: POSTS_SLUGS_QUERY,\n * perspective: 'published',\n * stega: false,\n * })\n *\n * return data\n * }\n *\n * export default async function Page(props: PageProps<'/[slug]'>) {\n * const {slug} = await props.params\n * const {data} = await sanityFetch({\n * query: POST_QUERY,\n * params: {slug},\n * })\n *\n * return <pre>{JSON.stringify(data, null, 2)}</pre>\n * }\n * ```\n *\n * @public\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 === 'development' && !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 === 'development' && !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({\n allowReconfigure: false,\n useCdn: true,\n perspective: 'published',\n stega: false,\n })\n const studioUrlDefined = typeof client.config().stega.studioUrl !== 'undefined'\n\n const sanityFetch: DefinedFetchType = async function sanityFetch({\n query,\n params = {},\n perspective: _perspective,\n variant: _variant,\n stega: _stega,\n tags = [],\n requestTag = 'next-loader.fetch',\n }) {\n if (strict) {\n validateStrictFetchOptions({perspective: _perspective, stega: _stega})\n }\n const stega = strict\n ? _stega\n : (_stega ?? (serverToken && studioUrlDefined ? (await draftMode()).isEnabled : false))\n const perspective = strict\n ? _perspective\n : (_perspective ?? (serverToken ? await resolveCookiePerspective() : undefined))\n // The variant cookie is only auto-resolved when the perspective is too:\n // an explicit `perspective` opts out of cookie resolution entirely, which\n // keeps fetches with explicit options free of dynamic API calls.\n const variant = strict\n ? _variant\n : (_variant ??\n (serverToken && typeof _perspective === 'undefined'\n ? await resolveCookieVariant()\n : undefined))\n const useCdn = perspective ? perspective === 'published' : undefined\n const isBuildPhase = process.env['NEXT_PHASE'] === PHASE_PRODUCTION_BUILD\n const cacheMode = useCdn !== false && !isBuildPhase ? 'noStale' : undefined\n const token =\n ((perspective && perspective !== 'published') || stega) && serverToken\n ? serverToken\n : undefined\n\n // 1. Fetch the tags first, with an uncached request, but that does not count towards the Sanity API quota\n const {syncTags} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n variant,\n stega: false,\n resultSourceMap: false,\n returnQuery: false,\n useCdn,\n cacheMode,\n tag: [requestTag, 'fetch-sync-tags'].filter(Boolean).join('.'),\n token,\n })\n\n const cacheTags = [...tags, ...(syncTags?.map((tag) => `${cacheTagPrefix}${tag}`) || [])]\n\n // 2. Then fetch the data, using the fetch cache with specified tags\n const {result, resultSourceMap} = await client.fetch(query, await params, {\n filterResponse: false,\n perspective,\n variant,\n stega,\n next: {revalidate: false, tags: cacheTags},\n useCdn,\n cacheMode,\n tag: requestTag,\n token,\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: _includeDrafts,\n requestTag = 'next-loader.live',\n waitFor,\n\n action,\n onError,\n onWelcome,\n onReconnect,\n onRestart,\n onGoAway,\n } = props\n const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =\n client.config()\n\n const includeDrafts =\n typeof browserToken === 'string' &&\n !!browserToken &&\n (_includeDrafts ?? (await draftMode()).isEnabled)\n const shouldWaitFor = waitFor === 'function' && !includeDrafts ? waitFor : undefined\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 preconnect(client)\n\n return (\n <SanityLiveClientComponent\n config={{\n projectId,\n dataset,\n apiHost: apiHost === defaultApiHost ? undefined : apiHost,\n apiVersion,\n useProjectHostname: useProjectHostname ? undefined : useProjectHostname,\n requestTagPrefix,\n token: includeDrafts ? browserToken : undefined,\n }}\n includeDrafts={includeDrafts ? true : undefined}\n requestTag={requestTag}\n waitFor={shouldWaitFor}\n action={\n action ??\n (shouldWaitFor === 'function' || includeDrafts ? 'refresh' : revalidateSyncTagsAction)\n }\n onError={onError}\n onWelcome={onWelcome}\n onReconnect={onReconnect}\n onRestart={onRestart}\n onGoAway={onGoAway}\n />\n )\n }\n SanityLive.displayName = 'SanityLiveServerComponent'\n\n return {sanityFetch, SanityLive}\n}\n\nasync function resolveCookiePerspective(): Promise<LivePerspective | undefined> {\n return (await draftMode()).isEnabled\n ? await resolvePerspectiveFromCookies({cookies: await cookies()})\n : undefined\n}\n\nasync function resolveCookieVariant(): Promise<string | undefined> {\n return (await draftMode()).isEnabled\n ? await resolveVariantFromCookies({cookies: await cookies()})\n : undefined\n}\n"],"mappings":"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"}
@@ -63,6 +63,75 @@ import { SyncTag } from "@sanity/client";
63
63
  declare function resolvePerspectiveFromCookies({ cookies: jar }: {
64
64
  cookies: Awaited<ReturnType<typeof cookies>>;
65
65
  }): Promise<LivePerspective>;
66
+ /**
67
+ * This helper is intended for use with Next.js Cache Components (`cacheComponents: true`),
68
+ * where `cookies()` and `draftMode()` cannot be called inside `'use cache'` boundaries.
69
+ * Resolve the variant once outside the cache boundary and pass it in as a prop / cache key.
70
+ *
71
+ * Unlike `resolvePerspectiveFromCookies` there is no fallback value: when no
72
+ * variant cookie is set (or its value is invalid) it resolves to `undefined`,
73
+ * meaning "no variant selected" and queries return base content.
74
+ *
75
+ * @example
76
+ * ```tsx
77
+ * import {cookies, draftMode} from 'next/headers'
78
+ * import {defineQuery} from 'next-sanity'
79
+ * import {
80
+ * resolvePerspectiveFromCookies,
81
+ * resolveVariantFromCookies,
82
+ * type LivePerspective,
83
+ * } from 'next-sanity/live'
84
+ * import {sanityFetch} from '#sanity/live'
85
+ *
86
+ * export default async function Page({params}: PageProps<'/[slug]'>) {
87
+ * const {isEnabled: isDraftMode} = await draftMode()
88
+ *
89
+ * if (isDraftMode) {
90
+ * return (
91
+ * <Suspense>
92
+ * <DynamicPage params={params} />
93
+ * </Suspense>
94
+ * )
95
+ * }
96
+ *
97
+ * const {slug} = await params
98
+ *
99
+ * return <CachedPage slug={slug} perspective="published" stega={false} />
100
+ * }
101
+ *
102
+ * async function DynamicPage({params}: Pick<PageProps<'/[slug]'>, 'params'>) {
103
+ * const {slug} = await params
104
+ * const jar = await cookies()
105
+ * const perspective = await resolvePerspectiveFromCookies({cookies: jar})
106
+ * const variant = await resolveVariantFromCookies({cookies: jar})
107
+ *
108
+ * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega />
109
+ * }
110
+ *
111
+ * async function CachedPage({
112
+ * slug,
113
+ * perspective,
114
+ * variant,
115
+ * stega,
116
+ * }: Awaited<PageProps<'/[slug]'>['params']> & {
117
+ * perspective: LivePerspective
118
+ * variant: string | undefined
119
+ * stega: boolean
120
+ * }) {
121
+ * 'use cache'
122
+ *
123
+ * const query = defineQuery(`*[_type == "page" && slug.current == $slug][0]`)
124
+ * const {data} = await sanityFetch({query, params: {slug}, perspective, variant, stega})
125
+ *
126
+ * return <article>...</article>
127
+ * }
128
+ * ```
129
+ *
130
+ * @public
131
+ */
132
+ declare function resolveVariantFromCookies({ cookies: jar }: {
133
+ cookies: Awaited<ReturnType<typeof cookies>>;
134
+ }): Promise<string | undefined>;
66
135
  declare const cacheTagPrefix: "sanity:";
67
136
  interface ParsedTags {
68
137
  tags: `${typeof cacheTagPrefix}${SyncTag}`[];
@@ -91,5 +160,5 @@ interface ParsedTags {
91
160
  * ```
92
161
  */
93
162
  declare function parseTags(unsafeTags: unknown): ParsedTags;
94
- export { resolvePerspectiveFromCookies as n, parseTags as t };
163
+ export { resolveVariantFromCookies as n, resolvePerspectiveFromCookies as r, parseTags as t };
95
164
  //# sourceMappingURL=parseTags.d.ts.map
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiEsB,gCACpB,SAAS;EAET,SAAS,QAAQ,kBAAkB;IACjC,QAAQ;cClEC;UCCH;EACR,gBAAgB,iBAAiB;EACjC,mBAAmB;EACnB,eAAe;;;;;;;;;;;;;;;;;;;;;;;iBAwBD,UAAU,sBAAsB"}
1
+ {"version":3,"file":"parseTags.d.ts","names":[],"sources":["../src/live/shared/resolvePerspectiveFromCookies.ts","../src/live/shared/resolveVariantFromCookies.ts","../src/live/shared/constants.ts","../src/live/shared/parseTags.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiEsB,gCACpB,SAAS;EAET,SAAS,QAAQ,kBAAkB;IACjC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCEU,4BACpB,SAAS;EAET,SAAS,QAAQ,kBAAkB;IACjC;cCxES;UCCH;EACR,gBAAgB,iBAAiB;EACjC,mBAAmB;EACnB,eAAe;;;;;;;;;;;;;;;;;;;;;;;iBAwBD,UAAU,sBAAsB"}
@@ -1,5 +1,5 @@
1
- import { t as sanitizePerspective } from "./sanitizePerspective.js";
2
- import { perspectiveCookieName } from "@sanity/preview-url-secret/constants";
1
+ import { n as sanitizePerspective, t as sanitizeVariant } from "./sanitizeVariant.js";
2
+ import { perspectiveCookieName, variantCookieName } from "@sanity/preview-url-secret/constants";
3
3
  import { preconnect } from "react-dom";
4
4
  import { generateHelpUrl } from "@sanity/generate-help-url";
5
5
  /**
@@ -78,6 +78,75 @@ function validateStrictFetchOptions(options) {
78
78
  async function resolvePerspectiveFromCookies({ cookies: jar }) {
79
79
  return jar.has(perspectiveCookieName) ? sanitizePerspective(jar.get(perspectiveCookieName)?.value, "drafts") : "drafts";
80
80
  }
81
- export { preconnect$1 as i, validateStrictFetchOptions as n, validateStrictSanityLiveProps as r, resolvePerspectiveFromCookies as t };
81
+ /**
82
+ * This helper is intended for use with Next.js Cache Components (`cacheComponents: true`),
83
+ * where `cookies()` and `draftMode()` cannot be called inside `'use cache'` boundaries.
84
+ * Resolve the variant once outside the cache boundary and pass it in as a prop / cache key.
85
+ *
86
+ * Unlike `resolvePerspectiveFromCookies` there is no fallback value: when no
87
+ * variant cookie is set (or its value is invalid) it resolves to `undefined`,
88
+ * meaning "no variant selected" and queries return base content.
89
+ *
90
+ * @example
91
+ * ```tsx
92
+ * import {cookies, draftMode} from 'next/headers'
93
+ * import {defineQuery} from 'next-sanity'
94
+ * import {
95
+ * resolvePerspectiveFromCookies,
96
+ * resolveVariantFromCookies,
97
+ * type LivePerspective,
98
+ * } from 'next-sanity/live'
99
+ * import {sanityFetch} from '#sanity/live'
100
+ *
101
+ * export default async function Page({params}: PageProps<'/[slug]'>) {
102
+ * const {isEnabled: isDraftMode} = await draftMode()
103
+ *
104
+ * if (isDraftMode) {
105
+ * return (
106
+ * <Suspense>
107
+ * <DynamicPage params={params} />
108
+ * </Suspense>
109
+ * )
110
+ * }
111
+ *
112
+ * const {slug} = await params
113
+ *
114
+ * return <CachedPage slug={slug} perspective="published" stega={false} />
115
+ * }
116
+ *
117
+ * async function DynamicPage({params}: Pick<PageProps<'/[slug]'>, 'params'>) {
118
+ * const {slug} = await params
119
+ * const jar = await cookies()
120
+ * const perspective = await resolvePerspectiveFromCookies({cookies: jar})
121
+ * const variant = await resolveVariantFromCookies({cookies: jar})
122
+ *
123
+ * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega />
124
+ * }
125
+ *
126
+ * async function CachedPage({
127
+ * slug,
128
+ * perspective,
129
+ * variant,
130
+ * stega,
131
+ * }: Awaited<PageProps<'/[slug]'>['params']> & {
132
+ * perspective: LivePerspective
133
+ * variant: string | undefined
134
+ * stega: boolean
135
+ * }) {
136
+ * 'use cache'
137
+ *
138
+ * const query = defineQuery(`*[_type == "page" && slug.current == $slug][0]`)
139
+ * const {data} = await sanityFetch({query, params: {slug}, perspective, variant, stega})
140
+ *
141
+ * return <article>...</article>
142
+ * }
143
+ * ```
144
+ *
145
+ * @public
146
+ */
147
+ async function resolveVariantFromCookies({ cookies: jar }) {
148
+ return jar.has(variantCookieName) ? sanitizeVariant(jar.get(variantCookieName)?.value) : void 0;
149
+ }
150
+ export { preconnect$1 as a, validateStrictSanityLiveProps as i, resolvePerspectiveFromCookies as n, validateStrictFetchOptions as r, resolveVariantFromCookies as t };
82
151
 
83
- //# sourceMappingURL=resolvePerspectiveFromCookies.js.map
152
+ //# sourceMappingURL=resolveVariantFromCookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveVariantFromCookies.js","names":["preconnect"],"sources":["../src/live/shared/preconnect.ts","../src/live/shared/strictValidation.ts","../src/live/shared/resolvePerspectiveFromCookies.ts","../src/live/shared/resolveVariantFromCookies.ts"],"sourcesContent":["import type {SanityClient} from 'next-sanity'\nimport {preconnect as reactDomPreconnect} from 'react-dom'\n\n/**\n * Uses the React DOM `preconnect` function to preconnect to the Live Event API origin early, Next.js will set the right headers and meta tags to speed up the connection.\n */\nexport function preconnect(client: SanityClient): void {\n const {origin} = new URL(client.getUrl('', false))\n reactDomPreconnect(origin)\n}\n","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 {perspectiveCookieName} from '@sanity/preview-url-secret/constants'\nimport type {cookies} from 'next/headers'\n\nimport {sanitizePerspective} from '#live/sanitizePerspective'\nimport type {LivePerspective} from '#live/types'\n\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 * @example\n * ```tsx\n * import {cookies, draftMode} from 'next/headers'\n * import {defineQuery} from 'next-sanity'\n * import {resolvePerspectiveFromCookies, type LivePerspective} from 'next-sanity/live'\n * import {sanityFetch, sanityFetchStaticParams} from '#sanity/live'\n *\n * export async function generateStaticParams() {\n * const query = defineQuery(`*[_type == \"page\" && defined(slug.current)]{\"slug\": slug.current}`)\n * return await sanityFetchStaticParams({query})\n * }\n *\n * export default async function Page({params}: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * if (isDraftMode) {\n * return (\n * <Suspense>\n * <DynamicPage params={params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await params\n *\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage({params}: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await params\n * const perspective = await resolvePerspectiveFromCookies({cookies: await cookies()})\n *\n * return <CachedPage slug={slug} perspective={perspective} stega />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * stega,\n * }: Awaited<PageProps<'/[slug]'>['params']> & {\n * perspective: LivePerspective\n * stega: boolean\n * }) {\n * 'use cache'\n *\n * const query = defineQuery(`*[_type == \"page\" && slug.current == $slug][0]`)\n * const {data} = await sanityFetch({query, params: {slug}, perspective, stega})\n *\n * return <article>...</article>\n * }\n * ```\n *\n * @public\n */\nexport async function resolvePerspectiveFromCookies({\n cookies: jar,\n}: {\n cookies: Awaited<ReturnType<typeof cookies>>\n}): Promise<LivePerspective> {\n return jar.has(perspectiveCookieName)\n ? sanitizePerspective(jar.get(perspectiveCookieName)?.value, 'drafts')\n : 'drafts'\n}\n","import {variantCookieName} from '@sanity/preview-url-secret/constants'\nimport type {cookies} from 'next/headers'\n\nimport {sanitizeVariant} from '#live/sanitizeVariant'\n\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 variant once outside the cache boundary and pass it in as a prop / cache key.\n *\n * Unlike `resolvePerspectiveFromCookies` there is no fallback value: when no\n * variant cookie is set (or its value is invalid) it resolves to `undefined`,\n * meaning \"no variant selected\" and queries return base content.\n *\n * @example\n * ```tsx\n * import {cookies, draftMode} from 'next/headers'\n * import {defineQuery} from 'next-sanity'\n * import {\n * resolvePerspectiveFromCookies,\n * resolveVariantFromCookies,\n * type LivePerspective,\n * } from 'next-sanity/live'\n * import {sanityFetch} from '#sanity/live'\n *\n * export default async function Page({params}: PageProps<'/[slug]'>) {\n * const {isEnabled: isDraftMode} = await draftMode()\n *\n * if (isDraftMode) {\n * return (\n * <Suspense>\n * <DynamicPage params={params} />\n * </Suspense>\n * )\n * }\n *\n * const {slug} = await params\n *\n * return <CachedPage slug={slug} perspective=\"published\" stega={false} />\n * }\n *\n * async function DynamicPage({params}: Pick<PageProps<'/[slug]'>, 'params'>) {\n * const {slug} = await params\n * const jar = await cookies()\n * const perspective = await resolvePerspectiveFromCookies({cookies: jar})\n * const variant = await resolveVariantFromCookies({cookies: jar})\n *\n * return <CachedPage slug={slug} perspective={perspective} variant={variant} stega />\n * }\n *\n * async function CachedPage({\n * slug,\n * perspective,\n * variant,\n * stega,\n * }: Awaited<PageProps<'/[slug]'>['params']> & {\n * perspective: LivePerspective\n * variant: string | undefined\n * stega: boolean\n * }) {\n * 'use cache'\n *\n * const query = defineQuery(`*[_type == \"page\" && slug.current == $slug][0]`)\n * const {data} = await sanityFetch({query, params: {slug}, perspective, variant, stega})\n *\n * return <article>...</article>\n * }\n * ```\n *\n * @public\n */\nexport async function resolveVariantFromCookies({\n cookies: jar,\n}: {\n cookies: Awaited<ReturnType<typeof cookies>>\n}): Promise<string | undefined> {\n return jar.has(variantCookieName) ? sanitizeVariant(jar.get(variantCookieName)?.value) : undefined\n}\n"],"mappings":";;;;;;;AAMA,SAAgBA,aAAW,QAA4B;CACrD,MAAM,EAAC,WAAU,IAAI,IAAI,OAAO,OAAO,IAAI,KAAK,CAAC;CACjD,WAAmB,MAAM;AAC3B;ACPA,SAAgB,8BAA8B,OAAwC;CACpF,IAAI,OAAO,MAAM,kBAAkB,WACjC,MAAM,IAAI,MACR,iJAAiJ,gBAAgB,yBAAyB,KAC1L,EAAC,OAAO,MAAK,CACf;AAEJ;AAEA,SAAgB,2BAA2B,SAGlC;CACP,IAAI,OAAO,QAAQ,gBAAgB,eAAe,QAAQ,gBAAgB,MACxE,MAAM,IAAI,MACR,kIAAkI,gBAAgB,0BAA0B,KAC5K,EAAC,OAAO,QAAO,CACjB;CAEF,IAAI,OAAO,QAAQ,UAAU,WAC3B,MAAM,IAAI,MACR,4IAA4I,gBAAgB,0BAA0B,KACtL,EAAC,OAAO,QAAO,CACjB;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACsCA,eAAsB,8BAA8B,EAClD,SAAS,OAGkB;CAC3B,OAAO,IAAI,IAAI,qBAAqB,IAChC,oBAAoB,IAAI,IAAI,qBAAqB,CAAC,EAAE,OAAO,QAAQ,IACnE;AACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFA,eAAsB,0BAA0B,EAC9C,SAAS,OAGqB;CAC9B,OAAO,IAAI,IAAI,iBAAiB,IAAI,gBAAgB,IAAI,IAAI,iBAAiB,CAAC,EAAE,KAAK,IAAI,KAAA;AAC3F"}
@@ -0,0 +1,37 @@
1
+ import { validateApiPerspective } from "@sanity/client";
2
+ function sanitizePerspective(_perspective, fallback) {
3
+ const perspective = typeof _perspective === "string" && _perspective.includes(",") ? _perspective.split(",") : _perspective;
4
+ try {
5
+ validateApiPerspective(perspective);
6
+ return perspective === "raw" ? fallback : perspective;
7
+ } catch (err) {
8
+ console.warn(`Invalid perspective:`, _perspective, perspective, err);
9
+ return fallback;
10
+ }
11
+ }
12
+ /**
13
+ * Editing variants are referenced by their bare variant id (e.g. `Ab12cd34`),
14
+ * never the full variant document id (`_.variants.Ab12cd34`, rejected since
15
+ * dots are not allowed). A single id, never comma-separated or an array.
16
+ */
17
+ const VARIANT_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
18
+ /**
19
+ * Unlike `sanitizePerspective` there is no fallback: an invalid or missing
20
+ * variant means "no variant selected" and resolves to `undefined`.
21
+ */
22
+ function sanitizeVariant(_variant) {
23
+ if (typeof _variant !== "string") {
24
+ if (typeof _variant !== "undefined" && _variant !== null) console.warn(`Invalid variant:`, _variant);
25
+ return;
26
+ }
27
+ const variant = _variant.trim();
28
+ if (variant === "") return;
29
+ if (!VARIANT_ID_PATTERN.test(variant)) {
30
+ console.warn(`Invalid variant:`, _variant);
31
+ return;
32
+ }
33
+ return variant;
34
+ }
35
+ export { sanitizePerspective as n, sanitizeVariant as t };
36
+
37
+ //# sourceMappingURL=sanitizeVariant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizeVariant.js","names":[],"sources":["../src/live/shared/sanitizePerspective.ts","../src/live/shared/sanitizeVariant.ts"],"sourcesContent":["import {validateApiPerspective} from '@sanity/client'\n\nimport type {LivePerspective} from '#live/types'\n\nexport function sanitizePerspective(\n _perspective: unknown,\n fallback: 'drafts' | 'published',\n): LivePerspective {\n const perspective =\n typeof _perspective === 'string' && _perspective.includes(',')\n ? _perspective.split(',')\n : _perspective\n try {\n validateApiPerspective(perspective)\n return perspective === 'raw' ? fallback : perspective\n } catch (err) {\n console.warn(`Invalid perspective:`, _perspective, perspective, err)\n return fallback\n }\n}\n","/**\n * Editing variants are referenced by their bare variant id (e.g. `Ab12cd34`),\n * never the full variant document id (`_.variants.Ab12cd34`, rejected since\n * dots are not allowed). A single id, never comma-separated or an array.\n */\nconst VARIANT_ID_PATTERN = /^[A-Za-z0-9_-]+$/\n\n/**\n * Unlike `sanitizePerspective` there is no fallback: an invalid or missing\n * variant means \"no variant selected\" and resolves to `undefined`.\n */\nexport function sanitizeVariant(_variant: unknown): string | undefined {\n if (typeof _variant !== 'string') {\n if (typeof _variant !== 'undefined' && _variant !== null) {\n console.warn(`Invalid variant:`, _variant)\n }\n return undefined\n }\n const variant = _variant.trim()\n if (variant === '') {\n return undefined\n }\n if (!VARIANT_ID_PATTERN.test(variant)) {\n console.warn(`Invalid variant:`, _variant)\n return undefined\n }\n return variant\n}\n"],"mappings":";AAIA,SAAgB,oBACd,cACA,UACiB;CACjB,MAAM,cACJ,OAAO,iBAAiB,YAAY,aAAa,SAAS,GAAG,IACzD,aAAa,MAAM,GAAG,IACtB;CACN,IAAI;EACF,uBAAuB,WAAW;EAClC,OAAO,gBAAgB,QAAQ,WAAW;CAC5C,SAAS,KAAK;EACZ,QAAQ,KAAK,wBAAwB,cAAc,aAAa,GAAG;EACnE,OAAO;CACT;AACF;;;;;;ACdA,MAAM,qBAAqB;;;;;AAM3B,SAAgB,gBAAgB,UAAuC;CACrE,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,OAAO,aAAa,eAAe,aAAa,MAClD,QAAQ,KAAK,oBAAoB,QAAQ;EAE3C;CACF;CACA,MAAM,UAAU,SAAS,KAAK;CAC9B,IAAI,YAAY,IACd;CAEF,IAAI,CAAC,mBAAmB,KAAK,OAAO,GAAG;EACrC,QAAQ,KAAK,oBAAoB,QAAQ;EACzC;CACF;CACA,OAAO;AACT"}
package/dist/types.d.ts CHANGED
@@ -36,6 +36,23 @@ type DefinedFetchType = <const QueryString extends string>(options: {
36
36
  * If all of the above conditions are met, then the default value will be resolved from attempting to read the `'sanity-preview-perspective'` cookie and fall back to `'drafts'` if not set
37
37
  */
38
38
  perspective?: LivePerspective;
39
+ /**
40
+ * Editing variant used for the fetch, as the bare variant id (e.g. `Ab12cd34`).
41
+ *
42
+ * @remarks
43
+ * Requires `serverToken` to be configured in `defineLive()`
44
+ *
45
+ * @defaultValue
46
+ * The default is `undefined` (no variant, base content) unless
47
+ * - `Cache Components` are disabled
48
+ * - `defineLive()` was given a `serverToken`
49
+ * - `defineLive()` is not set to `strict: true`
50
+ * - `perspective` is not explicitly provided (an explicit `perspective` opts out of cookie resolution so fetches with explicit options stay free of dynamic API calls)
51
+ * - `draftMode()` is enabled
52
+ *
53
+ * If all of the above conditions are met, then the default value will be resolved from attempting to read the `'sanity-preview-variant'` cookie and fall back to `undefined` if not set
54
+ */
55
+ variant?: string;
39
56
  /**
40
57
  * Enables stega encoding of the data. This is typically only used in draft
41
58
  * mode with `perspective: 'drafts'` and `@sanity/visual-editing`.
@@ -200,6 +217,14 @@ type StrictDefinedFetchType = <const QueryString extends string>(options: {
200
217
  query: QueryString;
201
218
  params?: QueryParams | Promise<QueryParams>;
202
219
  perspective: LivePerspective;
220
+ /**
221
+ * Editing variant used for the fetch, as the bare variant id (e.g. `Ab12cd34`).
222
+ *
223
+ * Stays optional in strict mode: the absence of a variant is a valid state
224
+ * (base content). With `strict: true` there is no cookie auto-resolution;
225
+ * only the explicit option is used.
226
+ */
227
+ variant?: string;
203
228
  stega: boolean;
204
229
  tags?: string[];
205
230
  requestTag?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/live/shared/types.ts"],"mappings":";;;;;KAcY,kBAAkB,QAAQ;;;;;;;;KAS1B,0BAA0B,4BAA4B;;;;EAIhE,OAAO;;;;EAIP,SAAS,cAAc,QAAQ;;;;;;;;;;;;;;;;EAgB/B,cAAc;;;;;;;;;;;;;;;;;;EAkBd;;;;;;;;;;;;;;EAcA;;;;;;;;;;EAUA;MACI;EACJ,MAAM,aAAa;EACnB,WAAW;EACX;;;;;;UAOe;;;;;;;;;;;;;;;;EAgBf;;;;;;;;;;EAUA;;;;;EAKA;;;;;;;EAOA,SAAS;;;;;;EAMT,UAAU;;;;;EAKV,YAAY;;;;;EAKZ,cAAc;;;;;EAKd,YAAY;;;;;EAKZ,WAAW;;UAGI;;;;EAIf,QAAQ;;;;;;;EAOR;;;;;;;;EAQA;;;;;;;;;;;EAWA;;;;;;UAOe,+BAA+B,KAAK;EACnD;;;;;;KAOU,gCAAgC,4BAA4B;EACtE,OAAO;EACP,SAAS,cAAc,QAAQ;EAC/B,aAAa;EACb;EACA;EACA;MACI;EACJ,MAAM,aAAa;EACnB,WAAW;EACX;;UAGe,2BAA2B,KAC1C;EAGA;EACA;;;;;UAMe;;;;;EAKf;;;;EAIA;;;;;;;;;;;;;;;;KAiBU,qBAAqB,wBAAwB;;;;;;;;;KAS7C,sBAAsB,gBAAgB,SAAS;;;;;;;;KAQ/C,uBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;KAMA,yBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;;KAQA,wBAEN,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;;;;KAUJ,sBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,mBACT,qBAAqB,qCACX"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/live/shared/types.ts"],"mappings":";;;;;KAcY,kBAAkB,QAAQ;;;;;;;;KAS1B,0BAA0B,4BAA4B;;;;EAIhE,OAAO;;;;EAIP,SAAS,cAAc,QAAQ;;;;;;;;;;;;;;;;EAgB/B,cAAc;;;;;;;;;;;;;;;;;EAiBd;;;;;;;;;;;;;;;;;;EAkBA;;;;;;;;;;;;;;EAcA;;;;;;;;;;EAUA;MACI;EACJ,MAAM,aAAa;EACnB,WAAW;EACX;;;;;;UAOe;;;;;;;;;;;;;;;;EAgBf;;;;;;;;;;EAUA;;;;;EAKA;;;;;;;EAOA,SAAS;;;;;;EAMT,UAAU;;;;;EAKV,YAAY;;;;;EAKZ,cAAc;;;;;EAKd,YAAY;;;;;EAKZ,WAAW;;UAGI;;;;EAIf,QAAQ;;;;;;;EAOR;;;;;;;;EAQA;;;;;;;;;;;EAWA;;;;;;UAOe,+BAA+B,KAAK;EACnD;;;;;;KAOU,gCAAgC,4BAA4B;EACtE,OAAO;EACP,SAAS,cAAc,QAAQ;EAC/B,aAAa;;;;;;;;EAQb;EACA;EACA;EACA;MACI;EACJ,MAAM,aAAa;EACnB,WAAW;EACX;;UAGe,2BAA2B,KAC1C;EAGA;EACA;;;;;UAMe;;;;;EAKf;;;;EAIA;;;;;;;;;;;;;;;;KAiBU,qBAAqB,wBAAwB;;;;;;;;;KAS7C,sBAAsB,gBAAgB,SAAS;;;;;;;;KAQ/C,uBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;KAMA,yBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;;KAQA,wBAEN,OAAO,QAAQ;EAAY;IAC3B,SAAS,6BACC;;;;;;;;;KAUJ,sBACV,OAAO,QAAQ;EAAY;IAC3B,SAAS,mBACT,qBAAqB,qCACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/visual-editing/VisualEditing.tsx"],"mappings":";;;;iBAOgB,cAAc,OAAO,uBAAqB,MAAM"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/visual-editing/VisualEditing.tsx"],"mappings":";;;;iBAUgB,cAAc,OAAO,uBAAqB,MAAM"}
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { VisualEditing as VisualEditing$1 } from "next-sanity/visual-editing/client-component";
3
- import { perspectiveChangeAction } from "next-sanity/visual-editing/server-actions";
3
+ import { perspectiveChangeAction, variantChangeAction } from "next-sanity/visual-editing/server-actions";
4
4
  /**
5
5
  * @public
6
6
  */
@@ -21,6 +21,7 @@ function VisualEditing(props) {
21
21
  }
22
22
  return /* @__PURE__ */ jsx(VisualEditing$1, {
23
23
  onPerspectiveChange: perspectiveChangeAction,
24
+ onVariantChange: variantChangeAction,
24
25
  ...props,
25
26
  basePath: props.basePath ?? autoBasePath,
26
27
  trailingSlash: props.trailingSlash ?? autoTrailingSlash
@@ -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 {perspectiveChangeAction} 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={perspectiveChangeAction}\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;CACJ,IAAI,OAAO,MAAM,aAAa,UAC5B,IAAI;EACF,eAAe,QAAQ,IAAI;EAC3B,IAAI,cAEF,QAAQ,IACN,6BAA6B,KAAK,UAAU,YAAY,EAAE,+JAC5D;CAEJ,SAAS,KAAK;EACZ,QAAQ,MAAM,6BAA6B,GAAG;CAChD;CAEF,IAAI;CACJ,IAAI,OAAO,MAAM,kBAAkB,WACjC,IAAI;EACF,oBAAoB,QAAQ,QAAQ,IAAI,wBAAwB;EAChE,IAAI,mBAEF,QAAQ,IACN,kCAAkC,KAAK,UAAU,iBAAiB,EAAE,mKACtE;CAEJ,SAAS,KAAK;EACZ,QAAQ,MAAM,kCAAkC,GAAG;CACrD;CAEF,OACE,oBAACA,iBAAD;EACE,qBAAqB;EACrB,GAAI;EACJ,UAAU,MAAM,YAAY;EAC5B,eAAe,MAAM,iBAAiB;CACvC,CAAA;AAEL"}
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 {\n perspectiveChangeAction,\n variantChangeAction,\n} 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={perspectiveChangeAction}\n onVariantChange={variantChangeAction}\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":";;;;;;AAUA,SAAgB,cAAc,OAA+C;CAC3E,IAAI;CACJ,IAAI,OAAO,MAAM,aAAa,UAC5B,IAAI;EACF,eAAe,QAAQ,IAAI;EAC3B,IAAI,cAEF,QAAQ,IACN,6BAA6B,KAAK,UAAU,YAAY,EAAE,+JAC5D;CAEJ,SAAS,KAAK;EACZ,QAAQ,MAAM,6BAA6B,GAAG;CAChD;CAEF,IAAI;CACJ,IAAI,OAAO,MAAM,kBAAkB,WACjC,IAAI;EACF,oBAAoB,QAAQ,QAAQ,IAAI,wBAAwB;EAChE,IAAI,mBAEF,QAAQ,IACN,kCAAkC,KAAK,UAAU,iBAAiB,EAAE,mKACtE;CAEJ,SAAS,KAAK;EACZ,QAAQ,MAAM,kCAAkC,GAAG;CACrD;CAEF,OACE,oBAACA,iBAAD;EACE,qBAAqB;EACrB,iBAAiB;EACjB,GAAI;EACJ,UAAU,MAAM,YAAY;EAC5B,eAAe,MAAM,iBAAiB;CACvC,CAAA;AAEL"}
@@ -3,5 +3,9 @@ import { ClientPerspective } from "@sanity/client";
3
3
  * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.
4
4
  */
5
5
  declare function perspectiveChangeAction(perspective: ClientPerspective): Promise<void>;
6
- export { perspectiveChangeAction };
6
+ /**
7
+ * @internal CAUTION: this is an internal action and does not follow semver. Using it directly is at your own risk.
8
+ */
9
+ declare function variantChangeAction(variant: string | undefined): Promise<void>;
10
+ export { perspectiveChangeAction, variantChangeAction };
7
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/visual-editing/server-actions/index.ts"],"mappings":";;;;iBAasB,wBAAwB,aAAa,oBAAoB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/visual-editing/server-actions/index.ts"],"mappings":";;;;iBAcsB,wBAAwB,aAAa,oBAAoB;;;;iBAuCzD,oBAAoB,8BAA8B"}