[{"data":1,"prerenderedAt":3879},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-key-value":493,"-docs-capabilities-key-value-surround":3874},[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":165,"body":495,"description":3867,"extension":3868,"links":3869,"meta":3870,"navigation":3871,"path":166,"seo":3872,"stem":167,"__hash__":3873},"docs\u002Fdocs\u002F03.capabilities\u002F06.key-value.md",{"type":496,"value":497,"toc":3848},"minimark",[498,511,519,524,538,595,599,604,980,991,1020,1270,1277,1371,1375,1384,1598,1604,1763,1779,1814,1818,1830,1885,1896,1975,1979,2011,2020,2050,2073,2241,2286,2293,2311,2495,2516,2524,2550,2564,2743,2780,2799,2803,2814,2840,2851,3007,3034,3395,3399,3507,3515,3518,3542,3789,3799,3803,3844],[499,500,501,502,506,507,510],"p",{},"Sometimes you just need a simple place to stash a session, cache a computed value, or check an\nidempotency key. Heximon gives you an abstract ",[503,504,505],"code",{},"Storage"," DI port for exactly that — a namespaced\nkey\u002Fvalue contract you inject, with the owning module deciding whether it's backed by an in-memory\n",[503,508,509],{},"Map"," under tests or Redis in production.",[499,512,513,514,518],{},"There's no SQL, no joins, no schema here — that's the point. A key\u002Fvalue store is a fast, swappable\nplace to put data you address by name. When you need relationships, transactions, or migrations,\nreach for ",[515,516,517],"a",{"href":83},"Drizzle"," instead.",[520,521,523],"h2",{"id":522},"install-the-port","Install the port",[499,525,526,529,530,533,534,537],{},[503,527,528],{},"MemoryStorage"," and the main entry are dependency-free. Only the ",[503,531,532],{},"\u002Funstorage"," subpath pulls in the\noptional ",[503,535,536],{},"unstorage"," peer, plus any driver you import from it.",[539,540,541,566,581],"code-group",{},[542,543,549],"pre",{"className":544,"code":545,"filename":546,"language":547,"meta":548,"style":548},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fkv\n","pnpm","bash","",[503,550,551],{"__ignoreMap":548},[552,553,556,559,563],"span",{"class":554,"line":555},"line",1,[552,557,546],{"class":558},"sBMFI",[552,560,562],{"class":561},"sfazB"," add",[552,564,565],{"class":561}," @heximon\u002Fkv\n",[542,567,570],{"className":544,"code":568,"filename":569,"language":547,"meta":548,"style":548},"npm install @heximon\u002Fkv\n","npm",[503,571,572],{"__ignoreMap":548},[552,573,574,576,579],{"class":554,"line":555},[552,575,569],{"class":558},[552,577,578],{"class":561}," install",[552,580,565],{"class":561},[542,582,585],{"className":544,"code":583,"filename":584,"language":547,"meta":548,"style":548},"bun add @heximon\u002Fkv\n","bun",[503,586,587],{"__ignoreMap":548},[552,588,589,591,593],{"class":554,"line":555},[552,590,584],{"class":558},[552,592,562],{"class":561},[552,594,565],{"class":561},[520,596,598],{"id":597},"use-the-storage-port","Use the Storage port",[499,600,601,603],{},[503,602,505],{}," is a seven-method key\u002Fvalue contract over opaque string keys. Every method is async, so a\nnetworked backend can stand in for the in-memory one without changing a single call site.",[542,605,609],{"className":606,"code":607,"language":608,"meta":548,"style":548},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","abstract class Storage\u003CTValue extends StorageValue = StorageValue> {\n  abstract has(key: string): Promise\u003Cboolean>;\n  abstract get\u003CTItem extends TValue = TValue>(key: string): Promise\u003CTItem | null>;\n  \u002F\u002F `options.ttl` (a TimeSpan) is a best-effort native-TTL hint (Redis EX, CF KV expirationTtl, …).\n  abstract set\u003CTItem extends TValue = TValue>(\n    key: string,\n    value: TItem,\n    options?: StorageSetOptions,\n  ): Promise\u003Cvoid>;\n  \u002F\u002F Write only when the key holds no live value; `true` = the write happened.\n  abstract setIfAbsent\u003CTItem extends TValue = TValue>(\n    key: string,\n    value: TItem,\n    options?: StorageSetOptions,\n  ): Promise\u003Cboolean>;\n  abstract delete(key: string): Promise\u003Cvoid>;\n  abstract getKeys(base?: string): Promise\u003Cstring[]>;\n  abstract clear(base?: string): Promise\u003Cvoid>;\n}\n","ts",[503,610,611,647,684,731,738,761,774,787,801,816,822,844,855,866,877,890,916,948,974],{"__ignoreMap":548},[552,612,613,617,620,623,627,630,633,636,639,641,644],{"class":554,"line":555},[552,614,616],{"class":615},"spNyl","abstract",[552,618,619],{"class":615}," class",[552,621,622],{"class":558}," Storage",[552,624,626],{"class":625},"sMK4o","\u003C",[552,628,629],{"class":558},"TValue",[552,631,632],{"class":615}," extends",[552,634,635],{"class":558}," StorageValue",[552,637,638],{"class":625}," =",[552,640,635],{"class":558},[552,642,643],{"class":625},">",[552,645,646],{"class":625}," {\n",[552,648,650,653,657,660,664,667,670,673,676,678,681],{"class":554,"line":649},2,[552,651,652],{"class":615},"  abstract",[552,654,656],{"class":655},"swJcz"," has",[552,658,659],{"class":625},"(",[552,661,663],{"class":662},"sHdIc","key",[552,665,666],{"class":625},":",[552,668,669],{"class":558}," string",[552,671,672],{"class":625},"):",[552,674,675],{"class":558}," Promise",[552,677,626],{"class":625},[552,679,680],{"class":558},"boolean",[552,682,683],{"class":625},">;\n",[552,685,687,689,692,694,697,699,702,704,706,709,711,713,715,717,719,721,723,726,729],{"class":554,"line":686},3,[552,688,652],{"class":615},[552,690,691],{"class":655}," get",[552,693,626],{"class":625},[552,695,696],{"class":558},"TItem",[552,698,632],{"class":615},[552,700,701],{"class":558}," TValue",[552,703,638],{"class":625},[552,705,701],{"class":558},[552,707,708],{"class":625},">(",[552,710,663],{"class":662},[552,712,666],{"class":625},[552,714,669],{"class":558},[552,716,672],{"class":625},[552,718,675],{"class":558},[552,720,626],{"class":625},[552,722,696],{"class":558},[552,724,725],{"class":625}," |",[552,727,728],{"class":558}," null",[552,730,683],{"class":625},[552,732,734],{"class":554,"line":733},4,[552,735,737],{"class":736},"sHwdD","  \u002F\u002F `options.ttl` (a TimeSpan) is a best-effort native-TTL hint (Redis EX, CF KV expirationTtl, …).\n",[552,739,741,743,746,748,750,752,754,756,758],{"class":554,"line":740},5,[552,742,652],{"class":615},[552,744,745],{"class":655}," set",[552,747,626],{"class":625},[552,749,696],{"class":558},[552,751,632],{"class":615},[552,753,701],{"class":558},[552,755,638],{"class":625},[552,757,701],{"class":558},[552,759,760],{"class":625},">(\n",[552,762,764,767,769,771],{"class":554,"line":763},6,[552,765,766],{"class":662},"    key",[552,768,666],{"class":625},[552,770,669],{"class":558},[552,772,773],{"class":625},",\n",[552,775,777,780,782,785],{"class":554,"line":776},7,[552,778,779],{"class":662},"    value",[552,781,666],{"class":625},[552,783,784],{"class":558}," TItem",[552,786,773],{"class":625},[552,788,790,793,796,799],{"class":554,"line":789},8,[552,791,792],{"class":662},"    options",[552,794,795],{"class":625},"?:",[552,797,798],{"class":558}," StorageSetOptions",[552,800,773],{"class":625},[552,802,804,807,809,811,814],{"class":554,"line":803},9,[552,805,806],{"class":625},"  ):",[552,808,675],{"class":558},[552,810,626],{"class":625},[552,812,813],{"class":558},"void",[552,815,683],{"class":625},[552,817,819],{"class":554,"line":818},10,[552,820,821],{"class":736},"  \u002F\u002F Write only when the key holds no live value; `true` = the write happened.\n",[552,823,825,827,830,832,834,836,838,840,842],{"class":554,"line":824},11,[552,826,652],{"class":615},[552,828,829],{"class":655}," setIfAbsent",[552,831,626],{"class":625},[552,833,696],{"class":558},[552,835,632],{"class":615},[552,837,701],{"class":558},[552,839,638],{"class":625},[552,841,701],{"class":558},[552,843,760],{"class":625},[552,845,847,849,851,853],{"class":554,"line":846},12,[552,848,766],{"class":662},[552,850,666],{"class":625},[552,852,669],{"class":558},[552,854,773],{"class":625},[552,856,858,860,862,864],{"class":554,"line":857},13,[552,859,779],{"class":662},[552,861,666],{"class":625},[552,863,784],{"class":558},[552,865,773],{"class":625},[552,867,869,871,873,875],{"class":554,"line":868},14,[552,870,792],{"class":662},[552,872,795],{"class":625},[552,874,798],{"class":558},[552,876,773],{"class":625},[552,878,880,882,884,886,888],{"class":554,"line":879},15,[552,881,806],{"class":625},[552,883,675],{"class":558},[552,885,626],{"class":625},[552,887,680],{"class":558},[552,889,683],{"class":625},[552,891,893,895,898,900,902,904,906,908,910,912,914],{"class":554,"line":892},16,[552,894,652],{"class":615},[552,896,897],{"class":655}," delete",[552,899,659],{"class":625},[552,901,663],{"class":662},[552,903,666],{"class":625},[552,905,669],{"class":558},[552,907,672],{"class":625},[552,909,675],{"class":558},[552,911,626],{"class":625},[552,913,813],{"class":558},[552,915,683],{"class":625},[552,917,919,921,924,926,929,931,933,935,937,939,942,946],{"class":554,"line":918},17,[552,920,652],{"class":615},[552,922,923],{"class":655}," getKeys",[552,925,659],{"class":625},[552,927,928],{"class":662},"base",[552,930,795],{"class":625},[552,932,669],{"class":558},[552,934,672],{"class":625},[552,936,675],{"class":558},[552,938,626],{"class":625},[552,940,941],{"class":558},"string",[552,943,945],{"class":944},"sTEyZ","[]",[552,947,683],{"class":625},[552,949,951,953,956,958,960,962,964,966,968,970,972],{"class":554,"line":950},18,[552,952,652],{"class":615},[552,954,955],{"class":655}," clear",[552,957,659],{"class":625},[552,959,928],{"class":662},[552,961,795],{"class":625},[552,963,669],{"class":558},[552,965,672],{"class":625},[552,967,675],{"class":558},[552,969,626],{"class":625},[552,971,813],{"class":558},[552,973,683],{"class":625},[552,975,977],{"class":554,"line":976},19,[552,978,979],{"class":625},"}\n",[499,981,982,983,986,987,990],{},"A missing key resolves to ",[503,984,985],{},"null"," — never ",[503,988,989],{},"undefined",", never a throw — so a read is always a single\nbranch.",[499,992,993,996,997,1001,1002,1005,1006,1008,1009,1011,1012,1015,1016,1019],{},[503,994,995],{},"setIfAbsent"," is the conditional write, and ",[998,999,1000],"strong",{},"how atomic it is depends on the backend",": Redis and\nUpstash execute it as one atomic ",[503,1003,1004],{},"SET … NX"," command, and ",[503,1007,528],{}," checks and writes in a\nsingle synchronous step, while the unstorage bridge and Cloudflare KV fall back to a documented\ncheck-then-set (two calls — concurrent callers can race). Reach for an atomic backend whenever the\nreturned boolean gates a side effect, like claiming an idempotency key. Keys are opaque strings: pick any namespace convention you like, and pass a ",[503,1010,928],{}," prefix to\nscope ",[503,1013,1014],{},"getKeys"," and ",[503,1017,1018],{},"clear"," to one namespace. One store can host several logical tiers (cache,\nsessions, flags) and clear them independently.",[542,1021,1023],{"className":606,"code":1022,"language":608,"meta":548,"style":548},"import { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\n\nconst storage = new MemoryStorage();\n\nawait storage.set(\"cache:user:1\", { name: \"Ada\", roles: [\"admin\"] });\nawait storage.set(\"session:1\", \"token\");\n\nawait storage.getKeys(\"cache:\"); \u002F\u002F [\"cache:user:1\"] — scoped to the cache: namespace\nawait storage.clear(\"cache:\");   \u002F\u002F removes only the cache: namespace\nawait storage.get(\"missing\");    \u002F\u002F null\n",[503,1024,1025,1055,1061,1083,1087,1155,1187,1191,1218,1243],{"__ignoreMap":548},[552,1026,1027,1031,1034,1037,1040,1043,1046,1049,1052],{"class":554,"line":555},[552,1028,1030],{"class":1029},"s7zQu","import",[552,1032,1033],{"class":625}," {",[552,1035,1036],{"class":944}," MemoryStorage",[552,1038,1039],{"class":625}," }",[552,1041,1042],{"class":1029}," from",[552,1044,1045],{"class":625}," \"",[552,1047,1048],{"class":561},"@heximon\u002Fkv\u002Fmemory",[552,1050,1051],{"class":625},"\"",[552,1053,1054],{"class":625},";\n",[552,1056,1057],{"class":554,"line":649},[552,1058,1060],{"emptyLinePlaceholder":1059},true,"\n",[552,1062,1063,1066,1069,1072,1075,1078,1081],{"class":554,"line":686},[552,1064,1065],{"class":615},"const",[552,1067,1068],{"class":944}," storage ",[552,1070,1071],{"class":625},"=",[552,1073,1074],{"class":625}," new",[552,1076,1036],{"class":1077},"s2Zo4",[552,1079,1080],{"class":944},"()",[552,1082,1054],{"class":625},[552,1084,1085],{"class":554,"line":733},[552,1086,1060],{"emptyLinePlaceholder":1059},[552,1088,1089,1092,1095,1098,1101,1103,1105,1108,1110,1113,1115,1118,1120,1122,1125,1127,1129,1132,1134,1137,1139,1142,1144,1147,1150,1153],{"class":554,"line":740},[552,1090,1091],{"class":1029},"await",[552,1093,1094],{"class":944}," storage",[552,1096,1097],{"class":625},".",[552,1099,1100],{"class":1077},"set",[552,1102,659],{"class":944},[552,1104,1051],{"class":625},[552,1106,1107],{"class":561},"cache:user:1",[552,1109,1051],{"class":625},[552,1111,1112],{"class":625},",",[552,1114,1033],{"class":625},[552,1116,1117],{"class":655}," name",[552,1119,666],{"class":625},[552,1121,1045],{"class":625},[552,1123,1124],{"class":561},"Ada",[552,1126,1051],{"class":625},[552,1128,1112],{"class":625},[552,1130,1131],{"class":655}," roles",[552,1133,666],{"class":625},[552,1135,1136],{"class":944}," [",[552,1138,1051],{"class":625},[552,1140,1141],{"class":561},"admin",[552,1143,1051],{"class":625},[552,1145,1146],{"class":944},"] ",[552,1148,1149],{"class":625},"}",[552,1151,1152],{"class":944},")",[552,1154,1054],{"class":625},[552,1156,1157,1159,1161,1163,1165,1167,1169,1172,1174,1176,1178,1181,1183,1185],{"class":554,"line":763},[552,1158,1091],{"class":1029},[552,1160,1094],{"class":944},[552,1162,1097],{"class":625},[552,1164,1100],{"class":1077},[552,1166,659],{"class":944},[552,1168,1051],{"class":625},[552,1170,1171],{"class":561},"session:1",[552,1173,1051],{"class":625},[552,1175,1112],{"class":625},[552,1177,1045],{"class":625},[552,1179,1180],{"class":561},"token",[552,1182,1051],{"class":625},[552,1184,1152],{"class":944},[552,1186,1054],{"class":625},[552,1188,1189],{"class":554,"line":776},[552,1190,1060],{"emptyLinePlaceholder":1059},[552,1192,1193,1195,1197,1199,1201,1203,1205,1208,1210,1212,1215],{"class":554,"line":789},[552,1194,1091],{"class":1029},[552,1196,1094],{"class":944},[552,1198,1097],{"class":625},[552,1200,1014],{"class":1077},[552,1202,659],{"class":944},[552,1204,1051],{"class":625},[552,1206,1207],{"class":561},"cache:",[552,1209,1051],{"class":625},[552,1211,1152],{"class":944},[552,1213,1214],{"class":625},";",[552,1216,1217],{"class":736}," \u002F\u002F [\"cache:user:1\"] — scoped to the cache: namespace\n",[552,1219,1220,1222,1224,1226,1228,1230,1232,1234,1236,1238,1240],{"class":554,"line":803},[552,1221,1091],{"class":1029},[552,1223,1094],{"class":944},[552,1225,1097],{"class":625},[552,1227,1018],{"class":1077},[552,1229,659],{"class":944},[552,1231,1051],{"class":625},[552,1233,1207],{"class":561},[552,1235,1051],{"class":625},[552,1237,1152],{"class":944},[552,1239,1214],{"class":625},[552,1241,1242],{"class":736},"   \u002F\u002F removes only the cache: namespace\n",[552,1244,1245,1247,1249,1251,1254,1256,1258,1261,1263,1265,1267],{"class":554,"line":818},[552,1246,1091],{"class":1029},[552,1248,1094],{"class":944},[552,1250,1097],{"class":625},[552,1252,1253],{"class":1077},"get",[552,1255,659],{"class":944},[552,1257,1051],{"class":625},[552,1259,1260],{"class":561},"missing",[552,1262,1051],{"class":625},[552,1264,1152],{"class":944},[552,1266,1214],{"class":625},[552,1268,1269],{"class":736},"    \u002F\u002F null\n",[499,1271,1272,1273,1276],{},"TTL is a ",[503,1274,1275],{},"TimeSpan",", not a bare number of seconds — a driver converts it to whatever unit its native\nexpiry takes:",[542,1278,1280],{"className":606,"code":1279,"language":608,"meta":548,"style":548},"import { TimeSpan } from \"@heximon\u002Fprimitives\";\n\nawait storage.set(\"session:1\", \"token\", { ttl: new TimeSpan(1, \"h\") });\n",[503,1281,1282,1304,1308],{"__ignoreMap":548},[552,1283,1284,1286,1288,1291,1293,1295,1297,1300,1302],{"class":554,"line":555},[552,1285,1030],{"class":1029},[552,1287,1033],{"class":625},[552,1289,1290],{"class":944}," TimeSpan",[552,1292,1039],{"class":625},[552,1294,1042],{"class":1029},[552,1296,1045],{"class":625},[552,1298,1299],{"class":561},"@heximon\u002Fprimitives",[552,1301,1051],{"class":625},[552,1303,1054],{"class":625},[552,1305,1306],{"class":554,"line":649},[552,1307,1060],{"emptyLinePlaceholder":1059},[552,1309,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330,1332,1334,1336,1338,1341,1343,1345,1347,1349,1353,1355,1357,1360,1362,1365,1367,1369],{"class":554,"line":686},[552,1311,1091],{"class":1029},[552,1313,1094],{"class":944},[552,1315,1097],{"class":625},[552,1317,1100],{"class":1077},[552,1319,659],{"class":944},[552,1321,1051],{"class":625},[552,1323,1171],{"class":561},[552,1325,1051],{"class":625},[552,1327,1112],{"class":625},[552,1329,1045],{"class":625},[552,1331,1180],{"class":561},[552,1333,1051],{"class":625},[552,1335,1112],{"class":625},[552,1337,1033],{"class":625},[552,1339,1340],{"class":655}," ttl",[552,1342,666],{"class":625},[552,1344,1074],{"class":625},[552,1346,1290],{"class":1077},[552,1348,659],{"class":944},[552,1350,1352],{"class":1351},"sbssI","1",[552,1354,1112],{"class":625},[552,1356,1045],{"class":625},[552,1358,1359],{"class":561},"h",[552,1361,1051],{"class":625},[552,1363,1364],{"class":944},") ",[552,1366,1149],{"class":625},[552,1368,1152],{"class":944},[552,1370,1054],{"class":625},[520,1372,1374],{"id":1373},"bind-a-backend-in-a-module","Bind a backend in a module",[499,1376,1377,1378,1380,1381,1383],{},"Application code injects the abstract ",[503,1379,505],{}," and never names a backend. The module picks one:\n",[503,1382,528],{}," for dev and tests (zero infrastructure), a networked driver in production. Swapping\nenvironments changes only this binding.",[542,1385,1388],{"className":606,"code":1386,"filename":1387,"language":608,"meta":548,"style":548},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\nimport { UnstorageStorage } from \"@heximon\u002Fkv\u002Funstorage\";\nimport redisDriver from \"unstorage\u002Fdrivers\u002Fredis\";\n\nexport class StorageModule extends Module({\n  providers: [\n    \u002F\u002F dev \u002F tests — the in-memory backend:\n    { provide: Storage, useClass: MemoryStorage },\n    \u002F\u002F production — wrap any unstorage driver behind the same Storage token:\n    \u002F\u002F { provide: Storage, useFactory: () => UnstorageStorage.fromDriver(redisDriver({})) },\n  ],\n  exports: [Storage], \u002F\u002F visible to any module that imports StorageModule\n}) {}\n","storage.module.ts",[503,1389,1390,1412,1433,1453,1475,1494,1498,1517,1527,1532,1557,1562,1567,1574,1589],{"__ignoreMap":548},[552,1391,1392,1394,1396,1399,1401,1403,1405,1408,1410],{"class":554,"line":555},[552,1393,1030],{"class":1029},[552,1395,1033],{"class":625},[552,1397,1398],{"class":944}," Module",[552,1400,1039],{"class":625},[552,1402,1042],{"class":1029},[552,1404,1045],{"class":625},[552,1406,1407],{"class":561},"@heximon\u002Fruntime",[552,1409,1051],{"class":625},[552,1411,1054],{"class":625},[552,1413,1414,1416,1418,1420,1422,1424,1426,1429,1431],{"class":554,"line":649},[552,1415,1030],{"class":1029},[552,1417,1033],{"class":625},[552,1419,622],{"class":944},[552,1421,1039],{"class":625},[552,1423,1042],{"class":1029},[552,1425,1045],{"class":625},[552,1427,1428],{"class":561},"@heximon\u002Fkv",[552,1430,1051],{"class":625},[552,1432,1054],{"class":625},[552,1434,1435,1437,1439,1441,1443,1445,1447,1449,1451],{"class":554,"line":686},[552,1436,1030],{"class":1029},[552,1438,1033],{"class":625},[552,1440,1036],{"class":944},[552,1442,1039],{"class":625},[552,1444,1042],{"class":1029},[552,1446,1045],{"class":625},[552,1448,1048],{"class":561},[552,1450,1051],{"class":625},[552,1452,1054],{"class":625},[552,1454,1455,1457,1459,1462,1464,1466,1468,1471,1473],{"class":554,"line":733},[552,1456,1030],{"class":1029},[552,1458,1033],{"class":625},[552,1460,1461],{"class":944}," UnstorageStorage",[552,1463,1039],{"class":625},[552,1465,1042],{"class":1029},[552,1467,1045],{"class":625},[552,1469,1470],{"class":561},"@heximon\u002Fkv\u002Funstorage",[552,1472,1051],{"class":625},[552,1474,1054],{"class":625},[552,1476,1477,1479,1482,1485,1487,1490,1492],{"class":554,"line":740},[552,1478,1030],{"class":1029},[552,1480,1481],{"class":944}," redisDriver ",[552,1483,1484],{"class":1029},"from",[552,1486,1045],{"class":625},[552,1488,1489],{"class":561},"unstorage\u002Fdrivers\u002Fredis",[552,1491,1051],{"class":625},[552,1493,1054],{"class":625},[552,1495,1496],{"class":554,"line":763},[552,1497,1060],{"emptyLinePlaceholder":1059},[552,1499,1500,1503,1505,1508,1510,1512,1514],{"class":554,"line":776},[552,1501,1502],{"class":1029},"export",[552,1504,619],{"class":615},[552,1506,1507],{"class":558}," StorageModule",[552,1509,632],{"class":615},[552,1511,1398],{"class":1077},[552,1513,659],{"class":944},[552,1515,1516],{"class":625},"{\n",[552,1518,1519,1522,1524],{"class":554,"line":789},[552,1520,1521],{"class":655},"  providers",[552,1523,666],{"class":625},[552,1525,1526],{"class":944}," [\n",[552,1528,1529],{"class":554,"line":803},[552,1530,1531],{"class":736},"    \u002F\u002F dev \u002F tests — the in-memory backend:\n",[552,1533,1534,1537,1540,1542,1544,1546,1549,1551,1554],{"class":554,"line":818},[552,1535,1536],{"class":625},"    {",[552,1538,1539],{"class":655}," provide",[552,1541,666],{"class":625},[552,1543,622],{"class":944},[552,1545,1112],{"class":625},[552,1547,1548],{"class":655}," useClass",[552,1550,666],{"class":625},[552,1552,1553],{"class":944}," MemoryStorage ",[552,1555,1556],{"class":625},"},\n",[552,1558,1559],{"class":554,"line":824},[552,1560,1561],{"class":736},"    \u002F\u002F production — wrap any unstorage driver behind the same Storage token:\n",[552,1563,1564],{"class":554,"line":846},[552,1565,1566],{"class":736},"    \u002F\u002F { provide: Storage, useFactory: () => UnstorageStorage.fromDriver(redisDriver({})) },\n",[552,1568,1569,1572],{"class":554,"line":857},[552,1570,1571],{"class":944},"  ]",[552,1573,773],{"class":625},[552,1575,1576,1579,1581,1584,1586],{"class":554,"line":868},[552,1577,1578],{"class":655},"  exports",[552,1580,666],{"class":625},[552,1582,1583],{"class":944}," [Storage]",[552,1585,1112],{"class":625},[552,1587,1588],{"class":736}," \u002F\u002F visible to any module that imports StorageModule\n",[552,1590,1591,1593,1595],{"class":554,"line":879},[552,1592,1149],{"class":625},[552,1594,1364],{"class":944},[552,1596,1597],{"class":625},"{}\n",[499,1599,1600,1601,1603],{},"A consumer declares the dependency the usual way — a constructor parameter typed ",[503,1602,505],{},", which the\ncompiler resolves to whatever the module bound:",[542,1605,1608],{"className":606,"code":1606,"filename":1607,"language":608,"meta":548,"style":548},"import { Storage } from \"@heximon\u002Fkv\";\n\nexport class SessionCache {\n  constructor(private readonly storage: Storage) {}\n\n  public async remember(id: string, value: object): Promise\u003Cvoid> {\n    await this.storage.set(`session:${id}`, value);\n  }\n}\n","session-cache.ts",[503,1609,1610,1630,1634,1645,1669,1673,1715,1754,1759],{"__ignoreMap":548},[552,1611,1612,1614,1616,1618,1620,1622,1624,1626,1628],{"class":554,"line":555},[552,1613,1030],{"class":1029},[552,1615,1033],{"class":625},[552,1617,622],{"class":944},[552,1619,1039],{"class":625},[552,1621,1042],{"class":1029},[552,1623,1045],{"class":625},[552,1625,1428],{"class":561},[552,1627,1051],{"class":625},[552,1629,1054],{"class":625},[552,1631,1632],{"class":554,"line":649},[552,1633,1060],{"emptyLinePlaceholder":1059},[552,1635,1636,1638,1640,1643],{"class":554,"line":686},[552,1637,1502],{"class":1029},[552,1639,619],{"class":615},[552,1641,1642],{"class":558}," SessionCache",[552,1644,646],{"class":625},[552,1646,1647,1650,1652,1655,1658,1660,1662,1664,1666],{"class":554,"line":733},[552,1648,1649],{"class":615},"  constructor",[552,1651,659],{"class":625},[552,1653,1654],{"class":615},"private",[552,1656,1657],{"class":615}," readonly",[552,1659,1094],{"class":662},[552,1661,666],{"class":625},[552,1663,622],{"class":558},[552,1665,1152],{"class":625},[552,1667,1668],{"class":625}," {}\n",[552,1670,1671],{"class":554,"line":740},[552,1672,1060],{"emptyLinePlaceholder":1059},[552,1674,1675,1678,1681,1684,1686,1689,1691,1693,1695,1698,1700,1703,1705,1707,1709,1711,1713],{"class":554,"line":763},[552,1676,1677],{"class":615},"  public",[552,1679,1680],{"class":615}," async",[552,1682,1683],{"class":655}," remember",[552,1685,659],{"class":625},[552,1687,1688],{"class":662},"id",[552,1690,666],{"class":625},[552,1692,669],{"class":558},[552,1694,1112],{"class":625},[552,1696,1697],{"class":662}," value",[552,1699,666],{"class":625},[552,1701,1702],{"class":558}," object",[552,1704,672],{"class":625},[552,1706,675],{"class":558},[552,1708,626],{"class":625},[552,1710,813],{"class":558},[552,1712,643],{"class":625},[552,1714,646],{"class":625},[552,1716,1717,1720,1723,1726,1728,1730,1732,1735,1738,1741,1743,1746,1748,1750,1752],{"class":554,"line":776},[552,1718,1719],{"class":1029},"    await",[552,1721,1722],{"class":625}," this.",[552,1724,1725],{"class":944},"storage",[552,1727,1097],{"class":625},[552,1729,1100],{"class":1077},[552,1731,659],{"class":655},[552,1733,1734],{"class":625},"`",[552,1736,1737],{"class":561},"session:",[552,1739,1740],{"class":625},"${",[552,1742,1688],{"class":944},[552,1744,1745],{"class":625},"}`",[552,1747,1112],{"class":625},[552,1749,1697],{"class":944},[552,1751,1152],{"class":655},[552,1753,1054],{"class":625},[552,1755,1756],{"class":554,"line":789},[552,1757,1758],{"class":625},"  }\n",[552,1760,1761],{"class":554,"line":803},[552,1762,979],{"class":625},[499,1764,1765,1768,1769,1775,1776,1778],{},[503,1766,1767],{},"UnstorageStorage"," bridges the whole ",[515,1770,1774],{"href":1771,"rel":1772},"https:\u002F\u002Funstorage.unjs.io\u002Fdrivers",[1773],"nofollow","unstorage driver ecosystem"," —\nmemory, fs, Redis, Cloudflare KV, Upstash, S3 — behind the same ",[503,1777,505],{}," contract, so application code\nstays on the one port no matter which driver is underneath.",[1780,1781,1783,1805],"callout",{"type":1782},"warning",[499,1784,1785,1788,1789,1791,1792,1796,1797,1800,1801,1804],{},[998,1786,1787],{},"Pick exactly one backend per app graph."," Because the abstract ",[503,1790,505],{}," class ",[1793,1794,1795],"em",{},"is"," the DI token, the\ngraph must resolve it to a single concrete subclass — binding two (one ",[503,1798,1799],{},"useClass",", one ",[503,1802,1803],{},"useFactory",")\nmakes the resolution ambiguous and the build fails. Use one binding per app, or compose a per-environment\nmodule that contributes exactly one.",[499,1806,1807,1809,1810,1813],{},[503,1808,528],{}," stores values ",[998,1811,1812],{},"by reference"," (no copy, no serialization), while the networked drivers\nserialize — so they round-trip JSON-compatible values only. Functions and symbols are out of contract\nfor both.",[520,1815,1817],{"id":1816},"memorystorage-ttl-and-lru-bounds","MemoryStorage — TTL and LRU bounds",[499,1819,1820,1822,1823,1825,1826,1829],{},[503,1821,528],{}," is the zero-dependency, ",[503,1824,509],{},"-backed backend for dev and tests. TTL is honored with\nlazy expiry (millisecond precision — an expired entry is dropped by the next operation that touches\nit), and it's ",[998,1827,1828],{},"unbounded by default",", because a general-purpose KV must not silently drop data like\nidempotency markers or sessions.",[542,1831,1833],{"className":606,"code":1832,"language":608,"meta":548,"style":548},"export interface MemoryStorageOptions {\n  readonly maxEntries?: number; \u002F\u002F LRU eviction past this entry count\n  readonly maxBytes?: number;   \u002F\u002F LRU eviction past this approximate serialized size\n}\n",[503,1834,1835,1847,1865,1881],{"__ignoreMap":548},[552,1836,1837,1839,1842,1845],{"class":554,"line":555},[552,1838,1502],{"class":1029},[552,1840,1841],{"class":615}," interface",[552,1843,1844],{"class":558}," MemoryStorageOptions",[552,1846,646],{"class":625},[552,1848,1849,1852,1855,1857,1860,1862],{"class":554,"line":649},[552,1850,1851],{"class":615},"  readonly",[552,1853,1854],{"class":655}," maxEntries",[552,1856,795],{"class":625},[552,1858,1859],{"class":558}," number",[552,1861,1214],{"class":625},[552,1863,1864],{"class":736}," \u002F\u002F LRU eviction past this entry count\n",[552,1866,1867,1869,1872,1874,1876,1878],{"class":554,"line":686},[552,1868,1851],{"class":615},[552,1870,1871],{"class":655}," maxBytes",[552,1873,795],{"class":625},[552,1875,1859],{"class":558},[552,1877,1214],{"class":625},[552,1879,1880],{"class":736},"   \u002F\u002F LRU eviction past this approximate serialized size\n",[552,1882,1883],{"class":554,"line":733},[552,1884,979],{"class":625},[499,1886,1887,1888,1891,1892,1895],{},"Opt into LRU bounds when you're using it as a cache tier rather than a source of truth — reads and\nwrites mark entries most-recently-used, and a write past a cap evicts least-recently-used keys first.\n",[503,1889,1890],{},"maxBytes"," is the out-of-memory guard for caching large values; ",[503,1893,1894],{},"maxEntries"," alone doesn't bound\nmemory if entries vary wildly in size.",[542,1897,1899],{"className":606,"code":1898,"language":608,"meta":548,"style":548},"import { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\n\nconst cache = new MemoryStorage({ maxEntries: 10_000, maxBytes: 50 * 1024 * 1024 });\n",[503,1900,1901,1921,1925],{"__ignoreMap":548},[552,1902,1903,1905,1907,1909,1911,1913,1915,1917,1919],{"class":554,"line":555},[552,1904,1030],{"class":1029},[552,1906,1033],{"class":625},[552,1908,1036],{"class":944},[552,1910,1039],{"class":625},[552,1912,1042],{"class":1029},[552,1914,1045],{"class":625},[552,1916,1048],{"class":561},[552,1918,1051],{"class":625},[552,1920,1054],{"class":625},[552,1922,1923],{"class":554,"line":649},[552,1924,1060],{"emptyLinePlaceholder":1059},[552,1926,1927,1929,1932,1934,1936,1938,1940,1943,1945,1947,1950,1952,1954,1956,1959,1962,1965,1967,1969,1971,1973],{"class":554,"line":686},[552,1928,1065],{"class":615},[552,1930,1931],{"class":944}," cache ",[552,1933,1071],{"class":625},[552,1935,1074],{"class":625},[552,1937,1036],{"class":1077},[552,1939,659],{"class":944},[552,1941,1942],{"class":625},"{",[552,1944,1854],{"class":655},[552,1946,666],{"class":625},[552,1948,1949],{"class":1351}," 10_000",[552,1951,1112],{"class":625},[552,1953,1871],{"class":655},[552,1955,666],{"class":625},[552,1957,1958],{"class":1351}," 50",[552,1960,1961],{"class":625}," *",[552,1963,1964],{"class":1351}," 1024",[552,1966,1961],{"class":625},[552,1968,1964],{"class":1351},[552,1970,1039],{"class":625},[552,1972,1152],{"class":944},[552,1974,1054],{"class":625},[520,1976,1978],{"id":1977},"first-class-networked-adapters","First-class networked adapters",[499,1980,1981,1982,1984,1985,1988,1989,1992,1993,1996,1997,2000,2001,2003,2004,2010],{},"Beyond the ",[503,1983,536],{}," bridge, three backends ship as first-class adapters on their own subpaths —\ntyped, with the right lifecycle for each. The two edge backends (Upstash, Cloudflare KV) are\nconnectionless (no ",[503,1986,1987],{},"onShutdown","); the Node Redis backend holds a real connection (it ",[503,1990,1991],{},"close()","s on\nshutdown). All ",[503,1994,1995],{},"extends Storage",", so they bind under the same token. A fourth first-class backend —\nthe strongly-consistent, Durable-Object-backed ",[503,1998,1999],{},"KvRoomStorage"," with a genuinely atomic ",[503,2002,995],{}," —\nships from ",[515,2005,2007],{"href":2006},"\u002Fdocs\u002Frealtime\u002Fdurable-objects#strongly-consistent-keyvalue-storage-heximondurablekv",[503,2008,2009],{},"@heximon\u002Fdurable\u002Fkv","\n(the DO satisfier lives with the DO machinery; this package stays dependency-thin).",[2012,2013,2015,2016,2019],"h3",{"id":2014},"upstash-redis-heximonkvupstash-edge-safe","Upstash Redis — ",[503,2017,2018],{},"@heximon\u002Fkv\u002Fupstash"," (edge-safe)",[499,2021,2022,2025,2026,2033,2034,2037,2038,2041,2042,2045,2046,2049],{},[503,2023,2024],{},"UpstashStorage"," wraps the fetch-based ",[515,2027,2030],{"href":2028,"rel":2029},"https:\u002F\u002Fgithub.com\u002Fupstash\u002Fredis-js",[1773],[503,2031,2032],{},"@upstash\u002Fredis"," client, so it\nruns on Cloudflare Workers, Vercel Edge, Deno, and Node with no TCP socket. ",[998,2035,2036],{},"This is also the Vercel KV\nstory"," — Vercel retired its standalone KV and migrated stores to Upstash, so ",[503,2039,2040],{},"Redis.fromEnv()"," reads\nthe ",[503,2043,2044],{},"KV_REST_API_URL"," \u002F ",[503,2047,2048],{},"KV_REST_API_TOKEN"," it injects with no extra glue.",[499,2051,2052,2053,2056,2057,2060,2061,2064,2065,2068,2069,2072],{},"Three construction paths are supported: inject a pre-configured ",[503,2054,2055],{},"Redis"," instance, or use the\nconvenience statics ",[503,2058,2059],{},"UpstashStorage.fromEnv()"," (reads ",[503,2062,2063],{},"UPSTASH_REDIS_REST_URL"," \u002F\n",[503,2066,2067],{},"UPSTASH_REDIS_REST_TOKEN",", with Vercel KV fallbacks) or ",[503,2070,2071],{},"UpstashStorage.fromConfig({ url, token })","\n(explicit credentials).",[542,2074,2076],{"className":606,"code":2075,"filename":1387,"language":608,"meta":548,"style":548},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { UpstashStorage } from \"@heximon\u002Fkv\u002Fupstash\";\n\nexport class StorageModule extends Module({\n  providers: [\n    \u002F\u002F From env vars (Vercel KV \u002F any Upstash project):\n    { provide: Storage, useFactory: () => UpstashStorage.fromEnv() },\n    \u002F\u002F Or explicit credentials:\n    \u002F\u002F { provide: Storage, useFactory: () => UpstashStorage.fromConfig({ url: \"...\", token: \"...\" }) },\n  ],\n  exports: [Storage],\n}) {}\n",[503,2077,2078,2098,2118,2139,2143,2159,2167,2172,2207,2212,2217,2223,2233],{"__ignoreMap":548},[552,2079,2080,2082,2084,2086,2088,2090,2092,2094,2096],{"class":554,"line":555},[552,2081,1030],{"class":1029},[552,2083,1033],{"class":625},[552,2085,1398],{"class":944},[552,2087,1039],{"class":625},[552,2089,1042],{"class":1029},[552,2091,1045],{"class":625},[552,2093,1407],{"class":561},[552,2095,1051],{"class":625},[552,2097,1054],{"class":625},[552,2099,2100,2102,2104,2106,2108,2110,2112,2114,2116],{"class":554,"line":649},[552,2101,1030],{"class":1029},[552,2103,1033],{"class":625},[552,2105,622],{"class":944},[552,2107,1039],{"class":625},[552,2109,1042],{"class":1029},[552,2111,1045],{"class":625},[552,2113,1428],{"class":561},[552,2115,1051],{"class":625},[552,2117,1054],{"class":625},[552,2119,2120,2122,2124,2127,2129,2131,2133,2135,2137],{"class":554,"line":686},[552,2121,1030],{"class":1029},[552,2123,1033],{"class":625},[552,2125,2126],{"class":944}," UpstashStorage",[552,2128,1039],{"class":625},[552,2130,1042],{"class":1029},[552,2132,1045],{"class":625},[552,2134,2018],{"class":561},[552,2136,1051],{"class":625},[552,2138,1054],{"class":625},[552,2140,2141],{"class":554,"line":733},[552,2142,1060],{"emptyLinePlaceholder":1059},[552,2144,2145,2147,2149,2151,2153,2155,2157],{"class":554,"line":740},[552,2146,1502],{"class":1029},[552,2148,619],{"class":615},[552,2150,1507],{"class":558},[552,2152,632],{"class":615},[552,2154,1398],{"class":1077},[552,2156,659],{"class":944},[552,2158,1516],{"class":625},[552,2160,2161,2163,2165],{"class":554,"line":763},[552,2162,1521],{"class":655},[552,2164,666],{"class":625},[552,2166,1526],{"class":944},[552,2168,2169],{"class":554,"line":776},[552,2170,2171],{"class":736},"    \u002F\u002F From env vars (Vercel KV \u002F any Upstash project):\n",[552,2173,2174,2176,2178,2180,2182,2184,2187,2189,2192,2195,2197,2199,2202,2205],{"class":554,"line":789},[552,2175,1536],{"class":625},[552,2177,1539],{"class":655},[552,2179,666],{"class":625},[552,2181,622],{"class":944},[552,2183,1112],{"class":625},[552,2185,2186],{"class":1077}," useFactory",[552,2188,666],{"class":625},[552,2190,2191],{"class":625}," ()",[552,2193,2194],{"class":615}," =>",[552,2196,2126],{"class":944},[552,2198,1097],{"class":625},[552,2200,2201],{"class":1077},"fromEnv",[552,2203,2204],{"class":944},"() ",[552,2206,1556],{"class":625},[552,2208,2209],{"class":554,"line":803},[552,2210,2211],{"class":736},"    \u002F\u002F Or explicit credentials:\n",[552,2213,2214],{"class":554,"line":818},[552,2215,2216],{"class":736},"    \u002F\u002F { provide: Storage, useFactory: () => UpstashStorage.fromConfig({ url: \"...\", token: \"...\" }) },\n",[552,2218,2219,2221],{"class":554,"line":824},[552,2220,1571],{"class":944},[552,2222,773],{"class":625},[552,2224,2225,2227,2229,2231],{"class":554,"line":846},[552,2226,1578],{"class":655},[552,2228,666],{"class":625},[552,2230,1583],{"class":944},[552,2232,773],{"class":625},[552,2234,2235,2237,2239],{"class":554,"line":857},[552,2236,1149],{"class":625},[552,2238,1364],{"class":944},[552,2240,1597],{"class":625},[499,2242,2243,2246,2247,2250,2251,2253,2254,2257,2258,2045,2260,2262,2263,2266,2267,2269,2270,2273,2274,2277,2278,2281,2282,2285],{},[503,2244,2245],{},"set(key, value, { ttl })"," maps to Redis ",[503,2248,2249],{},"SET … EX"," (1-second precision), and ",[503,2252,995],{}," to a\nsingle atomic ",[503,2255,2256],{},"SET … NX [EX]"," command. ",[503,2259,1014],{},[503,2261,1018],{}," use a\n",[503,2264,2265],{},"SCAN"," cursor loop and need a read-write token — they are O(n) admin\u002Fteardown operations, not hot-path\ncalls. ",[503,2268,2024],{}," also implements the optional ",[503,2271,2272],{},"BatchStorage"," capability interface (native\n",[503,2275,2276],{},"MGET","\u002F",[503,2279,2280],{},"MSET","; TTL path uses a single pipeline of ",[503,2283,2284],{},"SET EX"," commands).",[2012,2287,2289,2290,2019],{"id":2288},"cloudflare-workers-kv-heximonkvcloudflare-edge-safe","Cloudflare Workers KV — ",[503,2291,2292],{},"@heximon\u002Fkv\u002Fcloudflare",[499,2294,2295,2298,2299,2302,2303,2306,2307,2310],{},[503,2296,2297],{},"CloudflareKvStorage"," wraps a ",[503,2300,2301],{},"KVNamespace"," binding, resolved via the static ",[503,2304,2305],{},"Platform.binding(...)"," —\n",[503,2308,2309],{},"Platform"," is a static helper, not a DI token, so the factory takes no parameters:",[542,2312,2314],{"className":606,"code":2313,"filename":1387,"language":608,"meta":548,"style":548},"import { Module, Platform } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { CloudflareKvStorage } from \"@heximon\u002Fkv\u002Fcloudflare\";\n\nexport class StorageModule extends Module({\n  providers: [\n    {\n      provide: Storage,\n      useFactory: (): Storage => new CloudflareKvStorage(Platform.binding(\"MY_KV\")),\n    },\n  ],\n  exports: [Storage],\n}) {}\n",[503,2315,2316,2341,2361,2382,2386,2402,2410,2415,2426,2466,2471,2477,2487],{"__ignoreMap":548},[552,2317,2318,2320,2322,2324,2326,2329,2331,2333,2335,2337,2339],{"class":554,"line":555},[552,2319,1030],{"class":1029},[552,2321,1033],{"class":625},[552,2323,1398],{"class":944},[552,2325,1112],{"class":625},[552,2327,2328],{"class":944}," Platform",[552,2330,1039],{"class":625},[552,2332,1042],{"class":1029},[552,2334,1045],{"class":625},[552,2336,1407],{"class":561},[552,2338,1051],{"class":625},[552,2340,1054],{"class":625},[552,2342,2343,2345,2347,2349,2351,2353,2355,2357,2359],{"class":554,"line":649},[552,2344,1030],{"class":1029},[552,2346,1033],{"class":625},[552,2348,622],{"class":944},[552,2350,1039],{"class":625},[552,2352,1042],{"class":1029},[552,2354,1045],{"class":625},[552,2356,1428],{"class":561},[552,2358,1051],{"class":625},[552,2360,1054],{"class":625},[552,2362,2363,2365,2367,2370,2372,2374,2376,2378,2380],{"class":554,"line":686},[552,2364,1030],{"class":1029},[552,2366,1033],{"class":625},[552,2368,2369],{"class":944}," CloudflareKvStorage",[552,2371,1039],{"class":625},[552,2373,1042],{"class":1029},[552,2375,1045],{"class":625},[552,2377,2292],{"class":561},[552,2379,1051],{"class":625},[552,2381,1054],{"class":625},[552,2383,2384],{"class":554,"line":733},[552,2385,1060],{"emptyLinePlaceholder":1059},[552,2387,2388,2390,2392,2394,2396,2398,2400],{"class":554,"line":740},[552,2389,1502],{"class":1029},[552,2391,619],{"class":615},[552,2393,1507],{"class":558},[552,2395,632],{"class":615},[552,2397,1398],{"class":1077},[552,2399,659],{"class":944},[552,2401,1516],{"class":625},[552,2403,2404,2406,2408],{"class":554,"line":763},[552,2405,1521],{"class":655},[552,2407,666],{"class":625},[552,2409,1526],{"class":944},[552,2411,2412],{"class":554,"line":776},[552,2413,2414],{"class":625},"    {\n",[552,2416,2417,2420,2422,2424],{"class":554,"line":789},[552,2418,2419],{"class":655},"      provide",[552,2421,666],{"class":625},[552,2423,622],{"class":944},[552,2425,773],{"class":625},[552,2427,2428,2431,2433,2436,2438,2440,2442,2444,2447,2449,2452,2454,2456,2459,2461,2464],{"class":554,"line":803},[552,2429,2430],{"class":1077},"      useFactory",[552,2432,666],{"class":625},[552,2434,2435],{"class":625}," ():",[552,2437,622],{"class":558},[552,2439,2194],{"class":615},[552,2441,1074],{"class":625},[552,2443,2369],{"class":1077},[552,2445,2446],{"class":944},"(Platform",[552,2448,1097],{"class":625},[552,2450,2451],{"class":1077},"binding",[552,2453,659],{"class":944},[552,2455,1051],{"class":625},[552,2457,2458],{"class":561},"MY_KV",[552,2460,1051],{"class":625},[552,2462,2463],{"class":944},"))",[552,2465,773],{"class":625},[552,2467,2468],{"class":554,"line":818},[552,2469,2470],{"class":625},"    },\n",[552,2472,2473,2475],{"class":554,"line":824},[552,2474,1571],{"class":944},[552,2476,773],{"class":625},[552,2478,2479,2481,2483,2485],{"class":554,"line":846},[552,2480,1578],{"class":655},[552,2482,666],{"class":625},[552,2484,1583],{"class":944},[552,2486,773],{"class":625},[552,2488,2489,2491,2493],{"class":554,"line":857},[552,2490,1149],{"class":625},[552,2492,1364],{"class":944},[552,2494,1597],{"class":625},[1780,2496,2497,2500,2501,2504,2505,2508,2509,2512,2513,2515],{"type":1782},[998,2498,2499],{},"Cloudflare KV is eventually consistent"," (up to ~60 s global propagation) and ",[503,2502,2503],{},"expirationTtl"," has a\n60-second floor — a sub-minute ",[503,2506,2507],{},"ttl"," is clamped to 60 with a ",[503,2510,2511],{},"console.warn",". It is therefore the wrong\nstore for distributed idempotency or cross-region dedup, where a stale read across regions means a\nretried request slips past a dedup check that should have caught it — use Durable Objects or D1 for\nthose instead. ",[503,2514,995],{}," is a check-then-set fallback here (KV has no compare-and-swap), so it\nmust never gate a cross-isolate side effect.",[2012,2517,2519,2520,2523],{"id":2518},"redis-heximonkvredis-node-only","Redis — ",[503,2521,2522],{},"@heximon\u002Fkv\u002Fredis"," (Node-only)",[499,2525,2526,2298,2529,2534,2535,2538,2539,2542,2543,2546,2547,2549],{},[503,2527,2528],{},"RedisStorage",[515,2530,2533],{"href":2531,"rel":2532},"https:\u002F\u002Fgithub.com\u002Fredis\u002Fnode-redis",[1773],"node-redis"," TCP client (the ",[503,2536,2537],{},"redis","\npackage) — the durable Node-side backend for self-hosted Redis, Redis Cloud, and ",[998,2540,2541],{},"AWS ElastiCache","\n(point the URL at the managed endpoint). It opens a raw TCP socket, so it is ",[998,2544,2545],{},"Node-only"," — edge\nruntimes forbid raw sockets, so use ",[503,2548,2018],{}," there instead.",[499,2551,2552,2553,2556,2557,2559,2560,2563],{},"It owns the connection:\n",[503,2554,2555],{},"connect()"," on init, ",[503,2558,1991],{}," on shutdown. Use the ",[503,2561,2562],{},"fromUrl"," config-form, or inject a pre-built client\nfor full control (auth, TLS, reconnect, Sentinel).",[542,2565,2567],{"className":606,"code":2566,"filename":1387,"language":608,"meta":548,"style":548},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { RedisStorage } from \"@heximon\u002Fkv\u002Fredis\";\n\nexport class StorageModule extends Module({\n  providers: [\n    {\n      provide: Storage,\n      useFactory: () => RedisStorage.fromUrl(process.env.REDIS_URL ?? \"redis:\u002F\u002Flocalhost:6379\"),\n    },\n  ],\n  exports: [Storage],\n}) {}\n",[503,2568,2569,2589,2609,2630,2634,2650,2658,2662,2672,2715,2719,2725,2735],{"__ignoreMap":548},[552,2570,2571,2573,2575,2577,2579,2581,2583,2585,2587],{"class":554,"line":555},[552,2572,1030],{"class":1029},[552,2574,1033],{"class":625},[552,2576,1398],{"class":944},[552,2578,1039],{"class":625},[552,2580,1042],{"class":1029},[552,2582,1045],{"class":625},[552,2584,1407],{"class":561},[552,2586,1051],{"class":625},[552,2588,1054],{"class":625},[552,2590,2591,2593,2595,2597,2599,2601,2603,2605,2607],{"class":554,"line":649},[552,2592,1030],{"class":1029},[552,2594,1033],{"class":625},[552,2596,622],{"class":944},[552,2598,1039],{"class":625},[552,2600,1042],{"class":1029},[552,2602,1045],{"class":625},[552,2604,1428],{"class":561},[552,2606,1051],{"class":625},[552,2608,1054],{"class":625},[552,2610,2611,2613,2615,2618,2620,2622,2624,2626,2628],{"class":554,"line":686},[552,2612,1030],{"class":1029},[552,2614,1033],{"class":625},[552,2616,2617],{"class":944}," RedisStorage",[552,2619,1039],{"class":625},[552,2621,1042],{"class":1029},[552,2623,1045],{"class":625},[552,2625,2522],{"class":561},[552,2627,1051],{"class":625},[552,2629,1054],{"class":625},[552,2631,2632],{"class":554,"line":733},[552,2633,1060],{"emptyLinePlaceholder":1059},[552,2635,2636,2638,2640,2642,2644,2646,2648],{"class":554,"line":740},[552,2637,1502],{"class":1029},[552,2639,619],{"class":615},[552,2641,1507],{"class":558},[552,2643,632],{"class":615},[552,2645,1398],{"class":1077},[552,2647,659],{"class":944},[552,2649,1516],{"class":625},[552,2651,2652,2654,2656],{"class":554,"line":763},[552,2653,1521],{"class":655},[552,2655,666],{"class":625},[552,2657,1526],{"class":944},[552,2659,2660],{"class":554,"line":776},[552,2661,2414],{"class":625},[552,2663,2664,2666,2668,2670],{"class":554,"line":789},[552,2665,2419],{"class":655},[552,2667,666],{"class":625},[552,2669,622],{"class":944},[552,2671,773],{"class":625},[552,2673,2674,2676,2678,2680,2682,2684,2686,2688,2691,2693,2696,2698,2701,2704,2706,2709,2711,2713],{"class":554,"line":803},[552,2675,2430],{"class":1077},[552,2677,666],{"class":625},[552,2679,2191],{"class":625},[552,2681,2194],{"class":615},[552,2683,2617],{"class":944},[552,2685,1097],{"class":625},[552,2687,2562],{"class":1077},[552,2689,2690],{"class":944},"(process",[552,2692,1097],{"class":625},[552,2694,2695],{"class":944},"env",[552,2697,1097],{"class":625},[552,2699,2700],{"class":944},"REDIS_URL ",[552,2702,2703],{"class":625},"??",[552,2705,1045],{"class":625},[552,2707,2708],{"class":561},"redis:\u002F\u002Flocalhost:6379",[552,2710,1051],{"class":625},[552,2712,1152],{"class":944},[552,2714,773],{"class":625},[552,2716,2717],{"class":554,"line":818},[552,2718,2470],{"class":625},[552,2720,2721,2723],{"class":554,"line":824},[552,2722,1571],{"class":944},[552,2724,773],{"class":625},[552,2726,2727,2729,2731,2733],{"class":554,"line":846},[552,2728,1578],{"class":655},[552,2730,666],{"class":625},[552,2732,1583],{"class":944},[552,2734,773],{"class":625},[552,2736,2737,2739,2741],{"class":554,"line":857},[552,2738,1149],{"class":625},[552,2740,1364],{"class":944},[552,2742,1597],{"class":625},[499,2744,2745,2747,2748,2750,2751,2753,2754,2756,2757,2045,2759,2761,2762,2764,2765,2768,2769,2771,2772,2775,2776,2779],{},[503,2746,2245],{}," maps to ",[503,2749,2249],{},", and ",[503,2752,995],{}," to a single atomic ",[503,2755,2256],{},"\ncommand — safe across processes and isolates. ",[503,2758,1014],{},[503,2760,1018],{}," use a non-blocking ",[503,2763,2265],{}," loop\n(never ",[503,2766,2767],{},"KEYS","); ",[503,2770,1018],{}," removes with ",[503,2773,2774],{},"UNLINK"," (never ",[503,2777,2778],{},"FLUSHDB","), so it is safe on a shared instance.",[499,2781,2782,2783,2787,2788,2790,2791,2793,2794,2277,2796,2798],{},"Both are O(n) admin\u002Fteardown operations. Single-node, Sentinel, and Redis Cluster clients are all\naccepted — see ",[515,2784,2786],{"href":2785},"#redis-cluster-support","Redis Cluster support"," below. ",[503,2789,2528],{}," also implements\nthe optional ",[503,2792,2272],{}," capability interface (native ",[503,2795,2276],{},[503,2797,2280],{}," on single-node; parallel\nfallback on clusters).",[520,2800,2802],{"id":2801},"batch-operations","Batch operations",[499,2804,2805,2806,2808,2809,2813],{},"Some applications need to read or write many keys at once — warming a cache, seeding a batch of\nsession tokens, or applying a bulk import. ",[503,2807,505],{}," covers single-key ops; when you need native\nmulti-key commands, inject the ",[998,2810,2811],{},[503,2812,2272],{}," capability token instead.",[542,2815,2817],{"className":606,"code":2816,"language":608,"meta":548,"style":548},"import { BatchStorage } from \"@heximon\u002Fkv\";\n",[503,2818,2819],{"__ignoreMap":548},[552,2820,2821,2823,2825,2828,2830,2832,2834,2836,2838],{"class":554,"line":555},[552,2822,1030],{"class":1029},[552,2824,1033],{"class":625},[552,2826,2827],{"class":944}," BatchStorage",[552,2829,1039],{"class":625},[552,2831,1042],{"class":1029},[552,2833,1045],{"class":625},[552,2835,1428],{"class":561},[552,2837,1051],{"class":625},[552,2839,1054],{"class":625},[499,2841,2842,2844,2845,2847,2848,2850],{},[503,2843,2272],{}," extends ",[503,2846,505],{}," (so it satisfies any ",[503,2849,505],{}," injection too) and adds two methods:",[542,2852,2854],{"className":606,"code":2853,"language":608,"meta":548,"style":548},"abstract class BatchStorage\u003CTValue> extends Storage\u003CTValue> {\n  \u002F\u002F Result aligned 1:1 with keys; missing key → null.\n  abstract getMany\u003CTItem>(keys: string[]): Promise\u003C(TItem | null)[]>;\n  \u002F\u002F ttl applied uniformly to all entries when supplied.\n  abstract setMany\u003CTItem>(\n    entries: ReadonlyArray\u003C{ readonly key: string; readonly value: TItem }>,\n    options?: StorageSetOptions,\n  ): Promise\u003Cvoid>;\n}\n",[503,2855,2856,2882,2887,2928,2933,2946,2981,2991,3003],{"__ignoreMap":548},[552,2857,2858,2860,2862,2864,2866,2868,2870,2872,2874,2876,2878,2880],{"class":554,"line":555},[552,2859,616],{"class":615},[552,2861,619],{"class":615},[552,2863,2827],{"class":558},[552,2865,626],{"class":625},[552,2867,629],{"class":558},[552,2869,643],{"class":625},[552,2871,632],{"class":615},[552,2873,622],{"class":558},[552,2875,626],{"class":625},[552,2877,629],{"class":558},[552,2879,643],{"class":625},[552,2881,646],{"class":625},[552,2883,2884],{"class":554,"line":649},[552,2885,2886],{"class":736},"  \u002F\u002F Result aligned 1:1 with keys; missing key → null.\n",[552,2888,2889,2891,2894,2896,2898,2900,2903,2905,2907,2909,2911,2913,2915,2917,2919,2921,2923,2926],{"class":554,"line":686},[552,2890,652],{"class":615},[552,2892,2893],{"class":655}," getMany",[552,2895,626],{"class":625},[552,2897,696],{"class":558},[552,2899,708],{"class":625},[552,2901,2902],{"class":662},"keys",[552,2904,666],{"class":625},[552,2906,669],{"class":558},[552,2908,945],{"class":944},[552,2910,672],{"class":625},[552,2912,675],{"class":558},[552,2914,626],{"class":625},[552,2916,659],{"class":944},[552,2918,696],{"class":558},[552,2920,725],{"class":625},[552,2922,728],{"class":558},[552,2924,2925],{"class":944},")[]",[552,2927,683],{"class":625},[552,2929,2930],{"class":554,"line":733},[552,2931,2932],{"class":736},"  \u002F\u002F ttl applied uniformly to all entries when supplied.\n",[552,2934,2935,2937,2940,2942,2944],{"class":554,"line":740},[552,2936,652],{"class":615},[552,2938,2939],{"class":655}," setMany",[552,2941,626],{"class":625},[552,2943,696],{"class":558},[552,2945,760],{"class":625},[552,2947,2948,2951,2953,2956,2959,2961,2964,2966,2968,2970,2972,2974,2976,2978],{"class":554,"line":763},[552,2949,2950],{"class":662},"    entries",[552,2952,666],{"class":625},[552,2954,2955],{"class":558}," ReadonlyArray",[552,2957,2958],{"class":625},"\u003C{",[552,2960,1657],{"class":615},[552,2962,2963],{"class":655}," key",[552,2965,666],{"class":625},[552,2967,669],{"class":558},[552,2969,1214],{"class":625},[552,2971,1657],{"class":615},[552,2973,1697],{"class":655},[552,2975,666],{"class":625},[552,2977,784],{"class":558},[552,2979,2980],{"class":625}," }>,\n",[552,2982,2983,2985,2987,2989],{"class":554,"line":776},[552,2984,792],{"class":662},[552,2986,795],{"class":625},[552,2988,798],{"class":558},[552,2990,773],{"class":625},[552,2992,2993,2995,2997,2999,3001],{"class":554,"line":789},[552,2994,806],{"class":625},[552,2996,675],{"class":558},[552,2998,626],{"class":625},[552,3000,813],{"class":558},[552,3002,683],{"class":625},[552,3004,3005],{"class":554,"line":803},[552,3006,979],{"class":625},[499,3008,3009,3010,3012,3013,3012,3015,3017,3018,3020,3021,3023,3024,3012,3026,3028,3029,3031,3032,1097],{},"Backends that implement it natively (",[503,3011,528],{},", ",[503,3014,2528],{},[503,3016,2024],{},") extend\n",[503,3019,2272],{}," rather than ",[503,3022,505],{}," directly, so they are valid satisfiers for both tokens. Drivers\nthat cannot batch efficiently (",[503,3025,2297],{},[503,3027,1767],{},") stay ",[503,3030,1995],{}," — you\nsimply cannot bind or inject them as a ",[503,3033,2272],{},[542,3035,3038],{"className":606,"code":3036,"filename":3037,"language":608,"meta":548,"style":548},"import { BatchStorage } from \"@heximon\u002Fkv\";\nimport { TimeSpan } from \"@heximon\u002Fprimitives\";\n\nexport class SessionService {\n  constructor(private readonly store: BatchStorage) {}\n\n  public async warmSessions(sessions: { id: string; token: string }[]): Promise\u003Cvoid> {\n    await this.store.setMany(\n      sessions.map((session) => ({ key: `session:${session.id}`, value: session.token })),\n      { ttl: new TimeSpan(1, \"h\") },\n    );\n  }\n\n  public async readSessions(ids: string[]): Promise\u003C(string | null)[]> {\n    return this.store.getMany\u003Cstring>(ids.map((id) => `session:${id}`));\n  }\n}\n","session.service.ts",[503,3039,3040,3060,3080,3084,3095,3116,3120,3170,3187,3251,3280,3287,3291,3295,3335,3387,3391],{"__ignoreMap":548},[552,3041,3042,3044,3046,3048,3050,3052,3054,3056,3058],{"class":554,"line":555},[552,3043,1030],{"class":1029},[552,3045,1033],{"class":625},[552,3047,2827],{"class":944},[552,3049,1039],{"class":625},[552,3051,1042],{"class":1029},[552,3053,1045],{"class":625},[552,3055,1428],{"class":561},[552,3057,1051],{"class":625},[552,3059,1054],{"class":625},[552,3061,3062,3064,3066,3068,3070,3072,3074,3076,3078],{"class":554,"line":649},[552,3063,1030],{"class":1029},[552,3065,1033],{"class":625},[552,3067,1290],{"class":944},[552,3069,1039],{"class":625},[552,3071,1042],{"class":1029},[552,3073,1045],{"class":625},[552,3075,1299],{"class":561},[552,3077,1051],{"class":625},[552,3079,1054],{"class":625},[552,3081,3082],{"class":554,"line":686},[552,3083,1060],{"emptyLinePlaceholder":1059},[552,3085,3086,3088,3090,3093],{"class":554,"line":733},[552,3087,1502],{"class":1029},[552,3089,619],{"class":615},[552,3091,3092],{"class":558}," SessionService",[552,3094,646],{"class":625},[552,3096,3097,3099,3101,3103,3105,3108,3110,3112,3114],{"class":554,"line":740},[552,3098,1649],{"class":615},[552,3100,659],{"class":625},[552,3102,1654],{"class":615},[552,3104,1657],{"class":615},[552,3106,3107],{"class":662}," store",[552,3109,666],{"class":625},[552,3111,2827],{"class":558},[552,3113,1152],{"class":625},[552,3115,1668],{"class":625},[552,3117,3118],{"class":554,"line":763},[552,3119,1060],{"emptyLinePlaceholder":1059},[552,3121,3122,3124,3126,3129,3131,3134,3136,3138,3141,3143,3145,3147,3150,3152,3154,3156,3158,3160,3162,3164,3166,3168],{"class":554,"line":776},[552,3123,1677],{"class":615},[552,3125,1680],{"class":615},[552,3127,3128],{"class":655}," warmSessions",[552,3130,659],{"class":625},[552,3132,3133],{"class":662},"sessions",[552,3135,666],{"class":625},[552,3137,1033],{"class":625},[552,3139,3140],{"class":655}," id",[552,3142,666],{"class":625},[552,3144,669],{"class":558},[552,3146,1214],{"class":625},[552,3148,3149],{"class":655}," token",[552,3151,666],{"class":625},[552,3153,669],{"class":558},[552,3155,1039],{"class":625},[552,3157,945],{"class":944},[552,3159,672],{"class":625},[552,3161,675],{"class":558},[552,3163,626],{"class":625},[552,3165,813],{"class":558},[552,3167,643],{"class":625},[552,3169,646],{"class":625},[552,3171,3172,3174,3176,3179,3181,3184],{"class":554,"line":789},[552,3173,1719],{"class":1029},[552,3175,1722],{"class":625},[552,3177,3178],{"class":944},"store",[552,3180,1097],{"class":625},[552,3182,3183],{"class":1077},"setMany",[552,3185,3186],{"class":655},"(\n",[552,3188,3189,3192,3194,3197,3199,3201,3204,3206,3208,3211,3213,3215,3217,3220,3222,3224,3226,3228,3230,3232,3234,3236,3238,3241,3243,3245,3247,3249],{"class":554,"line":803},[552,3190,3191],{"class":944},"      sessions",[552,3193,1097],{"class":625},[552,3195,3196],{"class":1077},"map",[552,3198,659],{"class":655},[552,3200,659],{"class":625},[552,3202,3203],{"class":662},"session",[552,3205,1152],{"class":625},[552,3207,2194],{"class":615},[552,3209,3210],{"class":655}," (",[552,3212,1942],{"class":625},[552,3214,2963],{"class":655},[552,3216,666],{"class":625},[552,3218,3219],{"class":625}," `",[552,3221,1737],{"class":561},[552,3223,1740],{"class":625},[552,3225,3203],{"class":944},[552,3227,1097],{"class":625},[552,3229,1688],{"class":944},[552,3231,1745],{"class":625},[552,3233,1112],{"class":625},[552,3235,1697],{"class":655},[552,3237,666],{"class":625},[552,3239,3240],{"class":944}," session",[552,3242,1097],{"class":625},[552,3244,1180],{"class":944},[552,3246,1039],{"class":625},[552,3248,2463],{"class":655},[552,3250,773],{"class":625},[552,3252,3253,3256,3258,3260,3262,3264,3266,3268,3270,3272,3274,3276,3278],{"class":554,"line":818},[552,3254,3255],{"class":625},"      {",[552,3257,1340],{"class":655},[552,3259,666],{"class":625},[552,3261,1074],{"class":625},[552,3263,1290],{"class":1077},[552,3265,659],{"class":655},[552,3267,1352],{"class":1351},[552,3269,1112],{"class":625},[552,3271,1045],{"class":625},[552,3273,1359],{"class":561},[552,3275,1051],{"class":625},[552,3277,1364],{"class":655},[552,3279,1556],{"class":625},[552,3281,3282,3285],{"class":554,"line":824},[552,3283,3284],{"class":655},"    )",[552,3286,1054],{"class":625},[552,3288,3289],{"class":554,"line":846},[552,3290,1758],{"class":625},[552,3292,3293],{"class":554,"line":857},[552,3294,1060],{"emptyLinePlaceholder":1059},[552,3296,3297,3299,3301,3304,3306,3309,3311,3313,3315,3317,3319,3321,3323,3325,3327,3329,3331,3333],{"class":554,"line":868},[552,3298,1677],{"class":615},[552,3300,1680],{"class":615},[552,3302,3303],{"class":655}," readSessions",[552,3305,659],{"class":625},[552,3307,3308],{"class":662},"ids",[552,3310,666],{"class":625},[552,3312,669],{"class":558},[552,3314,945],{"class":944},[552,3316,672],{"class":625},[552,3318,675],{"class":558},[552,3320,626],{"class":625},[552,3322,659],{"class":944},[552,3324,941],{"class":558},[552,3326,725],{"class":625},[552,3328,728],{"class":558},[552,3330,2925],{"class":944},[552,3332,643],{"class":625},[552,3334,646],{"class":625},[552,3336,3337,3340,3342,3344,3346,3349,3351,3353,3355,3357,3359,3361,3363,3365,3367,3369,3371,3373,3375,3377,3379,3381,3383,3385],{"class":554,"line":879},[552,3338,3339],{"class":1029},"    return",[552,3341,1722],{"class":625},[552,3343,3178],{"class":944},[552,3345,1097],{"class":625},[552,3347,3348],{"class":1077},"getMany",[552,3350,626],{"class":625},[552,3352,941],{"class":558},[552,3354,643],{"class":625},[552,3356,659],{"class":655},[552,3358,3308],{"class":944},[552,3360,1097],{"class":625},[552,3362,3196],{"class":1077},[552,3364,659],{"class":655},[552,3366,659],{"class":625},[552,3368,1688],{"class":662},[552,3370,1152],{"class":625},[552,3372,2194],{"class":615},[552,3374,3219],{"class":625},[552,3376,1737],{"class":561},[552,3378,1740],{"class":625},[552,3380,1688],{"class":944},[552,3382,1745],{"class":625},[552,3384,2463],{"class":655},[552,3386,1054],{"class":625},[552,3388,3389],{"class":554,"line":892},[552,3390,1758],{"class":625},[552,3392,3393],{"class":554,"line":918},[552,3394,979],{"class":625},[2012,3396,3398],{"id":3397},"batch-behaviour-per-backend","Batch behaviour per backend",[3400,3401,3402,3427],"table",{},[3403,3404,3405],"thead",{},[3406,3407,3408,3413,3417,3422],"tr",{},[3409,3410,3412],"th",{"align":3411},"left","Backend",[3409,3414,3415],{"align":3411},[503,3416,3348],{},[3409,3418,3419,3421],{"align":3411},[503,3420,3183],{}," (no TTL)",[3409,3423,3424,3426],{"align":3411},[503,3425,3183],{}," (with TTL)",[3428,3429,3430,3444,3466,3487],"tbody",{},[3406,3431,3432,3437,3440,3442],{},[3433,3434,3435],"td",{"align":3411},[503,3436,528],{},[3433,3438,3439],{"align":3411},"Single in-memory loop",[3433,3441,3439],{"align":3411},[3433,3443,3439],{"align":3411},[3406,3445,3446,3451,3457,3461],{},[3433,3447,3448,3450],{"align":3411},[503,3449,2528],{}," (single-node)",[3433,3452,3453,3454,3456],{"align":3411},"One ",[503,3455,2276],{}," command",[3433,3458,3453,3459,3456],{"align":3411},[503,3460,2280],{},[3433,3462,3463,3464],{"align":3411},"Parallel per-key ",[503,3465,2284],{},[3406,3467,3468,3473,3478,3483],{},[3433,3469,3470,3472],{"align":3411},[503,3471,2528],{}," (cluster)",[3433,3474,3463,3475],{"align":3411},[503,3476,3477],{},"GET",[3433,3479,3463,3480],{"align":3411},[503,3481,3482],{},"SET",[3433,3484,3463,3485],{"align":3411},[503,3486,2284],{},[3406,3488,3489,3493,3498,3502],{},[3433,3490,3491],{"align":3411},[503,3492,2024],{},[3433,3494,3453,3495,3497],{"align":3411},[503,3496,2276],{}," REST call",[3433,3499,3453,3500,3497],{"align":3411},[503,3501,2280],{},[3433,3503,3504,3505],{"align":3411},"One pipeline of ",[503,3506,2284],{},[499,3508,3509,3510,2277,3512,3514],{},"Redis Cluster does not support ",[503,3511,2276],{},[503,3513,2280],{}," across hash-slot boundaries, so cluster clients fall back\nto parallel single-key operations automatically — same semantics, more round-trips.",[520,3516,2786],{"id":3517},"redis-cluster-support",[499,3519,3520,3522,3523,3526,3527,3530,3531,3534,3535,3538,3539,3541],{},[503,3521,2528],{}," accepts both a single-node\u002FSentinel ",[503,3524,3525],{},"RedisClientType"," ",[998,3528,3529],{},"and"," a ",[503,3532,3533],{},"RedisClusterType"," from\nnode-redis. For a cluster, construct a ",[503,3536,3537],{},"createCluster(...)"," client and pass it directly to the\nconstructor — ",[503,3540,2562],{}," creates a single-node client only.",[542,3543,3545],{"className":606,"code":3544,"filename":1387,"language":608,"meta":548,"style":548},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { RedisStorage } from \"@heximon\u002Fkv\u002Fredis\";\nimport { createCluster } from \"redis\";\n\nexport class StorageModule extends Module({\n  providers: [\n    {\n      provide: Storage,\n      useFactory: () =>\n        new RedisStorage(\n          createCluster({\n            rootNodes: [{ url: \"redis:\u002F\u002Fnode1:6379\" }, { url: \"redis:\u002F\u002Fnode2:6379\" }],\n          }),\n        ),\n    },\n  ],\n  exports: [Storage],\n}) {}\n",[503,3546,3547,3567,3587,3607,3628,3632,3648,3656,3660,3670,3681,3690,3699,3745,3754,3761,3765,3771,3781],{"__ignoreMap":548},[552,3548,3549,3551,3553,3555,3557,3559,3561,3563,3565],{"class":554,"line":555},[552,3550,1030],{"class":1029},[552,3552,1033],{"class":625},[552,3554,1398],{"class":944},[552,3556,1039],{"class":625},[552,3558,1042],{"class":1029},[552,3560,1045],{"class":625},[552,3562,1407],{"class":561},[552,3564,1051],{"class":625},[552,3566,1054],{"class":625},[552,3568,3569,3571,3573,3575,3577,3579,3581,3583,3585],{"class":554,"line":649},[552,3570,1030],{"class":1029},[552,3572,1033],{"class":625},[552,3574,622],{"class":944},[552,3576,1039],{"class":625},[552,3578,1042],{"class":1029},[552,3580,1045],{"class":625},[552,3582,1428],{"class":561},[552,3584,1051],{"class":625},[552,3586,1054],{"class":625},[552,3588,3589,3591,3593,3595,3597,3599,3601,3603,3605],{"class":554,"line":686},[552,3590,1030],{"class":1029},[552,3592,1033],{"class":625},[552,3594,2617],{"class":944},[552,3596,1039],{"class":625},[552,3598,1042],{"class":1029},[552,3600,1045],{"class":625},[552,3602,2522],{"class":561},[552,3604,1051],{"class":625},[552,3606,1054],{"class":625},[552,3608,3609,3611,3613,3616,3618,3620,3622,3624,3626],{"class":554,"line":733},[552,3610,1030],{"class":1029},[552,3612,1033],{"class":625},[552,3614,3615],{"class":944}," createCluster",[552,3617,1039],{"class":625},[552,3619,1042],{"class":1029},[552,3621,1045],{"class":625},[552,3623,2537],{"class":561},[552,3625,1051],{"class":625},[552,3627,1054],{"class":625},[552,3629,3630],{"class":554,"line":740},[552,3631,1060],{"emptyLinePlaceholder":1059},[552,3633,3634,3636,3638,3640,3642,3644,3646],{"class":554,"line":763},[552,3635,1502],{"class":1029},[552,3637,619],{"class":615},[552,3639,1507],{"class":558},[552,3641,632],{"class":615},[552,3643,1398],{"class":1077},[552,3645,659],{"class":944},[552,3647,1516],{"class":625},[552,3649,3650,3652,3654],{"class":554,"line":776},[552,3651,1521],{"class":655},[552,3653,666],{"class":625},[552,3655,1526],{"class":944},[552,3657,3658],{"class":554,"line":789},[552,3659,2414],{"class":625},[552,3661,3662,3664,3666,3668],{"class":554,"line":803},[552,3663,2419],{"class":655},[552,3665,666],{"class":625},[552,3667,622],{"class":944},[552,3669,773],{"class":625},[552,3671,3672,3674,3676,3678],{"class":554,"line":818},[552,3673,2430],{"class":1077},[552,3675,666],{"class":625},[552,3677,2191],{"class":625},[552,3679,3680],{"class":615}," =>\n",[552,3682,3683,3686,3688],{"class":554,"line":824},[552,3684,3685],{"class":625},"        new",[552,3687,2617],{"class":1077},[552,3689,3186],{"class":944},[552,3691,3692,3695,3697],{"class":554,"line":846},[552,3693,3694],{"class":1077},"          createCluster",[552,3696,659],{"class":944},[552,3698,1516],{"class":625},[552,3700,3701,3704,3706,3708,3710,3713,3715,3717,3720,3722,3725,3727,3729,3731,3733,3736,3738,3740,3743],{"class":554,"line":857},[552,3702,3703],{"class":655},"            rootNodes",[552,3705,666],{"class":625},[552,3707,1136],{"class":944},[552,3709,1942],{"class":625},[552,3711,3712],{"class":655}," url",[552,3714,666],{"class":625},[552,3716,1045],{"class":625},[552,3718,3719],{"class":561},"redis:\u002F\u002Fnode1:6379",[552,3721,1051],{"class":625},[552,3723,3724],{"class":625}," },",[552,3726,1033],{"class":625},[552,3728,3712],{"class":655},[552,3730,666],{"class":625},[552,3732,1045],{"class":625},[552,3734,3735],{"class":561},"redis:\u002F\u002Fnode2:6379",[552,3737,1051],{"class":625},[552,3739,1039],{"class":625},[552,3741,3742],{"class":944},"]",[552,3744,773],{"class":625},[552,3746,3747,3750,3752],{"class":554,"line":868},[552,3748,3749],{"class":625},"          }",[552,3751,1152],{"class":944},[552,3753,773],{"class":625},[552,3755,3756,3759],{"class":554,"line":879},[552,3757,3758],{"class":944},"        )",[552,3760,773],{"class":625},[552,3762,3763],{"class":554,"line":892},[552,3764,2470],{"class":625},[552,3766,3767,3769],{"class":554,"line":918},[552,3768,1571],{"class":944},[552,3770,773],{"class":625},[552,3772,3773,3775,3777,3779],{"class":554,"line":950},[552,3774,1578],{"class":655},[552,3776,666],{"class":625},[552,3778,1583],{"class":944},[552,3780,773],{"class":625},[552,3782,3783,3785,3787],{"class":554,"line":976},[552,3784,1149],{"class":625},[552,3786,1364],{"class":944},[552,3788,1597],{"class":625},[499,3790,3791,1015,3793,3795,3796,3798],{},[503,3792,1014],{},[503,3794,1018],{}," on a cluster iterate over each master node independently (a cluster has no global\n",[503,3797,2265],{}," cursor) and union the results — O(n) admin-only ops, not hot-path calls.",[520,3800,3802],{"id":3801},"see-also","See also",[3804,3805,3806,3816,3821,3829],"ul",{},[3807,3808,3809,3811,3812,3815],"li",{},[515,3810,170],{"href":171}," — reach for ",[503,3813,3814],{},"BlobStore"," instead when the payload is files or streamed\nbytes rather than JSON-shaped values.",[3807,3817,3818,3820],{},[515,3819,82],{"href":83}," — when you outgrow key\u002Fvalue and need relational queries, transactions,\nand migrations.",[3807,3822,3823,3825,3826,3828],{},[515,3824,185],{"href":186}," — the CQRS\u002Fqueue\u002Fevent idempotency interceptors that inject\n",[503,3827,505],{}," to dedup by key.",[3807,3830,3831,3838,3839,2277,3841,3843],{},[515,3832,3835],{"href":3833,"rel":3834},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fstorage-blob-adapters",[1773],[998,3836,3837],{},"Example: Storage & blob adapters","\n— swappable ",[503,3840,505],{},[503,3842,3814],{}," bindings and signed URL issuance, wired end-to-end.",[3845,3846,3847],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":548,"searchDepth":649,"depth":649,"links":3849},[3850,3851,3852,3853,3854,3862,3865,3866],{"id":522,"depth":649,"text":523},{"id":597,"depth":649,"text":598},{"id":1373,"depth":649,"text":1374},{"id":1816,"depth":649,"text":1817},{"id":1977,"depth":649,"text":1978,"children":3855},[3856,3858,3860],{"id":2014,"depth":686,"text":3857},"Upstash Redis — @heximon\u002Fkv\u002Fupstash (edge-safe)",{"id":2288,"depth":686,"text":3859},"Cloudflare Workers KV — @heximon\u002Fkv\u002Fcloudflare (edge-safe)",{"id":2518,"depth":686,"text":3861},"Redis — @heximon\u002Fkv\u002Fredis (Node-only)",{"id":2801,"depth":649,"text":2802,"children":3863},[3864],{"id":3397,"depth":686,"text":3398},{"id":3517,"depth":649,"text":2786},{"id":3801,"depth":649,"text":3802},"The abstract Storage DI token and its BatchStorage capability, MemoryStorage with TTL and LRU bounds, and the first-class UpstashStorage, CloudflareKvStorage, RedisStorage, and UnstorageStorage adapters.","md",null,{},{"icon":168},{"title":165,"description":3867},"txqtV8R4fWzQx9bH8RxCNl7ywUNCMk1oA5_VBjLc4UQ",[3875,3877],{"title":161,"path":162,"stem":163,"description":3876,"icon":85,"children":-1},"Multi-tier caching — TieredCache over the Storage port, the Cache facade with single-flight and tag invalidation, QueryCacheInterceptor for CQRS query results, CacheMiddleware for HTTP responses, CacheEnvelope TTL, CdnPurgeAdapter.",{"title":170,"path":171,"stem":172,"description":3878,"icon":173,"children":-1},"The abstract BlobStore DI token for streamed bodies and byte ranges, the memory\u002Ffilesystem\u002FR2\u002FS3 drivers, and the SignedUrlBlobStore capability for direct-to-storage signed upload\u002Fdownload URLs.",1783300761903]