[{"data":1,"prerenderedAt":919},["ShallowReactive",2],{"navigation":3,"-guide-invalidation":57,"-guide-invalidation-surround":916},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":16},"Guide","\u002Fguide","1.guide\u002F1.index",[9,12,17,22,27,32,37,42,47,52],{"title":10,"path":6,"stem":7,"icon":11},"Getting Started","lucide:rocket",{"title":13,"path":14,"stem":15,"icon":16},"API Reference","\u002Fguide\u002Fapi","1.guide\u002F10.api","lucide:book-open",{"title":18,"path":19,"stem":20,"icon":21},"Caching Functions","\u002Fguide\u002Ffunctions","1.guide\u002F2.functions","lucide:square-function",{"title":23,"path":24,"stem":25,"icon":26},"Invalidation & Expiration","\u002Fguide\u002Finvalidation","1.guide\u002F3.invalidation","lucide:trash-2",{"title":28,"path":29,"stem":30,"icon":31},"Storage","\u002Fguide\u002Fstorage","1.guide\u002F4.storage","lucide:database",{"title":33,"path":34,"stem":35,"icon":36},"Caching HTTP Handlers","\u002Fguide\u002Fhandler","1.guide\u002F5.handler","lucide:server",{"title":38,"path":39,"stem":40,"icon":41},"Query Parameters","\u002Fguide\u002Fquery-params","1.guide\u002F6.query-params","lucide:link-2",{"title":43,"path":44,"stem":45,"icon":46},"Cookies","\u002Fguide\u002Fcookies","1.guide\u002F7.cookies","lucide:cookie",{"title":48,"path":49,"stem":50,"icon":51},"Cache-Control & Eligibility","\u002Fguide\u002Fcache-control","1.guide\u002F8.cache-control","lucide:sliders-horizontal",{"title":53,"path":54,"stem":55,"icon":56},"Incremental Static Regeneration","\u002Fguide\u002Fisr","1.guide\u002F9.isr","lucide:refresh-cw",{"id":58,"title":23,"body":59,"description":107,"extension":911,"meta":912,"navigation":913,"path":24,"seo":914,"stem":25,"__hash__":915},"content\u002F1.guide\u002F3.invalidation.md",{"type":60,"value":61,"toc":906,"icon":26},"minimark",[62,86,91,101,312,333,405,420,424,441,559,575,594,702,714,718,724,757,763,892,902],[63,64,65,66,73,74,77,78,81,82,85],"p",{},"A cached function returned by ",[67,68,69],"a",{"href":19},[70,71,72],"code",{},"defineCachedFunction"," exposes three methods for purging or refreshing its entries: ",[70,75,76],{},".invalidate()",", ",[70,79,80],{},".expire()",", and ",[70,83,84],{},".resolveKeys()",". Each takes the same arguments as the cached function. Standalone helpers cover the case where you don't have a reference to the cached function.",[87,88,90],"h2",{"id":89},"invalidate","Invalidate",[63,92,93,95,96,100],{},[70,94,76],{}," ",[97,98,99],"strong",{},"removes"," cached entries across all base prefixes. The next call re-invokes the function and waits for a fresh value.",[102,103,108],"pre",{"className":104,"code":105,"language":106,"meta":107,"style":107},"language-ts shiki shiki-themes github-light github-dark github-dark","import { defineCachedFunction } from \"ocache\";\n\nconst getUser = defineCachedFunction(async (id: string) => db.users.find(id), {\n  name: \"getUser\",\n  maxAge: 60,\n  getKey: (id) => id,\n});\n\nawait getUser(\"user-123\"); \u002F\u002F resolves and caches\n\n\u002F\u002F e.g. after the user updates their profile\nawait getUser.invalidate(\"user-123\");\n\nawait getUser(\"user-123\"); \u002F\u002F re-invokes the function, waits for the fresh value\n","ts","",[70,109,110,133,140,191,203,214,232,238,243,263,268,274,291,296],{"__ignoreMap":107},[111,112,115,119,123,126,130],"span",{"class":113,"line":114},"line",1,[111,116,118],{"class":117},"so5gQ","import",[111,120,122],{"class":121},"slsVL"," { defineCachedFunction } ",[111,124,125],{"class":117},"from",[111,127,129],{"class":128},"sfrk1"," \"ocache\"",[111,131,132],{"class":121},";\n",[111,134,136],{"class":113,"line":135},2,[111,137,139],{"emptyLinePlaceholder":138},true,"\n",[111,141,143,146,150,153,157,160,163,166,170,173,176,179,182,185,188],{"class":113,"line":142},3,[111,144,145],{"class":117},"const",[111,147,149],{"class":148},"suiK_"," getUser",[111,151,152],{"class":117}," =",[111,154,156],{"class":155},"shcOC"," defineCachedFunction",[111,158,159],{"class":121},"(",[111,161,162],{"class":117},"async",[111,164,165],{"class":121}," (",[111,167,169],{"class":168},"sQHwn","id",[111,171,172],{"class":117},":",[111,174,175],{"class":148}," string",[111,177,178],{"class":121},") ",[111,180,181],{"class":117},"=>",[111,183,184],{"class":121}," db.users.",[111,186,187],{"class":155},"find",[111,189,190],{"class":121},"(id), {\n",[111,192,194,197,200],{"class":113,"line":193},4,[111,195,196],{"class":121},"  name: ",[111,198,199],{"class":128},"\"getUser\"",[111,201,202],{"class":121},",\n",[111,204,206,209,212],{"class":113,"line":205},5,[111,207,208],{"class":121},"  maxAge: ",[111,210,211],{"class":148},"60",[111,213,202],{"class":121},[111,215,217,220,223,225,227,229],{"class":113,"line":216},6,[111,218,219],{"class":155},"  getKey",[111,221,222],{"class":121},": (",[111,224,169],{"class":168},[111,226,178],{"class":121},[111,228,181],{"class":117},[111,230,231],{"class":121}," id,\n",[111,233,235],{"class":113,"line":234},7,[111,236,237],{"class":121},"});\n",[111,239,241],{"class":113,"line":240},8,[111,242,139],{"emptyLinePlaceholder":138},[111,244,246,249,251,253,256,259],{"class":113,"line":245},9,[111,247,248],{"class":117},"await",[111,250,149],{"class":155},[111,252,159],{"class":121},[111,254,255],{"class":128},"\"user-123\"",[111,257,258],{"class":121},"); ",[111,260,262],{"class":261},"sCsY4","\u002F\u002F resolves and caches\n",[111,264,266],{"class":113,"line":265},10,[111,267,139],{"emptyLinePlaceholder":138},[111,269,271],{"class":113,"line":270},11,[111,272,273],{"class":261},"\u002F\u002F e.g. after the user updates their profile\n",[111,275,277,279,282,284,286,288],{"class":113,"line":276},12,[111,278,248],{"class":117},[111,280,281],{"class":121}," getUser.",[111,283,89],{"class":155},[111,285,159],{"class":121},[111,287,255],{"class":128},[111,289,290],{"class":121},");\n",[111,292,294],{"class":113,"line":293},13,[111,295,139],{"emptyLinePlaceholder":138},[111,297,299,301,303,305,307,309],{"class":113,"line":298},14,[111,300,248],{"class":117},[111,302,149],{"class":155},[111,304,159],{"class":121},[111,306,255],{"class":128},[111,308,258],{"class":121},[111,310,311],{"class":261},"\u002F\u002F re-invokes the function, waits for the fresh value\n",[63,313,314,315,318,319,77,322,81,325,328,329,332],{},"Use the standalone ",[70,316,317],{},"invalidateCache()"," when you don't hold a reference to the cached function — for example from a webhook or a different module. Pass the same key options (",[70,320,321],{},"name",[70,323,324],{},"getKey",[70,326,327],{},"group"," \u002F ",[70,330,331],{},"base"," if you customized them):",[102,334,336],{"className":104,"code":335,"language":106,"meta":107,"style":107},"import { invalidateCache } from \"ocache\";\n\nawait invalidateCache({\n  options: { name: \"getUser\", getKey: (id: string) => id },\n  args: [\"user-123\"],\n});\n",[70,337,338,351,355,365,391,401],{"__ignoreMap":107},[111,339,340,342,345,347,349],{"class":113,"line":114},[111,341,118],{"class":117},[111,343,344],{"class":121}," { invalidateCache } ",[111,346,125],{"class":117},[111,348,129],{"class":128},[111,350,132],{"class":121},[111,352,353],{"class":113,"line":135},[111,354,139],{"emptyLinePlaceholder":138},[111,356,357,359,362],{"class":113,"line":142},[111,358,248],{"class":117},[111,360,361],{"class":155}," invalidateCache",[111,363,364],{"class":121},"({\n",[111,366,367,370,372,374,376,378,380,382,384,386,388],{"class":113,"line":193},[111,368,369],{"class":121},"  options: { name: ",[111,371,199],{"class":128},[111,373,77],{"class":121},[111,375,324],{"class":155},[111,377,222],{"class":121},[111,379,169],{"class":168},[111,381,172],{"class":117},[111,383,175],{"class":148},[111,385,178],{"class":121},[111,387,181],{"class":117},[111,389,390],{"class":121}," id },\n",[111,392,393,396,398],{"class":113,"line":205},[111,394,395],{"class":121},"  args: [",[111,397,255],{"class":128},[111,399,400],{"class":121},"],\n",[111,402,403],{"class":113,"line":216},[111,404,237],{"class":121},[406,407,408],"important",{},[63,409,410,411,77,413,77,415,81,417,419],{},"\nThe standalone helpers rebuild the cache key from the options you pass — they can't see the original function. They must match the ",[70,412,321],{},[70,414,324],{},[70,416,327],{},[70,418,331],{}," you cached with, or they'll target a different key and no-op.",[87,421,423],{"id":422},"expire-swr-refresh","Expire (SWR refresh)",[63,425,426,427,429,430,432,433,436,437,440],{},"Where ",[70,428,76],{}," removes an entry entirely (the next call must wait for a fresh value), ",[70,431,80],{}," only marks it ",[97,434,435],{},"stale",". With SWR enabled, the stale value keeps being served — still bounded by the originally configured ",[70,438,439],{},"staleMaxAge"," window — while the next access triggers a background refresh:",[102,442,444],{"className":104,"code":443,"language":106,"meta":107,"style":107},"const getUser = defineCachedFunction(async (id: string) => db.users.find(id), {\n  name: \"getUser\",\n  maxAge: 60,\n  staleMaxAge: 300,\n  swr: true, \u002F\u002F required to actually serve stale values\n  getKey: (id) => id,\n});\n\n\u002F\u002F Next reader gets the stale value instantly; a refresh runs in the background\nawait getUser.expire(\"user-123\");\n",[70,445,446,478,486,494,504,517,531,535,539,544],{"__ignoreMap":107},[111,447,448,450,452,454,456,458,460,462,464,466,468,470,472,474,476],{"class":113,"line":114},[111,449,145],{"class":117},[111,451,149],{"class":148},[111,453,152],{"class":117},[111,455,156],{"class":155},[111,457,159],{"class":121},[111,459,162],{"class":117},[111,461,165],{"class":121},[111,463,169],{"class":168},[111,465,172],{"class":117},[111,467,175],{"class":148},[111,469,178],{"class":121},[111,471,181],{"class":117},[111,473,184],{"class":121},[111,475,187],{"class":155},[111,477,190],{"class":121},[111,479,480,482,484],{"class":113,"line":135},[111,481,196],{"class":121},[111,483,199],{"class":128},[111,485,202],{"class":121},[111,487,488,490,492],{"class":113,"line":142},[111,489,208],{"class":121},[111,491,211],{"class":148},[111,493,202],{"class":121},[111,495,496,499,502],{"class":113,"line":193},[111,497,498],{"class":121},"  staleMaxAge: ",[111,500,501],{"class":148},"300",[111,503,202],{"class":121},[111,505,506,509,512,514],{"class":113,"line":205},[111,507,508],{"class":121},"  swr: ",[111,510,511],{"class":148},"true",[111,513,77],{"class":121},[111,515,516],{"class":261},"\u002F\u002F required to actually serve stale values\n",[111,518,519,521,523,525,527,529],{"class":113,"line":216},[111,520,219],{"class":155},[111,522,222],{"class":121},[111,524,169],{"class":168},[111,526,178],{"class":121},[111,528,181],{"class":117},[111,530,231],{"class":121},[111,532,533],{"class":113,"line":234},[111,534,237],{"class":121},[111,536,537],{"class":113,"line":240},[111,538,139],{"emptyLinePlaceholder":138},[111,540,541],{"class":113,"line":245},[111,542,543],{"class":261},"\u002F\u002F Next reader gets the stale value instantly; a refresh runs in the background\n",[111,545,546,548,550,553,555,557],{"class":113,"line":265},[111,547,248],{"class":117},[111,549,281],{"class":121},[111,551,552],{"class":155},"expire",[111,554,159],{"class":121},[111,556,255],{"class":128},[111,558,290],{"class":121},[560,561,562],"note",{},[63,563,564,565,568,569,571,572,574],{},"\nWithout ",[70,566,567],{},"swr: true",", an expired entry is re-resolved in the foreground, so ",[70,570,80],{}," behaves much like ",[70,573,76],{}," for the next reader (they wait for a fresh value).",[63,576,577,578,581,582,584,585,328,588,328,591,593],{},"The standalone ",[70,579,580],{},"expireCache()"," mirrors ",[70,583,317],{},". Pass the same ",[70,586,587],{},"maxAge",[70,589,590],{},"swr",[70,592,439],{}," options you cache with, so the entry's remaining storage TTL is preserved rather than extended:",[102,595,597],{"className":104,"code":596,"language":106,"meta":107,"style":107},"import { expireCache } from \"ocache\";\n\nawait expireCache({\n  options: {\n    name: \"getUser\",\n    getKey: (id: string) => id,\n    maxAge: 60,\n    swr: true,\n    staleMaxAge: 300,\n  },\n  args: [\"user-123\"],\n});\n",[70,598,599,612,616,625,630,639,658,667,676,685,690,698],{"__ignoreMap":107},[111,600,601,603,606,608,610],{"class":113,"line":114},[111,602,118],{"class":117},[111,604,605],{"class":121}," { expireCache } ",[111,607,125],{"class":117},[111,609,129],{"class":128},[111,611,132],{"class":121},[111,613,614],{"class":113,"line":135},[111,615,139],{"emptyLinePlaceholder":138},[111,617,618,620,623],{"class":113,"line":142},[111,619,248],{"class":117},[111,621,622],{"class":155}," expireCache",[111,624,364],{"class":121},[111,626,627],{"class":113,"line":193},[111,628,629],{"class":121},"  options: {\n",[111,631,632,635,637],{"class":113,"line":205},[111,633,634],{"class":121},"    name: ",[111,636,199],{"class":128},[111,638,202],{"class":121},[111,640,641,644,646,648,650,652,654,656],{"class":113,"line":216},[111,642,643],{"class":155},"    getKey",[111,645,222],{"class":121},[111,647,169],{"class":168},[111,649,172],{"class":117},[111,651,175],{"class":148},[111,653,178],{"class":121},[111,655,181],{"class":117},[111,657,231],{"class":121},[111,659,660,663,665],{"class":113,"line":234},[111,661,662],{"class":121},"    maxAge: ",[111,664,211],{"class":148},[111,666,202],{"class":121},[111,668,669,672,674],{"class":113,"line":240},[111,670,671],{"class":121},"    swr: ",[111,673,511],{"class":148},[111,675,202],{"class":121},[111,677,678,681,683],{"class":113,"line":245},[111,679,680],{"class":121},"    staleMaxAge: ",[111,682,501],{"class":148},[111,684,202],{"class":121},[111,686,687],{"class":113,"line":265},[111,688,689],{"class":121},"  },\n",[111,691,692,694,696],{"class":113,"line":270},[111,693,395],{"class":121},[111,695,255],{"class":128},[111,697,400],{"class":121},[111,699,700],{"class":113,"line":276},[111,701,237],{"class":121},[703,704,705],"tip",{},[63,706,707,708,710,711,713],{},"\nPrefer ",[70,709,80],{}," when you want a smooth refresh with no blocking gap for readers. Reach for ",[70,712,76],{}," only when the next reader must get a guaranteed-fresh value.",[87,715,717],{"id":716},"resolving-keys","Resolving keys",[63,719,720,721,723],{},"For advanced use cases — inspecting entries, custom storage operations — ",[70,722,84],{}," returns the raw storage keys for a set of arguments (one per base prefix):",[102,725,727],{"className":104,"code":726,"language":106,"meta":107,"style":107},"const keys = await getUser.resolveKeys(\"user-123\");\n\u002F\u002F [\"\u002Fcache:functions:getUser:user-123.json\"]\n",[70,728,729,752],{"__ignoreMap":107},[111,730,731,733,736,738,741,743,746,748,750],{"class":113,"line":114},[111,732,145],{"class":117},[111,734,735],{"class":148}," keys",[111,737,152],{"class":117},[111,739,740],{"class":117}," await",[111,742,281],{"class":121},[111,744,745],{"class":155},"resolveKeys",[111,747,159],{"class":121},[111,749,255],{"class":128},[111,751,290],{"class":121},[111,753,754],{"class":113,"line":135},[111,755,756],{"class":261},"\u002F\u002F [\"\u002Fcache:functions:getUser:user-123.json\"]\n",[63,758,577,759,762],{},[70,760,761],{},"resolveCacheKeys()"," does the same without a function reference (again, pass matching key options):",[102,764,766],{"className":104,"code":765,"language":106,"meta":107,"style":107},"import { resolveCacheKeys, useStorage } from \"ocache\";\n\nconst keys = await resolveCacheKeys({\n  options: { name: \"getUser\", getKey: (id: string) => id },\n  args: [\"user-123\"],\n});\n\nfor (const key of keys) {\n  const entry = await useStorage().get(key);\n  \u002F\u002F ...inspect or manipulate the raw entry\n}\n",[70,767,768,781,785,800,824,832,836,840,858,882,887],{"__ignoreMap":107},[111,769,770,772,775,777,779],{"class":113,"line":114},[111,771,118],{"class":117},[111,773,774],{"class":121}," { resolveCacheKeys, useStorage } ",[111,776,125],{"class":117},[111,778,129],{"class":128},[111,780,132],{"class":121},[111,782,783],{"class":113,"line":135},[111,784,139],{"emptyLinePlaceholder":138},[111,786,787,789,791,793,795,798],{"class":113,"line":142},[111,788,145],{"class":117},[111,790,735],{"class":148},[111,792,152],{"class":117},[111,794,740],{"class":117},[111,796,797],{"class":155}," resolveCacheKeys",[111,799,364],{"class":121},[111,801,802,804,806,808,810,812,814,816,818,820,822],{"class":113,"line":193},[111,803,369],{"class":121},[111,805,199],{"class":128},[111,807,77],{"class":121},[111,809,324],{"class":155},[111,811,222],{"class":121},[111,813,169],{"class":168},[111,815,172],{"class":117},[111,817,175],{"class":148},[111,819,178],{"class":121},[111,821,181],{"class":117},[111,823,390],{"class":121},[111,825,826,828,830],{"class":113,"line":205},[111,827,395],{"class":121},[111,829,255],{"class":128},[111,831,400],{"class":121},[111,833,834],{"class":113,"line":216},[111,835,237],{"class":121},[111,837,838],{"class":113,"line":234},[111,839,139],{"emptyLinePlaceholder":138},[111,841,842,845,847,849,852,855],{"class":113,"line":240},[111,843,844],{"class":117},"for",[111,846,165],{"class":121},[111,848,145],{"class":117},[111,850,851],{"class":148}," key",[111,853,854],{"class":117}," of",[111,856,857],{"class":121}," keys) {\n",[111,859,860,863,866,868,870,873,876,879],{"class":113,"line":245},[111,861,862],{"class":117},"  const",[111,864,865],{"class":148}," entry",[111,867,152],{"class":117},[111,869,740],{"class":117},[111,871,872],{"class":155}," useStorage",[111,874,875],{"class":121},"().",[111,877,878],{"class":155},"get",[111,880,881],{"class":121},"(key);\n",[111,883,884],{"class":113,"line":265},[111,885,886],{"class":261},"  \u002F\u002F ...inspect or manipulate the raw entry\n",[111,888,889],{"class":113,"line":270},[111,890,891],{"class":121},"}\n",[63,893,894,895,897,898,901],{},"See ",[67,896,28],{"href":29}," for the underlying store, and ",[67,899,900],{"href":34},"HTTP Handlers"," for invalidating cached responses.",[903,904,905],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":107,"searchDepth":135,"depth":135,"links":907},[908,909,910],{"id":89,"depth":135,"text":90},{"id":422,"depth":135,"text":423},{"id":716,"depth":135,"text":717},"md",{"icon":26},{"icon":26},{"title":23,"description":107},"EeGrHFLkJBH_hiM06b1pVnHOKKdPItyY0HZ4fAP20hg",[917,918],{"title":18,"path":19,"stem":20,"description":107,"icon":21,"children":-1},{"title":28,"path":29,"stem":30,"description":107,"icon":31,"children":-1},1783601179225]