hydrogen-sanity 5.1.0 → 5.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks-es/provider.js +2 -2
- package/dist/_chunks-es/provider.js.map +1 -1
- package/dist/index.d.ts +9 -11
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/vite/index.js.map +1 -1
- package/package.json +21 -15
- package/src/Query.tsx +4 -2
- package/src/context.test.ts +139 -0
- package/src/context.ts +19 -9
- package/src/image.ts +3 -5
- package/src/provider.tsx +3 -7
- package/src/vite/plugin.ts +1 -1
|
@@ -9,7 +9,7 @@ function assertSanityProviderValue(value) {
|
|
|
9
9
|
return true;
|
|
10
10
|
}
|
|
11
11
|
function useSanityProviderValue() {
|
|
12
|
-
const providerValue = globalThis[Symbol.for("Sanity Provider")];
|
|
12
|
+
const providerValue = globalThis[/* @__PURE__ */ Symbol.for("Sanity Provider")];
|
|
13
13
|
assertSanityProviderValue(providerValue);
|
|
14
14
|
return providerValue;
|
|
15
15
|
}
|
|
@@ -35,7 +35,7 @@ function Sanity(props) {
|
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
function setProviderValue(value) {
|
|
38
|
-
globalThis[Symbol.for("Sanity Provider")] = Object.freeze(value);
|
|
38
|
+
globalThis[/* @__PURE__ */ Symbol.for("Sanity Provider")] = Object.freeze(value);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export { Sanity, SanityProvider, useSanityProviderValue };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sources":["../../src/provider.tsx"],"sourcesContent":["import type {InitializedClientConfig} from '@sanity/client'\nimport type {HTMLProps, PropsWithChildren, ReactNode} from 'react'\n\n/**\n * Contains essential Sanity client configuration and preview/stega state.\n */\nexport interface SanityProviderValue
|
|
1
|
+
{"version":3,"file":"provider.js","sources":["../../src/provider.tsx"],"sourcesContent":["import type {InitializedClientConfig} from '@sanity/client'\nimport type {HTMLProps, PropsWithChildren, ReactNode} from 'react'\n\n/**\n * Contains essential Sanity client configuration and preview/stega state.\n */\nexport interface SanityProviderValue extends Required<\n Pick<InitializedClientConfig, 'projectId' | 'dataset' | 'apiHost' | 'apiVersion' | 'perspective'>\n> {\n previewEnabled: boolean\n stegaEnabled: boolean\n}\n\n/**\n * Type guard that asserts a value is a valid SanityProviderValue.\n * Throws an error if the provider value is missing or invalid.\n */\nexport function assertSanityProviderValue(value: unknown): value is SanityProviderValue {\n if (typeof value === 'undefined') {\n throw new Error(\n 'Failed to find a Sanity provider value. Did you forget to wrap your app in a `SanityProvider`?',\n )\n }\n\n return true\n}\n\n/**\n * Hook that retrieves the current Sanity provider configuration.\n * Must be used within a SanityProvider component tree.\n */\nexport function useSanityProviderValue(): SanityProviderValue {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const providerValue = (globalThis as any)[Symbol.for('Sanity Provider')]\n assertSanityProviderValue(providerValue)\n return providerValue\n}\n\n/**\n * Provider that makes Sanity configuration available to child components.\n * Serializes configuration across server-client boundary via globalThis.\n */\nexport function SanityProvider({\n value,\n children,\n}: PropsWithChildren<{value: SanityProviderValue}>): ReactNode {\n setProviderValue(value)\n return <>{children}</>\n}\n\n/**\n * Script component that hydrates Sanity configuration on the client side.\n * Injects provider configuration into the client bundle for SSR compatibility.\n */\nexport function Sanity(props: SanityProps): ReactNode {\n const providerValue = useSanityProviderValue()\n assertSanityProviderValue(providerValue)\n\n return (\n <script\n {...props}\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{\n __html: `(${setProviderValue})(${JSON.stringify(providerValue)})`,\n }}\n suppressHydrationWarning\n />\n )\n}\n\n/**\n * Props for the Sanity script component.\n * Extends HTMLScriptElement props while excluding conflicting attributes.\n */\nexport type SanityProps = Omit<\n HTMLProps<HTMLScriptElement>,\n | 'children'\n | 'async'\n | 'defer'\n | 'src'\n | 'type'\n | 'noModule'\n | 'dangerouslySetInnerHTML'\n | 'suppressHydrationWarning'\n>\n\nfunction setProviderValue(value: SanityProviderValue) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ;(globalThis as any)[Symbol.for('Sanity Provider')] = Object.freeze(value)\n}\n"],"names":[],"mappings":";;AAiBO,SAAS,0BAA0B,KAAA,EAA8C;AACtF,EAAA,IAAI,OAAO,UAAU,WAAA,EAAa;AAChC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAMO,SAAS,sBAAA,GAA8C;AAE5D,EAAA,MAAM,aAAA,GAAiB,UAAA,iBAAmB,MAAA,CAAO,GAAA,CAAI,iBAAiB,CAAC,CAAA;AACvE,EAAA,yBAAA,CAA0B,aAAa,CAAA;AACvC,EAAA,OAAO,aAAA;AACT;AAMO,SAAS,cAAA,CAAe;AAAA,EAC7B,KAAA;AAAA,EACA;AACF,CAAA,EAA+D;AAC7D,EAAA,gBAAA,CAAiB,KAAK,CAAA;AACtB,EAAA,uCAAU,QAAA,EAAS,CAAA;AACrB;AAMO,SAAS,OAAO,KAAA,EAA+B;AACpD,EAAA,MAAM,gBAAgB,sBAAA,EAAuB;AAC7C,EAAA,yBAAA,CAA0B,aAAa,CAAA;AAEvC,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MAEJ,uBAAA,EAAyB;AAAA,QACvB,QAAQ,CAAA,CAAA,EAAI,gBAAgB,KAAK,IAAA,CAAK,SAAA,CAAU,aAAa,CAAC,CAAA,CAAA;AAAA,OAChE;AAAA,MACA,wBAAA,EAAwB;AAAA;AAAA,GAC1B;AAEJ;AAkBA,SAAS,iBAAiB,KAAA,EAA4B;AAEnD,EAAC,UAAA,wBAA0B,GAAA,CAAI,iBAAiB,CAAC,CAAA,GAAI,MAAA,CAAO,OAAO,KAAK,CAAA;AAC3E;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {createDataAttribute} from '@sanity/react-loader'
|
|
|
6
6
|
import {EncodeDataAttributeFunction} from '@sanity/core-loader/encode-data-attribute'
|
|
7
7
|
import type {HTMLProps} from 'react'
|
|
8
8
|
import {HydrogenSession} from '@shopify/hydrogen'
|
|
9
|
-
import type {ImageUrlBuilder} from '@sanity/image-url
|
|
9
|
+
import type {ImageUrlBuilder} from '@sanity/image-url'
|
|
10
10
|
import type {InitializedClientConfig} from '@sanity/client'
|
|
11
11
|
import {PropsWithChildren} from 'react'
|
|
12
12
|
import {QueryParams} from '@sanity/client'
|
|
@@ -15,7 +15,7 @@ import {QueryWithoutParams} from '@sanity/client'
|
|
|
15
15
|
import {ReactNode} from 'react'
|
|
16
16
|
import {ResponseQueryOptions} from '@sanity/client'
|
|
17
17
|
import {SanityClient} from '@sanity/client'
|
|
18
|
-
import type {SanityImageSource} from '@sanity/image-url
|
|
18
|
+
import type {SanityImageSource} from '@sanity/image-url'
|
|
19
19
|
import {Session} from 'react-router'
|
|
20
20
|
import {SessionStorage} from 'react-router'
|
|
21
21
|
import {SuspenseProps} from 'react'
|
|
@@ -143,8 +143,10 @@ declare interface QueryClientProps<Result = Any, Query extends string = string>
|
|
|
143
143
|
) => ReactNode
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
export declare interface QueryProps<Result = Any, Query extends string = string>
|
|
147
|
-
|
|
146
|
+
export declare interface QueryProps<Result = Any, Query extends string = string> extends Omit<
|
|
147
|
+
QueryClientProps<Result, Query>,
|
|
148
|
+
'options'
|
|
149
|
+
> {
|
|
148
150
|
query: Query
|
|
149
151
|
params?: QueryParams | QueryWithoutParams
|
|
150
152
|
options: {
|
|
@@ -253,13 +255,9 @@ declare type SanityProps = Omit<
|
|
|
253
255
|
/**
|
|
254
256
|
* Contains essential Sanity client configuration and preview/stega state.
|
|
255
257
|
*/
|
|
256
|
-
declare interface SanityProviderValue
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
InitializedClientConfig,
|
|
260
|
-
'projectId' | 'dataset' | 'apiHost' | 'apiVersion' | 'perspective'
|
|
261
|
-
>
|
|
262
|
-
> {
|
|
258
|
+
declare interface SanityProviderValue extends Required<
|
|
259
|
+
Pick<InitializedClientConfig, 'projectId' | 'dataset' | 'apiHost' | 'apiVersion' | 'perspective'>
|
|
260
|
+
> {
|
|
263
261
|
previewEnabled: boolean
|
|
264
262
|
stegaEnabled: boolean
|
|
265
263
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isPreviewEnabled, usePreviewMode } from './preview/index.js';
|
|
|
5
5
|
import { SanityProvider, useSanityProviderValue } from './_chunks-es/provider.js';
|
|
6
6
|
export { Sanity } from './_chunks-es/provider.js';
|
|
7
7
|
import { supportsPerspectiveStack, getPerspective, hashQuery, isServer } from './_chunks-es/utils.js';
|
|
8
|
-
import createImageUrlBuilder from '@sanity/image-url';
|
|
8
|
+
import { createImageUrlBuilder } from '@sanity/image-url';
|
|
9
9
|
import { jsx } from 'react/jsx-runtime';
|
|
10
10
|
import { useQuery as useQuery$1 } from '@sanity/react-loader';
|
|
11
11
|
export { createDataAttribute, useEncodeDataAttribute } from '@sanity/react-loader';
|
|
@@ -16,6 +16,8 @@ const DEFAULT_CACHE_STRATEGY = CacheLong();
|
|
|
16
16
|
|
|
17
17
|
let didWarnAboutNoApiVersion = false;
|
|
18
18
|
let didWarnAboutNoPerspectiveSupport = false;
|
|
19
|
+
let didWarnAboutLoadQuery = false;
|
|
20
|
+
let didInitializeLoader = false;
|
|
19
21
|
async function createSanityContext(options) {
|
|
20
22
|
const { cache, waitUntil = () => Promise.resolve(), request, preview, defaultStrategy } = options;
|
|
21
23
|
const withCache = cache ? createWithCache({ cache, waitUntil, request }) : null;
|
|
@@ -57,8 +59,6 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
57
59
|
token: preview.token,
|
|
58
60
|
perspective
|
|
59
61
|
});
|
|
60
|
-
const { setServerClient } = await import('@sanity/react-loader');
|
|
61
|
-
setServerClient(client);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
const { apiHost, projectId, dataset, apiVersion } = client.config();
|
|
@@ -71,12 +71,23 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
71
71
|
perspective: client.config().perspective || "published",
|
|
72
72
|
stegaEnabled: client.config().stega?.enabled ?? false
|
|
73
73
|
};
|
|
74
|
-
|
|
74
|
+
return {
|
|
75
75
|
/**
|
|
76
76
|
* Loads a Sanity query with client-side loader support and Hydrogen cache integration.
|
|
77
77
|
* Bypasses Hydrogen cache in preview mode.
|
|
78
78
|
*/
|
|
79
79
|
async loadQuery(query, params, loaderOptions) {
|
|
80
|
+
if (!didInitializeLoader) {
|
|
81
|
+
const { setServerClient } = await import('@sanity/react-loader');
|
|
82
|
+
setServerClient(client);
|
|
83
|
+
didInitializeLoader = true;
|
|
84
|
+
}
|
|
85
|
+
if (!previewEnabled && process.env.NODE_ENV === "development" && !didWarnAboutLoadQuery) {
|
|
86
|
+
console.warn(
|
|
87
|
+
`\`loadQuery\` is being called outside of preview mode. Consider using \`query\` instead, which automatically handles both preview and production modes efficiently, or use \`fetch\`. \`loadQuery\` is intended to be called conditionally in preview and visual editing contexts.`
|
|
88
|
+
);
|
|
89
|
+
didWarnAboutLoadQuery = true;
|
|
90
|
+
}
|
|
80
91
|
if (!withCache || previewEnabled) {
|
|
81
92
|
const { loadQuery } = await import('@sanity/react-loader');
|
|
82
93
|
return await loadQuery(query, params, loaderOptions);
|
|
@@ -144,7 +155,6 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
144
155
|
);
|
|
145
156
|
}
|
|
146
157
|
};
|
|
147
|
-
return sanityContext;
|
|
148
158
|
}
|
|
149
159
|
|
|
150
160
|
function useImageUrlBuilder() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/constants.ts","../src/context.ts","../src/image.ts","../src/Query.tsx","../src/visual-editing/useQuery.tsx"],"sourcesContent":["import {CacheLong, type CachingStrategy} from '@shopify/hydrogen'\n\n/** Default Sanity API version with perspective stack support */\nexport const DEFAULT_API_VERSION = 'v2025-02-19'\n\n/** Default Hydrogen caching strategy for Sanity queries */\nexport const DEFAULT_CACHE_STRATEGY: CachingStrategy = CacheLong()\n","import {\n type Any,\n type ClientConfig,\n type ClientPerspective,\n type ClientReturn,\n createClient,\n type QueryParams,\n type QueryWithoutParams,\n type ResponseQueryOptions,\n SanityClient,\n} from '@sanity/client'\nimport type {QueryResponseInitial} from '@sanity/react-loader'\nimport {type CachingStrategy, createWithCache, type HydrogenSession} from '@shopify/hydrogen'\nimport {createElement, type PropsWithChildren, type ReactNode} from 'react'\n\nimport {DEFAULT_API_VERSION, DEFAULT_CACHE_STRATEGY} from './constants'\nimport type {SanityPreviewSession} from './preview/session'\nimport {isPreviewEnabled} from './preview/utils'\nimport {SanityProvider, type SanityProviderValue} from './provider'\nimport type {CacheActionFunctionParam, WaitUntil} from './types'\nimport {getPerspective} from './utils'\nimport {hashQuery, supportsPerspectiveStack} from './utils'\n\nlet didWarnAboutNoApiVersion = false\nlet didWarnAboutNoPerspectiveSupport = false\n\nexport type CreateSanityContextOptions = {\n request: Request\n\n cache?: Cache | undefined\n waitUntil?: WaitUntil | undefined\n\n /**\n * Sanity client or configuration to use.\n */\n client: SanityClient | ClientConfig\n\n /**\n * The default caching strategy to use for `loadQuery` subrequests.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n *\n * Defaults to `CacheLong`\n */\n defaultStrategy?: CachingStrategy | null\n\n /**\n * Configuration for enabling preview mode.\n */\n preview?: {\n token: string\n session: SanityPreviewSession | HydrogenSession\n }\n}\n\ninterface RequestInit {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n }\n}\n\ntype HydrogenResponseQueryOptions = Omit<ResponseQueryOptions, 'next' | 'cache'> & {\n hydrogen?: 'hydrogen' extends keyof RequestInit ? RequestInit['hydrogen'] : never\n}\n\nexport type LoadQueryOptions<T> = Pick<\n HydrogenResponseQueryOptions,\n 'perspective' | 'hydrogen' | 'useCdn' | 'stega' | 'headers' | 'tag'\n> & {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n\n /**\n * Whether to cache the result of the query or not.\n * @defaultValue () => true\n */\n shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean\n }\n}\n\nexport type FetchOptions<T> = HydrogenResponseQueryOptions & {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n\n /**\n * Whether to cache the result of the query or not.\n * @defaultValue () => true\n */\n shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean\n }\n}\n\nexport interface SanityContext {\n /**\n * Query Sanity using the loader.\n * @see https://www.sanity.io/docs/loaders\n */\n loadQuery<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: LoadQueryOptions<ClientReturn<Query, Result>>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>>>\n\n /**\n * Query Sanity using direct client fetch with Hydrogen caching.\n * Use this when you need direct client results without react-loader integration.\n * Automatically disables caching in preview mode for real-time updates.\n */\n fetch<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: FetchOptions<Result>,\n ): Promise<ClientReturn<Query, Result>>\n\n /**\n * Conditionally query Sanity using either loadQuery (for preview mode) or fetch (for static mode).\n * This optimizes bundle size by only loading @sanity/react-loader dependencies when in preview mode.\n */\n query<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: LoadQueryOptions<ClientReturn<Query, Result>> & FetchOptions<Result>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>> | ClientReturn<Query, Result>>\n\n /**\n * The Sanity client, automatically configured for preview mode when enabled.\n * Uses preview token, perspective, and CDN settings based on session state.\n */\n client: SanityClient\n\n preview?: CreateSanityContextOptions['preview'] & {\n /**\n * Whether preview mode is currently enabled based on session detection\n */\n enabled: boolean\n }\n\n SanityProvider: (props: PropsWithChildren<object>) => ReactNode\n}\n\n/**\n * @public\n */\nexport async function createSanityContext(\n options: CreateSanityContextOptions,\n): Promise<SanityContext> {\n const {cache, waitUntil = () => Promise.resolve(), request, preview, defaultStrategy} = options\n const withCache = cache ? createWithCache({cache, waitUntil, request}) : null\n let client =\n options.client instanceof SanityClient ? options.client : createClient(options.client)\n\n if (client.config().apiVersion === '1') {\n if (process.env.NODE_ENV === 'development' && !didWarnAboutNoApiVersion) {\n console.warn(\n `\nNo API version specified, defaulting to \\`${DEFAULT_API_VERSION}\\` which supports perspectives and Content Releases.\nYou can find the latest version in the Sanity changelog: https://www.sanity.io/changelog.\n `.trim(),\n )\n\n didWarnAboutNoApiVersion = true\n }\n\n client = client.withConfig({apiVersion: DEFAULT_API_VERSION})\n }\n\n // Determine if preview is enabled and configure the client accordingly\n let previewEnabled = false\n if (preview) {\n if (!preview.token) {\n throw new Error('Enabling preview mode requires a token.')\n }\n\n previewEnabled = isPreviewEnabled(client.config().projectId!, preview.session)\n\n if (previewEnabled) {\n const apiVersion = client.config().apiVersion\n let perspective: ClientPerspective\n if (supportsPerspectiveStack(apiVersion)) {\n perspective = getPerspective(preview.session)\n } else {\n if (process.env.NODE_ENV === 'development' && !didWarnAboutNoPerspectiveSupport) {\n console.warn(\n `API version \\`${apiVersion}\\` does not support perspective stacks. Using \\`previewDrafts\\` perspective. Consider upgrading to \\`v2025-02-19\\` or later for full perspective support.`,\n )\n\n didWarnAboutNoPerspectiveSupport = true\n }\n perspective = 'previewDrafts'\n }\n\n client = client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective,\n })\n\n // Set server client for react-loader when in preview mode\n const {setServerClient} = await import('@sanity/react-loader')\n setServerClient(client)\n }\n }\n\n // Server client will be initialized lazily on first loadQuery call\n\n const {apiHost, projectId, dataset, apiVersion} = client.config()\n const providerValue: SanityProviderValue = {\n projectId: projectId!,\n dataset: dataset!,\n apiHost,\n apiVersion: apiVersion!,\n previewEnabled,\n perspective: client.config().perspective || 'published',\n stegaEnabled: client.config().stega?.enabled ?? false,\n }\n\n const sanityContext: SanityContext = {\n /**\n * Loads a Sanity query with client-side loader support and Hydrogen cache integration.\n * Bypasses Hydrogen cache in preview mode.\n */\n async loadQuery<Result = Any, Query extends string = string>(\n query: Query,\n params: QueryParams | QueryWithoutParams,\n loaderOptions?: LoadQueryOptions<ClientReturn<Query, Result>>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>>> {\n if (!withCache || previewEnabled) {\n const {loadQuery} = await import('@sanity/react-loader')\n return await loadQuery<ClientReturn<Query, Result>>(query, params, loaderOptions)\n }\n\n const cacheStrategy =\n loaderOptions?.hydrogen?.cache || defaultStrategy || DEFAULT_CACHE_STRATEGY\n const queryHash = await hashQuery(query, params)\n const shouldCacheResult = loaderOptions?.hydrogen?.shouldCacheResult ?? (() => true)\n\n return await withCache.run(\n {cacheKey: queryHash, cacheStrategy, shouldCacheResult},\n async ({\n addDebugData,\n }: CacheActionFunctionParam): Promise<\n QueryResponseInitial<ClientReturn<Query, Result>>\n > => {\n // Name displayed in the subrequest profiler\n const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'\n\n addDebugData({\n displayName,\n })\n\n const {loadQuery} = await import('@sanity/react-loader')\n return await loadQuery<ClientReturn<Query, Result>>(query, params, loaderOptions)\n },\n )\n },\n\n /**\n * Executes a Sanity query with Hydrogen cache integration.\n * Direct client fetch without loader integration. Bypasses cache in preview mode.\n */\n async fetch<Result = Any, Query extends string = string>(\n query: Query,\n params: QueryParams | QueryWithoutParams = {},\n fetchOptions?: Pick<\n LoadQueryOptions<Result>,\n 'perspective' | 'hydrogen' | 'useCdn' | 'headers' | 'tag'\n >,\n ): Promise<ClientReturn<Query, Result>> {\n if (!withCache || previewEnabled) {\n return await client.fetch<ClientReturn<Query, Result>>(query, params, fetchOptions)\n }\n\n const cacheStrategy =\n fetchOptions?.hydrogen?.cache || defaultStrategy || DEFAULT_CACHE_STRATEGY\n const queryHash = await hashQuery(query, params)\n\n return await withCache.run(\n {cacheKey: queryHash, cacheStrategy, shouldCacheResult: () => true},\n async ({addDebugData}: CacheActionFunctionParam): Promise<ClientReturn<Query, Result>> => {\n // Name displayed in the subrequest profiler\n const displayName = fetchOptions?.hydrogen?.debug?.displayName || 'fetch Sanity'\n\n addDebugData({\n displayName,\n })\n\n return await client.fetch<ClientReturn<Query, Result>>(query, params, fetchOptions)\n },\n )\n },\n\n /**\n * Automatic query method that automatically adapts based on preview mode state.\n * Uses `loadQuery` (with client-side loader integration) when preview is enabled, `fetch` otherwise.\n * Bypasses cache in preview mode.\n */\n async query<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n queryOptions?: LoadQueryOptions<ClientReturn<Query, Result>> & FetchOptions<Result>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>> | ClientReturn<Query, Result>> {\n return await (previewEnabled ? this.loadQuery : this.fetch)(query, params, queryOptions)\n },\n\n /** The configured Sanity client instance */\n client,\n\n /** Preview configuration with session-based state, undefined when preview is not configured */\n preview: preview ? {...preview, enabled: previewEnabled} : undefined,\n\n /**\n * React Provider component that serializes Sanity configuration across server-client boundary.\n */\n SanityProvider({children}: PropsWithChildren<object>) {\n return createElement(\n SanityProvider,\n {\n value: Object.freeze(providerValue),\n },\n children,\n )\n },\n }\n\n return sanityContext\n}\n","import {default as createImageUrlBuilder} from '@sanity/image-url'\nimport type {ImageUrlBuilder} from '@sanity/image-url/lib/types/builder'\nimport type {SanityImageSource, SanityModernClientLike} from '@sanity/image-url/lib/types/types'\nimport {useMemo} from 'react'\n\nimport {useSanityProviderValue} from './provider'\n\n/**\n * Hook that returns a Sanity image URL builder configured with current provider settings.\n * Use this to create custom image transformations beyond `useImageUrl`.\n */\nexport function useImageUrlBuilder(): ImageUrlBuilder {\n const {projectId, dataset, apiHost} = useSanityProviderValue()\n return useMemo(() => {\n return createImageUrlBuilder({\n config: () => ({projectId, dataset, apiHost}),\n } as SanityModernClientLike)\n }, [apiHost, dataset, projectId])\n}\n\n/**\n * Hook that generates image URLs from Sanity image assets.\n * Returns a configured image URL builder for the given source.\n */\nexport function useImageUrl(source: SanityImageSource): ImageUrlBuilder {\n const builder = useImageUrlBuilder()\n return builder.image(source)\n}\n\nexport type {ImageUrlBuilder} from '@sanity/image-url/lib/types/builder'\nexport type * from '@sanity/image-url/lib/types/types'\n","import type {Any, ClientReturn, QueryParams, QueryWithoutParams} from '@sanity/client'\nimport type {EncodeDataAttributeFunction} from '@sanity/core-loader/encode-data-attribute'\nimport type {QueryResponseInitial} from '@sanity/react-loader'\nimport {lazy, type ReactNode, Suspense, type SuspenseProps, useSyncExternalStore} from 'react'\n\nimport type {LoadQueryOptions} from './context'\nimport {usePreviewMode} from './preview/hooks'\nimport type {QueryClientProps} from './Query.client'\nimport {isServer} from './utils'\n\n/**\n * Fallback component that renders nothing, preventing hydration mismatches.\n */\nfunction SanityQueryFallback(): ReactNode {\n return null\n}\n\n/**\n * Simple hydration store to avoid hydration mismatches.\n * Returns false on server, true on client after hydration.\n */\nfunction useIsHydrated(): boolean {\n return useSyncExternalStore(\n // eslint-disable-next-line no-empty-function\n () => () => {},\n () => true,\n () => false,\n )\n}\n\nconst QueryClient = isServer()\n ? SanityQueryFallback\n : (lazy(\n () =>\n /**\n * `lazy` expects the component as the default export\n * @see https://react.dev/reference/react/lazy\n */\n import('./Query.client'),\n ) as <Result = Any, Query extends string = string>(\n props: QueryClientProps<Result, Query>,\n ) => ReactNode)\n\nconst noopEncodeDataAttribute: EncodeDataAttributeFunction = Object.assign(() => undefined, {\n scope: () => noopEncodeDataAttribute,\n})\n\nexport interface QueryProps<Result = Any, Query extends string = string>\n extends Omit<QueryClientProps<Result, Query>, 'options'> {\n query: Query\n params?: QueryParams | QueryWithoutParams\n options: {\n initial: ClientReturn<Query, Result> | QueryResponseInitial<ClientReturn<Query, Result>>\n } & LoadQueryOptions<ClientReturn<Query, Result>>\n children: (\n data: ClientReturn<Query, Result>,\n encodeDataAttribute: EncodeDataAttributeFunction,\n ) => ReactNode\n}\n\n/**\n * Query component that provides live updates in preview mode and static data otherwise.\n *\n * @public\n */\nexport function Query<Result = Any, Query extends string = string>({\n query,\n params,\n options,\n children,\n ...suspenseProps\n}: QueryProps<Result, Query> & Omit<SuspenseProps, 'children'>): ReactNode {\n const isPreviewMode = usePreviewMode()\n const isHydrated = useIsHydrated()\n\n // If in preview mode and hydrated, render the client component\n if (isPreviewMode && isHydrated) {\n return (\n <Suspense {...suspenseProps} fallback={suspenseProps.fallback ?? <SanityQueryFallback />}>\n <QueryClient<Result, Query>\n query={query}\n params={params}\n options={options as QueryClientProps<Result, Query>['options']}\n >\n {children}\n </QueryClient>\n </Suspense>\n )\n }\n\n // Render static data in non-preview mode or during hydration\n return children(options.initial as ClientReturn<Query, Result>, noopEncodeDataAttribute)\n}\n","import {useQuery as _useQuery, type UseQueryOptionsDefinedInitial} from '@sanity/react-loader'\nimport {useEffect, useId} from 'react'\n\nimport {registerQuery} from './registry'\n\n/**\n * Automatically registers with the query detection system.\n * This enables automatic live mode detection in `VisualEditing` components.\n */\nexport function useQuery<QueryResponseResult = unknown>(\n query: string,\n params?: Record<string, unknown>,\n options?: UseQueryOptionsDefinedInitial<QueryResponseResult>,\n): ReturnType<typeof _useQuery<QueryResponseResult>> {\n // Generate stable ID for this `useQuery` instance\n const id = useId()\n\n // Register this `useQuery` instance with the detection system\n useEffect(() => {\n const unregister = registerQuery(id)\n return unregister\n }, [id])\n\n // Call the original `useQuery` with all the same arguments\n return _useQuery<QueryResponseResult>(query, params, options)\n}\n"],"names":["apiVersion","_useQuery"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/constants.ts","../src/context.ts","../src/image.ts","../src/Query.tsx","../src/visual-editing/useQuery.tsx"],"sourcesContent":["import {CacheLong, type CachingStrategy} from '@shopify/hydrogen'\n\n/** Default Sanity API version with perspective stack support */\nexport const DEFAULT_API_VERSION = 'v2025-02-19'\n\n/** Default Hydrogen caching strategy for Sanity queries */\nexport const DEFAULT_CACHE_STRATEGY: CachingStrategy = CacheLong()\n","import {\n type Any,\n type ClientConfig,\n type ClientPerspective,\n type ClientReturn,\n createClient,\n type QueryParams,\n type QueryWithoutParams,\n type ResponseQueryOptions,\n SanityClient,\n} from '@sanity/client'\nimport type {QueryResponseInitial} from '@sanity/react-loader'\nimport {type CachingStrategy, createWithCache, type HydrogenSession} from '@shopify/hydrogen'\nimport {createElement, type PropsWithChildren, type ReactNode} from 'react'\n\nimport {DEFAULT_API_VERSION, DEFAULT_CACHE_STRATEGY} from './constants'\nimport type {SanityPreviewSession} from './preview/session'\nimport {isPreviewEnabled} from './preview/utils'\nimport {SanityProvider, type SanityProviderValue} from './provider'\nimport type {CacheActionFunctionParam, WaitUntil} from './types'\nimport {getPerspective} from './utils'\nimport {hashQuery, supportsPerspectiveStack} from './utils'\n\nlet didWarnAboutNoApiVersion = false\nlet didWarnAboutNoPerspectiveSupport = false\nlet didWarnAboutLoadQuery = false\nlet didInitializeLoader = false\n\nexport type CreateSanityContextOptions = {\n request: Request\n\n cache?: Cache | undefined\n waitUntil?: WaitUntil | undefined\n\n /**\n * Sanity client or configuration to use.\n */\n client: SanityClient | ClientConfig\n\n /**\n * The default caching strategy to use for `loadQuery` subrequests.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n *\n * Defaults to `CacheLong`\n */\n defaultStrategy?: CachingStrategy | null\n\n /**\n * Configuration for enabling preview mode.\n */\n preview?: {\n token: string\n session: SanityPreviewSession | HydrogenSession\n }\n}\n\ninterface RequestInit {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n }\n}\n\ntype HydrogenResponseQueryOptions = Omit<ResponseQueryOptions, 'next' | 'cache'> & {\n hydrogen?: 'hydrogen' extends keyof RequestInit ? RequestInit['hydrogen'] : never\n}\n\nexport type LoadQueryOptions<T> = Pick<\n HydrogenResponseQueryOptions,\n 'perspective' | 'hydrogen' | 'useCdn' | 'stega' | 'headers' | 'tag'\n> & {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n\n /**\n * Whether to cache the result of the query or not.\n * @defaultValue () => true\n */\n shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean\n }\n}\n\nexport type FetchOptions<T> = HydrogenResponseQueryOptions & {\n hydrogen?: {\n /**\n * The caching strategy to use for the subrequest.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/caching#caching-strategies\n */\n cache?: CachingStrategy\n\n /**\n * Optional debugging information to be displayed in the subrequest profiler.\n * @see https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler#how-to-provide-more-debug-information-for-a-request\n */\n debug?: {\n displayName: string\n }\n\n /**\n * Whether to cache the result of the query or not.\n * @defaultValue () => true\n */\n shouldCacheResult?: (value: QueryResponseInitial<T>) => boolean\n }\n}\n\nexport interface SanityContext {\n /**\n * Query Sanity using the loader.\n * @see https://www.sanity.io/docs/loaders\n */\n loadQuery<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: LoadQueryOptions<ClientReturn<Query, Result>>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>>>\n\n /**\n * Query Sanity using direct client fetch with Hydrogen caching.\n * Use this when you need direct client results without react-loader integration.\n * Automatically disables caching in preview mode for real-time updates.\n */\n fetch<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: FetchOptions<Result>,\n ): Promise<ClientReturn<Query, Result>>\n\n /**\n * Conditionally query Sanity using either loadQuery (for preview mode) or fetch (for static mode).\n * This optimizes bundle size by only loading @sanity/react-loader dependencies when in preview mode.\n */\n query<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n options?: LoadQueryOptions<ClientReturn<Query, Result>> & FetchOptions<Result>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>> | ClientReturn<Query, Result>>\n\n /**\n * The Sanity client, automatically configured for preview mode when enabled.\n * Uses preview token, perspective, and CDN settings based on session state.\n */\n client: SanityClient\n\n preview?: CreateSanityContextOptions['preview'] & {\n /**\n * Whether preview mode is currently enabled based on session detection\n */\n enabled: boolean\n }\n\n SanityProvider: (props: PropsWithChildren<object>) => ReactNode\n}\n\n/**\n * @public\n */\nexport async function createSanityContext(\n options: CreateSanityContextOptions,\n): Promise<SanityContext> {\n const {cache, waitUntil = () => Promise.resolve(), request, preview, defaultStrategy} = options\n const withCache = cache ? createWithCache({cache, waitUntil, request}) : null\n let client =\n options.client instanceof SanityClient ? options.client : createClient(options.client)\n\n if (client.config().apiVersion === '1') {\n if (process.env.NODE_ENV === 'development' && !didWarnAboutNoApiVersion) {\n console.warn(\n `\nNo API version specified, defaulting to \\`${DEFAULT_API_VERSION}\\` which supports perspectives and Content Releases.\nYou can find the latest version in the Sanity changelog: https://www.sanity.io/changelog.\n `.trim(),\n )\n\n didWarnAboutNoApiVersion = true\n }\n\n client = client.withConfig({apiVersion: DEFAULT_API_VERSION})\n }\n\n // Determine if preview is enabled and configure the client accordingly\n let previewEnabled = false\n if (preview) {\n if (!preview.token) {\n throw new Error('Enabling preview mode requires a token.')\n }\n\n previewEnabled = isPreviewEnabled(client.config().projectId!, preview.session)\n\n if (previewEnabled) {\n const apiVersion = client.config().apiVersion\n let perspective: ClientPerspective\n if (supportsPerspectiveStack(apiVersion)) {\n perspective = getPerspective(preview.session)\n } else {\n if (process.env.NODE_ENV === 'development' && !didWarnAboutNoPerspectiveSupport) {\n console.warn(\n `API version \\`${apiVersion}\\` does not support perspective stacks. Using \\`previewDrafts\\` perspective. Consider upgrading to \\`v2025-02-19\\` or later for full perspective support.`,\n )\n\n didWarnAboutNoPerspectiveSupport = true\n }\n perspective = 'previewDrafts'\n }\n\n client = client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective,\n })\n }\n }\n\n // Server client will be initialized lazily on first loadQuery call\n const {apiHost, projectId, dataset, apiVersion} = client.config()\n const providerValue: SanityProviderValue = {\n projectId: projectId!,\n dataset: dataset!,\n apiHost,\n apiVersion: apiVersion!,\n previewEnabled,\n perspective: client.config().perspective || 'published',\n stegaEnabled: client.config().stega?.enabled ?? false,\n }\n\n return {\n /**\n * Loads a Sanity query with client-side loader support and Hydrogen cache integration.\n * Bypasses Hydrogen cache in preview mode.\n */\n async loadQuery<Result = Any, Query extends string = string>(\n query: Query,\n params: QueryParams | QueryWithoutParams,\n loaderOptions?: LoadQueryOptions<ClientReturn<Query, Result>>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>>> {\n // Lazy initialize the loader on first call with the configured client\n if (!didInitializeLoader) {\n const {setServerClient} = await import('@sanity/react-loader')\n setServerClient(client)\n didInitializeLoader = true\n }\n\n // Warn users to migrate to `query` method when using loadQuery outside preview mode\n if (!previewEnabled && process.env.NODE_ENV === 'development' && !didWarnAboutLoadQuery) {\n console.warn(\n `\\`loadQuery\\` is being called outside of preview mode. Consider using \\`query\\` instead, which automatically handles both preview and production modes efficiently, or use \\`fetch\\`. \\`loadQuery\\` is intended to be called conditionally in preview and visual editing contexts.`,\n )\n didWarnAboutLoadQuery = true\n }\n\n if (!withCache || previewEnabled) {\n const {loadQuery} = await import('@sanity/react-loader')\n return await loadQuery<ClientReturn<Query, Result>>(query, params, loaderOptions)\n }\n\n const cacheStrategy =\n loaderOptions?.hydrogen?.cache || defaultStrategy || DEFAULT_CACHE_STRATEGY\n const queryHash = await hashQuery(query, params)\n const shouldCacheResult = loaderOptions?.hydrogen?.shouldCacheResult ?? (() => true)\n\n return await withCache.run(\n {cacheKey: queryHash, cacheStrategy, shouldCacheResult},\n async ({\n addDebugData,\n }: CacheActionFunctionParam): Promise<\n QueryResponseInitial<ClientReturn<Query, Result>>\n > => {\n // Name displayed in the subrequest profiler\n const displayName = loaderOptions?.hydrogen?.debug?.displayName || 'query Sanity'\n\n addDebugData({\n displayName,\n })\n\n const {loadQuery} = await import('@sanity/react-loader')\n return await loadQuery<ClientReturn<Query, Result>>(query, params, loaderOptions)\n },\n )\n },\n\n /**\n * Executes a Sanity query with Hydrogen cache integration.\n * Direct client fetch without loader integration. Bypasses cache in preview mode.\n */\n async fetch<Result = Any, Query extends string = string>(\n query: Query,\n params: QueryParams | QueryWithoutParams = {},\n fetchOptions?: Pick<\n LoadQueryOptions<Result>,\n 'perspective' | 'hydrogen' | 'useCdn' | 'headers' | 'tag'\n >,\n ): Promise<ClientReturn<Query, Result>> {\n if (!withCache || previewEnabled) {\n return await client.fetch<ClientReturn<Query, Result>>(query, params, fetchOptions)\n }\n\n const cacheStrategy =\n fetchOptions?.hydrogen?.cache || defaultStrategy || DEFAULT_CACHE_STRATEGY\n const queryHash = await hashQuery(query, params)\n\n return await withCache.run(\n {cacheKey: queryHash, cacheStrategy, shouldCacheResult: () => true},\n async ({addDebugData}: CacheActionFunctionParam): Promise<ClientReturn<Query, Result>> => {\n // Name displayed in the subrequest profiler\n const displayName = fetchOptions?.hydrogen?.debug?.displayName || 'fetch Sanity'\n\n addDebugData({\n displayName,\n })\n\n return await client.fetch<ClientReturn<Query, Result>>(query, params, fetchOptions)\n },\n )\n },\n\n /**\n * Automatic query method that automatically adapts based on preview mode state.\n * Uses `loadQuery` (with client-side loader integration) when preview is enabled, `fetch` otherwise.\n * Bypasses cache in preview mode.\n */\n async query<Result = Any, Query extends string = string>(\n query: Query,\n params?: QueryParams | QueryWithoutParams,\n queryOptions?: LoadQueryOptions<ClientReturn<Query, Result>> & FetchOptions<Result>,\n ): Promise<QueryResponseInitial<ClientReturn<Query, Result>> | ClientReturn<Query, Result>> {\n return await (previewEnabled ? this.loadQuery : this.fetch)(query, params, queryOptions)\n },\n\n /** The configured Sanity client instance */\n client,\n\n /** Preview configuration with session-based state, undefined when preview is not configured */\n preview: preview ? {...preview, enabled: previewEnabled} : undefined,\n\n /**\n * React Provider component that serializes Sanity configuration across server-client boundary.\n */\n SanityProvider({children}: PropsWithChildren<object>) {\n return createElement(\n SanityProvider,\n {\n value: Object.freeze(providerValue),\n },\n children,\n )\n },\n } satisfies SanityContext\n}\n","import type {ImageUrlBuilder, SanityImageSource, SanityModernClientLike} from '@sanity/image-url'\nimport {createImageUrlBuilder} from '@sanity/image-url'\nimport {useMemo} from 'react'\n\nimport {useSanityProviderValue} from './provider'\n\n/**\n * Hook that returns a Sanity image URL builder configured with current provider settings.\n * Use this to create custom image transformations beyond `useImageUrl`.\n */\nexport function useImageUrlBuilder(): ImageUrlBuilder {\n const {projectId, dataset, apiHost} = useSanityProviderValue()\n return useMemo(() => {\n return createImageUrlBuilder({\n config: () => ({projectId, dataset, apiHost}),\n } as SanityModernClientLike)\n }, [apiHost, dataset, projectId])\n}\n\n/**\n * Hook that generates image URLs from Sanity image assets.\n * Returns a configured image URL builder for the given source.\n */\nexport function useImageUrl(source: SanityImageSource): ImageUrlBuilder {\n const builder = useImageUrlBuilder()\n return builder.image(source)\n}\n\nexport type * from '@sanity/image-url'\n","import type {Any, ClientReturn, QueryParams, QueryWithoutParams} from '@sanity/client'\nimport type {EncodeDataAttributeFunction} from '@sanity/core-loader/encode-data-attribute'\nimport type {QueryResponseInitial} from '@sanity/react-loader'\nimport {lazy, type ReactNode, Suspense, type SuspenseProps, useSyncExternalStore} from 'react'\n\nimport type {LoadQueryOptions} from './context'\nimport {usePreviewMode} from './preview/hooks'\nimport type {QueryClientProps} from './Query.client'\nimport {isServer} from './utils'\n\n/**\n * Fallback component that renders nothing, preventing hydration mismatches.\n */\nfunction SanityQueryFallback(): ReactNode {\n return null\n}\n\n/**\n * Simple hydration store to avoid hydration mismatches.\n * Returns false on server, true on client after hydration.\n */\nfunction useIsHydrated(): boolean {\n return useSyncExternalStore(\n // eslint-disable-next-line no-empty-function\n () => () => {},\n () => true,\n () => false,\n )\n}\n\nconst QueryClient = isServer()\n ? SanityQueryFallback\n : (lazy(\n () =>\n /**\n * `lazy` expects the component as the default export\n * @see https://react.dev/reference/react/lazy\n */\n import('./Query.client'),\n ) as <Result = Any, Query extends string = string>(\n props: QueryClientProps<Result, Query>,\n ) => ReactNode)\n\nconst noopEncodeDataAttribute: EncodeDataAttributeFunction = Object.assign(() => undefined, {\n scope: () => noopEncodeDataAttribute,\n})\n\nexport interface QueryProps<Result = Any, Query extends string = string> extends Omit<\n QueryClientProps<Result, Query>,\n 'options'\n> {\n query: Query\n params?: QueryParams | QueryWithoutParams\n options: {\n initial: ClientReturn<Query, Result> | QueryResponseInitial<ClientReturn<Query, Result>>\n } & LoadQueryOptions<ClientReturn<Query, Result>>\n children: (\n data: ClientReturn<Query, Result>,\n encodeDataAttribute: EncodeDataAttributeFunction,\n ) => ReactNode\n}\n\n/**\n * Query component that provides live updates in preview mode and static data otherwise.\n *\n * @public\n */\nexport function Query<Result = Any, Query extends string = string>({\n query,\n params,\n options,\n children,\n ...suspenseProps\n}: QueryProps<Result, Query> & Omit<SuspenseProps, 'children'>): ReactNode {\n const isPreviewMode = usePreviewMode()\n const isHydrated = useIsHydrated()\n\n // If in preview mode and hydrated, render the client component\n if (isPreviewMode && isHydrated) {\n return (\n <Suspense {...suspenseProps} fallback={suspenseProps.fallback ?? <SanityQueryFallback />}>\n <QueryClient<Result, Query>\n query={query}\n params={params}\n options={options as QueryClientProps<Result, Query>['options']}\n >\n {children}\n </QueryClient>\n </Suspense>\n )\n }\n\n // Render static data in non-preview mode or during hydration\n return children(options.initial as ClientReturn<Query, Result>, noopEncodeDataAttribute)\n}\n","import {useQuery as _useQuery, type UseQueryOptionsDefinedInitial} from '@sanity/react-loader'\nimport {useEffect, useId} from 'react'\n\nimport {registerQuery} from './registry'\n\n/**\n * Automatically registers with the query detection system.\n * This enables automatic live mode detection in `VisualEditing` components.\n */\nexport function useQuery<QueryResponseResult = unknown>(\n query: string,\n params?: Record<string, unknown>,\n options?: UseQueryOptionsDefinedInitial<QueryResponseResult>,\n): ReturnType<typeof _useQuery<QueryResponseResult>> {\n // Generate stable ID for this `useQuery` instance\n const id = useId()\n\n // Register this `useQuery` instance with the detection system\n useEffect(() => {\n const unregister = registerQuery(id)\n return unregister\n }, [id])\n\n // Call the original `useQuery` with all the same arguments\n return _useQuery<QueryResponseResult>(query, params, options)\n}\n"],"names":["apiVersion","_useQuery"],"mappings":"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"}
|
package/dist/vite/index.js
CHANGED
|
@@ -7,7 +7,7 @@ function sanity() {
|
|
|
7
7
|
ssr: {
|
|
8
8
|
optimizeDeps: {
|
|
9
9
|
// Pre-bundle Sanity dependencies for better SSR performance
|
|
10
|
-
include: ["@sanity/client"
|
|
10
|
+
include: ["@sanity/client"]
|
|
11
11
|
},
|
|
12
12
|
// Prevent externalization of Sanity dependencies to ensure proper ESM resolution
|
|
13
13
|
noExternal: ["@sanity/client"]
|
package/dist/vite/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/vite/plugin.ts"],"sourcesContent":["import type {Plugin, ResolvedConfig} from 'vite'\n\n/**\n * Vite plugin for optimizing Sanity integration in Hydrogen applications.\n * Configures SSR optimization, dependency bundling, and ESM resolution for Sanity packages.\n */\nexport function sanity(): Plugin {\n return {\n name: 'sanity',\n\n async config() {\n return {\n envPrefix: ['SANITY_STUDIO_'],\n ssr: {\n optimizeDeps: {\n // Pre-bundle Sanity dependencies for better SSR performance\n include: ['@sanity/client'
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/vite/plugin.ts"],"sourcesContent":["import type {Plugin, ResolvedConfig} from 'vite'\n\n/**\n * Vite plugin for optimizing Sanity integration in Hydrogen applications.\n * Configures SSR optimization, dependency bundling, and ESM resolution for Sanity packages.\n */\nexport function sanity(): Plugin {\n return {\n name: 'sanity',\n\n async config() {\n return {\n envPrefix: ['SANITY_STUDIO_'],\n ssr: {\n optimizeDeps: {\n // Pre-bundle Sanity dependencies for better SSR performance\n include: ['@sanity/client'],\n },\n // Prevent externalization of Sanity dependencies to ensure proper ESM resolution\n noExternal: ['@sanity/client'],\n },\n }\n },\n\n configResolved(resolvedConfig: ResolvedConfig) {\n // Force ESM resolution for transitive dependencies (specifically `rxjs`) in SSR builds\n // The Hydrogen/Oxygen plugins add 'node' conditions which cause packages like rxjs\n // to resolve to their CJS versions (dist/cjs/index.js) instead of ESM versions\n // We prepend 'es2015' and filter out 'node'/'require' to force ESM resolution\n\n // Prepend es2015 and remove node/require to force ESM resolution in SSR\n const ssrConditions = [\n 'es2015',\n ...(resolvedConfig.ssr?.resolve?.conditions || []).filter(\n (condition) => condition !== 'es2015' && condition !== 'node' && condition !== 'require',\n ),\n ]\n\n // Override SSR resolve conditions\n if (resolvedConfig.ssr?.resolve) {\n resolvedConfig.ssr.resolve.conditions = ssrConditions\n }\n\n // Handle SSR environment (modern environments API)\n if (resolvedConfig.environments?.ssr?.resolve?.conditions) {\n const envConditions = [\n 'es2015',\n ...resolvedConfig.environments.ssr.resolve.conditions.filter(\n (condition) =>\n condition !== 'es2015' && condition !== 'node' && condition !== 'require',\n ),\n ]\n resolvedConfig.environments.ssr.resolve.conditions = envConditions\n }\n },\n }\n}\n"],"names":[],"mappings":"AAMO,SAAS,MAAA,GAAiB;AAC/B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IAEN,MAAM,MAAA,GAAS;AACb,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,CAAC,gBAAgB,CAAA;AAAA,QAC5B,GAAA,EAAK;AAAA,UACH,YAAA,EAAc;AAAA;AAAA,YAEZ,OAAA,EAAS,CAAC,gBAAgB;AAAA,WAC5B;AAAA;AAAA,UAEA,UAAA,EAAY,CAAC,gBAAgB;AAAA;AAC/B,OACF;AAAA,IACF,CAAA;AAAA,IAEA,eAAe,cAAA,EAAgC;AAO7C,MAAA,MAAM,aAAA,GAAgB;AAAA,QACpB,QAAA;AAAA,QACA,IAAI,cAAA,CAAe,GAAA,EAAK,OAAA,EAAS,UAAA,IAAc,EAAC,EAAG,MAAA;AAAA,UACjD,CAAC,SAAA,KAAc,SAAA,KAAc,QAAA,IAAY,SAAA,KAAc,UAAU,SAAA,KAAc;AAAA;AACjF,OACF;AAGA,MAAA,IAAI,cAAA,CAAe,KAAK,OAAA,EAAS;AAC/B,QAAA,cAAA,CAAe,GAAA,CAAI,QAAQ,UAAA,GAAa,aAAA;AAAA,MAC1C;AAGA,MAAA,IAAI,cAAA,CAAe,YAAA,EAAc,GAAA,EAAK,OAAA,EAAS,UAAA,EAAY;AACzD,QAAA,MAAM,aAAA,GAAgB;AAAA,UACpB,QAAA;AAAA,UACA,GAAG,cAAA,CAAe,YAAA,CAAa,GAAA,CAAI,QAAQ,UAAA,CAAW,MAAA;AAAA,YACpD,CAAC,SAAA,KACC,SAAA,KAAc,QAAA,IAAY,SAAA,KAAc,UAAU,SAAA,KAAc;AAAA;AACpE,SACF;AACA,QAAA,cAAA,CAAe,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,UAAA,GAAa,aAAA;AAAA,MACvD;AAAA,IACF;AAAA,GACF;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hydrogen-sanity",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.2",
|
|
4
4
|
"description": "Sanity.io toolkit for Hydrogen",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -17,11 +17,17 @@
|
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "git+
|
|
20
|
+
"url": "git+https://github.com/sanity-io/hydrogen-sanity.git",
|
|
21
|
+
"directory": "packages/hydrogen-sanity"
|
|
21
22
|
},
|
|
22
23
|
"license": "MIT",
|
|
23
24
|
"author": "Sanity.io <hello@sanity.io>",
|
|
24
25
|
"sideEffects": false,
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/",
|
|
29
|
+
"provenance": true
|
|
30
|
+
},
|
|
25
31
|
"type": "module",
|
|
26
32
|
"exports": {
|
|
27
33
|
".": {
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
"dependencies": {
|
|
96
102
|
"@sanity/comlink": "^3.0.9",
|
|
97
103
|
"@sanity/core-loader": "^1.8.18",
|
|
98
|
-
"@sanity/image-url": "^
|
|
104
|
+
"@sanity/image-url": "^2.0.2",
|
|
99
105
|
"@sanity/presentation-comlink": "^1.0.28",
|
|
100
106
|
"@sanity/preview-url-secret": "^2.1.14",
|
|
101
107
|
"@sanity/react-loader": "^1.11.18",
|
|
@@ -103,32 +109,32 @@
|
|
|
103
109
|
"use-effect-event": "^2.0.3"
|
|
104
110
|
},
|
|
105
111
|
"devDependencies": {
|
|
106
|
-
"@eslint/eslintrc": "^3.3.
|
|
107
|
-
"@eslint/js": "^9.
|
|
108
|
-
"@rollup/plugin-node-resolve": "^16.0.
|
|
112
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
113
|
+
"@eslint/js": "^9.39.1",
|
|
114
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
109
115
|
"@sanity/client": "^7.9.0",
|
|
110
|
-
"@sanity/pkg-utils": "^
|
|
111
|
-
"@sanity/semantic-release-preset": "^
|
|
116
|
+
"@sanity/pkg-utils": "^10.1.2",
|
|
117
|
+
"@sanity/semantic-release-preset": "^6.0.0",
|
|
112
118
|
"@shopify/hydrogen": "~2025.7.0",
|
|
113
119
|
"@testing-library/react": "^16.3.0",
|
|
114
120
|
"@types/react": "^18.3.24",
|
|
115
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
116
|
-
"@typescript-eslint/parser": "^8.
|
|
117
|
-
"eslint": "^9.
|
|
121
|
+
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
|
122
|
+
"@typescript-eslint/parser": "^8.49.0",
|
|
123
|
+
"eslint": "^9.39.1",
|
|
118
124
|
"eslint-config-prettier": "^10.1.8",
|
|
119
125
|
"eslint-config-sanity": "^7.1.4",
|
|
120
126
|
"eslint-plugin-prettier": "^5.5.4",
|
|
121
127
|
"eslint-plugin-react": "^7.37.5",
|
|
122
128
|
"eslint-plugin-react-hooks": "0.0.0-experimental-f3a80361-20250911",
|
|
123
129
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
124
|
-
"groq": "^4.
|
|
130
|
+
"groq": "^4.21.0",
|
|
125
131
|
"react": "^18.3.1",
|
|
126
132
|
"react-dom": "^18.3.1",
|
|
127
133
|
"react-router": "7.9.2",
|
|
128
|
-
"semantic-release": "^
|
|
129
|
-
"typescript": "^5.9.
|
|
134
|
+
"semantic-release": "^25.0.2",
|
|
135
|
+
"typescript": "^5.9.3",
|
|
130
136
|
"vite": "^6.3.5",
|
|
131
|
-
"vitest": "^
|
|
137
|
+
"vitest": "^4.0.15"
|
|
132
138
|
},
|
|
133
139
|
"peerDependencies": {
|
|
134
140
|
"@sanity/client": "^7",
|
package/src/Query.tsx
CHANGED
|
@@ -45,8 +45,10 @@ const noopEncodeDataAttribute: EncodeDataAttributeFunction = Object.assign(() =>
|
|
|
45
45
|
scope: () => noopEncodeDataAttribute,
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
export interface QueryProps<Result = Any, Query extends string = string>
|
|
49
|
-
|
|
48
|
+
export interface QueryProps<Result = Any, Query extends string = string> extends Omit<
|
|
49
|
+
QueryClientProps<Result, Query>,
|
|
50
|
+
'options'
|
|
51
|
+
> {
|
|
50
52
|
query: Query
|
|
51
53
|
params?: QueryParams | QueryWithoutParams
|
|
52
54
|
options: {
|
package/src/context.test.ts
CHANGED
|
@@ -21,6 +21,7 @@ const cache = vi.hoisted<Cache>(() => ({
|
|
|
21
21
|
}))
|
|
22
22
|
|
|
23
23
|
const loadQuery = vi.hoisted<QueryStore['loadQuery']>(() => vi.fn().mockResolvedValue(null))
|
|
24
|
+
const setServerClient = vi.hoisted(() => vi.fn())
|
|
24
25
|
let withCache = vi.hoisted<WithCache | null>(() => null)
|
|
25
26
|
|
|
26
27
|
vi.mock('@shopify/hydrogen', async (importOriginal) => {
|
|
@@ -43,6 +44,7 @@ vi.mock('@sanity/react-loader', async (importOriginal) => {
|
|
|
43
44
|
return {
|
|
44
45
|
...module,
|
|
45
46
|
loadQuery,
|
|
47
|
+
setServerClient,
|
|
46
48
|
}
|
|
47
49
|
})
|
|
48
50
|
|
|
@@ -436,3 +438,140 @@ describe('stegaEnabled serialization', () => {
|
|
|
436
438
|
expect(Object.isFrozen(providerValue)).toBe(true)
|
|
437
439
|
})
|
|
438
440
|
})
|
|
441
|
+
|
|
442
|
+
describe('lazy-initialize loaders', () => {
|
|
443
|
+
const request = new Request('https://example.com')
|
|
444
|
+
|
|
445
|
+
beforeEach(() => {
|
|
446
|
+
vi.clearAllMocks()
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
it("shouldn't call `setServerClient` during context creation", async () => {
|
|
450
|
+
await createSanityContext({
|
|
451
|
+
request,
|
|
452
|
+
cache,
|
|
453
|
+
client,
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
expect(setServerClient).not.toHaveBeenCalled()
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('should allow `loadQuery` to be called not in preview mode', async () => {
|
|
460
|
+
const context = await createSanityContext({
|
|
461
|
+
request,
|
|
462
|
+
cache,
|
|
463
|
+
client,
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
// loadQuery should work in non-preview mode (backwards compatibility)
|
|
467
|
+
// The actual loadQuery function will be called from the mocked module
|
|
468
|
+
await context.loadQuery<boolean>(query, params)
|
|
469
|
+
|
|
470
|
+
// Verify the mock was called (actual behavior testing is done in other tests)
|
|
471
|
+
expect(loadQuery).toHaveBeenCalled()
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
it('should call `setServerClient` on first `loadQuery` invocation in preview mode', async () => {
|
|
475
|
+
const previewSession = new PreviewSession()
|
|
476
|
+
previewSession.set('projectId', projectId)
|
|
477
|
+
|
|
478
|
+
const context = await createSanityContext({
|
|
479
|
+
request,
|
|
480
|
+
cache,
|
|
481
|
+
client,
|
|
482
|
+
preview: {
|
|
483
|
+
token: 'my-token',
|
|
484
|
+
session: previewSession,
|
|
485
|
+
},
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
// First call to `loadQuery`
|
|
489
|
+
await context.loadQuery<boolean>(query, params)
|
|
490
|
+
|
|
491
|
+
// Should be called with the preview-configured client
|
|
492
|
+
// Check the most recent call
|
|
493
|
+
const latestCall = setServerClient.mock.calls[setServerClient.mock.calls.length - 1]
|
|
494
|
+
if (latestCall) {
|
|
495
|
+
const calledWithClient = latestCall[0]
|
|
496
|
+
expect(calledWithClient.config().useCdn).toBe(false)
|
|
497
|
+
expect(calledWithClient.config().token).toBe('my-token')
|
|
498
|
+
}
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
it('should display warning when `loadQuery` called outside preview mode in development', async () => {
|
|
502
|
+
const originalNodeEnv = process.env.NODE_ENV
|
|
503
|
+
process.env.NODE_ENV = 'development'
|
|
504
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
505
|
+
|
|
506
|
+
const context = await createSanityContext({
|
|
507
|
+
request,
|
|
508
|
+
cache,
|
|
509
|
+
client,
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
const callsBefore = warnSpy.mock.calls.length
|
|
513
|
+
|
|
514
|
+
await context.loadQuery<boolean>(query, params)
|
|
515
|
+
|
|
516
|
+
// Should have warned about loadQuery usage (may have other warnings too)
|
|
517
|
+
expect(warnSpy.mock.calls.length).toBeGreaterThan(callsBefore)
|
|
518
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
519
|
+
expect.stringContaining('`loadQuery` is being called outside of preview mode'),
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
const callsAfterFirst = warnSpy.mock.calls.length
|
|
523
|
+
|
|
524
|
+
// Second call should not warn again about loadQuery
|
|
525
|
+
await context.loadQuery<boolean>(query, params)
|
|
526
|
+
expect(warnSpy.mock.calls.length).toBe(callsAfterFirst)
|
|
527
|
+
|
|
528
|
+
warnSpy.mockRestore()
|
|
529
|
+
process.env.NODE_ENV = originalNodeEnv
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
it("shouldn't display warning in production", async () => {
|
|
533
|
+
const originalNodeEnv = process.env.NODE_ENV
|
|
534
|
+
process.env.NODE_ENV = 'production'
|
|
535
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
536
|
+
|
|
537
|
+
const context = await createSanityContext({
|
|
538
|
+
request,
|
|
539
|
+
cache,
|
|
540
|
+
client,
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
await context.loadQuery<boolean>(query, params)
|
|
544
|
+
|
|
545
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
546
|
+
|
|
547
|
+
warnSpy.mockRestore()
|
|
548
|
+
process.env.NODE_ENV = originalNodeEnv
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
it("shouldn't display warning when in preview mode", async () => {
|
|
552
|
+
const originalNodeEnv = process.env.NODE_ENV
|
|
553
|
+
process.env.NODE_ENV = 'development'
|
|
554
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
555
|
+
|
|
556
|
+
const previewSession = new PreviewSession()
|
|
557
|
+
previewSession.set('projectId', projectId)
|
|
558
|
+
|
|
559
|
+
const context = await createSanityContext({
|
|
560
|
+
request,
|
|
561
|
+
cache,
|
|
562
|
+
client,
|
|
563
|
+
preview: {
|
|
564
|
+
token: 'my-token',
|
|
565
|
+
session: previewSession,
|
|
566
|
+
},
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
await context.loadQuery<boolean>(query, params)
|
|
570
|
+
|
|
571
|
+
// Should not warn because we're in preview mode
|
|
572
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
573
|
+
|
|
574
|
+
warnSpy.mockRestore()
|
|
575
|
+
process.env.NODE_ENV = originalNodeEnv
|
|
576
|
+
})
|
|
577
|
+
})
|
package/src/context.ts
CHANGED
|
@@ -23,6 +23,8 @@ import {hashQuery, supportsPerspectiveStack} from './utils'
|
|
|
23
23
|
|
|
24
24
|
let didWarnAboutNoApiVersion = false
|
|
25
25
|
let didWarnAboutNoPerspectiveSupport = false
|
|
26
|
+
let didWarnAboutLoadQuery = false
|
|
27
|
+
let didInitializeLoader = false
|
|
26
28
|
|
|
27
29
|
export type CreateSanityContextOptions = {
|
|
28
30
|
request: Request
|
|
@@ -229,15 +231,10 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
229
231
|
token: preview.token,
|
|
230
232
|
perspective,
|
|
231
233
|
})
|
|
232
|
-
|
|
233
|
-
// Set server client for react-loader when in preview mode
|
|
234
|
-
const {setServerClient} = await import('@sanity/react-loader')
|
|
235
|
-
setServerClient(client)
|
|
236
234
|
}
|
|
237
235
|
}
|
|
238
236
|
|
|
239
237
|
// Server client will be initialized lazily on first loadQuery call
|
|
240
|
-
|
|
241
238
|
const {apiHost, projectId, dataset, apiVersion} = client.config()
|
|
242
239
|
const providerValue: SanityProviderValue = {
|
|
243
240
|
projectId: projectId!,
|
|
@@ -249,7 +246,7 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
249
246
|
stegaEnabled: client.config().stega?.enabled ?? false,
|
|
250
247
|
}
|
|
251
248
|
|
|
252
|
-
|
|
249
|
+
return {
|
|
253
250
|
/**
|
|
254
251
|
* Loads a Sanity query with client-side loader support and Hydrogen cache integration.
|
|
255
252
|
* Bypasses Hydrogen cache in preview mode.
|
|
@@ -259,6 +256,21 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
259
256
|
params: QueryParams | QueryWithoutParams,
|
|
260
257
|
loaderOptions?: LoadQueryOptions<ClientReturn<Query, Result>>,
|
|
261
258
|
): Promise<QueryResponseInitial<ClientReturn<Query, Result>>> {
|
|
259
|
+
// Lazy initialize the loader on first call with the configured client
|
|
260
|
+
if (!didInitializeLoader) {
|
|
261
|
+
const {setServerClient} = await import('@sanity/react-loader')
|
|
262
|
+
setServerClient(client)
|
|
263
|
+
didInitializeLoader = true
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Warn users to migrate to `query` method when using loadQuery outside preview mode
|
|
267
|
+
if (!previewEnabled && process.env.NODE_ENV === 'development' && !didWarnAboutLoadQuery) {
|
|
268
|
+
console.warn(
|
|
269
|
+
`\`loadQuery\` is being called outside of preview mode. Consider using \`query\` instead, which automatically handles both preview and production modes efficiently, or use \`fetch\`. \`loadQuery\` is intended to be called conditionally in preview and visual editing contexts.`,
|
|
270
|
+
)
|
|
271
|
+
didWarnAboutLoadQuery = true
|
|
272
|
+
}
|
|
273
|
+
|
|
262
274
|
if (!withCache || previewEnabled) {
|
|
263
275
|
const {loadQuery} = await import('@sanity/react-loader')
|
|
264
276
|
return await loadQuery<ClientReturn<Query, Result>>(query, params, loaderOptions)
|
|
@@ -355,7 +367,5 @@ You can find the latest version in the Sanity changelog: https://www.sanity.io/c
|
|
|
355
367
|
children,
|
|
356
368
|
)
|
|
357
369
|
},
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return sanityContext
|
|
370
|
+
} satisfies SanityContext
|
|
361
371
|
}
|
package/src/image.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type {SanityImageSource, SanityModernClientLike} from '@sanity/image-url/lib/types/types'
|
|
1
|
+
import type {ImageUrlBuilder, SanityImageSource, SanityModernClientLike} from '@sanity/image-url'
|
|
2
|
+
import {createImageUrlBuilder} from '@sanity/image-url'
|
|
4
3
|
import {useMemo} from 'react'
|
|
5
4
|
|
|
6
5
|
import {useSanityProviderValue} from './provider'
|
|
@@ -27,5 +26,4 @@ export function useImageUrl(source: SanityImageSource): ImageUrlBuilder {
|
|
|
27
26
|
return builder.image(source)
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
export type
|
|
31
|
-
export type * from '@sanity/image-url/lib/types/types'
|
|
29
|
+
export type * from '@sanity/image-url'
|
package/src/provider.tsx
CHANGED
|
@@ -4,13 +4,9 @@ import type {HTMLProps, PropsWithChildren, ReactNode} from 'react'
|
|
|
4
4
|
/**
|
|
5
5
|
* Contains essential Sanity client configuration and preview/stega state.
|
|
6
6
|
*/
|
|
7
|
-
export interface SanityProviderValue
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
InitializedClientConfig,
|
|
11
|
-
'projectId' | 'dataset' | 'apiHost' | 'apiVersion' | 'perspective'
|
|
12
|
-
>
|
|
13
|
-
> {
|
|
7
|
+
export interface SanityProviderValue extends Required<
|
|
8
|
+
Pick<InitializedClientConfig, 'projectId' | 'dataset' | 'apiHost' | 'apiVersion' | 'perspective'>
|
|
9
|
+
> {
|
|
14
10
|
previewEnabled: boolean
|
|
15
11
|
stegaEnabled: boolean
|
|
16
12
|
}
|
package/src/vite/plugin.ts
CHANGED
|
@@ -14,7 +14,7 @@ export function sanity(): Plugin {
|
|
|
14
14
|
ssr: {
|
|
15
15
|
optimizeDeps: {
|
|
16
16
|
// Pre-bundle Sanity dependencies for better SSR performance
|
|
17
|
-
include: ['@sanity/client'
|
|
17
|
+
include: ['@sanity/client'],
|
|
18
18
|
},
|
|
19
19
|
// Prevent externalization of Sanity dependencies to ensure proper ESM resolution
|
|
20
20
|
noExternal: ['@sanity/client'],
|