hydrogen-sanity 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -288,6 +288,24 @@ export const loader: LoaderFunction = async function ({request, context}) {
288
288
  }
289
289
  ```
290
290
 
291
+ ## Request Options
292
+
293
+ If you need to pass any additional options to the request, provide `queryOptions` like so:
294
+
295
+ ```ts
296
+ const page = await context.sanity.query<HomePage>({
297
+ query: HOME_PAGE_QUERY,
298
+ cache,
299
+ // These additional options will be passed to `sanity.fetch`
300
+ queryOptions: {
301
+ tag: 'home',
302
+ headers: {
303
+ 'Accept-Encoding': 'br, gzip, *',
304
+ },
305
+ },
306
+ })
307
+ ```
308
+
291
309
  ## Limits
292
310
 
293
311
  The real-time preview comes with a configured limit of 3000 documents. You can experiment with larger datasets by configuring `cache.maxDocuments: <Integer>` in your `PreviewProvider`. Be aware that this might affect the preview performance.
package/dist/index.d.ts CHANGED
@@ -4,14 +4,17 @@ import type {CacheShort} from '@shopify/hydrogen'
4
4
  import {ClientConfig} from '@sanity/preview-kit/client'
5
5
  import type {ClientConfig as ClientConfig_2} from '@sanity/client'
6
6
  import {ClientPerspective} from '@sanity/preview-kit/client'
7
+ import {FilteredResponseQueryOptions} from '@sanity/preview-kit/client'
7
8
  import type {LiveQueryProviderProps} from '@sanity/preview-kit'
8
9
  import {QueryParams} from '@sanity/preview-kit/client'
9
10
  import type {QueryParams as QueryParams_2} from '@sanity/client'
11
+ import {RawQueryResponse} from '@sanity/preview-kit/client'
10
12
  import {ReactElement} from 'react'
11
13
  import {ReactNode} from 'react'
12
14
  import {SanityClient} from '@sanity/preview-kit/client'
13
15
  import {Session} from '@shopify/remix-oxygen'
14
16
  import {SessionStorage} from '@shopify/remix-oxygen'
17
+ import {UnfilteredResponseQueryOptions} from '@sanity/preview-kit/client'
15
18
 
16
19
  /** @see https://shopify.dev/docs/custom-storefronts/hydrogen/data-fetching/cache#caching-strategies */
17
20
  export declare type CachingStrategy = ReturnType<typeof CacheShort>
@@ -100,6 +103,7 @@ export declare type Sanity = {
100
103
  session: PreviewSession
101
104
  }
102
105
  query<T>(options: useSanityQuery): Promise<T>
106
+ query<T>(options: useRawSanityQuery): Promise<RawQueryResponse<T>>
103
107
  }
104
108
 
105
109
  /**
@@ -128,10 +132,18 @@ export declare const usePreviewContext: () =>
128
132
  }
129
133
  | undefined
130
134
 
135
+ declare type useRawSanityQuery = {
136
+ query: string
137
+ params?: QueryParams
138
+ cache?: CachingStrategy
139
+ queryOptions: UnfilteredResponseQueryOptions
140
+ }
141
+
131
142
  declare type useSanityQuery = {
132
143
  query: string
133
144
  params?: QueryParams
134
145
  cache?: CachingStrategy
146
+ queryOptions?: FilteredResponseQueryOptions
135
147
  }
136
148
 
137
149
  export {}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@sanity/preview-kit/client"),t=require("@shopify/hydrogen"),r=require("react"),i=require("react/jsx-runtime"),n=require("@shopify/remix-oxygen"),s=require("@sanity/preview-kit");function a(e){return Boolean(e&&e.token&&null!==e.token)}async function o(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const c=r.createContext(void 0),u=()=>r.useContext(c);const l=r.lazy((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));var p,d,h=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},v=(e,t,r)=>(h(e,t,"read from private field"),r?r.call(e):t.get(e)),y=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},f=(e,t,r,i)=>(h(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);function w(e){const{initialData:t,query:r,params:n,children:a}=e,[o]=s.useLiveQuery(t,r,n);return i.jsx(i.Fragment,{children:a(o)})}p=new WeakMap,d=new WeakMap,exports.PreviewProvider=function(t){const{children:n,previewConfig:s,fallback:a=n,...o}=t,[,u]=r.useTransition(),[p,d]=r.useState(!1);if(r.useEffect((()=>u((()=>d(!0)))),[]),!p||!s||!s.projectId)return i.jsx(i.Fragment,{children:n});const h=e.createClient(s);return i.jsx(c.Provider,{value:{projectId:s.projectId},children:i.jsx(r.Suspense,{fallback:a,children:i.jsx(l,{...o,client:h,children:n})})})},exports.PreviewSession=class{constructor(e,t){y(this,p,void 0),y(this,d,void 0),f(this,p,e),f(this,d,t)}static async init(e,t){const r=n.createCookieSessionStorage({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return v(this,d).has(e)}destroy(){return v(this,p).destroySession(v(this,d))}set(e,t){v(this,d).set(e,t)}commit(){return v(this,p).commitSession(v(this,d))}},exports.SanityPreview=function(e){const{data:t,children:r,query:n,params:s}=e,a=Boolean(u());return"function"!=typeof r?i.jsx(i.Fragment,{children:r}):a&&n?i.jsx(w,{query:n,params:s,initialData:t,children:r}):i.jsx(i.Fragment,{children:r(t)})},exports.createSanityClient=function(r){const{cache:i,waitUntil:n,preview:s,config:a}=r,c={client:e.createClient(a),async query(e){let{query:r,params:s,cache:a=t.CacheLong()}=e;const u=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return o(r)}(r,s);return t.createWithCache({cache:i,waitUntil:n})(u,a,(()=>c.client.fetch(r,s)))}};return s&&(c.preview={session:s.session},s.session.has("projectId")&&(c.preview={...c.preview,projectId:a.projectId,dataset:a.dataset,token:s.token},c.client=c.client.withConfig({useCdn:!1,token:s.token,perspective:s.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r}=e;return c.client.fetch(t,r)})),c},exports.getPreview=function(e){return a(e.sanity.preview)?{...e.sanity.client.config()}:void 0},exports.isPreviewModeEnabled=a,exports.sha256=o,exports.usePreviewContext=u;//# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@sanity/preview-kit/client"),t=require("@shopify/hydrogen"),r=require("react"),i=require("react/jsx-runtime"),n=require("@shopify/remix-oxygen"),s=require("@sanity/preview-kit");function o(e){return Boolean(e&&e.token&&null!==e.token)}async function a(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const c=r.createContext(void 0),u=()=>r.useContext(c);const l=r.lazy((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));var p,h,d=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},f=(e,t,r)=>(d(e,t,"read from private field"),r?r.call(e):t.get(e)),y=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},v=(e,t,r,i)=>(d(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);function w(e){const{initialData:t,query:r,params:n,children:o}=e,[a]=s.useLiveQuery(t,r,n);return i.jsx(i.Fragment,{children:o(a)})}p=new WeakMap,h=new WeakMap,exports.PreviewProvider=function(t){const{children:n,previewConfig:s,fallback:o=n,...a}=t,[,u]=r.useTransition(),[p,h]=r.useState(!1);if(r.useEffect((()=>u((()=>h(!0)))),[]),!p||!s||!s.projectId)return i.jsx(i.Fragment,{children:n});const d=e.createClient(s);return i.jsx(c.Provider,{value:{projectId:s.projectId},children:i.jsx(r.Suspense,{fallback:o,children:i.jsx(l,{...a,client:d,children:n})})})},exports.PreviewSession=class{constructor(e,t){y(this,p,void 0),y(this,h,void 0),v(this,p,e),v(this,h,t)}static async init(e,t){const r=n.createCookieSessionStorage({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return f(this,h).has(e)}destroy(){return f(this,p).destroySession(f(this,h))}set(e,t){f(this,h).set(e,t)}commit(){return f(this,p).commitSession(f(this,h))}},exports.SanityPreview=function(e){const{data:t,children:r,query:n,params:s}=e,o=Boolean(u());return"function"!=typeof r?i.jsx(i.Fragment,{children:r}):o&&n?i.jsx(w,{query:n,params:s,initialData:t,children:r}):i.jsx(i.Fragment,{children:r(t)})},exports.createSanityClient=function(r){const{cache:i,waitUntil:n,preview:s,config:o}=r,c={client:e.createClient(o),async query(e){let{query:r,params:s,cache:o=t.CacheLong(),queryOptions:u}=e;const l=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return a(r)}(r,s);return t.createWithCache({cache:i,waitUntil:n})(l,o,(()=>u?(u.filterResponse,c.client.fetch(r,s,u)):c.client.fetch(r,s)))}};return s&&(c.preview={session:s.session},s.session.has("projectId")&&(c.preview={...c.preview,projectId:o.projectId,dataset:o.dataset,token:s.token},c.client=c.client.withConfig({useCdn:!1,token:s.token,perspective:s.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r,queryOptions:i}=e;return i?(i.filterResponse,c.client.fetch(t,r,i)):c.client.fetch(t,r)})),c},exports.getPreview=function(e){return o(e.sanity.preview)?{...e.sanity.client.config()}:void 0},exports.isPreviewModeEnabled=o,exports.sha256=a,exports.usePreviewContext=u;//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx","../src/preview/getPreview.ts"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type QueryParams,\n type SanityClient,\n} from '@sanity/preview-kit/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache<T>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","/* eslint-disable react/require-default-props */\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {type ClientConfig, createClient} from '@sanity/preview-kit/client'\nimport {\n lazy,\n type ReactElement,\n type ReactNode,\n Suspense,\n useEffect,\n useState,\n useTransition,\n} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps): ReactElement {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return <>{children}</>\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactElement, type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>): ReactElement {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return <>{children}</>\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n"],"names":["isPreviewModeEnabled","preview","Boolean","token","async","sha256","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","LiveQueryProvider","lazy","import","then","m","default","_sessionStorage","_session","ResolvePreview","props","initialData","query","params","children","data","useLiveQuery","jsx","Fragment","WeakMap","exports","PreviewProvider","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","projectId","client","createClient","Provider","value","Suspense","PreviewSession","constructor","sessionStorage","session","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","has","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","isPreview","createSanityClient","options","cache","waitUntil","config","sanity","strategy","CacheLong","_ref","queryHash","hash","JSON","stringify","hashQuery","createWithCache","withCache","fetch","dataset","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","getPreview","context"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx","../src/preview/getPreview.ts"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type FilteredResponseQueryOptions,\n type QueryParams,\n type RawQueryResponse,\n type SanityClient,\n type UnfilteredResponseQueryOptions,\n} from '@sanity/preview-kit/client'\nimport {CacheLong, createWithCache} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n queryOptions?: FilteredResponseQueryOptions\n}\n\ntype useRawSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n queryOptions: UnfilteredResponseQueryOptions\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n query<T>(options: useRawSanityQuery): Promise<RawQueryResponse<T>>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({\n query,\n params,\n cache: strategy = CacheLong(),\n queryOptions,\n }: useSanityQuery | useRawSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache<T | RawQueryResponse<T>>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => {\n if (!queryOptions) {\n return sanity.client.fetch(query, params)\n }\n\n // NOTE: satisfy union type\n if (queryOptions.filterResponse === false) {\n return sanity.client.fetch(query, params, queryOptions)\n }\n\n return sanity.client.fetch(query, params, queryOptions)\n })\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params, queryOptions}) => {\n if (!queryOptions) {\n return sanity.client.fetch(query, params)\n }\n\n // NOTE: satisfy union type\n if (queryOptions.filterResponse === false) {\n return sanity.client.fetch(query, params, queryOptions)\n }\n\n return sanity.client.fetch(query, params, queryOptions)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","/* eslint-disable react/require-default-props */\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {type ClientConfig, createClient} from '@sanity/preview-kit/client'\nimport {\n lazy,\n type ReactElement,\n type ReactNode,\n Suspense,\n useEffect,\n useState,\n useTransition,\n} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps): ReactElement {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return <>{children}</>\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactElement, type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>): ReactElement {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return <>{children}</>\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n"],"names":["isPreviewModeEnabled","preview","Boolean","token","async","sha256","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","LiveQueryProvider","lazy","import","then","m","default","_sessionStorage","_session","ResolvePreview","props","initialData","query","params","children","data","useLiveQuery","jsx","Fragment","WeakMap","exports","PreviewProvider","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","projectId","client","createClient","Provider","value","Suspense","PreviewSession","constructor","sessionStorage","session","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","has","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","isPreview","createSanityClient","options","cache","waitUntil","config","sanity","_ref","strategy","CacheLong","queryOptions","queryHash","hash","JSON","stringify","hashQuery","createWithCache","withCache","filterResponse","fetch","dataset","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","getPreview","context"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createClient as e}from"@sanity/preview-kit/client";import{createWithCache as t,CacheLong as r}from"@shopify/hydrogen";import{createContext as i,useContext as n,lazy as o,useTransition as a,useState as s,useEffect as c,Suspense as p}from"react";import{jsx as l,Fragment as d}from"react/jsx-runtime";import{createCookieSessionStorage as h}from"@shopify/remix-oxygen";import{useLiveQuery as u}from"@sanity/preview-kit";function f(i){const{cache:n,waitUntil:o,preview:a,config:s}=i,c={client:e(s),async query(e){let{query:i,params:a,cache:s=r()}=e;const p=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return y(r)}(i,a);return t({cache:n,waitUntil:o})(p,s,(()=>c.client.fetch(i,a)))}};return a&&(c.preview={session:a.session},a.session.has("projectId")&&(c.preview={...c.preview,projectId:s.projectId,dataset:s.dataset,token:a.token},c.client=c.client.withConfig({useCdn:!1,token:a.token,perspective:a.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r}=e;return c.client.fetch(t,r)})),c}function m(e){return Boolean(e&&e.token&&null!==e.token)}async function y(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const w=i(void 0),v=()=>n(w);function k(e){return m(e.sanity.preview)?{...e.sanity.client.config()}:void 0}const g=o((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));function S(t){const{children:r,previewConfig:i,fallback:n=r,...o}=t,[,h]=a(),[u,f]=s(!1);if(c((()=>h((()=>f(!0)))),[]),!u||!i||!i.projectId)return l(d,{children:r});const m=e(i);return l(w.Provider,{value:{projectId:i.projectId},children:l(p,{fallback:n,children:l(g,{...o,client:m,children:r})})})}var j,q,C=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},I=(e,t,r)=>(C(e,t,"read from private field"),r?r.call(e):t.get(e)),x=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},b=(e,t,r,i)=>(C(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);class T{constructor(e,t){x(this,j,void 0),x(this,q,void 0),b(this,j,e),b(this,q,t)}static async init(e,t){const r=h({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return I(this,q).has(e)}destroy(){return I(this,j).destroySession(I(this,q))}set(e,t){I(this,q).set(e,t)}commit(){return I(this,j).commitSession(I(this,q))}}function W(e){const{data:t,children:r,query:i,params:n}=e,o=Boolean(v());return"function"!=typeof r?l(d,{children:r}):o&&i?l(A,{query:i,params:n,initialData:t,children:r}):l(d,{children:r(t)})}function A(e){const{initialData:t,query:r,params:i,children:n}=e,[o]=u(t,r,i);return l(d,{children:n(o)})}j=new WeakMap,q=new WeakMap;export{S as PreviewProvider,T as PreviewSession,W as SanityPreview,f as createSanityClient,k as getPreview,m as isPreviewModeEnabled,y as sha256,v as usePreviewContext};//# sourceMappingURL=index.mjs.map
1
+ import{createClient as e}from"@sanity/preview-kit/client";import{createWithCache as t,CacheLong as r}from"@shopify/hydrogen";import{createContext as i,useContext as n,lazy as o,useTransition as a,useState as s,useEffect as c,Suspense as p}from"react";import{jsx as l,Fragment as h}from"react/jsx-runtime";import{createCookieSessionStorage as d}from"@shopify/remix-oxygen";import{useLiveQuery as u}from"@sanity/preview-kit";function f(i){const{cache:n,waitUntil:o,preview:a,config:s}=i,c={client:e(s),async query(e){let{query:i,params:a,cache:s=r(),queryOptions:p}=e;const l=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return y(r)}(i,a);return t({cache:n,waitUntil:o})(l,s,(()=>p?(p.filterResponse,c.client.fetch(i,a,p)):c.client.fetch(i,a)))}};return a&&(c.preview={session:a.session},a.session.has("projectId")&&(c.preview={...c.preview,projectId:s.projectId,dataset:s.dataset,token:a.token},c.client=c.client.withConfig({useCdn:!1,token:a.token,perspective:a.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r,queryOptions:i}=e;return i?(i.filterResponse,c.client.fetch(t,r,i)):c.client.fetch(t,r)})),c}function m(e){return Boolean(e&&e.token&&null!==e.token)}async function y(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const w=i(void 0),v=()=>n(w);function k(e){return m(e.sanity.preview)?{...e.sanity.client.config()}:void 0}const g=o((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));function q(t){const{children:r,previewConfig:i,fallback:n=r,...o}=t,[,d]=a(),[u,f]=s(!1);if(c((()=>d((()=>f(!0)))),[]),!u||!i||!i.projectId)return l(h,{children:r});const m=e(i);return l(w.Provider,{value:{projectId:i.projectId},children:l(p,{fallback:n,children:l(g,{...o,client:m,children:r})})})}var S,j,C=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},I=(e,t,r)=>(C(e,t,"read from private field"),r?r.call(e):t.get(e)),x=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},b=(e,t,r,i)=>(C(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);class O{constructor(e,t){x(this,S,void 0),x(this,j,void 0),b(this,S,e),b(this,j,t)}static async init(e,t){const r=d({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return I(this,j).has(e)}destroy(){return I(this,S).destroySession(I(this,j))}set(e,t){I(this,j).set(e,t)}commit(){return I(this,S).commitSession(I(this,j))}}function T(e){const{data:t,children:r,query:i,params:n}=e,o=Boolean(v());return"function"!=typeof r?l(h,{children:r}):o&&i?l(W,{query:i,params:n,initialData:t,children:r}):l(h,{children:r(t)})}function W(e){const{initialData:t,query:r,params:i,children:n}=e,[o]=u(t,r,i);return l(h,{children:n(o)})}S=new WeakMap,j=new WeakMap;export{q as PreviewProvider,O as PreviewSession,T as SanityPreview,f as createSanityClient,k as getPreview,m as isPreviewModeEnabled,y as sha256,v as usePreviewContext};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/getPreview.ts","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type QueryParams,\n type SanityClient,\n} from '@sanity/preview-kit/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache<T>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n","/* eslint-disable react/require-default-props */\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {type ClientConfig, createClient} from '@sanity/preview-kit/client'\nimport {\n lazy,\n type ReactElement,\n type ReactNode,\n Suspense,\n useEffect,\n useState,\n useTransition,\n} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps): ReactElement {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return <>{children}</>\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactElement, type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>): ReactElement {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return <>{children}</>\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n"],"names":["createSanityClient","options","cache","waitUntil","preview","config","sanity","client","createClient","async","query","params","strategy","CacheLong","_ref","queryHash","hash","JSON","stringify","sha256","hashQuery","createWithCache","withCache","fetch","session","has","projectId","dataset","token","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","isPreviewModeEnabled","Boolean","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","getPreview","context","LiveQueryProvider","lazy","import","then","m","default","PreviewProvider","props","children","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","jsx","Provider","value","Suspense","_sessionStorage","_session","PreviewSession","constructor","sessionStorage","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","data","isPreview","ResolvePreview","initialData","Fragment","useLiveQuery","WeakMap"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/getPreview.ts","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type FilteredResponseQueryOptions,\n type QueryParams,\n type RawQueryResponse,\n type SanityClient,\n type UnfilteredResponseQueryOptions,\n} from '@sanity/preview-kit/client'\nimport {CacheLong, createWithCache} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n queryOptions?: FilteredResponseQueryOptions\n}\n\ntype useRawSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n queryOptions: UnfilteredResponseQueryOptions\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n query<T>(options: useRawSanityQuery): Promise<RawQueryResponse<T>>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({\n query,\n params,\n cache: strategy = CacheLong(),\n queryOptions,\n }: useSanityQuery | useRawSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache<T | RawQueryResponse<T>>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => {\n if (!queryOptions) {\n return sanity.client.fetch(query, params)\n }\n\n // NOTE: satisfy union type\n if (queryOptions.filterResponse === false) {\n return sanity.client.fetch(query, params, queryOptions)\n }\n\n return sanity.client.fetch(query, params, queryOptions)\n })\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params, queryOptions}) => {\n if (!queryOptions) {\n return sanity.client.fetch(query, params)\n }\n\n // NOTE: satisfy union type\n if (queryOptions.filterResponse === false) {\n return sanity.client.fetch(query, params, queryOptions)\n }\n\n return sanity.client.fetch(query, params, queryOptions)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n","/* eslint-disable react/require-default-props */\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {type ClientConfig, createClient} from '@sanity/preview-kit/client'\nimport {\n lazy,\n type ReactElement,\n type ReactNode,\n Suspense,\n useEffect,\n useState,\n useTransition,\n} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps): ReactElement {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return <>{children}</>\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactElement, type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>): ReactElement {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return <>{children}</>\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n"],"names":["createSanityClient","options","cache","waitUntil","preview","config","sanity","client","createClient","async","_ref","query","params","strategy","CacheLong","queryOptions","queryHash","hash","JSON","stringify","sha256","hashQuery","createWithCache","withCache","filterResponse","fetch","session","has","projectId","dataset","token","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","isPreviewModeEnabled","Boolean","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","getPreview","context","LiveQueryProvider","lazy","import","then","m","default","PreviewProvider","props","children","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","jsx","Provider","value","Suspense","_sessionStorage","_session","PreviewSession","constructor","sessionStorage","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","data","isPreview","ResolvePreview","initialData","Fragment","useLiveQuery","WeakMap"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hydrogen-sanity",
3
- "version": "3.0.1",
3
+ "version": "3.1.1",
4
4
  "description": "Sanity.io toolkit for Hydrogen",
5
5
  "keywords": [
6
6
  "sanity",
package/src/client.ts CHANGED
@@ -2,10 +2,12 @@ import {
2
2
  type ClientConfig,
3
3
  type ClientPerspective,
4
4
  createClient,
5
+ type FilteredResponseQueryOptions,
5
6
  type QueryParams,
7
+ type RawQueryResponse,
6
8
  type SanityClient,
9
+ type UnfilteredResponseQueryOptions,
7
10
  } from '@sanity/preview-kit/client'
8
- // eslint-disable-next-line camelcase
9
11
  import {CacheLong, createWithCache} from '@shopify/hydrogen'
10
12
 
11
13
  import type {PreviewSession} from './preview'
@@ -24,6 +26,14 @@ type useSanityQuery = {
24
26
  query: string
25
27
  params?: QueryParams
26
28
  cache?: CachingStrategy
29
+ queryOptions?: FilteredResponseQueryOptions
30
+ }
31
+
32
+ type useRawSanityQuery = {
33
+ query: string
34
+ params?: QueryParams
35
+ cache?: CachingStrategy
36
+ queryOptions: UnfilteredResponseQueryOptions
27
37
  }
28
38
 
29
39
  export type Sanity = {
@@ -32,6 +42,7 @@ export type Sanity = {
32
42
  | {session: PreviewSession; projectId: string; dataset: string; token: string}
33
43
  | {session: PreviewSession}
34
44
  query<T>(options: useSanityQuery): Promise<T>
45
+ query<T>(options: useRawSanityQuery): Promise<RawQueryResponse<T>>
35
46
  }
36
47
 
37
48
  /**
@@ -42,14 +53,30 @@ export function createSanityClient(options: CreateSanityClientOptions): Sanity {
42
53
 
43
54
  const sanity: Sanity = {
44
55
  client: createClient(config),
45
- async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {
56
+ async query<T = any>({
57
+ query,
58
+ params,
59
+ cache: strategy = CacheLong(),
60
+ queryOptions,
61
+ }: useSanityQuery | useRawSanityQuery) {
46
62
  const queryHash = await hashQuery(query, params)
47
- const withCache = createWithCache<T>({
63
+ const withCache = createWithCache<T | RawQueryResponse<T>>({
48
64
  cache,
49
65
  waitUntil,
50
66
  })
51
67
 
52
- return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))
68
+ return withCache(queryHash, strategy, () => {
69
+ if (!queryOptions) {
70
+ return sanity.client.fetch(query, params)
71
+ }
72
+
73
+ // NOTE: satisfy union type
74
+ if (queryOptions.filterResponse === false) {
75
+ return sanity.client.fetch(query, params, queryOptions)
76
+ }
77
+
78
+ return sanity.client.fetch(query, params, queryOptions)
79
+ })
53
80
  },
54
81
  }
55
82
 
@@ -71,8 +98,17 @@ export function createSanityClient(options: CreateSanityClientOptions): Sanity {
71
98
  ignoreBrowserTokenWarning: true,
72
99
  })
73
100
 
74
- sanity.query = ({query, params}) => {
75
- return sanity.client.fetch(query, params)
101
+ sanity.query = ({query, params, queryOptions}) => {
102
+ if (!queryOptions) {
103
+ return sanity.client.fetch(query, params)
104
+ }
105
+
106
+ // NOTE: satisfy union type
107
+ if (queryOptions.filterResponse === false) {
108
+ return sanity.client.fetch(query, params, queryOptions)
109
+ }
110
+
111
+ return sanity.client.fetch(query, params, queryOptions)
76
112
  }
77
113
  }
78
114
  }