[{"data":1,"prerenderedAt":1718},["ShallowReactive",2],{"navigation_docs":3,"-docs-recipes-cache-an-expensive-call":493,"-docs-recipes-cache-an-expensive-call-surround":1713},[4,46,135,218,257,292,355,377,420],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":45},"Getting Started","i-lucide-rocket","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"What is Heximon?","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F01.getting-started\u002F01.introduction","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F01.getting-started\u002F02.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F01.getting-started\u002F03.quick-start","i-lucide-zap",{"title":26,"path":27,"stem":28,"icon":29},"Core Concepts","\u002Fdocs\u002Fgetting-started\u002Fcore-concepts","docs\u002F01.getting-started\u002F04.core-concepts","i-lucide-shapes",{"title":31,"path":32,"stem":33,"icon":34},"Examples","\u002Fdocs\u002Fgetting-started\u002Fexamples","docs\u002F01.getting-started\u002F05.examples","i-lucide-library",{"title":36,"path":37,"stem":38,"icon":39},"Where Next?","\u002Fdocs\u002Fgetting-started\u002Fwhere-next","docs\u002F01.getting-started\u002F06.where-next","i-lucide-signpost",{"title":41,"path":42,"stem":43,"icon":44},"Troubleshooting","\u002Fdocs\u002Fgetting-started\u002Ftroubleshooting","docs\u002F01.getting-started\u002F07.troubleshooting","i-lucide-life-buoy",false,{"title":47,"icon":48,"path":49,"stem":50,"children":51,"page":45},"Essentials","i-lucide-boxes","\u002Fdocs\u002Fessentials","docs\u002F02.essentials",[52,56,61,66,71,76,81,86,91,96,101,105,110,115,120,125,130],{"title":53,"path":54,"stem":55,"icon":48},"Modules & DI","\u002Fdocs\u002Fessentials\u002Fmodules-and-di","docs\u002F02.essentials\u002F01.modules-and-di",{"title":57,"path":58,"stem":59,"icon":60},"Controllers","\u002Fdocs\u002Fessentials\u002Fcontrollers","docs\u002F02.essentials\u002F02.controllers","i-lucide-route",{"title":62,"path":63,"stem":64,"icon":65},"Validation & DTOs","\u002Fdocs\u002Fessentials\u002Fvalidation","docs\u002F02.essentials\u002F03.validation","i-lucide-shield-check",{"title":67,"path":68,"stem":69,"icon":70},"Contracts","\u002Fdocs\u002Fessentials\u002Fcontracts","docs\u002F02.essentials\u002F04.contracts","i-lucide-file-signature",{"title":72,"path":73,"stem":74,"icon":75},"REST Client","\u002Fdocs\u002Fessentials\u002Fclient","docs\u002F02.essentials\u002F05.client","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":80},"Database","\u002Fdocs\u002Fessentials\u002Fdatabase","docs\u002F02.essentials\u002F06.database","i-lucide-database",{"title":82,"path":83,"stem":84,"icon":85},"Drizzle ORM","\u002Fdocs\u002Fessentials\u002Fdrizzle","docs\u002F02.essentials\u002F07.drizzle","i-lucide-database-zap",{"title":87,"path":88,"stem":89,"icon":90},"Persistence & Transactions","\u002Fdocs\u002Fessentials\u002Fpersistence","docs\u002F02.essentials\u002F08.persistence","i-lucide-database-backup",{"title":92,"path":93,"stem":94,"icon":95},"Migrations","\u002Fdocs\u002Fessentials\u002Fmigrations","docs\u002F02.essentials\u002F09.migrations","i-lucide-git-branch",{"title":97,"path":98,"stem":99,"icon":100},"Authentication","\u002Fdocs\u002Fessentials\u002Fauthentication","docs\u002F02.essentials\u002F10.authentication","i-lucide-key-round",{"title":102,"path":103,"stem":104,"icon":65},"Permissions & scopes","\u002Fdocs\u002Fessentials\u002Fpermissions","docs\u002F02.essentials\u002F11.permissions",{"title":106,"path":107,"stem":108,"icon":109},"Error Handling","\u002Fdocs\u002Fessentials\u002Ferrors","docs\u002F02.essentials\u002F12.errors","i-lucide-triangle-alert",{"title":111,"path":112,"stem":113,"icon":114},"Testing a Heximon App","\u002Fdocs\u002Fessentials\u002Ftesting","docs\u002F02.essentials\u002F13.testing","i-lucide-flask-conical",{"title":116,"path":117,"stem":118,"icon":119},"Test app harness","\u002Fdocs\u002Fessentials\u002Fcreatetestapp","docs\u002F02.essentials\u002F14.createtestapp","i-lucide-test-tube",{"title":121,"path":122,"stem":123,"icon":124},"Logging & Observability","\u002Fdocs\u002Fessentials\u002Flogging","docs\u002F02.essentials\u002F17.logging","i-lucide-scroll-text",{"title":126,"path":127,"stem":128,"icon":129},"Context & Lifecycle","\u002Fdocs\u002Fessentials\u002Fcontext-and-lifecycle","docs\u002F02.essentials\u002F18.context-and-lifecycle","i-lucide-radio",{"title":131,"path":132,"stem":133,"icon":134},"Project Structure","\u002Fdocs\u002Fessentials\u002Fproject-structure","docs\u002F02.essentials\u002F19.project-structure","i-lucide-folder-tree",{"title":136,"icon":137,"path":138,"stem":139,"children":140,"page":45},"Capabilities","i-lucide-sparkles","\u002Fdocs\u002Fcapabilities","docs\u002F03.capabilities",[141,145,150,155,160,164,169,174,179,184,188,193,198,203,208,213],{"title":142,"path":143,"stem":144,"icon":137},"Overview","\u002Fdocs\u002Fcapabilities\u002Foverview","docs\u002F03.capabilities\u002F01.overview",{"title":146,"path":147,"stem":148,"icon":149},"Events","\u002Fdocs\u002Fcapabilities\u002Fevents","docs\u002F03.capabilities\u002F02.events","i-lucide-radio-tower",{"title":151,"path":152,"stem":153,"icon":154},"Queue","\u002Fdocs\u002Fcapabilities\u002Fbackground-jobs","docs\u002F03.capabilities\u002F03.background-jobs","i-lucide-list-ordered",{"title":156,"path":157,"stem":158,"icon":159},"Scheduled Work","\u002Fdocs\u002Fcapabilities\u002Fscheduled-jobs","docs\u002F03.capabilities\u002F04.scheduled-jobs","i-lucide-clock",{"title":161,"path":162,"stem":163,"icon":85},"Caching","\u002Fdocs\u002Fcapabilities\u002Fcaching","docs\u002F03.capabilities\u002F05.caching",{"title":165,"path":166,"stem":167,"icon":168},"Key\u002FValue Storage","\u002Fdocs\u002Fcapabilities\u002Fkey-value","docs\u002F03.capabilities\u002F06.key-value","i-lucide-hard-drive",{"title":170,"path":171,"stem":172,"icon":173},"Blob Storage","\u002Fdocs\u002Fcapabilities\u002Fblob","docs\u002F03.capabilities\u002F07.blob","i-lucide-folder-open",{"title":175,"path":176,"stem":177,"icon":178},"Health & Readiness","\u002Fdocs\u002Fcapabilities\u002Fhealth","docs\u002F03.capabilities\u002F08.health","i-lucide-heart-pulse",{"title":180,"path":181,"stem":182,"icon":183},"Notifications","\u002Fdocs\u002Fcapabilities\u002Fnotifications","docs\u002F03.capabilities\u002F09.notifications","i-lucide-mail",{"title":185,"path":186,"stem":187,"icon":65},"Idempotency","\u002Fdocs\u002Fcapabilities\u002Fidempotency","docs\u002F03.capabilities\u002F10.idempotency",{"title":189,"path":190,"stem":191,"icon":192},"Security Hardening","\u002Fdocs\u002Fcapabilities\u002Fsecurity","docs\u002F03.capabilities\u002F11.security","i-lucide-shield",{"title":194,"path":195,"stem":196,"icon":197},"Observability & Tracing","\u002Fdocs\u002Fcapabilities\u002Fobservability","docs\u002F03.capabilities\u002F12.observability","i-lucide-activity",{"title":199,"path":200,"stem":201,"icon":202},"OpenAPI","\u002Fdocs\u002Fcapabilities\u002Fopenapi","docs\u002F03.capabilities\u002F13.openapi","i-lucide-book-marked",{"title":204,"path":205,"stem":206,"icon":207},"MCP Server","\u002Fdocs\u002Fcapabilities\u002Fmcp","docs\u002F03.capabilities\u002F14.mcp","i-lucide-bot",{"title":209,"path":210,"stem":211,"icon":212},"Schema DTOs","\u002Fdocs\u002Fcapabilities\u002Fschema","docs\u002F03.capabilities\u002F15.schema","i-lucide-file-json",{"title":214,"path":215,"stem":216,"icon":217},"Branded IDs","\u002Fdocs\u002Fcapabilities\u002Fbranded-ids","docs\u002F03.capabilities\u002F16.branded-ids","i-lucide-tag",{"title":219,"icon":220,"path":221,"stem":222,"children":223,"page":45},"Architecture","i-lucide-building","\u002Fdocs\u002Farchitecture","docs\u002F04.architecture",[224,227,232,237,242,247,252],{"title":142,"path":225,"stem":226,"icon":220},"\u002Fdocs\u002Farchitecture\u002Foverview","docs\u002F04.architecture\u002F01.overview",{"title":228,"path":229,"stem":230,"icon":231},"Domain-Driven Design","\u002Fdocs\u002Farchitecture\u002Fddd","docs\u002F04.architecture\u002F02.ddd","i-lucide-hexagon",{"title":233,"path":234,"stem":235,"icon":236},"CQRS","\u002Fdocs\u002Farchitecture\u002Fcqrs","docs\u002F04.architecture\u002F03.cqrs","i-lucide-split",{"title":238,"path":239,"stem":240,"icon":241},"Repository Pattern","\u002Fdocs\u002Farchitecture\u002Frepository-pattern","docs\u002F04.architecture\u002F04.repository-pattern","i-lucide-archive",{"title":243,"path":244,"stem":245,"icon":246},"Integration Events","\u002Fdocs\u002Farchitecture\u002Fintegration-events","docs\u002F04.architecture\u002F05.integration-events","i-lucide-send-horizontal",{"title":248,"path":249,"stem":250,"icon":251},"Saga Orchestration","\u002Fdocs\u002Farchitecture\u002Fsagas","docs\u002F04.architecture\u002F06.sagas","i-lucide-hourglass",{"title":253,"path":254,"stem":255,"icon":256},"Durable Workflows","\u002Fdocs\u002Farchitecture\u002Fworkflows","docs\u002F04.architecture\u002F07.workflows","i-lucide-workflow",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":45},"Realtime","i-lucide-cable","\u002Fdocs\u002Frealtime","docs\u002F05.realtime",[263,266,270,274,279,284,288],{"title":142,"path":264,"stem":265,"icon":259},"\u002Fdocs\u002Frealtime\u002Foverview","docs\u002F05.realtime\u002F01.overview",{"title":267,"path":268,"stem":269,"icon":129},"WebSockets","\u002Fdocs\u002Frealtime\u002Fwebsockets","docs\u002F05.realtime\u002F02.websockets",{"title":271,"path":272,"stem":273,"icon":70},"WebSocket Contracts","\u002Fdocs\u002Frealtime\u002Fwebsocket-contracts","docs\u002F05.realtime\u002F03.websocket-contracts",{"title":275,"path":276,"stem":277,"icon":278},"Server-Sent Events","\u002Fdocs\u002Frealtime\u002Fserver-sent-events","docs\u002F05.realtime\u002F04.server-sent-events","i-lucide-rss",{"title":280,"path":281,"stem":282,"icon":283},"Typed Clients","\u002Fdocs\u002Frealtime\u002Ftyped-clients","docs\u002F05.realtime\u002F05.typed-clients","i-lucide-plug-zap",{"title":285,"path":286,"stem":287,"icon":259},"AsyncAPI","\u002Fdocs\u002Frealtime\u002Fasyncapi","docs\u002F05.realtime\u002F06.asyncapi",{"title":289,"path":290,"stem":291,"icon":80},"Durable Objects","\u002Fdocs\u002Frealtime\u002Fdurable-objects","docs\u002F05.realtime\u002F07.durable-objects",{"title":293,"icon":294,"path":295,"stem":296,"children":297,"page":45},"Deploy","i-lucide-cloud-upload","\u002Fdocs\u002Fdeploy","docs\u002F06.deploy",[298,301,306,311,316,321,326,331,336,341,345,350],{"title":142,"path":299,"stem":300,"icon":6},"\u002Fdocs\u002Fdeploy\u002Foverview","docs\u002F06.deploy\u002F01.overview",{"title":302,"path":303,"stem":304,"icon":305},"Node","\u002Fdocs\u002Fdeploy\u002Fnode","docs\u002F06.deploy\u002F02.node","la:node-js",{"title":307,"path":308,"stem":309,"icon":310},"Cloudflare","\u002Fdocs\u002Fdeploy\u002Fcloudflare","docs\u002F06.deploy\u002F03.cloudflare","simple-icons:cloudflare",{"title":312,"path":313,"stem":314,"icon":315},"Vercel","\u002Fdocs\u002Fdeploy\u002Fvercel","docs\u002F06.deploy\u002F04.vercel","ri:vercel-fill",{"title":317,"path":318,"stem":319,"icon":320},"Netlify","\u002Fdocs\u002Fdeploy\u002Fnetlify","docs\u002F06.deploy\u002F05.netlify","i-simple-icons-netlify",{"title":322,"path":323,"stem":324,"icon":325},"AWS Lambda","\u002Fdocs\u002Fdeploy\u002Faws-lambda","docs\u002F06.deploy\u002F06.aws-lambda","hugeicons:aws-lambda",{"title":327,"path":328,"stem":329,"icon":330},"Deno Deploy","\u002Fdocs\u002Fdeploy\u002Fdeno-deploy","docs\u002F06.deploy\u002F07.deno-deploy","simple-icons:denodeploy",{"title":332,"path":333,"stem":334,"icon":335},"Nitro","\u002Fdocs\u002Fdeploy\u002Fnitro","docs\u002F06.deploy\u002F08.nitro","i-unjs-nitro",{"title":337,"path":338,"stem":339,"icon":340},"Nuxt","\u002Fdocs\u002Fdeploy\u002Fnuxt","docs\u002F06.deploy\u002F09.nuxt","i-devicon-nuxt",{"title":342,"path":343,"stem":344,"icon":236},"Mixed-runtime split","\u002Fdocs\u002Fdeploy\u002Fmixed-runtime-split","docs\u002F06.deploy\u002F10.mixed-runtime-split",{"title":346,"path":347,"stem":348,"icon":349},"Hosts","\u002Fdocs\u002Fdeploy\u002Fhosts","docs\u002F06.deploy\u002F11.hosts","i-lucide-map",{"title":351,"path":352,"stem":353,"icon":354},"Cross-service events","\u002Fdocs\u002Fdeploy\u002Fcross-service-events","docs\u002F06.deploy\u002F12.cross-service-events","i-lucide-network",{"title":356,"icon":357,"path":358,"stem":359,"children":360,"page":45},"CLI","i-lucide-terminal","\u002Fdocs\u002Fcli","docs\u002F07.cli",[361,365,369,373],{"title":362,"path":363,"stem":364,"icon":357},"The heximon CLI","\u002Fdocs\u002Fcli\u002Foverview","docs\u002F07.cli\u002F01.overview",{"title":366,"path":367,"stem":368,"icon":137},"Create a New App","\u002Fdocs\u002Fcli\u002Fcreate","docs\u002F07.cli\u002F02.create",{"title":370,"path":371,"stem":372,"icon":95},"Migrations from the CLI","\u002Fdocs\u002Fcli\u002Fmigrations","docs\u002F07.cli\u002F03.migrations",{"title":374,"path":375,"stem":376,"icon":6},"Deploying a Heximon app","\u002Fdocs\u002Fcli\u002Fdeploy","docs\u002F07.cli\u002F04.deploy",{"title":378,"icon":379,"path":380,"stem":381,"children":382,"page":45},"Under the Hood","i-lucide-wrench","\u002Fdocs\u002Funder-the-hood","docs\u002F08.under-the-hood",[383,388,393,397,402,407,411,415],{"title":384,"path":385,"stem":386,"icon":387},"How the Compiler Works","\u002Fdocs\u002Funder-the-hood\u002Fhow-the-compiler-works","docs\u002F08.under-the-hood\u002F01.how-the-compiler-works","i-lucide-cog",{"title":389,"path":390,"stem":391,"icon":392},"Compiler","\u002Fdocs\u002Funder-the-hood\u002Fextending-the-compiler","docs\u002F08.under-the-hood\u002F02.extending-the-compiler","i-lucide-cpu",{"title":394,"path":395,"stem":396,"icon":357},"Compiler Diagnostics","\u002Fdocs\u002Funder-the-hood\u002Fcompiler-diagnostics","docs\u002F08.under-the-hood\u002F03.compiler-diagnostics",{"title":398,"path":399,"stem":400,"icon":401},"Library Mode","\u002Fdocs\u002Funder-the-hood\u002Flibrary-mode","docs\u002F08.under-the-hood\u002F04.library-mode","i-lucide-package",{"title":403,"path":404,"stem":405,"icon":406},"Other bundlers","\u002Fdocs\u002Funder-the-hood\u002Falternate-bundlers","docs\u002F08.under-the-hood\u002F05.alternate-bundlers","i-lucide-blocks",{"title":408,"path":409,"stem":410,"icon":401},"Packages","\u002Fdocs\u002Funder-the-hood\u002Fpackages","docs\u002F08.under-the-hood\u002F06.packages",{"title":412,"path":413,"stem":414,"icon":207},"AI Skills","\u002Fdocs\u002Funder-the-hood\u002Fai-and-agents","docs\u002F08.under-the-hood\u002F07.ai-and-agents",{"title":416,"path":417,"stem":418,"icon":419},"Advanced DI","\u002Fdocs\u002Funder-the-hood\u002Fadvanced-di","docs\u002F08.under-the-hood\u002F08.advanced-di","i-lucide-git-fork",{"title":421,"icon":422,"path":423,"stem":424,"children":425,"page":45},"Recipes","i-lucide-book-open-check","\u002Fdocs\u002Frecipes","docs\u002F09.recipes",[426,431,436,440,444,448,452,456,460,465,469,474,479,484,488],{"title":427,"path":428,"stem":429,"icon":430},"Send an Email","\u002Fdocs\u002Frecipes\u002Fsend-an-email","docs\u002F09.recipes\u002F01.send-an-email","i-lucide-send",{"title":432,"path":433,"stem":434,"icon":435},"Upload a File","\u002Fdocs\u002Frecipes\u002Fupload-a-file","docs\u002F09.recipes\u002F02.upload-a-file","i-lucide-upload",{"title":437,"path":438,"stem":439,"icon":24},"Cache an Expensive Call","\u002Fdocs\u002Frecipes\u002Fcache-an-expensive-call","docs\u002F09.recipes\u002F03.cache-an-expensive-call",{"title":441,"path":442,"stem":443,"icon":154},"Paginate a List","\u002Fdocs\u002Frecipes\u002Fpaginate-a-list","docs\u002F09.recipes\u002F04.paginate-a-list",{"title":445,"path":446,"stem":447,"icon":65},"Protect Admin Routes","\u002Fdocs\u002Frecipes\u002Fprotect-admin-routes","docs\u002F09.recipes\u002F05.protect-admin-routes",{"title":449,"path":450,"stem":451,"icon":178},"Health Probes and a Nightly Job","\u002Fdocs\u002Frecipes\u002Fhealth-probes-and-a-nightly-job","docs\u002F09.recipes\u002F06.health-probes-and-a-nightly-job",{"title":453,"path":454,"stem":455,"icon":80},"Build a CRUD API","\u002Fdocs\u002Frecipes\u002Fcrud-api","docs\u002F09.recipes\u002F07.crud-api",{"title":457,"path":458,"stem":459,"icon":100},"Add Authentication","\u002Fdocs\u002Frecipes\u002Fadd-authentication","docs\u002F09.recipes\u002F08.add-authentication",{"title":461,"path":462,"stem":463,"icon":464},"Background Jobs","\u002Fdocs\u002Frecipes\u002Fbackground-jobs","docs\u002F09.recipes\u002F09.background-jobs","i-lucide-timer",{"title":466,"path":467,"stem":468,"icon":149},"Decouple Features with Events","\u002Fdocs\u002Frecipes\u002Fevent-driven-module","docs\u002F09.recipes\u002F10.event-driven-module",{"title":470,"path":471,"stem":472,"icon":473},"Build a DDD Aggregate","\u002Fdocs\u002Frecipes\u002Fddd-aggregate","docs\u002F09.recipes\u002F11.ddd-aggregate","i-lucide-box",{"title":475,"path":476,"stem":477,"icon":478},"Publish a Feature Package","\u002Fdocs\u002Frecipes\u002Ffeature-package","docs\u002F09.recipes\u002F12.feature-package","i-lucide-package-open",{"title":480,"path":481,"stem":482,"icon":483},"Reliable Integration Events","\u002Fdocs\u002Frecipes\u002Freliable-integration-events","docs\u002F09.recipes\u002F13.reliable-integration-events","i-lucide-inbox",{"title":485,"path":486,"stem":487,"icon":95},"Reactive Choreography","\u002Fdocs\u002Frecipes\u002Freactive-choreography","docs\u002F09.recipes\u002F14.reactive-choreography",{"title":489,"path":490,"stem":491,"icon":492},"Build a Production CRUD API","\u002Fdocs\u002Frecipes\u002Fproduction-crud-api","docs\u002F09.recipes\u002F15.production-crud-api","i-lucide-layers",{"id":494,"title":437,"body":495,"description":1706,"extension":1707,"links":1708,"meta":1709,"navigation":1710,"path":438,"seo":1711,"stem":439,"__hash__":1712},"docs\u002Fdocs\u002F09.recipes\u002F03.cache-an-expensive-call.md",{"type":496,"value":497,"toc":1698},"minimark",[498,507,515,539,775,791,795,805,1063,1074,1078,1081,1146,1180,1189,1193,1199,1643,1647,1694],[499,500,501,502,506],"p",{},"A product lookup that hits a slow upstream, or a report that scans a big table, shouldn't run on every\nrequest when the answer hasn't changed. ",[503,504,505],"code",{},"Cache.getOrSet"," wraps the read: a hit returns the cached value, a\nmiss runs your factory once — even under concurrent callers — and caches the result.",[508,509,511,512],"h2",{"id":510},"bind-a-cache","Bind a ",[503,513,514],{},"Cache",[499,516,517,519,520,523,524,527,528,531,532,534,535,538],{},[503,518,514],{}," takes a config object: a ",[503,521,522],{},"Storage"," for one tier (the common case), or a ",[503,525,526],{},"TieredCache"," for several.\nThere's no framework tier token — bind your own storage bare, and hand it to a ",[503,529,530],{},"useFactory"," for the ",[503,533,514],{},"\nitself, since its ",[503,536,537],{},"ttlSeconds"," is a literal config argument DI can't express.",[540,541,547],"pre",{"className":542,"code":543,"filename":544,"language":545,"meta":546,"style":546},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Cache } from \"@heximon\u002Fcache\";\nimport { Module } from \"@heximon\u002Fruntime\";\nimport { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\n\nexport class AppModule extends Module({\n  providers: [\n    MemoryStorage,\n    { provide: Cache, useFactory: (storage: MemoryStorage) => new Cache({ storage, ttlSeconds: 86_400 }) },\n  ],\n}) {}\n","src\u002Fapp.module.ts","ts","",[503,548,549,585,608,631,638,664,677,686,756,764],{"__ignoreMap":546},[550,551,554,558,562,566,569,572,575,579,582],"span",{"class":552,"line":553},"line",1,[550,555,557],{"class":556},"s7zQu","import",[550,559,561],{"class":560},"sMK4o"," {",[550,563,565],{"class":564},"sTEyZ"," Cache",[550,567,568],{"class":560}," }",[550,570,571],{"class":556}," from",[550,573,574],{"class":560}," \"",[550,576,578],{"class":577},"sfazB","@heximon\u002Fcache",[550,580,581],{"class":560},"\"",[550,583,584],{"class":560},";\n",[550,586,588,590,592,595,597,599,601,604,606],{"class":552,"line":587},2,[550,589,557],{"class":556},[550,591,561],{"class":560},[550,593,594],{"class":564}," Module",[550,596,568],{"class":560},[550,598,571],{"class":556},[550,600,574],{"class":560},[550,602,603],{"class":577},"@heximon\u002Fruntime",[550,605,581],{"class":560},[550,607,584],{"class":560},[550,609,611,613,615,618,620,622,624,627,629],{"class":552,"line":610},3,[550,612,557],{"class":556},[550,614,561],{"class":560},[550,616,617],{"class":564}," MemoryStorage",[550,619,568],{"class":560},[550,621,571],{"class":556},[550,623,574],{"class":560},[550,625,626],{"class":577},"@heximon\u002Fkv\u002Fmemory",[550,628,581],{"class":560},[550,630,584],{"class":560},[550,632,634],{"class":552,"line":633},4,[550,635,637],{"emptyLinePlaceholder":636},true,"\n",[550,639,641,644,648,652,655,658,661],{"class":552,"line":640},5,[550,642,643],{"class":556},"export",[550,645,647],{"class":646},"spNyl"," class",[550,649,651],{"class":650},"sBMFI"," AppModule",[550,653,654],{"class":646}," extends",[550,656,594],{"class":657},"s2Zo4",[550,659,660],{"class":564},"(",[550,662,663],{"class":560},"{\n",[550,665,667,671,674],{"class":552,"line":666},6,[550,668,670],{"class":669},"swJcz","  providers",[550,672,673],{"class":560},":",[550,675,676],{"class":564}," [\n",[550,678,680,683],{"class":552,"line":679},7,[550,681,682],{"class":564},"    MemoryStorage",[550,684,685],{"class":560},",\n",[550,687,689,692,695,697,699,702,705,707,710,714,716,718,721,724,727,729,731,734,737,739,742,744,748,750,753],{"class":552,"line":688},8,[550,690,691],{"class":560},"    {",[550,693,694],{"class":669}," provide",[550,696,673],{"class":560},[550,698,565],{"class":564},[550,700,701],{"class":560},",",[550,703,704],{"class":657}," useFactory",[550,706,673],{"class":560},[550,708,709],{"class":560}," (",[550,711,713],{"class":712},"sHdIc","storage",[550,715,673],{"class":560},[550,717,617],{"class":650},[550,719,720],{"class":560},")",[550,722,723],{"class":646}," =>",[550,725,726],{"class":560}," new",[550,728,565],{"class":657},[550,730,660],{"class":564},[550,732,733],{"class":560},"{",[550,735,736],{"class":564}," storage",[550,738,701],{"class":560},[550,740,741],{"class":669}," ttlSeconds",[550,743,673],{"class":560},[550,745,747],{"class":746},"sbssI"," 86_400",[550,749,568],{"class":560},[550,751,752],{"class":564},") ",[550,754,755],{"class":560},"},\n",[550,757,759,762],{"class":552,"line":758},9,[550,760,761],{"class":564},"  ]",[550,763,685],{"class":560},[550,765,767,770,772],{"class":552,"line":766},10,[550,768,769],{"class":560},"}",[550,771,752],{"class":564},[550,773,774],{"class":560},"{}\n",[499,776,777,779,780,783,784,787,788,790],{},[503,778,537],{}," is the default TTL applied when a call doesn't pass its own (",[503,781,782],{},"0"," = no expiry). One\n",[503,785,786],{},"MemoryStorage"," is enough for dev; swap in a networked ",[503,789,522],{}," for production without touching a caller.",[508,792,794],{"id":793},"wrap-the-slow-read","Wrap the slow read",[499,796,797,800,801,804],{},[503,798,799],{},"getOrSet(key, factory, options)"," checks the cache first; on a miss it runs ",[503,802,803],{},"factory",", caches the result,\nand returns it. Concurrent misses for the same key share one factory call (single-flight), so a burst of\nrequests for a cold key still hits the upstream once.",[540,806,809],{"className":542,"code":807,"filename":808,"language":545,"meta":546,"style":546},"import { Cache } from \"@heximon\u002Fcache\";\n\nexport class ProductLookup {\n  public constructor(\n    private readonly cache: Cache,\n    private readonly upstream: SlowProductApi,\n  ) {}\n\n  public async find(sku: string): Promise\u003CProduct> {\n    return this.cache.getOrSet(\n      `product:${sku}`,\n      () => this.upstream.fetch(sku),\n      { ttlSeconds: 30, tags: [`product:${sku}`] },\n    );\n  }\n}\n","src\u002Fcatalog\u002Fproduct-lookup.ts",[503,810,811,831,835,847,858,875,891,899,903,940,959,978,1004,1043,1051,1057],{"__ignoreMap":546},[550,812,813,815,817,819,821,823,825,827,829],{"class":552,"line":553},[550,814,557],{"class":556},[550,816,561],{"class":560},[550,818,565],{"class":564},[550,820,568],{"class":560},[550,822,571],{"class":556},[550,824,574],{"class":560},[550,826,578],{"class":577},[550,828,581],{"class":560},[550,830,584],{"class":560},[550,832,833],{"class":552,"line":587},[550,834,637],{"emptyLinePlaceholder":636},[550,836,837,839,841,844],{"class":552,"line":610},[550,838,643],{"class":556},[550,840,647],{"class":646},[550,842,843],{"class":650}," ProductLookup",[550,845,846],{"class":560}," {\n",[550,848,849,852,855],{"class":552,"line":633},[550,850,851],{"class":646},"  public",[550,853,854],{"class":646}," constructor",[550,856,857],{"class":560},"(\n",[550,859,860,863,866,869,871,873],{"class":552,"line":640},[550,861,862],{"class":646},"    private",[550,864,865],{"class":646}," readonly",[550,867,868],{"class":712}," cache",[550,870,673],{"class":560},[550,872,565],{"class":650},[550,874,685],{"class":560},[550,876,877,879,881,884,886,889],{"class":552,"line":666},[550,878,862],{"class":646},[550,880,865],{"class":646},[550,882,883],{"class":712}," upstream",[550,885,673],{"class":560},[550,887,888],{"class":650}," SlowProductApi",[550,890,685],{"class":560},[550,892,893,896],{"class":552,"line":679},[550,894,895],{"class":560},"  )",[550,897,898],{"class":560}," {}\n",[550,900,901],{"class":552,"line":688},[550,902,637],{"emptyLinePlaceholder":636},[550,904,905,907,910,913,915,918,920,923,926,929,932,935,938],{"class":552,"line":758},[550,906,851],{"class":646},[550,908,909],{"class":646}," async",[550,911,912],{"class":669}," find",[550,914,660],{"class":560},[550,916,917],{"class":712},"sku",[550,919,673],{"class":560},[550,921,922],{"class":650}," string",[550,924,925],{"class":560},"):",[550,927,928],{"class":650}," Promise",[550,930,931],{"class":560},"\u003C",[550,933,934],{"class":650},"Product",[550,936,937],{"class":560},">",[550,939,846],{"class":560},[550,941,942,945,948,951,954,957],{"class":552,"line":766},[550,943,944],{"class":556},"    return",[550,946,947],{"class":560}," this.",[550,949,950],{"class":564},"cache",[550,952,953],{"class":560},".",[550,955,956],{"class":657},"getOrSet",[550,958,857],{"class":669},[550,960,962,965,968,971,973,976],{"class":552,"line":961},11,[550,963,964],{"class":560},"      `",[550,966,967],{"class":577},"product:",[550,969,970],{"class":560},"${",[550,972,917],{"class":564},[550,974,975],{"class":560},"}`",[550,977,685],{"class":560},[550,979,981,984,986,988,991,993,996,998,1000,1002],{"class":552,"line":980},12,[550,982,983],{"class":560},"      ()",[550,985,723],{"class":646},[550,987,947],{"class":560},[550,989,990],{"class":564},"upstream",[550,992,953],{"class":560},[550,994,995],{"class":657},"fetch",[550,997,660],{"class":669},[550,999,917],{"class":564},[550,1001,720],{"class":669},[550,1003,685],{"class":560},[550,1005,1007,1010,1012,1014,1017,1019,1022,1024,1027,1030,1032,1034,1036,1038,1041],{"class":552,"line":1006},13,[550,1008,1009],{"class":560},"      {",[550,1011,741],{"class":669},[550,1013,673],{"class":560},[550,1015,1016],{"class":746}," 30",[550,1018,701],{"class":560},[550,1020,1021],{"class":669}," tags",[550,1023,673],{"class":560},[550,1025,1026],{"class":669}," [",[550,1028,1029],{"class":560},"`",[550,1031,967],{"class":577},[550,1033,970],{"class":560},[550,1035,917],{"class":564},[550,1037,975],{"class":560},[550,1039,1040],{"class":669},"] ",[550,1042,755],{"class":560},[550,1044,1046,1049],{"class":552,"line":1045},14,[550,1047,1048],{"class":669},"    )",[550,1050,584],{"class":560},[550,1052,1054],{"class":552,"line":1053},15,[550,1055,1056],{"class":560},"  }\n",[550,1058,1060],{"class":552,"line":1059},16,[550,1061,1062],{"class":560},"}\n",[499,1064,1065,1066,1070,1071,1073],{},"A cached hit returns ",[1067,1068,1069],"strong",{},"plain data",", not a class instance — the value round-trips through a JSON-domain\n",[503,1072,522],{},", so cache DTOs, not domain entities with methods.",[508,1075,1077],{"id":1076},"tag-it-then-bust-it-on-write","Tag it, then bust it on write",[499,1079,1080],{},"TTL alone means a write has to wait out the expiry before readers see it. Tags fix that: register a key\nunder one or more tags at write time, then drop every key under a tag with one call — no need to\nreconstruct or guess every cache key that touched that product.",[540,1082,1084],{"className":542,"code":1083,"filename":808,"language":545,"meta":546,"style":546},"public async updatePrice(sku: string, priceCents: number): Promise\u003Cvoid> {\n  await this.upstream.updatePrice(sku, priceCents);\n  await this.cache.invalidate(`product:${sku}`); \u002F\u002F drops every key tagged with it\n}\n",[503,1085,1086,1110,1120,1142],{"__ignoreMap":546},[550,1087,1088,1091,1094,1097,1099,1102,1105,1108],{"class":552,"line":553},[550,1089,1090],{"class":564},"public async ",[550,1092,1093],{"class":657},"updatePrice",[550,1095,1096],{"class":564},"(sku: string",[550,1098,701],{"class":560},[550,1100,1101],{"class":564}," priceCents: number): ",[550,1103,1104],{"class":650},"Promise",[550,1106,1107],{"class":560},"\u003Cvoid>",[550,1109,846],{"class":560},[550,1111,1112,1115,1117],{"class":552,"line":587},[550,1113,1114],{"class":564},"  await this.upstream.updatePrice(sku",[550,1116,701],{"class":560},[550,1118,1119],{"class":564}," priceCents);\n",[550,1121,1122,1125,1127,1129,1131,1133,1135,1138],{"class":552,"line":610},[550,1123,1124],{"class":564},"  await this.cache.invalidate(",[550,1126,1029],{"class":560},[550,1128,967],{"class":669},[550,1130,970],{"class":560},[550,1132,917],{"class":564},[550,1134,975],{"class":560},[550,1136,1137],{"class":669},"); ",[550,1139,1141],{"class":1140},"sHwdD","\u002F\u002F drops every key tagged with it\n",[550,1143,1144],{"class":552,"line":633},[550,1145,1062],{"class":669},[540,1147,1149],{"className":542,"code":1148,"language":545,"meta":546,"style":546},"await cache.invalidate(\"product\"); \u002F\u002F a coarser tag clears every key registered under it, across tiers\n",[503,1150,1151],{"__ignoreMap":546},[550,1152,1153,1156,1158,1160,1163,1165,1167,1170,1172,1174,1177],{"class":552,"line":553},[550,1154,1155],{"class":556},"await",[550,1157,868],{"class":564},[550,1159,953],{"class":560},[550,1161,1162],{"class":657},"invalidate",[550,1164,660],{"class":564},[550,1166,581],{"class":560},[550,1168,1169],{"class":577},"product",[550,1171,581],{"class":560},[550,1173,720],{"class":564},[550,1175,1176],{"class":560},";",[550,1178,1179],{"class":1140}," \u002F\u002F a coarser tag clears every key registered under it, across tiers\n",[1181,1182,1184,1185,1188],"callout",{"type":1183},"info","Tags cost a little: each tagged write adds one marker entry per tag, and those markers live in the durable\ntier of a multi-tier cache (an LRU-bounded tier would evict them first). Tag what you'll actually\ninvalidate together — a per-entity tag like ",[503,1186,1187],{},"product:${sku}",", not one tag per field.",[508,1190,1192],{"id":1191},"prove-the-misshitbust-cycle","Prove the miss\u002Fhit\u002Fbust cycle",[499,1194,1195,1196,1198],{},"A ",[503,1197,514],{}," is a plain class, so a test constructs it directly — no compiler, no running server — and\nasserts the upstream ran once, not once per call:",[540,1200,1203],{"className":542,"code":1201,"filename":1202,"language":545,"meta":546,"style":546},"import { Cache } from \"@heximon\u002Fcache\";\nimport { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\nimport { expect, test, vi } from \"vitest\";\nimport { ProductLookup } from \"..\u002Fsrc\u002Fcatalog\u002Fproduct-lookup\";\n\ntest(\"caches a lookup, then a price update busts it\", async () => {\n  const cache = new Cache({ storage: new MemoryStorage() });\n  const fetch = vi.fn(async () => ({ sku: \"ABC-1\", priceCents: 1999 }));\n  const upstream = { fetch, updatePrice: vi.fn() };\n  const lookup = new ProductLookup(cache, upstream);\n\n  await lookup.find(\"ABC-1\");\n  await lookup.find(\"ABC-1\"); \u002F\u002F served from cache\n  expect(fetch).toHaveBeenCalledTimes(1);\n\n  await lookup.updatePrice(\"ABC-1\", 2499);\n  await lookup.find(\"ABC-1\"); \u002F\u002F tag invalidated the entry — runs again\n  expect(fetch).toHaveBeenCalledTimes(2);\n});\n","test\u002Fproduct-lookup.test.ts",[503,1204,1205,1225,1245,1277,1298,1302,1327,1362,1420,1450,1475,1479,1503,1528,1553,1557,1584,1610,1634],{"__ignoreMap":546},[550,1206,1207,1209,1211,1213,1215,1217,1219,1221,1223],{"class":552,"line":553},[550,1208,557],{"class":556},[550,1210,561],{"class":560},[550,1212,565],{"class":564},[550,1214,568],{"class":560},[550,1216,571],{"class":556},[550,1218,574],{"class":560},[550,1220,578],{"class":577},[550,1222,581],{"class":560},[550,1224,584],{"class":560},[550,1226,1227,1229,1231,1233,1235,1237,1239,1241,1243],{"class":552,"line":587},[550,1228,557],{"class":556},[550,1230,561],{"class":560},[550,1232,617],{"class":564},[550,1234,568],{"class":560},[550,1236,571],{"class":556},[550,1238,574],{"class":560},[550,1240,626],{"class":577},[550,1242,581],{"class":560},[550,1244,584],{"class":560},[550,1246,1247,1249,1251,1254,1256,1259,1261,1264,1266,1268,1270,1273,1275],{"class":552,"line":610},[550,1248,557],{"class":556},[550,1250,561],{"class":560},[550,1252,1253],{"class":564}," expect",[550,1255,701],{"class":560},[550,1257,1258],{"class":564}," test",[550,1260,701],{"class":560},[550,1262,1263],{"class":564}," vi",[550,1265,568],{"class":560},[550,1267,571],{"class":556},[550,1269,574],{"class":560},[550,1271,1272],{"class":577},"vitest",[550,1274,581],{"class":560},[550,1276,584],{"class":560},[550,1278,1279,1281,1283,1285,1287,1289,1291,1294,1296],{"class":552,"line":633},[550,1280,557],{"class":556},[550,1282,561],{"class":560},[550,1284,843],{"class":564},[550,1286,568],{"class":560},[550,1288,571],{"class":556},[550,1290,574],{"class":560},[550,1292,1293],{"class":577},"..\u002Fsrc\u002Fcatalog\u002Fproduct-lookup",[550,1295,581],{"class":560},[550,1297,584],{"class":560},[550,1299,1300],{"class":552,"line":640},[550,1301,637],{"emptyLinePlaceholder":636},[550,1303,1304,1307,1309,1311,1314,1316,1318,1320,1323,1325],{"class":552,"line":666},[550,1305,1306],{"class":657},"test",[550,1308,660],{"class":564},[550,1310,581],{"class":560},[550,1312,1313],{"class":577},"caches a lookup, then a price update busts it",[550,1315,581],{"class":560},[550,1317,701],{"class":560},[550,1319,909],{"class":646},[550,1321,1322],{"class":560}," ()",[550,1324,723],{"class":646},[550,1326,846],{"class":560},[550,1328,1329,1332,1334,1337,1339,1341,1343,1345,1347,1349,1351,1353,1356,1358,1360],{"class":552,"line":679},[550,1330,1331],{"class":646},"  const",[550,1333,868],{"class":564},[550,1335,1336],{"class":560}," =",[550,1338,726],{"class":560},[550,1340,565],{"class":657},[550,1342,660],{"class":669},[550,1344,733],{"class":560},[550,1346,736],{"class":669},[550,1348,673],{"class":560},[550,1350,726],{"class":560},[550,1352,617],{"class":657},[550,1354,1355],{"class":669},"() ",[550,1357,769],{"class":560},[550,1359,720],{"class":669},[550,1361,584],{"class":560},[550,1363,1364,1366,1369,1371,1373,1375,1378,1380,1383,1385,1387,1389,1391,1394,1396,1398,1401,1403,1405,1408,1410,1413,1415,1418],{"class":552,"line":688},[550,1365,1331],{"class":646},[550,1367,1368],{"class":564}," fetch",[550,1370,1336],{"class":560},[550,1372,1263],{"class":564},[550,1374,953],{"class":560},[550,1376,1377],{"class":657},"fn",[550,1379,660],{"class":669},[550,1381,1382],{"class":646},"async",[550,1384,1322],{"class":560},[550,1386,723],{"class":646},[550,1388,709],{"class":669},[550,1390,733],{"class":560},[550,1392,1393],{"class":669}," sku",[550,1395,673],{"class":560},[550,1397,574],{"class":560},[550,1399,1400],{"class":577},"ABC-1",[550,1402,581],{"class":560},[550,1404,701],{"class":560},[550,1406,1407],{"class":669}," priceCents",[550,1409,673],{"class":560},[550,1411,1412],{"class":746}," 1999",[550,1414,568],{"class":560},[550,1416,1417],{"class":669},"))",[550,1419,584],{"class":560},[550,1421,1422,1424,1426,1428,1430,1432,1434,1437,1439,1441,1443,1445,1447],{"class":552,"line":758},[550,1423,1331],{"class":646},[550,1425,883],{"class":564},[550,1427,1336],{"class":560},[550,1429,561],{"class":560},[550,1431,1368],{"class":564},[550,1433,701],{"class":560},[550,1435,1436],{"class":669}," updatePrice",[550,1438,673],{"class":560},[550,1440,1263],{"class":564},[550,1442,953],{"class":560},[550,1444,1377],{"class":657},[550,1446,1355],{"class":669},[550,1448,1449],{"class":560},"};\n",[550,1451,1452,1454,1457,1459,1461,1463,1465,1467,1469,1471,1473],{"class":552,"line":766},[550,1453,1331],{"class":646},[550,1455,1456],{"class":564}," lookup",[550,1458,1336],{"class":560},[550,1460,726],{"class":560},[550,1462,843],{"class":657},[550,1464,660],{"class":669},[550,1466,950],{"class":564},[550,1468,701],{"class":560},[550,1470,883],{"class":564},[550,1472,720],{"class":669},[550,1474,584],{"class":560},[550,1476,1477],{"class":552,"line":961},[550,1478,637],{"emptyLinePlaceholder":636},[550,1480,1481,1484,1486,1488,1491,1493,1495,1497,1499,1501],{"class":552,"line":980},[550,1482,1483],{"class":556},"  await",[550,1485,1456],{"class":564},[550,1487,953],{"class":560},[550,1489,1490],{"class":657},"find",[550,1492,660],{"class":669},[550,1494,581],{"class":560},[550,1496,1400],{"class":577},[550,1498,581],{"class":560},[550,1500,720],{"class":669},[550,1502,584],{"class":560},[550,1504,1505,1507,1509,1511,1513,1515,1517,1519,1521,1523,1525],{"class":552,"line":1006},[550,1506,1483],{"class":556},[550,1508,1456],{"class":564},[550,1510,953],{"class":560},[550,1512,1490],{"class":657},[550,1514,660],{"class":669},[550,1516,581],{"class":560},[550,1518,1400],{"class":577},[550,1520,581],{"class":560},[550,1522,720],{"class":669},[550,1524,1176],{"class":560},[550,1526,1527],{"class":1140}," \u002F\u002F served from cache\n",[550,1529,1530,1533,1535,1537,1539,1541,1544,1546,1549,1551],{"class":552,"line":1045},[550,1531,1532],{"class":657},"  expect",[550,1534,660],{"class":669},[550,1536,995],{"class":564},[550,1538,720],{"class":669},[550,1540,953],{"class":560},[550,1542,1543],{"class":657},"toHaveBeenCalledTimes",[550,1545,660],{"class":669},[550,1547,1548],{"class":746},"1",[550,1550,720],{"class":669},[550,1552,584],{"class":560},[550,1554,1555],{"class":552,"line":1053},[550,1556,637],{"emptyLinePlaceholder":636},[550,1558,1559,1561,1563,1565,1567,1569,1571,1573,1575,1577,1580,1582],{"class":552,"line":1059},[550,1560,1483],{"class":556},[550,1562,1456],{"class":564},[550,1564,953],{"class":560},[550,1566,1093],{"class":657},[550,1568,660],{"class":669},[550,1570,581],{"class":560},[550,1572,1400],{"class":577},[550,1574,581],{"class":560},[550,1576,701],{"class":560},[550,1578,1579],{"class":746}," 2499",[550,1581,720],{"class":669},[550,1583,584],{"class":560},[550,1585,1587,1589,1591,1593,1595,1597,1599,1601,1603,1605,1607],{"class":552,"line":1586},17,[550,1588,1483],{"class":556},[550,1590,1456],{"class":564},[550,1592,953],{"class":560},[550,1594,1490],{"class":657},[550,1596,660],{"class":669},[550,1598,581],{"class":560},[550,1600,1400],{"class":577},[550,1602,581],{"class":560},[550,1604,720],{"class":669},[550,1606,1176],{"class":560},[550,1608,1609],{"class":1140}," \u002F\u002F tag invalidated the entry — runs again\n",[550,1611,1613,1615,1617,1619,1621,1623,1625,1627,1630,1632],{"class":552,"line":1612},18,[550,1614,1532],{"class":657},[550,1616,660],{"class":669},[550,1618,995],{"class":564},[550,1620,720],{"class":669},[550,1622,953],{"class":560},[550,1624,1543],{"class":657},[550,1626,660],{"class":669},[550,1628,1629],{"class":746},"2",[550,1631,720],{"class":669},[550,1633,584],{"class":560},[550,1635,1637,1639,1641],{"class":552,"line":1636},19,[550,1638,769],{"class":560},[550,1640,720],{"class":564},[550,1642,584],{"class":560},[508,1644,1646],{"id":1645},"see-also","See also",[1648,1649,1650,1671,1680],"ul",{},[1651,1652,1653,1656,1657,1659,1660,1663,1664,1667,1668,1670],"li",{},[1654,1655,161],"a",{"href":162}," — the full tier chain (",[503,1658,526],{},", L1\u002FL2), ",[503,1661,1662],{},"QueryCacheInterceptor"," for\nCQRS query results, ",[503,1665,1666],{},"CacheMiddleware"," for whole HTTP responses, and bounding ",[503,1669,786],{}," by size.",[1651,1672,1673,1676,1677,1679],{},[1654,1674,1675],{"href":166},"Key-value storage"," — the ",[503,1678,522],{}," port a cache tier binds, and its networked\ndrivers.",[1651,1681,1682,1690,1691,1693],{},[1654,1683,1687],{"href":1684,"rel":1685},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fflagship",[1686],"nofollow",[1067,1688,1689],{},"the flagship app's caching"," — both\nconsumers over one ",[503,1692,514],{},", with tag invalidation, end-to-end tested.",[1695,1696,1697],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":546,"searchDepth":587,"depth":587,"links":1699},[1700,1702,1703,1704,1705],{"id":510,"depth":587,"text":1701},"Bind a Cache",{"id":793,"depth":587,"text":794},{"id":1076,"depth":587,"text":1077},{"id":1191,"depth":587,"text":1192},{"id":1645,"depth":587,"text":1646},"Wrap a slow read with the Cache facade's getOrSet over a Storage tier, tag the entry for invalidation, and bust it after a write — MemoryStorage, Cache.invalidate, tags.","md",null,{},{"icon":24},{"title":437,"description":1706},"7Dog-SFFHM5MKw24rilFgP4D8hgV268UjEWkbcgxYsE",[1714,1716],{"title":432,"path":433,"stem":434,"description":1715,"icon":435,"children":-1},"Accept a multipart\u002Fform-data upload validated by Route.files(), read it with readValidatedFormData(), and stream it into the abstract BlobStore DI token — swappable for filesystem, S3, or R2 with no controller change.",{"title":441,"path":442,"stem":443,"description":1717,"icon":154,"children":-1},"Validate a list route's filter\u002Forder\u002Fpage query with QuerySchema.create, and shape its response with PaginatedResponseSchema — capped page size, coerced numeric operands, a total-count envelope.",1783300761903]