{"_id":"@21phi/hydrogen-sanity","_rev":"4-488913d0651d297e64756903f4de8a5b","name":"@21phi/hydrogen-sanity","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@21phi/hydrogen-sanity","version":"0.1.0","keywords":["sanity","sanity.io","shopify","hydrogen","remix","live","preview"],"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","_id":"@21phi/hydrogen-sanity@0.1.0","maintainers":[{"name":"sergeygridin","email":"gridin21@gmail.com"}],"homepage":"https://github.com/sanity-io/hydrogen-sanity#readme","bugs":{"url":"https://github.com/sanity-io/hydrogen-sanity/issues"},"dist":{"shasum":"8f16d0adb5ffa99c7b5f011581336ab61a695e2f","tarball":"https://registry.npmjs.org/@21phi/hydrogen-sanity/-/hydrogen-sanity-0.1.0.tgz","fileCount":48,"integrity":"sha512-ngOKuzJ+yxZAandBT7S3ofBnRu8yrGXvs4X3sf9IMoiIakZmiCHm83dVygNorki670MyO8eur2fHDCH1Aag2Hg==","signatures":[{"sig":"MEQCIFZJv2HoMdcKSQHMBL69w63qF5HD/p7FrXZhw8KCvSz3AiBmEKhIkJ3T7iIn2Mts0AjY6rpQSNrcneCAYNt2V9HXhw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116014},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":"./dist/index.js","source":"./src/index.ts","default":"./dist/index.js","require":"./dist/index.cjs"},"./groq":{"import":"./dist/groq.js","source":"./src/groq.ts","default":"./dist/groq.js","require":"./dist/groq.cjs"},"./package.json":"./package.json","./preview/route":{"import":"./dist/preview/route.js","source":"./src/preview/route.ts","default":"./dist/preview/route.js","require":"./dist/preview/route.cjs"},"./visual-editing":{"import":"./dist/visual-editing/index.js","source":"./src/visual-editing/index.ts","default":"./dist/visual-editing/index.js","require":"./dist/visual-editing/index.cjs"}},"gitHead":"269cec1d80bd9777678ccc750a699ffd2e4fba3a","scripts":{"lint":"eslint --cache .","build":"pkg build --strict --clean --check","watch":"pkg-utils watch --strict","typecheck":"tsc","link-watch":"plugin-kit link-watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"sergeygridin","email":"gridin21@gmail.com"},"repository":{"url":"git+https://github.com/21phi/hydrogen-sanity.git","type":"git"},"_npmVersion":"11.4.2","description":"Sanity.io toolkit for Hydrogen","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"groq":"^3.62.3","@sanity/client":"^6.22.2","@sanity/react-loader":"^1.10.14","@sanity/visual-editing":"^2.4.2","@sanity/preview-url-secret":"^2.0.0"},"typesVersions":{"*":{"groq":["./dist/groq.d.ts"],"preview/route":["./dist/preview/route.d.ts"],"visual-editing":["./dist/visual-editing/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","eslint":"^8.57.1","vitest":"^2.1.5","react-dom":"^18.3.1","typescript":"^5.6.3","@types/react":"^18.3.12","semantic-release":"^23.1.1","@sanity/pkg-utils":"^6.11.11","@shopify/hydrogen":"~2024.10.0","@sanity/plugin-kit":"^4.0.18","eslint-plugin-react":"^7.37.2","eslint-config-sanity":"^7.1.3","@shopify/remix-oxygen":"^2.0.9","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@typescript-eslint/parser":"^7.18.0","eslint-plugin-react-hooks":"^4.6.2","vitest-github-actions-reporter":"^0.11.1","@sanity/semantic-release-preset":"^4.1.8","@typescript-eslint/eslint-plugin":"^7.18.0","eslint-plugin-simple-import-sort":"^12.1.1"},"peerDependencies":{"groq":"^3.41.0 || ^4.0.0","react":"^18.0.0","react-dom":"^18.0.0","@sanity/client":"^6.18.0 || ^7.0.0","@shopify/hydrogen":"^2023.7.0 || ~2024.1.0 || ~2024.4.0 || ~2024.7.0 || ~2024.10.0 || ~2025.1.0 || ^2025.5.0","@shopify/remix-oxygen":"^1.0.0 || ^2.0.0 || ^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/hydrogen-sanity_0.1.0_1752639190932_0.2628969876891243","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@21phi/hydrogen-sanity","version":"0.1.1","keywords":["sanity","sanity.io","shopify","hydrogen","remix","live","preview"],"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","_id":"@21phi/hydrogen-sanity@0.1.1","maintainers":[{"name":"sergeygridin","email":"gridin21@gmail.com"}],"homepage":"https://github.com/sanity-io/hydrogen-sanity#readme","bugs":{"url":"https://github.com/sanity-io/hydrogen-sanity/issues"},"dist":{"shasum":"83b7db0aac719191a5ae39b746211632f2eb5d8f","tarball":"https://registry.npmjs.org/@21phi/hydrogen-sanity/-/hydrogen-sanity-0.1.1.tgz","fileCount":48,"integrity":"sha512-sqx+FD+ijIHh+3dsD8e5I1ExzAiJcAryjCDL5KAGYWaqNgWrFLL1NYnIiCCV1IAL6UG6Y+jCVlRDwNzb687XPg==","signatures":[{"sig":"MEYCIQD1OMnjouyRX0lFBrNi9lpf3HymN6bp7YhKutZVBLNPDgIhAJqSTosPXfV/LPX7QayqcUYiYvFJjtKiyoDabFbcusg2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116014},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":"./dist/index.js","source":"./src/index.ts","default":"./dist/index.js","require":"./dist/index.cjs"},"./groq":{"import":"./dist/groq.js","source":"./src/groq.ts","default":"./dist/groq.js","require":"./dist/groq.cjs"},"./package.json":"./package.json","./preview/route":{"import":"./dist/preview/route.js","source":"./src/preview/route.ts","default":"./dist/preview/route.js","require":"./dist/preview/route.cjs"},"./visual-editing":{"import":"./dist/visual-editing/index.js","source":"./src/visual-editing/index.ts","default":"./dist/visual-editing/index.js","require":"./dist/visual-editing/index.cjs"}},"gitHead":"269cec1d80bd9777678ccc750a699ffd2e4fba3a","scripts":{"lint":"eslint --cache .","build":"pkg build --strict --clean --check","watch":"pkg-utils watch --strict","typecheck":"tsc","link-watch":"plugin-kit link-watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"sergeygridin","email":"gridin21@gmail.com"},"repository":{"url":"git+https://github.com/21phi/hydrogen-sanity.git","type":"git"},"_npmVersion":"11.4.2","description":"Sanity.io toolkit for Hydrogen","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"groq":"^3.62.3","@sanity/client":"^6.22.2","@sanity/react-loader":"^1.10.14","@sanity/visual-editing":"^2.4.2","@sanity/preview-url-secret":"^2.0.0"},"typesVersions":{"*":{"groq":["./dist/groq.d.ts"],"preview/route":["./dist/preview/route.d.ts"],"visual-editing":["./dist/visual-editing/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","eslint":"^8.57.1","vitest":"^2.1.5","react-dom":"^18.3.1","typescript":"^5.6.3","@types/react":"^18.3.12","semantic-release":"^23.1.1","@sanity/pkg-utils":"^6.11.11","@shopify/hydrogen":"~2024.10.0","@sanity/plugin-kit":"^4.0.18","eslint-plugin-react":"^7.37.2","eslint-config-sanity":"^7.1.3","@shopify/remix-oxygen":"^2.0.9","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@typescript-eslint/parser":"^7.18.0","eslint-plugin-react-hooks":"^4.6.2","vitest-github-actions-reporter":"^0.11.1","@sanity/semantic-release-preset":"^4.1.8","@typescript-eslint/eslint-plugin":"^7.18.0","eslint-plugin-simple-import-sort":"^12.1.1"},"peerDependencies":{"groq":"^3.41.0 || ^4.0.0","react":"^18.0.0","react-dom":"^18.0.0","@sanity/client":"^6.18.0 || ^7.0.0","@shopify/hydrogen":"^2023.7.0 || ~2024.1.0 || ~2024.4.0 || ~2024.7.0 || ~2024.10.0 || ~2025.1.0 || ^2025.5.0","@shopify/remix-oxygen":"^1.0.0 || ^2.0.0 || ^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/hydrogen-sanity_0.1.1_1752639591932_0.4195487943119205","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@21phi/hydrogen-sanity","version":"0.1.2","keywords":["sanity","sanity.io","shopify","hydrogen","remix","live","preview"],"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","_id":"@21phi/hydrogen-sanity@0.1.2","maintainers":[{"name":"sergeygridin","email":"gridin21@gmail.com"}],"homepage":"https://github.com/sanity-io/hydrogen-sanity#readme","bugs":{"url":"https://github.com/sanity-io/hydrogen-sanity/issues"},"dist":{"shasum":"d9965e636333eedfd03122487dd41c46ade00146","tarball":"https://registry.npmjs.org/@21phi/hydrogen-sanity/-/hydrogen-sanity-0.1.2.tgz","fileCount":48,"integrity":"sha512-f2krdpYJq13mjVGJhCtqjp4wIVopfNEdc0cXbTtY9Pg1r3ADR3nhZ/haitK/6SYA32KrIRWHKCh/wXlnd+xcFA==","signatures":[{"sig":"MEYCIQD0df9/OQinezrctdG7olsLQUVWoXyyiwhD7rNssdA0hwIhAMSnOAHH1WbtHJhOyoocSB/Y+CJIwPx3aYlG8ALphpmE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116063},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":"./dist/index.js","source":"./src/index.ts","default":"./dist/index.js","require":"./dist/index.cjs"},"./groq":{"import":"./dist/groq.js","source":"./src/groq.ts","default":"./dist/groq.js","require":"./dist/groq.cjs"},"./package.json":"./package.json","./preview/route":{"import":"./dist/preview/route.js","source":"./src/preview/route.ts","default":"./dist/preview/route.js","require":"./dist/preview/route.cjs"},"./visual-editing":{"import":"./dist/visual-editing/index.js","source":"./src/visual-editing/index.ts","default":"./dist/visual-editing/index.js","require":"./dist/visual-editing/index.cjs"}},"gitHead":"ae4b2664d9f7f594247e6b645940fac312a86dfd","scripts":{"lint":"eslint --cache .","build":"pkg build --strict --clean --check","watch":"pkg-utils watch --strict","typecheck":"tsc","link-watch":"plugin-kit link-watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"sergeygridin","email":"gridin21@gmail.com"},"repository":{"url":"git+https://github.com/21phi/hydrogen-sanity.git","type":"git"},"_npmVersion":"11.4.2","description":"Sanity.io toolkit for Hydrogen","directories":{},"sideEffects":false,"_nodeVersion":"24.4.0","dependencies":{"groq":"^3.62.3","@sanity/client":"^6.22.2","@sanity/react-loader":"^1.10.14","@sanity/visual-editing":"^2.15.2","@sanity/preview-url-secret":"^2.0.0"},"typesVersions":{"*":{"groq":["./dist/groq.d.ts"],"preview/route":["./dist/preview/route.d.ts"],"visual-editing":["./dist/visual-editing/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.1","eslint":"^8.57.1","vitest":"^2.1.5","react-dom":"^18.3.1","typescript":"^5.6.3","@types/react":"^18.3.12","semantic-release":"^23.1.1","@sanity/pkg-utils":"^6.11.11","@shopify/hydrogen":"~2024.10.0","@sanity/plugin-kit":"^4.0.18","eslint-plugin-react":"^7.37.2","eslint-config-sanity":"^7.1.3","@shopify/remix-oxygen":"^2.0.9","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@typescript-eslint/parser":"^7.18.0","eslint-plugin-react-hooks":"^4.6.2","vitest-github-actions-reporter":"^0.11.1","@sanity/semantic-release-preset":"^4.1.8","@typescript-eslint/eslint-plugin":"^7.18.0","eslint-plugin-simple-import-sort":"^12.1.1"},"peerDependencies":{"groq":"^3.41.0 || ^4.0.0","react":"^18.0.0","react-dom":"^18.0.0","@sanity/client":"^6.18.0 || ^7.0.0","@shopify/hydrogen":"^2023.7.0 || ~2024.1.0 || ~2024.4.0 || ~2024.7.0 || ~2024.10.0 || ~2025.1.0 || ^2025.5.0","@shopify/remix-oxygen":"^1.0.0 || ^2.0.0 || ^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/hydrogen-sanity_0.1.2_1752644455847_0.2052562372607063","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@21phi/hydrogen-sanity","version":"0.2.2","description":"Sanity.io toolkit for Hydrogen","keywords":["sanity","sanity.io","shopify","hydrogen","remix","live","preview"],"homepage":"https://github.com/sanity-io/hydrogen-sanity#readme","bugs":{"url":"https://github.com/sanity-io/hydrogen-sanity/issues"},"repository":{"type":"git","url":"git+https://github.com/21phi/hydrogen-sanity.git"},"license":"MIT","author":{"name":"Sanity.io","email":"hello@sanity.io"},"sideEffects":false,"type":"module","exports":{".":{"source":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs","default":"./dist/index.js"},"./preview/route":{"source":"./src/preview/route.ts","import":"./dist/preview/route.js","require":"./dist/preview/route.cjs","default":"./dist/preview/route.js"},"./visual-editing":{"source":"./src/visual-editing/index.ts","import":"./dist/visual-editing/index.js","require":"./dist/visual-editing/index.cjs","default":"./dist/visual-editing/index.js"},"./groq":{"source":"./src/groq.ts","import":"./dist/groq.js","require":"./dist/groq.cjs","default":"./dist/groq.js"},"./package.json":"./package.json"},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","typesVersions":{"*":{"preview/route":["./dist/preview/route.d.ts"],"visual-editing":["./dist/visual-editing/index.d.ts"],"groq":["./dist/groq.d.ts"]}},"dependencies":{"@sanity/client":"^6.22.2","@sanity/preview-url-secret":"^2.0.0","@sanity/react-loader":"^1.10.14","@sanity/visual-editing":"^2.15.2","groq":"^3.62.3"},"devDependencies":{"@sanity/pkg-utils":"^6.11.11","@sanity/plugin-kit":"^4.0.18","@sanity/semantic-release-preset":"^4.1.8","@shopify/hydrogen":"~2024.10.0","@shopify/remix-oxygen":"^3.0.0","@types/react":"^18.3.12","@typescript-eslint/eslint-plugin":"^7.18.0","@typescript-eslint/parser":"^7.18.0","eslint":"^8.57.1","eslint-config-prettier":"^9.1.0","eslint-config-sanity":"^7.1.3","eslint-plugin-prettier":"^5.2.1","eslint-plugin-react":"^7.37.2","eslint-plugin-react-hooks":"^4.6.2","eslint-plugin-simple-import-sort":"^12.1.1","react":"^18.3.1","react-dom":"^18.3.1","semantic-release":"^23.1.1","typescript":"^5.6.3","vitest":"^2.1.5","vitest-github-actions-reporter":"^0.11.1"},"peerDependencies":{"@sanity/client":"^6.18.0 || ^7.0.0","@shopify/hydrogen":"^2023.7.0 || ~2024.1.0 || ~2024.4.0 || ~2024.7.0 || ~2024.10.0 || ~2025.1.0 || ^2025.5.0","@shopify/remix-oxygen":"^1.0.0 || ^2.0.0 || ^3.0.0","groq":"^3.41.0 || ^4.0.0","react":"^18.0.0","react-dom":"^18.0.0"},"engines":{"node":">=18"},"scripts":{"build":"pkg build --strict --clean --check","link-watch":"plugin-kit link-watch","lint":"eslint --cache .","typecheck":"tsc","watch":"pkg-utils watch --strict"},"_id":"@21phi/hydrogen-sanity@0.2.2","_integrity":"sha512-4Q9HTsf9awTe9fV1hk68coBGUK5hh2KK3xbyk/l4gC1GZJjigexJie7dauRUupngsuW7Vs7fAjEu8AraF2DWcA==","_resolved":"/private/var/folders/m4/1ccpwpcx7pngdcgq9xz2v7k00000gn/T/48a4d23f961f5e9b0e0a14ab9dd82a5c/21phi-hydrogen-sanity-0.2.2.tgz","_from":"file:21phi-hydrogen-sanity-0.2.2.tgz","_nodeVersion":"24.4.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-4Q9HTsf9awTe9fV1hk68coBGUK5hh2KK3xbyk/l4gC1GZJjigexJie7dauRUupngsuW7Vs7fAjEu8AraF2DWcA==","shasum":"0da0f1eae901935bf32e6949b440453fa2b91c54","tarball":"https://registry.npmjs.org/@21phi/hydrogen-sanity/-/hydrogen-sanity-0.2.2.tgz","fileCount":48,"unpackedSize":116098,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDcN+y52j6Sh0tAOVT2AzBTsmNZHuUrb72MlRaP1Aed2wIgfSJauMCCKwLC+oFao/pjYQdyC+oHPp6quQP6f9csox8="}]},"_npmUser":{"name":"sergeygridin","email":"gridin21@gmail.com"},"directories":{},"maintainers":[{"name":"sergeygridin","email":"gridin21@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/hydrogen-sanity_0.2.2_1753831247202_0.5493954866168493"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-16T04:13:10.831Z","modified":"2025-07-29T23:20:47.579Z","0.1.0":"2025-07-16T04:13:11.135Z","0.1.1":"2025-07-16T04:19:52.092Z","0.1.2":"2025-07-16T05:40:56.021Z","0.2.2":"2025-07-29T23:20:47.363Z"},"bugs":{"url":"https://github.com/sanity-io/hydrogen-sanity/issues"},"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","homepage":"https://github.com/sanity-io/hydrogen-sanity#readme","keywords":["sanity","sanity.io","shopify","hydrogen","remix","live","preview"],"repository":{"type":"git","url":"git+https://github.com/21phi/hydrogen-sanity.git"},"description":"Sanity.io toolkit for Hydrogen","maintainers":[{"name":"sergeygridin","email":"gridin21@gmail.com"}],"readme":"# hydrogen-sanity\n\n[Sanity.io](https://www.sanity.io) toolkit for [Hydrogen](https://hydrogen.shopify.dev/). Requires `@shopify/hydrogen >= 2023.7.0`.\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Satisfy TypeScript](#satisfy-typescript)\n- [Interacting with Sanity data](#interacting-with-sanity-data)\n  - [Preferred: Cached queries using `loadQuery`](#preferred-cached-queries-using-loadquery)\n  - [Additional `loadQuery` options](#additional-loadquery-options)\n  - [Alternatively: Using `client` directly](#alternatively-using-client-directly)\n- [Enable Visual Editing](#enable-visual-editing)\n  - [Enabling preview mode](#enabling-preview-mode)\n  - [Setup CORS for front-end domains](#setup-cors-for-front-end-domains)\n  - [Modify storefront's Content Security Policy (CSP)](#modify-storefronts-content-security-policy-csp)\n  - [Setup Presentation tool](#setup-presentation-tool)\n  - [Troubleshooting](#troubleshooting)\n- [Using `@sanity/client` instead of `hydrogen-sanity`](#using-sanityclient-instead-of-hydrogen-sanity)\n- [Migration Guides](#migration-guides)\n- [License](#license)\n- [Develop \\& test](#develop--test)\n  - [Release new version](#release-new-version)\n\n**Features:**\n\n- Cacheable queries to [Sanity API CDN](https://www.sanity.io/docs/api-cdn)\n- Interactive live preview with [Visual Editing](https://www.sanity.io/docs/loaders-and-overlays)\n\n> [!TIP]\n>\n> If you'd prefer a self-paced course on how to use Sanity and Hydrogen, check out the [Sanity and Shopify with Hydrogen on Sanity Learn](https://www.sanity.io/learn/course/sanity-and-shopify-with-hydrogen).\n\n> [!NOTE]\n>\n> Using this package isn't strictly required for working with Sanity in a Hydrogen storefront. If you'd like to use `@sanity/react-loader` and/or `@sanity/client` directly, see [Using `@sanity/client` directly](#using-sanityclient-directly) below.\n\n## Installation\n\n```sh\nnpm install hydrogen-sanity\n```\n\n```sh\nyarn add hydrogen-sanity\n```\n\n```sh\npnpm install hydrogen-sanity\n```\n\n## Usage\n\nUpdate the server file to include the Sanity Loader, and optionally, configure the preview mode if you plan to setup Visual Editing\n\n> [!NOTE]\n> The examples below are up-to-date as of `npm create @shopify/hydrogen@2024.7.9`\n\n```ts\n// ./lib/context.ts\n\n// ...all other imports\nimport {createSanityContext} from 'hydrogen-sanity';\n\nexport async function createAppLoadContext(\n  request: Request,\n  env: Env,\n  executionContext: ExecutionContext,\n) {\n  // ... Leave all other functions like the Hydrogen context as-is\n  const waitUntil = executionContext.waitUntil.bind(executionContext);\n  const [cache, session] = await Promise.all([\n    caches.open('hydrogen'),\n    AppSession.init(request, [env.SESSION_SECRET]),\n  ]);\n\n  // 1. Configure the Sanity Loader and preview mode\n  const sanity = createSanityContext({\n    request,\n\n    // To use the Hydrogen cache for queries\n    cache,\n    waitUntil,\n\n    // Sanity client configuration\n    client: {\n      projectId: env.SANITY_PROJECT_ID,\n      dataset: env.SANITY_DATASET || 'production',\n      apiVersion: env.SANITY_API_VERSION || 'v2024-08-08',\n      useCdn: process.env.NODE_ENV === 'production',\n\n      // In preview mode, `stega` will be enabled automatically\n      // If you need to configure the client's steganography settings,\n      // you can do so here\n      // stega: {\n      //   logger: console\n      // }\n    }),\n\n    // You can also initialize a client and pass it instead\n    // client: createClient({\n    //   projectId: env.SANITY_PROJECT_ID,\n    //   dataset: env.SANITY_DATASET,\n    //   apiVersion: env.SANITY_API_VERSION || '2023-03-30',\n    //   useCdn: process.env.NODE_ENV === 'production',\n    // }),\n\n    // Optionally, set a default cache strategy, defaults to `CacheLong`\n    // strategy: CacheShort() | null,\n\n    // Optionally, enable Visual Editing\n    // See \"Visual Editing\" section below to setup the preview route\n    // preview: env.SANITY_API_TOKEN\n    //   ? {\n    //       enabled: session.get('projectId') === env.SANITY_PROJECT_ID,\n    //       token: env.SANITY_API_TOKEN,\n    //       studioUrl: 'http://localhost:3333',\n    //     }\n    //   : undefined,\n  })\n\n  // 2. Make Sanity available to loaders and actions in the request context\n  return {\n    ...hydrogenContext,\n    sanity,\n  };\n}\n```\n\nUpdate your environment variables with settings from your Sanity project.\n\n- Copy these from [sanity.io/manage](https://sanity.io/manage)\n- or run `npx sanity@latest init --env` to fill the minimum required values from a new or existing project\n\n```sh\n# Project ID\nSANITY_PROJECT_ID=\"\"\n# Dataset name\nSANITY_DATASET=\"\"\n# (Optional) Sanity API version\nSANITY_API_VERSION=\"\"\n# Sanity token to authenticate requests in \"preview\" mode\n# must have `viewer` role or higher access\n# Create in sanity.io/manage\nSANITY_API_TOKEN=\"\"\n```\n\n### Satisfy TypeScript\n\nUpdate the environment variables in `Env` to include the ones you created above:\n\n```ts\n// ./env.d.ts\n\ndeclare global {\n  // ...other types\n\n  interface Env extends HydrogenEnv {\n    // ...other environment variables\n\n    SANITY_PROJECT_ID: string\n    SANITY_DATASET?: string\n    SANITY_API_VERSION?: string\n    SANITY_API_TOKEN: string\n  }\n}\n```\n\n## Interacting with Sanity data\n\n### Preferred: Cached queries using `loadQuery`\n\nQuery Sanity's API and use Hydrogen's cache to store the response (defaults to `CacheLong` caching strategy). While in preview mode, `loadQuery` will use `CacheNone` to prevent results from being cached.\n\n> [!TIP]\n> You can use [Sanity TypeGen tooling](https://www.sanity.io/docs/sanity-typegen) to generate TypeScript definitions for your GROQ queries.\n\nLearn more about configuring [caching in Hydrogen on the Shopify documentation](https://shopify.dev/docs/custom-storefronts/hydrogen/caching).\n\nSanity queries will appear in Hydrogen's [Subrequest Profiler](https://shopify.dev/docs/custom-storefronts/hydrogen/debugging/subrequest-profiler). By default, they're titled `Sanity query`; however, you can give your queries more descriptive titles by using the request option below.\n\n```ts\nexport async function loader({context, params}: LoaderFunctionArgs) {\n  const query = `*[_type == \"page\" && _id == $id][0]`\n  const params = {id: 'home'}\n  const initial = await context.sanity.loadQuery(query, params)\n\n  return json({initial})\n}\n```\n\n### Additional `loadQuery` options\n\nIf you need to pass any additional options to the request provide `queryOptions` like so:\n\n```ts\nconst page = await context.sanity.loadQuery<HomePage>(query, params, {\n  // Optionally customize the cache strategy for this request\n  hydrogen: {\n    cache: CacheShort(),\n    // Or disable caching for this request\n    // cache: CacheNone(),\n\n    // If you'd like to add a custom display title that will\n    // display in the subrequest profiler, you can pass that here:\n    // debug: {\n    //   displayName: 'query Homepage'\n    // },\n\n    // You can also pass a function do determine whether or not to cache the response\n    // shouldCacheResult(value){\n    //  return true\n    // },\n  },\n\n  // ...as well as other request options\n  // tag: 'home',\n  // headers: {\n  //   'Accept-Encoding': 'br, gzip, *',\n  // },\n})\n```\n\n> [!TIP]\n> You can learn more about request tagging in [the documentation](https://www.sanity.io/docs/reference-api-request-tags).\n\n### Alternatively: Using `client` directly\n\nThe Sanity client (either instantiated from your configuration or passed through directly) is also available in your app's context. It is recommended to use `loadQuery` for data fetching; but the Sanity client can be used for mutations within actions, for example:\n\n```ts\nexport async function action({context, request}: ActionFunctionArgs) {\n  if (!isAuthenticated(request)) {\n    return redirect('/login')\n  }\n\n  return context.sanity\n    .withConfig({\n      token: context.env.SANITY_WRITE_TOKEN,\n    })\n    .client.create({\n      _type: 'comment',\n      text: request.body.get('text'),\n    })\n}\n```\n\n## Enable Visual Editing\n\nEnable real-time, interactive live preview inside the Presentation tool of your Sanity Studio. `hydrogen-sanity` comes with a ready-to-use version of the `VisualEditing` component that's compatible with Hydrogen and Oxygen.\n\n> [!NOTE]\n>\n> These instructions assume some familiarity with Sanity's Visual Editing concepts, like loaders and overlays. To learn more, please visit the [Visual Editing documentation](https://www.sanity.io/docs/introduction-to-visual-editing).\n\nFirst set up your root route to enable preview mode across the entire application, if the preview session is active:\n\n```tsx\n// ./app/root.tsx\n\n// ...other imports\nimport {VisualEditing} from 'hydrogen-sanity/visual-editing'\n\nexport async function loader({context}: LoaderArgs) {\n  return json({\n    // ... other loader data\n    isPreviewEnabled: context.sanity.preview?.enabled,\n  })\n}\n\nexport function Layout({children}: {children?: React.ReactNode}) {\n  const nonce = useNonce()\n  const data = useRouteLoaderData<RootLoader>('root')\n\n  return (\n    <html lang=\"en\">\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n        <Meta />\n        <Links />\n      </head>\n      <body>\n        {/* ...rest of the root layout */}\n\n        {/* Conditionally render `VisualEditing` component only when in preview mode */}\n        {data?.isPreviewEnabled ? <VisualEditing /> : null}\n\n        <ScrollRestoration nonce={nonce} />\n        <Scripts nonce={nonce} />\n      </body>\n    </html>\n  )\n}\n```\n\nThis Visual Editing component will trigger incremental updates to draft documents from the server for users with a valid preview session. [Duplicate its source](https://github.com/sanity-io/visual-editing/blob/main/packages/visual-editing/src/remix/VisualEditing.tsx) into your own project if you wish to customize its behavior.\n\n### Enabling preview mode\n\nFor users to enter preview mode, they will need to visit a route that performs some authentication and then writes to the session.\n\n`hydrogen-sanity` comes with a preconfigured route for this purpose. It checks the value of a secret in the URL used by Presentation tool - and if valid - writes the `projectId` to the Hydrogen session.\n\n> [!NOTE]\n>\n> By default, `hydrogen-sanity` will enable stega-encoded Content Source Maps when preview mode is enabled.\n>\n> You can learn more about Content Source Maps and working with stega-encoded strings in [the documentation](https://www.sanity.io/docs/stega).\n\nAdd this route to your project like below, or view the source to copy and modify it in your project.\n\n```tsx\n// ./app/routes/api.preview.ts\n\nexport {loader} from 'hydrogen-sanity/preview/route'\n\n// Optionally, export the supplied action which will disable preview mode when POSTed to\n// export {action, loader} from 'hydrogen-sanity/preview/route'\n```\n\n### Setup CORS for front-end domains\n\nIf your Sanity Studio is not embedded in your Hydrogen App, you will need to add a CORS origin to your project for every URL where your app is hosted or running in development.\n\nAdd `http://localhost:3000` to the CORS origins in your Sanity project settings at [sanity.io/manage](https://sanity.io/manage).\n\n### Modify storefront's Content Security Policy (CSP)\n\nSince Sanity Studio's Presentation tool displays the storefront inside an iframe, you will need to adjust the Content Security Policy (CSP) in `entry.server.tsx`.\n\n> [!TIP]\n>\n> Review Hydrogen's [content security policy documentation](https://shopify.dev/docs/storefronts/headless/hydrogen/content-security-policy) to ensure your storefront is secure.\n\n```ts\n// ./app/entry.server.tsx\n\n// ...all other imports\nimport type {AppLoadContext, EntryContext} from '@shopify/remix-oxygen'\n\nexport default async function handleRequest(\n  request: Request,\n  responseStatusCode: number,\n  responseHeaders: Headers,\n  remixContext: EntryContext,\n  context: AppLoadContext,\n) {\n  const projectId = context.env.SANITY_PROJECT_ID\n  const studioHostname = context.env.SANITY_STUDIO_HOSTNAME || 'http://localhost:3333'\n  const isPreviewEnabled = context.sanity.preview?.enabled\n\n  const {nonce, header, NonceProvider} = createContentSecurityPolicy({\n    // If your storefront and Studio are on separate domains...\n    // ...allow Sanity assets loaded from the CDN to be loaded in your storefront\n    defaultSrc: ['https://cdn.sanity.io'],\n    // ...allow Studio to load your storefront in Presentation's iframe\n    frameAncestors: isPreviewEnabled ? [studioHostname] : undefined,\n\n    // If you've embedded your Studio in your storefront...\n    // ...allow Sanity assets to be loaded in your storefront and allow user avatars in Studio\n    defaultSrc: ['https://cdn.sanity.io', 'https://lh3.googleusercontent.com'],\n    // ...allow client-side requests for Studio to do realtime collaboration\n    connectSrc: [`https://${projectId}.api.sanity.io`, `wss://${projectId}.api.sanity.io`],\n    // ...allow embedded Studio to load storefront\n    frameAncestors: [`'self'`],\n  })\n\n  // ...and the rest\n}\n```\n\n### Setup Presentation tool\n\nNow in your Sanity Studio config, import the Presentation tool with the Preview URL set to the preview route you created.\n\n> [!TIP]\n>\n> Consult the Visual Editing documentation for how to [configure the Presentation tool](https://www.sanity.io/docs/configuring-the-presentation-tool).\n\n```ts\n// ./sanity.config.ts\n\n// Add this import\nimport {presentationTool} from 'sanity/presentation'\n\nexport default defineConfig({\n  // ...all other settings\n\n  plugins: [\n    presentationTool({\n      previewUrl: {\n        // If you're hosting your storefront on a separate domain, you'll need to provide an `origin`:\n        // origin: process.env.SANITY_STUDIO_STOREFRONT_ORIGIN\n        previewMode: {\n          // This path is relative to the origin above and should match the route in your storefront that you've setup above\n          enable: '/api/preview',\n        },\n      },\n    }),\n    // ..all other plugins\n  ],\n})\n```\n\nYou should now be able to view your Hydrogen app in the Presentation tool, click to edit any Sanity content and see live updates as you make changes.\n\n> [!NOTE]\n>\n> If you're able to see Presentation working locally, but not when you've deployed your application, check that your session cookie is using `sameSite: 'none'` and `secure: true`.\n>\n> Since Presentation displays your site in an iframe, the session cookie by default won't be sent through. You can learn more about session cookie configuation in [MDN's documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value).\n\n### Troubleshooting\n\nAre you getting the following error when trying to load your storefront in the Presentation tool?\n\n> Unable to connect to visual editing. Make sure you've setup '@sanity/visual-editing' correctly\n\nPresentation will throw this error if it can't establish a connection to your storefront. Here are a few things to double-check in your setup to try and troubleshoot:\n\n1. Confirm that you've provided `preview` configuration to the Sanity context.\n2. Confirm that you've added the `VisualEditing` component to your root layout.\n3. If you've followed the instructions above, the `VisualEditing` component will be conditionally rendered if the app has been successfully put into preview mode.\n4. If you're using a session cookie, check your browser devtools and confirm that the cookie has been set as expected.\n5. Since Presentation loads your storefront in an `iframe`, double check your cookie and CSP configuration.\n\n## Using `@sanity/client` instead of `hydrogen-sanity`\n\nFor whatever reason, if you choose not to use `hydrogen-sanity` you could still configure `@sanity/react-loader` or `@sanity/client` to get Sanity content into your Hydrogen storefront.\n\nThe following example configures Sanity Client and provides it in the request context.\n\n```ts\n// ./server.ts\n\n// ...all other imports\nimport {createClient} from '@sanity/client'\n\nexport async function createAppLoadContext(\n  request: Request,\n  env: Env,\n  executionContext: ExecutionContext,\n) {\n  // ... all other functions\n  const withCache = createWithCache({cache, waitUntil, request})\n\n  // Create the Sanity Client\n  const sanity = createClient({\n    projectId: env.SANITY_PROJECT_ID,\n    dataset: env.SANITY_DATASET,\n    apiVersion: env.SANITY_API_VERSION ?? 'v2024-08-08',\n    useCdn: process.env.NODE_ENV === 'production',\n  })\n\n  // Pass it along to every request by\n  // adding it to `handleRequest`\n  return {\n    ...hydrogenContext,\n\n    sanity,\n    withCache,\n  }\n}\n```\n\nThen, in your loaders and actions you'll have access to Sanity Client in context:\n\n```ts\nexport async function loader({context, params}: LoaderArgs) {\n  const {sanity} = context\n  const homepage = await sanity.fetch(`*[_type == \"page\" && _id == $id][0]`, {id: 'home'})\n\n  return json({homepage})\n}\n```\n\nIf you want to cache your query responses in Hydrogen, you can use the [`withCache` utility](https://shopify.dev/docs/custom-storefronts/hydrogen/caching/third-party#hydrogen-s-built-in-withcache-utility):\n\n```ts\nexport async function loader({context, params}: LoaderArgs) {\n  const {withCache, sanity} = context\n\n  const homepage = await withCache('home', CacheLong(), () =>\n    sanity.fetch(`*[_type == \"page\" && _id == $id][0]`, {id: 'home'}),\n  )\n\n  return json({homepage})\n}\n```\n\n## Migration Guides\n\n- [From `v3` to `v4`](https://github.com/sanity-io/hydrogen-sanity/blob/main/package/MIGRATE-v3-to-v4.md)\n\n## License\n\n[MIT](LICENSE) © Sanity.io <hello@sanity.io>\n\n## Develop & test\n\nThis plugin uses [@sanity/pkg-utils](https://github.com/sanity-io/pkg-utils)\nwith default configuration for build & watch scripts.\n\n### Release new version\n\nRun [\"CI & Release\" workflow](https://github.com/sanity-io/hydrogen-sanity/actions/workflows/main.yml).\nMake sure to select the main branch and check \"Release new version\".\n\nSemantic release will only release on configured branches, so it is safe to run release on any branch.\n","readmeFilename":"README.md"}