[{"data":1,"prerenderedAt":975},["ShallowReactive",2],{"docs-\u002Fsanity":3},{"id":4,"title":5,"body":6,"description":968,"extension":969,"meta":970,"navigation":255,"path":971,"seo":972,"stem":973,"__hash__":974},"docs\u002Fdocs\u002Fsanity.md","Sanity Integration",{"type":7,"value":8,"toc":949},"minimark",[9,13,17,20,25,28,34,45,50,56,59,65,67,71,78,125,128,149,160,162,166,173,187,190,192,196,199,222,227,336,340,343,359,366,370,380,425,429,439,454,482,486,489,599,603,610,671,673,677,692,703,706,708,712,716,719,811,815,818,878,882,885,945],[10,11,5],"h1",{"id":12},"sanity-integration",[14,15,16],"p",{},"Cachely has first-class support for Sanity. It handles both image and file\u002Fvideo asset URLs and provides a response transformer that rewrites Sanity CDN URLs in your API responses.",[18,19],"hr",{},[21,22,24],"h2",{"id":23},"supported-url-patterns","Supported URL patterns",[14,26,27],{},"Sanity serves all assets from a single CDN domain with different path prefixes for images and files.",[14,29,30],{},[31,32,33],"strong",{},"Images:",[35,36,41],"pre",{"className":37,"code":39,"language":40},[38],"language-text","https:\u002F\u002Fcdn.sanity.io\u002Fimages\u002F{projectId}\u002F{dataset}\u002F{assetId}-{width}x{height}.{format}\n","text",[42,43,39],"code",{"__ignoreMap":44},"",[14,46,47],{},[31,48,49],{},"Files (video, PDF, etc.):",[35,51,54],{"className":52,"code":53,"language":40},[38],"https:\u002F\u002Fcdn.sanity.io\u002Ffiles\u002F{projectId}\u002F{dataset}\u002F{hash}.{extension}\n",[42,55,53],{"__ignoreMap":44},[14,57,58],{},"Both are rewritten to:",[35,60,63],{"className":61,"code":62,"language":40},[38],"https:\u002F\u002Fyour-tenant.cmsassets.com\u002F{assetId-or-hash}.{ext}\n",[42,64,62],{"__ignoreMap":44},[18,66],{},[21,68,70],{"id":69},"tenant-setup","Tenant setup",[14,72,73,74,77],{},"When creating your tenant, select ",[31,75,76],{},"Sanity"," as the CMS type and provide your project ID:",[79,80,81,94],"table",{},[82,83,84],"thead",{},[85,86,87,91],"tr",{},[88,89,90],"th",{},"Field",[88,92,93],{},"Value",[95,96,97,105,115],"tbody",{},[85,98,99,103],{},[100,101,102],"td",{},"CMS",[100,104,76],{},[85,106,107,110],{},[100,108,109],{},"Project ID",[100,111,112],{},[42,113,114],{},"your-project-id",[85,116,117,120],{},[100,118,119],{},"Website domain",[100,121,122],{},[42,123,124],{},"your-site.com",[14,126,127],{},"Two origins are automatically configured:",[129,130,131,141],"ul",{},[132,133,134,137,138],"li",{},[31,135,136],{},"Image origin:"," ",[42,139,140],{},"https:\u002F\u002Fcdn.sanity.io\u002Fimages\u002F{projectId}\u002Fproduction",[132,142,143,137,146],{},[31,144,145],{},"File origin:",[42,147,148],{},"https:\u002F\u002Fcdn.sanity.io\u002Ffiles\u002F{projectId}\u002Fproduction",[14,150,151,152,155,156,159],{},"The dataset defaults to ",[42,153,154],{},"production",". If your project uses a different dataset (e.g. ",[42,157,158],{},"staging","), use the custom origin override instead of the Project ID field and set both origins manually.",[18,161],{},[21,163,165],{"id":164},"file-and-video-support","File and video support",[14,167,168,169,172],{},"Sanity serves images and files from the same domain (",[42,170,171],{},"cdn.sanity.io",") using different path prefixes. Cachely handles both automatically:",[129,174,175,181],{},[132,176,177,178],{},"Image requests (jpeg, jpg, png, webp, avif, svg) route to ",[42,179,180],{},"cdn.sanity.io\u002Fimages\u002F…",[132,182,183,184],{},"File requests (mp4, webm, mov, m4v, pdf) route to ",[42,185,186],{},"cdn.sanity.io\u002Ffiles\u002F…",[14,188,189],{},"Range requests for video seeking and streaming are fully supported.",[18,191],{},[21,193,195],{"id":194},"response-transformer","Response transformer",[14,197,198],{},"Install the response transformer to automatically rewrite Sanity asset URLs in your API responses:",[35,200,204],{"className":201,"code":202,"language":203,"meta":44,"style":44},"language-bash shiki shiki-themes github-dark","npm install @synchronized-studio\u002Fresponse-transformer\n","bash",[42,205,206],{"__ignoreMap":44},[207,208,211,215,219],"span",{"class":209,"line":210},"line",1,[207,212,214],{"class":213},"svObZ","npm",[207,216,218],{"class":217},"sU2Wk"," install",[207,220,221],{"class":217}," @synchronized-studio\u002Fresponse-transformer\n",[223,224,226],"h3",{"id":225},"basic-usage","Basic usage",[35,228,232],{"className":229,"code":230,"language":231,"meta":44,"style":44},"language-typescript shiki shiki-themes github-dark","import { transformSanityAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nconst data = await sanityClient.fetch('*[_type == \"page\"]{ ..., \"imageUrl\": image.asset->url }')\n\nconst transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\",\n  cmsAssetsUrl: \"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n})\n","typescript",[42,233,234,250,257,288,293,309,321,330],{"__ignoreMap":44},[207,235,236,240,244,247],{"class":209,"line":210},[207,237,239],{"class":238},"snl16","import",[207,241,243],{"class":242},"s95oV"," { transformSanityAssetUrls } ",[207,245,246],{"class":238},"from",[207,248,249],{"class":217}," \"@synchronized-studio\u002Fresponse-transformer\"\n",[207,251,253],{"class":209,"line":252},2,[207,254,256],{"emptyLinePlaceholder":255},true,"\n",[207,258,260,263,267,270,273,276,279,282,285],{"class":209,"line":259},3,[207,261,262],{"class":238},"const",[207,264,266],{"class":265},"sDLfK"," data",[207,268,269],{"class":238}," =",[207,271,272],{"class":238}," await",[207,274,275],{"class":242}," sanityClient.",[207,277,278],{"class":213},"fetch",[207,280,281],{"class":242},"(",[207,283,284],{"class":217},"'*[_type == \"page\"]{ ..., \"imageUrl\": image.asset->url }'",[207,286,287],{"class":242},")\n",[207,289,291],{"class":209,"line":290},4,[207,292,256],{"emptyLinePlaceholder":255},[207,294,296,298,301,303,306],{"class":209,"line":295},5,[207,297,262],{"class":238},[207,299,300],{"class":265}," transformed",[207,302,269],{"class":238},[207,304,305],{"class":213}," transformSanityAssetUrls",[207,307,308],{"class":242},"(data, {\n",[207,310,312,315,318],{"class":209,"line":311},6,[207,313,314],{"class":242},"  projectId: ",[207,316,317],{"class":217},"\"your-project-id\"",[207,319,320],{"class":242},",\n",[207,322,324,327],{"class":209,"line":323},7,[207,325,326],{"class":242},"  cmsAssetsUrl: ",[207,328,329],{"class":217},"\"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n",[207,331,333],{"class":209,"line":332},8,[207,334,335],{"class":242},"})\n",[223,337,339],{"id":338},"what-gets-transformed","What gets transformed",[14,341,342],{},"The transformer processes the entire JSON response and rewrites all matching URLs. This includes:",[129,344,345,351,356],{},[132,346,347,348,350],{},"Resolved image asset URLs (",[42,349,180],{},")",[132,352,353,354,350],{},"Resolved file asset URLs (",[42,355,186],{},[132,357,358],{},"Any URL matching the project ID and dataset in the Sanity CDN pattern",[14,360,361,362,365],{},"Query parameters (like Sanity's image transformations ",[42,363,364],{},"?w=800&h=600&fit=crop",") are stripped during rewriting.",[223,367,369],{"id":368},"non-production-datasets","Non-production datasets",[14,371,372,373,375,376,379],{},"If your project uses a dataset other than ",[42,374,154],{},", pass the ",[42,377,378],{},"dataset"," option:",[35,381,383],{"className":229,"code":382,"language":231,"meta":44,"style":44},"const transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\",\n  dataset: \"staging\",\n  cmsAssetsUrl: \"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n})\n",[42,384,385,397,405,415,421],{"__ignoreMap":44},[207,386,387,389,391,393,395],{"class":209,"line":210},[207,388,262],{"class":238},[207,390,300],{"class":265},[207,392,269],{"class":238},[207,394,305],{"class":213},[207,396,308],{"class":242},[207,398,399,401,403],{"class":209,"line":252},[207,400,314],{"class":242},[207,402,317],{"class":217},[207,404,320],{"class":242},[207,406,407,410,413],{"class":209,"line":259},[207,408,409],{"class":242},"  dataset: ",[207,411,412],{"class":217},"\"staging\"",[207,414,320],{"class":242},[207,416,417,419],{"class":209,"line":290},[207,418,326],{"class":242},[207,420,329],{"class":217},[207,422,423],{"class":209,"line":295},[207,424,335],{"class":242},[223,426,428],{"id":427},"using-an-environment-variable","Using an environment variable",[14,430,431,432,435,436,379],{},"Set ",[42,433,434],{},"CMS_ASSETS_URL"," in your environment and omit the ",[42,437,438],{},"cmsAssetsUrl",[35,440,442],{"className":201,"code":441,"language":203,"meta":44,"style":44},"CMS_ASSETS_URL=https:\u002F\u002Fyour-tenant.cmsassets.com\n",[42,443,444],{"__ignoreMap":44},[207,445,446,448,451],{"class":209,"line":210},[207,447,434],{"class":242},[207,449,450],{"class":238},"=",[207,452,453],{"class":217},"https:\u002F\u002Fyour-tenant.cmsassets.com\n",[35,455,457],{"className":229,"code":456,"language":231,"meta":44,"style":44},"const transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\"\n})\n",[42,458,459,471,478],{"__ignoreMap":44},[207,460,461,463,465,467,469],{"class":209,"line":210},[207,462,262],{"class":238},[207,464,300],{"class":265},[207,466,269],{"class":238},[207,468,305],{"class":213},[207,470,308],{"class":242},[207,472,473,475],{"class":209,"line":252},[207,474,314],{"class":242},[207,476,477],{"class":217},"\"your-project-id\"\n",[207,479,480],{"class":209,"line":259},[207,481,335],{"class":242},[223,483,485],{"id":484},"nuxt-ssr-integration","Nuxt \u002F SSR integration",[14,487,488],{},"For Nuxt or other SSR frameworks, wrap your Sanity client or API layer:",[35,490,492],{"className":229,"code":491,"language":231,"meta":44,"style":44},"\u002F\u002F composables\u002FuseSanityData.ts\nimport { transformSanityAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nexport async function useSanityData() {\n  const data = await sanityClient.fetch('*[_type == \"page\"]{ ... }')\n\n  return transformSanityAssetUrls(data, {\n    projectId: \"your-project-id\",\n    cmsAssetsUrl: useRuntimeConfig().public.cmsAssetsUrl\n  })\n}\n",[42,493,494,500,510,514,531,553,557,566,575,587,593],{"__ignoreMap":44},[207,495,496],{"class":209,"line":210},[207,497,499],{"class":498},"sAwPA","\u002F\u002F composables\u002FuseSanityData.ts\n",[207,501,502,504,506,508],{"class":209,"line":252},[207,503,239],{"class":238},[207,505,243],{"class":242},[207,507,246],{"class":238},[207,509,249],{"class":217},[207,511,512],{"class":209,"line":259},[207,513,256],{"emptyLinePlaceholder":255},[207,515,516,519,522,525,528],{"class":209,"line":290},[207,517,518],{"class":238},"export",[207,520,521],{"class":238}," async",[207,523,524],{"class":238}," function",[207,526,527],{"class":213}," useSanityData",[207,529,530],{"class":242},"() {\n",[207,532,533,536,538,540,542,544,546,548,551],{"class":209,"line":295},[207,534,535],{"class":238},"  const",[207,537,266],{"class":265},[207,539,269],{"class":238},[207,541,272],{"class":238},[207,543,275],{"class":242},[207,545,278],{"class":213},[207,547,281],{"class":242},[207,549,550],{"class":217},"'*[_type == \"page\"]{ ... }'",[207,552,287],{"class":242},[207,554,555],{"class":209,"line":311},[207,556,256],{"emptyLinePlaceholder":255},[207,558,559,562,564],{"class":209,"line":323},[207,560,561],{"class":238},"  return",[207,563,305],{"class":213},[207,565,308],{"class":242},[207,567,568,571,573],{"class":209,"line":332},[207,569,570],{"class":242},"    projectId: ",[207,572,317],{"class":217},[207,574,320],{"class":242},[207,576,578,581,584],{"class":209,"line":577},9,[207,579,580],{"class":242},"    cmsAssetsUrl: ",[207,582,583],{"class":213},"useRuntimeConfig",[207,585,586],{"class":242},"().public.cmsAssetsUrl\n",[207,588,590],{"class":209,"line":589},10,[207,591,592],{"class":242},"  })\n",[207,594,596],{"class":209,"line":595},11,[207,597,598],{"class":242},"}\n",[223,600,602],{"id":601},"using-the-generic-transformer","Using the generic transformer",[14,604,605,606,609],{},"You can also use the unified ",[42,607,608],{},"transformCmsAssetUrls"," function:",[35,611,613],{"className":229,"code":612,"language":231,"meta":44,"style":44},"import { transformCmsAssetUrls } from \"@synchronized-studio\u002Fresponse-transformer\"\n\nconst transformed = transformCmsAssetUrls(data, {\n  cms: \"sanity\",\n  projectId: \"your-project-id\",\n  cmsAssetsUrl: \"https:\u002F\u002Fyour-tenant.cmsassets.com\"\n})\n",[42,614,615,626,630,643,653,661,667],{"__ignoreMap":44},[207,616,617,619,622,624],{"class":209,"line":210},[207,618,239],{"class":238},[207,620,621],{"class":242}," { transformCmsAssetUrls } ",[207,623,246],{"class":238},[207,625,249],{"class":217},[207,627,628],{"class":209,"line":252},[207,629,256],{"emptyLinePlaceholder":255},[207,631,632,634,636,638,641],{"class":209,"line":259},[207,633,262],{"class":238},[207,635,300],{"class":265},[207,637,269],{"class":238},[207,639,640],{"class":213}," transformCmsAssetUrls",[207,642,308],{"class":242},[207,644,645,648,651],{"class":209,"line":290},[207,646,647],{"class":242},"  cms: ",[207,649,650],{"class":217},"\"sanity\"",[207,652,320],{"class":242},[207,654,655,657,659],{"class":209,"line":295},[207,656,314],{"class":242},[207,658,317],{"class":217},[207,660,320],{"class":242},[207,662,663,665],{"class":209,"line":311},[207,664,326],{"class":242},[207,666,329],{"class":217},[207,668,669],{"class":209,"line":323},[207,670,335],{"class":242},[18,672],{},[21,674,676],{"id":675},"sanity-image-pipeline","Sanity Image Pipeline",[14,678,679,680,687,688,691],{},"Sanity's ",[681,682,686],"a",{"href":683,"rel":684},"https:\u002F\u002Fwww.sanity.io\u002Fdocs\u002Fimage-urls",[685],"nofollow","image pipeline"," adds query parameters like ",[42,689,690],{},"?w=800&h=600&fit=crop&auto=format"," for on-the-fly image transformations. When assets are proxied through Cachely:",[129,693,694,697,700],{},[132,695,696],{},"The edge cache strips query parameters from the cache key for image types",[132,698,699],{},"This means all image transformation variants share the same cache entry",[132,701,702],{},"If you rely on Sanity's image pipeline transformations, the first cached version will be served for all variants",[14,704,705],{},"If you need different image sizes, apply transformations on the client side or serve each size from a different path.",[18,707],{},[21,709,711],{"id":710},"advanced-options","Advanced options",[223,713,715],{"id":714},"custom-transformers","Custom transformers",[14,717,718],{},"Add additional transformers that run after the default Sanity ones:",[35,720,722],{"className":229,"code":721,"language":231,"meta":44,"style":44},"const transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\",\n  transformers: [\n    (jsonStr, { base }) => {\n      return jsonStr.replaceAll(\"old-pattern\", \"new-pattern\")\n    }\n  ]\n})\n",[42,723,724,736,744,749,773,797,802,807],{"__ignoreMap":44},[207,725,726,728,730,732,734],{"class":209,"line":210},[207,727,262],{"class":238},[207,729,300],{"class":265},[207,731,269],{"class":238},[207,733,305],{"class":213},[207,735,308],{"class":242},[207,737,738,740,742],{"class":209,"line":252},[207,739,314],{"class":242},[207,741,317],{"class":217},[207,743,320],{"class":242},[207,745,746],{"class":209,"line":259},[207,747,748],{"class":242},"  transformers: [\n",[207,750,751,754,758,761,764,767,770],{"class":209,"line":290},[207,752,753],{"class":242},"    (",[207,755,757],{"class":756},"s9osk","jsonStr",[207,759,760],{"class":242},", { ",[207,762,763],{"class":756},"base",[207,765,766],{"class":242}," }) ",[207,768,769],{"class":238},"=>",[207,771,772],{"class":242}," {\n",[207,774,775,778,781,784,786,789,792,795],{"class":209,"line":295},[207,776,777],{"class":238},"      return",[207,779,780],{"class":242}," jsonStr.",[207,782,783],{"class":213},"replaceAll",[207,785,281],{"class":242},[207,787,788],{"class":217},"\"old-pattern\"",[207,790,791],{"class":242},", ",[207,793,794],{"class":217},"\"new-pattern\"",[207,796,287],{"class":242},[207,798,799],{"class":209,"line":311},[207,800,801],{"class":242},"    }\n",[207,803,804],{"class":209,"line":323},[207,805,806],{"class":242},"  ]\n",[207,808,809],{"class":209,"line":332},[207,810,335],{"class":242},[223,812,814],{"id":813},"post-transform-hook","Post-transform hook",[14,816,817],{},"Run a function on the parsed result after all URL replacements:",[35,819,821],{"className":229,"code":820,"language":231,"meta":44,"style":44},"const transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\",\n  postTransform: (data) => {\n    return data\n  }\n})\n",[42,822,823,835,843,861,869,874],{"__ignoreMap":44},[207,824,825,827,829,831,833],{"class":209,"line":210},[207,826,262],{"class":238},[207,828,300],{"class":265},[207,830,269],{"class":238},[207,832,305],{"class":213},[207,834,308],{"class":242},[207,836,837,839,841],{"class":209,"line":252},[207,838,314],{"class":242},[207,840,317],{"class":217},[207,842,320],{"class":242},[207,844,845,848,851,854,857,859],{"class":209,"line":259},[207,846,847],{"class":213},"  postTransform",[207,849,850],{"class":242},": (",[207,852,853],{"class":756},"data",[207,855,856],{"class":242},") ",[207,858,769],{"class":238},[207,860,772],{"class":242},[207,862,863,866],{"class":209,"line":290},[207,864,865],{"class":238},"    return",[207,867,868],{"class":242}," data\n",[207,870,871],{"class":209,"line":295},[207,872,873],{"class":242},"  }\n",[207,875,876],{"class":209,"line":311},[207,877,335],{"class":242},[223,879,881],{"id":880},"error-handling","Error handling",[14,883,884],{},"By default, transform errors are logged as warnings and the original data is returned unchanged. You can provide a custom error handler:",[35,886,888],{"className":229,"code":887,"language":231,"meta":44,"style":44},"const transformed = transformSanityAssetUrls(data, {\n  projectId: \"your-project-id\",\n  onError: (error) => {\n    Sentry.captureException(error)\n  }\n})\n",[42,889,890,902,910,926,937,941],{"__ignoreMap":44},[207,891,892,894,896,898,900],{"class":209,"line":210},[207,893,262],{"class":238},[207,895,300],{"class":265},[207,897,269],{"class":238},[207,899,305],{"class":213},[207,901,308],{"class":242},[207,903,904,906,908],{"class":209,"line":252},[207,905,314],{"class":242},[207,907,317],{"class":217},[207,909,320],{"class":242},[207,911,912,915,917,920,922,924],{"class":209,"line":259},[207,913,914],{"class":213},"  onError",[207,916,850],{"class":242},[207,918,919],{"class":756},"error",[207,921,856],{"class":242},[207,923,769],{"class":238},[207,925,772],{"class":242},[207,927,928,931,934],{"class":209,"line":290},[207,929,930],{"class":242},"    Sentry.",[207,932,933],{"class":213},"captureException",[207,935,936],{"class":242},"(error)\n",[207,938,939],{"class":209,"line":295},[207,940,873],{"class":242},[207,942,943],{"class":209,"line":311},[207,944,335],{"class":242},[946,947,948],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":44,"searchDepth":252,"depth":252,"links":950},[951,952,953,954,962,963],{"id":23,"depth":252,"text":24},{"id":69,"depth":252,"text":70},{"id":164,"depth":252,"text":165},{"id":194,"depth":252,"text":195,"children":955},[956,957,958,959,960,961],{"id":225,"depth":259,"text":226},{"id":338,"depth":259,"text":339},{"id":368,"depth":259,"text":369},{"id":427,"depth":259,"text":428},{"id":484,"depth":259,"text":485},{"id":601,"depth":259,"text":602},{"id":675,"depth":252,"text":676},{"id":710,"depth":252,"text":711,"children":964},[965,966,967],{"id":714,"depth":259,"text":715},{"id":813,"depth":259,"text":814},{"id":880,"depth":259,"text":881},"Proxy Sanity API requests and cdn.sanity.io assets through your own edge domain. Global caching with Sanity image pipeline parameters preserved.","md",{},"\u002Fdocs\u002Fsanity",{"title":5,"description":968},"docs\u002Fsanity","jkGGcMpLYE7zre74FkduDNi9P6Mg-W3fy9aYCv-al0w",1777579477885]