[{"data":1,"prerenderedAt":3236},["ShallowReactive",2],{"navigation_docs":3,"-docs-realtime-durable-objects":493,"-docs-realtime-durable-objects-surround":3231},[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":289,"body":495,"description":3224,"extension":3225,"links":3226,"meta":3227,"navigation":3228,"path":290,"seo":3229,"stem":291,"__hash__":3230},"docs\u002Fdocs\u002F05.realtime\u002F07.durable-objects.md",{"type":496,"value":497,"toc":3207},"minimark",[498,518,525,536,551,556,566,637,777,898,918,922,938,942,956,1167,1178,1182,1196,1271,1278,1517,1531,1549,1553,1570,1771,1775,1788,2006,2051,2155,2175,2192,2334,2347,2351,2356,2410,2435,2438,2442,2449,2521,2525,2532,2544,2548,2573,2580,2605,2822,2829,2834,2870,2882,2889,2914,2932,3120,3138,3142,3203],[499,500,501,507,508,512,513,517],"p",{},[502,503,289],"a",{"href":504,"rel":505},"https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002F",[506],"nofollow"," are ",[509,510,511],"strong",{},"Cloudflare-specific"," — there's no\nequivalent to deploy on Node, Vercel, AWS Lambda, or Netlify. ",[514,515,516],"code",{},"pnpm dev"," runs a faithful Node shim so the same\ncode path runs in dev and tests, but a production Durable Object only ever runs on Cloudflare Workers.",[499,519,520,521,524],{},"Most realtime apps never need one. A single Node server already holds every connection in one process, so\nplain ",[502,522,523],{"href":264},"WebSockets or Server-Sent Events"," cover chat, presence, and live feeds with no\nextra concept.",[499,526,527,528,531,532,535],{},"Reach for a Durable Object only when your app deploys to Cloudflare ",[509,529,530],{},"and"," clients of the same room or topic\ncan land on different isolates — at that point one isolate's ",[514,533,534],{},"publish"," can't reach a connection held by\nanother, and a Durable Object gives that room a single, addressable, stateful home.",[499,537,538,539,542,543,546,547,550],{},"Heximon lets you write one as an ordinary injectable class: a ",[514,540,541],{},"DurableObject"," (the actor) plus a\n",[514,544,545],{},"DurableFactory\u003CCounter>"," (the handle you call it through). Your constructor takes injected dependencies, never\nthe Workers ",[514,548,549],{},"(state, env)"," pair — so a Durable Object stays a plain Heximon class, testable like every other\nprovider.",[552,553,555],"h2",{"id":554},"set-up-the-plugin","Set up the plugin",[499,557,558,559,562,563,565],{},"Install the package and list ",[514,560,561],{},"DurablePlugin"," alongside HTTP. (See ",[502,564,57],{"href":58}," for the\nfull install + register walkthrough every transport shares.)",[567,568,569,594,609,623],"code-group",{},[570,571,577],"pre",{"className":572,"code":573,"filename":574,"language":575,"meta":576,"style":576},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fdurable\n","pnpm","bash","",[514,578,579],{"__ignoreMap":576},[580,581,584,587,591],"span",{"class":582,"line":583},"line",1,[580,585,574],{"class":586},"sBMFI",[580,588,590],{"class":589},"sfazB"," add",[580,592,593],{"class":589}," @heximon\u002Fdurable\n",[570,595,598],{"className":572,"code":596,"filename":597,"language":575,"meta":576,"style":576},"npm install @heximon\u002Fdurable\n","npm",[514,599,600],{"__ignoreMap":576},[580,601,602,604,607],{"class":582,"line":583},[580,603,597],{"class":586},[580,605,606],{"class":589}," install",[580,608,593],{"class":589},[570,610,613],{"className":572,"code":611,"filename":612,"language":575,"meta":576,"style":576},"yarn add @heximon\u002Fdurable\n","yarn",[514,614,615],{"__ignoreMap":576},[580,616,617,619,621],{"class":582,"line":583},[580,618,612],{"class":586},[580,620,590],{"class":589},[580,622,593],{"class":589},[570,624,627],{"className":572,"code":625,"filename":626,"language":575,"meta":576,"style":576},"bun add @heximon\u002Fdurable\n","bun",[514,628,629],{"__ignoreMap":576},[580,630,631,633,635],{"class":582,"line":583},[580,632,626],{"class":586},[580,634,590],{"class":589},[580,636,593],{"class":589},[570,638,643],{"className":639,"code":640,"filename":641,"language":642,"meta":576,"style":576},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import heximon from \"@heximon\u002Fbuild\u002Fvite\";\nimport { defineConfig } from \"vite-plus\";\n\nexport default defineConfig({\n  plugins: [heximon()],\n  server: { port: 3000 },\n});\n","vite.config.ts","ts",[514,644,645,671,697,704,722,744,766],{"__ignoreMap":576},[580,646,647,651,655,658,662,665,668],{"class":582,"line":583},[580,648,650],{"class":649},"s7zQu","import",[580,652,654],{"class":653},"sTEyZ"," heximon ",[580,656,657],{"class":649},"from",[580,659,661],{"class":660},"sMK4o"," \"",[580,663,664],{"class":589},"@heximon\u002Fbuild\u002Fvite",[580,666,667],{"class":660},"\"",[580,669,670],{"class":660},";\n",[580,672,674,676,679,682,685,688,690,693,695],{"class":582,"line":673},2,[580,675,650],{"class":649},[580,677,678],{"class":660}," {",[580,680,681],{"class":653}," defineConfig",[580,683,684],{"class":660}," }",[580,686,687],{"class":649}," from",[580,689,661],{"class":660},[580,691,692],{"class":589},"vite-plus",[580,694,667],{"class":660},[580,696,670],{"class":660},[580,698,700],{"class":582,"line":699},3,[580,701,703],{"emptyLinePlaceholder":702},true,"\n",[580,705,707,710,713,716,719],{"class":582,"line":706},4,[580,708,709],{"class":649},"export",[580,711,712],{"class":649}," default",[580,714,681],{"class":715},"s2Zo4",[580,717,718],{"class":653},"(",[580,720,721],{"class":660},"{\n",[580,723,725,729,732,735,738,741],{"class":582,"line":724},5,[580,726,728],{"class":727},"swJcz","  plugins",[580,730,731],{"class":660},":",[580,733,734],{"class":653}," [",[580,736,737],{"class":715},"heximon",[580,739,740],{"class":653},"()]",[580,742,743],{"class":660},",\n",[580,745,747,750,752,754,757,759,763],{"class":582,"line":746},6,[580,748,749],{"class":727},"  server",[580,751,731],{"class":660},[580,753,678],{"class":660},[580,755,756],{"class":727}," port",[580,758,731],{"class":660},[580,760,762],{"class":761},"sbssI"," 3000",[580,764,765],{"class":660}," },\n",[580,767,769,772,775],{"class":582,"line":768},7,[580,770,771],{"class":660},"}",[580,773,774],{"class":653},")",[580,776,670],{"class":660},[570,778,781],{"className":639,"code":779,"filename":780,"language":642,"meta":576,"style":576},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { DurablePlugin } from \"@heximon\u002Fdurable\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\n\nexport default defineHeximonConfig({ plugins: [new HttpPlugin(), new DurablePlugin()] });\n","heximon.config.ts",[514,782,783,805,827,849,853],{"__ignoreMap":576},[580,784,785,787,789,792,794,796,798,801,803],{"class":582,"line":583},[580,786,650],{"class":649},[580,788,678],{"class":660},[580,790,791],{"class":653}," defineHeximonConfig",[580,793,684],{"class":660},[580,795,687],{"class":649},[580,797,661],{"class":660},[580,799,800],{"class":589},"@heximon\u002Fbuild",[580,802,667],{"class":660},[580,804,670],{"class":660},[580,806,807,809,811,814,816,818,820,823,825],{"class":582,"line":673},[580,808,650],{"class":649},[580,810,678],{"class":660},[580,812,813],{"class":653}," DurablePlugin",[580,815,684],{"class":660},[580,817,687],{"class":649},[580,819,661],{"class":660},[580,821,822],{"class":589},"@heximon\u002Fdurable\u002Fcompiler",[580,824,667],{"class":660},[580,826,670],{"class":660},[580,828,829,831,833,836,838,840,842,845,847],{"class":582,"line":699},[580,830,650],{"class":649},[580,832,678],{"class":660},[580,834,835],{"class":653}," HttpPlugin",[580,837,684],{"class":660},[580,839,687],{"class":649},[580,841,661],{"class":660},[580,843,844],{"class":589},"@heximon\u002Fhttp\u002Fcompiler",[580,846,667],{"class":660},[580,848,670],{"class":660},[580,850,851],{"class":582,"line":706},[580,852,703],{"emptyLinePlaceholder":702},[580,854,855,857,859,861,863,866,869,871,873,876,878,881,884,887,889,892,894,896],{"class":582,"line":724},[580,856,709],{"class":649},[580,858,712],{"class":649},[580,860,791],{"class":715},[580,862,718],{"class":653},[580,864,865],{"class":660},"{",[580,867,868],{"class":727}," plugins",[580,870,731],{"class":660},[580,872,734],{"class":653},[580,874,875],{"class":660},"new",[580,877,835],{"class":715},[580,879,880],{"class":653},"()",[580,882,883],{"class":660},",",[580,885,886],{"class":660}," new",[580,888,813],{"class":715},[580,890,891],{"class":653},"()] ",[580,893,771],{"class":660},[580,895,774],{"class":653},[580,897,670],{"class":660},[499,899,900,901,904,905,907,908,911,912,914,915,917],{},"For a production build, add ",[514,902,903],{},"new DurablePlugin()"," to the ",[514,906,780],{}," config file's ",[514,909,910],{},"plugins","\narray — ",[502,913,332],{"href":333}," and ",[502,916,337],{"href":338}," read the same config file.",[552,919,921],{"id":920},"the-concept-one-addressable-instance-per-id","The concept: one addressable instance per id",[499,923,924,925,928,929,933,934,937],{},"A Durable Object is a ",[509,926,927],{},"single-threaded, stateful actor at the edge"," — one addressable instance per id, with\npersistent storage and no concurrency to reason about, because every call to a given object runs serially. Two\nrequests to the ",[930,931,932],"em",{},"same"," object queue behind each other, so a read-modify-write needs no lock; requests to\n",[930,935,936],{},"different"," ids run fully in parallel across the platform.",[552,939,941],{"id":940},"author-the-actor","Author the actor",[499,943,944,945,947,948,951,952,955],{},"A ",[514,946,541],{}," is your single-instance actor. Its public, non-lifecycle methods are the ",[509,949,950],{},"RPC\nsurface"," callers invoke over the network, and its constructor declares injected dependencies like any\nprovider. (",[514,953,954],{},"extends DurableObject\u003C...>"," binds identically — use it when you want your own base-class\nhierarchy on top of an actor.)",[570,957,960],{"className":639,"code":958,"filename":959,"language":642,"meta":576,"style":576},"import type { DurableObject } from \"@heximon\u002Fdurable\";\nimport { CounterRepository } from \".\u002Fcounter.repository\";\n\nexport class Counter implements DurableObject\u003C{ storage: \"sql\" }> {\n  constructor(private readonly repo: CounterRepository) {}\n\n  public async increment(by = 1): Promise\u003Cnumber> {\n    return this.repo.increment(\"count\", by);\n  }\n}\n","src\u002Fcounters\u002Fcounter.ts",[514,961,962,987,1009,1013,1050,1076,1080,1119,1155,1161],{"__ignoreMap":576},[580,963,964,966,969,971,974,976,978,980,983,985],{"class":582,"line":583},[580,965,650],{"class":649},[580,967,968],{"class":649}," type",[580,970,678],{"class":660},[580,972,973],{"class":653}," DurableObject",[580,975,684],{"class":660},[580,977,687],{"class":649},[580,979,661],{"class":660},[580,981,982],{"class":589},"@heximon\u002Fdurable",[580,984,667],{"class":660},[580,986,670],{"class":660},[580,988,989,991,993,996,998,1000,1002,1005,1007],{"class":582,"line":673},[580,990,650],{"class":649},[580,992,678],{"class":660},[580,994,995],{"class":653}," CounterRepository",[580,997,684],{"class":660},[580,999,687],{"class":649},[580,1001,661],{"class":660},[580,1003,1004],{"class":589},".\u002Fcounter.repository",[580,1006,667],{"class":660},[580,1008,670],{"class":660},[580,1010,1011],{"class":582,"line":699},[580,1012,703],{"emptyLinePlaceholder":702},[580,1014,1015,1017,1021,1024,1027,1029,1032,1035,1037,1039,1042,1044,1047],{"class":582,"line":706},[580,1016,709],{"class":649},[580,1018,1020],{"class":1019},"spNyl"," class",[580,1022,1023],{"class":586}," Counter",[580,1025,1026],{"class":1019}," implements",[580,1028,973],{"class":586},[580,1030,1031],{"class":660},"\u003C{",[580,1033,1034],{"class":727}," storage",[580,1036,731],{"class":660},[580,1038,661],{"class":660},[580,1040,1041],{"class":589},"sql",[580,1043,667],{"class":660},[580,1045,1046],{"class":660}," }>",[580,1048,1049],{"class":660}," {\n",[580,1051,1052,1055,1057,1060,1063,1067,1069,1071,1073],{"class":582,"line":724},[580,1053,1054],{"class":1019},"  constructor",[580,1056,718],{"class":660},[580,1058,1059],{"class":1019},"private",[580,1061,1062],{"class":1019}," readonly",[580,1064,1066],{"class":1065},"sHdIc"," repo",[580,1068,731],{"class":660},[580,1070,995],{"class":586},[580,1072,774],{"class":660},[580,1074,1075],{"class":660}," {}\n",[580,1077,1078],{"class":582,"line":746},[580,1079,703],{"emptyLinePlaceholder":702},[580,1081,1082,1085,1088,1091,1093,1096,1099,1102,1105,1108,1111,1114,1117],{"class":582,"line":768},[580,1083,1084],{"class":1019},"  public",[580,1086,1087],{"class":1019}," async",[580,1089,1090],{"class":727}," increment",[580,1092,718],{"class":660},[580,1094,1095],{"class":1065},"by",[580,1097,1098],{"class":660}," =",[580,1100,1101],{"class":761}," 1",[580,1103,1104],{"class":660},"):",[580,1106,1107],{"class":586}," Promise",[580,1109,1110],{"class":660},"\u003C",[580,1112,1113],{"class":586},"number",[580,1115,1116],{"class":660},">",[580,1118,1049],{"class":660},[580,1120,1122,1125,1128,1131,1134,1137,1139,1141,1144,1146,1148,1151,1153],{"class":582,"line":1121},8,[580,1123,1124],{"class":649},"    return",[580,1126,1127],{"class":660}," this.",[580,1129,1130],{"class":653},"repo",[580,1132,1133],{"class":660},".",[580,1135,1136],{"class":715},"increment",[580,1138,718],{"class":727},[580,1140,667],{"class":660},[580,1142,1143],{"class":589},"count",[580,1145,667],{"class":660},[580,1147,883],{"class":660},[580,1149,1150],{"class":653}," by",[580,1152,774],{"class":727},[580,1154,670],{"class":660},[580,1156,1158],{"class":582,"line":1157},9,[580,1159,1160],{"class":660},"  }\n",[580,1162,1164],{"class":582,"line":1163},10,[580,1165,1166],{"class":660},"}\n",[499,1168,1169,1170,1173,1174,1177],{},"Choose ",[514,1171,1172],{},"\"sql\""," for SQLite-backed storage or ",[514,1175,1176],{},"\"kv\""," (the default) for key-value.",[552,1179,1181],{"id":1180},"address-it-through-a-factory","Address it through a factory",[499,1183,1184,1185,1187,1188,1191,1192,1195],{},"You never construct a Durable Object directly; you call it through a ",[514,1186,545],{},". Extend it\nwith an ",[509,1189,1190],{},"empty body"," and the compiler registers the factory as a provider for you, bound to the object\nnamed in the ",[514,1193,1194],{},"extends DurableFactory\u003C...>"," type argument.",[570,1197,1200],{"className":639,"code":1198,"filename":1199,"language":642,"meta":576,"style":576},"import { DurableFactory } from \"@heximon\u002Fdurable\";\nimport { Counter } from \".\u002Fcounter\";\n\nexport class CounterFactory extends DurableFactory\u003CCounter> {}\n","src\u002Fcounters\u002Fcounter.factory.ts",[514,1201,1202,1223,1244,1248],{"__ignoreMap":576},[580,1203,1204,1206,1208,1211,1213,1215,1217,1219,1221],{"class":582,"line":583},[580,1205,650],{"class":649},[580,1207,678],{"class":660},[580,1209,1210],{"class":653}," DurableFactory",[580,1212,684],{"class":660},[580,1214,687],{"class":649},[580,1216,661],{"class":660},[580,1218,982],{"class":589},[580,1220,667],{"class":660},[580,1222,670],{"class":660},[580,1224,1225,1227,1229,1231,1233,1235,1237,1240,1242],{"class":582,"line":673},[580,1226,650],{"class":649},[580,1228,678],{"class":660},[580,1230,1023],{"class":653},[580,1232,684],{"class":660},[580,1234,687],{"class":649},[580,1236,661],{"class":660},[580,1238,1239],{"class":589},".\u002Fcounter",[580,1241,667],{"class":660},[580,1243,670],{"class":660},[580,1245,1246],{"class":582,"line":699},[580,1247,703],{"emptyLinePlaceholder":702},[580,1249,1250,1252,1254,1257,1260,1262,1264,1267,1269],{"class":582,"line":706},[580,1251,709],{"class":649},[580,1253,1020],{"class":1019},[580,1255,1256],{"class":586}," CounterFactory",[580,1258,1259],{"class":1019}," extends",[580,1261,1210],{"class":586},[580,1263,1110],{"class":660},[580,1265,1266],{"class":586},"Counter",[580,1268,1116],{"class":660},[580,1270,1075],{"class":660},[499,1272,1273,1274,1277],{},"Inject the factory anywhere, then resolve an object and call its RPC methods. ",[514,1275,1276],{},"getByName"," derives a\nstable id from a human-readable name:",[570,1279,1282],{"className":639,"code":1280,"filename":1281,"language":642,"meta":576,"style":576},"import type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport { CounterFactory } from \".\u002Fcounter.factory\";\n\nexport class CountersController implements Controller\u003C\"\u002Fcounters\"> {\n  constructor(private readonly counters: CounterFactory) {}\n\n  public async bump(action: Post\u003C\"\u002F:id\u002Fbump\">): Promise\u003C{ count: number }> {\n    \u002F\u002F `id` is a human name → resolve with getByName, then call the RPC method.\n    const count = await this.counters.getByName(action.request.pathParams.id).increment(1);\n    return { count };\n  }\n}\n","src\u002Fcounters\u002Fcounters.controller.ts",[514,1283,1284,1313,1334,1338,1364,1385,1389,1435,1441,1496,1507,1512],{"__ignoreMap":576},[580,1285,1286,1288,1290,1292,1295,1297,1300,1302,1304,1306,1309,1311],{"class":582,"line":583},[580,1287,650],{"class":649},[580,1289,968],{"class":649},[580,1291,678],{"class":660},[580,1293,1294],{"class":653}," Controller",[580,1296,883],{"class":660},[580,1298,1299],{"class":653}," Post",[580,1301,684],{"class":660},[580,1303,687],{"class":649},[580,1305,661],{"class":660},[580,1307,1308],{"class":589},"@heximon\u002Fhttp",[580,1310,667],{"class":660},[580,1312,670],{"class":660},[580,1314,1315,1317,1319,1321,1323,1325,1327,1330,1332],{"class":582,"line":673},[580,1316,650],{"class":649},[580,1318,678],{"class":660},[580,1320,1256],{"class":653},[580,1322,684],{"class":660},[580,1324,687],{"class":649},[580,1326,661],{"class":660},[580,1328,1329],{"class":589},".\u002Fcounter.factory",[580,1331,667],{"class":660},[580,1333,670],{"class":660},[580,1335,1336],{"class":582,"line":699},[580,1337,703],{"emptyLinePlaceholder":702},[580,1339,1340,1342,1344,1347,1349,1351,1353,1355,1358,1360,1362],{"class":582,"line":706},[580,1341,709],{"class":649},[580,1343,1020],{"class":1019},[580,1345,1346],{"class":586}," CountersController",[580,1348,1026],{"class":1019},[580,1350,1294],{"class":586},[580,1352,1110],{"class":660},[580,1354,667],{"class":660},[580,1356,1357],{"class":589},"\u002Fcounters",[580,1359,667],{"class":660},[580,1361,1116],{"class":660},[580,1363,1049],{"class":660},[580,1365,1366,1368,1370,1372,1374,1377,1379,1381,1383],{"class":582,"line":724},[580,1367,1054],{"class":1019},[580,1369,718],{"class":660},[580,1371,1059],{"class":1019},[580,1373,1062],{"class":1019},[580,1375,1376],{"class":1065}," counters",[580,1378,731],{"class":660},[580,1380,1256],{"class":586},[580,1382,774],{"class":660},[580,1384,1075],{"class":660},[580,1386,1387],{"class":582,"line":746},[580,1388,703],{"emptyLinePlaceholder":702},[580,1390,1391,1393,1395,1398,1400,1403,1405,1407,1409,1411,1414,1416,1419,1421,1423,1426,1428,1431,1433],{"class":582,"line":768},[580,1392,1084],{"class":1019},[580,1394,1087],{"class":1019},[580,1396,1397],{"class":727}," bump",[580,1399,718],{"class":660},[580,1401,1402],{"class":1065},"action",[580,1404,731],{"class":660},[580,1406,1299],{"class":586},[580,1408,1110],{"class":660},[580,1410,667],{"class":660},[580,1412,1413],{"class":589},"\u002F:id\u002Fbump",[580,1415,667],{"class":660},[580,1417,1418],{"class":660},">):",[580,1420,1107],{"class":586},[580,1422,1031],{"class":660},[580,1424,1425],{"class":727}," count",[580,1427,731],{"class":660},[580,1429,1430],{"class":586}," number",[580,1432,1046],{"class":660},[580,1434,1049],{"class":660},[580,1436,1437],{"class":582,"line":1121},[580,1438,1440],{"class":1439},"sHwdD","    \u002F\u002F `id` is a human name → resolve with getByName, then call the RPC method.\n",[580,1442,1443,1446,1448,1450,1453,1455,1458,1460,1462,1464,1466,1468,1471,1473,1476,1478,1481,1483,1485,1487,1489,1492,1494],{"class":582,"line":1157},[580,1444,1445],{"class":1019},"    const",[580,1447,1425],{"class":653},[580,1449,1098],{"class":660},[580,1451,1452],{"class":649}," await",[580,1454,1127],{"class":660},[580,1456,1457],{"class":653},"counters",[580,1459,1133],{"class":660},[580,1461,1276],{"class":715},[580,1463,718],{"class":727},[580,1465,1402],{"class":653},[580,1467,1133],{"class":660},[580,1469,1470],{"class":653},"request",[580,1472,1133],{"class":660},[580,1474,1475],{"class":653},"pathParams",[580,1477,1133],{"class":660},[580,1479,1480],{"class":653},"id",[580,1482,774],{"class":727},[580,1484,1133],{"class":660},[580,1486,1136],{"class":715},[580,1488,718],{"class":727},[580,1490,1491],{"class":761},"1",[580,1493,774],{"class":727},[580,1495,670],{"class":660},[580,1497,1498,1500,1502,1504],{"class":582,"line":1163},[580,1499,1124],{"class":649},[580,1501,678],{"class":660},[580,1503,1425],{"class":653},[580,1505,1506],{"class":660}," };\n",[580,1508,1510],{"class":582,"line":1509},11,[580,1511,1160],{"class":660},[580,1513,1515],{"class":582,"line":1514},12,[580,1516,1166],{"class":660},[499,1518,1519,1520,1523,1524,1527,1528,1530],{},"The lower-level ",[514,1521,1522],{},"factory.get(id)"," takes a ",[514,1525,1526],{},"DurableObjectId",", not a string — passing a bare string is a\ncompile error, so reach for ",[514,1529,1276],{}," whenever your key is a name.",[499,1532,1533,1534,1537,1538,1541,1542,1544,1545,1548],{},"Never list a ",[514,1535,1536],{},"DurableFactory"," in ",[514,1539,1540],{},"providers"," — the compiler already registers it, and a ",[514,1543,1540],{},"\nentry would shadow that binding. List it only under ",[514,1546,1547],{},"durable: { factories }",", as the module below shows.",[552,1550,1552],{"id":1551},"wire-the-module","Wire the module",[499,1554,1555,1556,1559,1560,1563,1564,1537,1567,1569],{},"Each concept lives under the namespace its plugin owns: the object and its factory under ",[514,1557,1558],{},"durable",", the\ncontroller under ",[514,1561,1562],{},"http",", and the plain ",[514,1565,1566],{},"CounterRepository",[514,1568,1540],{}," like any injectable.",[570,1571,1574],{"className":639,"code":1572,"filename":1573,"language":642,"meta":576,"style":576},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Counter } from \".\u002Fcounter\";\nimport { CounterFactory } from \".\u002Fcounter.factory\";\nimport { CounterRepository } from \".\u002Fcounter.repository\";\nimport { CountersController } from \".\u002Fcounters.controller\";\n\nexport class CountersModule extends Module({\n  providers: [CounterRepository],\n  http: { controllers: [CountersController] },\n  durable: { objects: [Counter], factories: [CounterFactory] },\n}) {}\n","src\u002Fcounters\u002Fcounters.module.ts",[514,1575,1576,1598,1618,1638,1658,1679,1683,1700,1712,1732,1761],{"__ignoreMap":576},[580,1577,1578,1580,1582,1585,1587,1589,1591,1594,1596],{"class":582,"line":583},[580,1579,650],{"class":649},[580,1581,678],{"class":660},[580,1583,1584],{"class":653}," Module",[580,1586,684],{"class":660},[580,1588,687],{"class":649},[580,1590,661],{"class":660},[580,1592,1593],{"class":589},"@heximon\u002Fruntime",[580,1595,667],{"class":660},[580,1597,670],{"class":660},[580,1599,1600,1602,1604,1606,1608,1610,1612,1614,1616],{"class":582,"line":673},[580,1601,650],{"class":649},[580,1603,678],{"class":660},[580,1605,1023],{"class":653},[580,1607,684],{"class":660},[580,1609,687],{"class":649},[580,1611,661],{"class":660},[580,1613,1239],{"class":589},[580,1615,667],{"class":660},[580,1617,670],{"class":660},[580,1619,1620,1622,1624,1626,1628,1630,1632,1634,1636],{"class":582,"line":699},[580,1621,650],{"class":649},[580,1623,678],{"class":660},[580,1625,1256],{"class":653},[580,1627,684],{"class":660},[580,1629,687],{"class":649},[580,1631,661],{"class":660},[580,1633,1329],{"class":589},[580,1635,667],{"class":660},[580,1637,670],{"class":660},[580,1639,1640,1642,1644,1646,1648,1650,1652,1654,1656],{"class":582,"line":706},[580,1641,650],{"class":649},[580,1643,678],{"class":660},[580,1645,995],{"class":653},[580,1647,684],{"class":660},[580,1649,687],{"class":649},[580,1651,661],{"class":660},[580,1653,1004],{"class":589},[580,1655,667],{"class":660},[580,1657,670],{"class":660},[580,1659,1660,1662,1664,1666,1668,1670,1672,1675,1677],{"class":582,"line":724},[580,1661,650],{"class":649},[580,1663,678],{"class":660},[580,1665,1346],{"class":653},[580,1667,684],{"class":660},[580,1669,687],{"class":649},[580,1671,661],{"class":660},[580,1673,1674],{"class":589},".\u002Fcounters.controller",[580,1676,667],{"class":660},[580,1678,670],{"class":660},[580,1680,1681],{"class":582,"line":746},[580,1682,703],{"emptyLinePlaceholder":702},[580,1684,1685,1687,1689,1692,1694,1696,1698],{"class":582,"line":768},[580,1686,709],{"class":649},[580,1688,1020],{"class":1019},[580,1690,1691],{"class":586}," CountersModule",[580,1693,1259],{"class":1019},[580,1695,1584],{"class":715},[580,1697,718],{"class":653},[580,1699,721],{"class":660},[580,1701,1702,1705,1707,1710],{"class":582,"line":1121},[580,1703,1704],{"class":727},"  providers",[580,1706,731],{"class":660},[580,1708,1709],{"class":653}," [CounterRepository]",[580,1711,743],{"class":660},[580,1713,1714,1717,1719,1721,1724,1726,1729],{"class":582,"line":1157},[580,1715,1716],{"class":727},"  http",[580,1718,731],{"class":660},[580,1720,678],{"class":660},[580,1722,1723],{"class":727}," controllers",[580,1725,731],{"class":660},[580,1727,1728],{"class":653}," [CountersController] ",[580,1730,1731],{"class":660},"},\n",[580,1733,1734,1737,1739,1741,1744,1746,1749,1751,1754,1756,1759],{"class":582,"line":1163},[580,1735,1736],{"class":727},"  durable",[580,1738,731],{"class":660},[580,1740,678],{"class":660},[580,1742,1743],{"class":727}," objects",[580,1745,731],{"class":660},[580,1747,1748],{"class":653}," [Counter]",[580,1750,883],{"class":660},[580,1752,1753],{"class":727}," factories",[580,1755,731],{"class":660},[580,1757,1758],{"class":653}," [CounterFactory] ",[580,1760,1731],{"class":660},[580,1762,1763,1765,1768],{"class":582,"line":1509},[580,1764,771],{"class":660},[580,1766,1767],{"class":653},") ",[580,1769,1770],{"class":660},"{}\n",[552,1772,1774],{"id":1773},"reach-storage-and-id","Reach storage and id",[499,1776,1777,1778,914,1781,1783,1784,1787],{},"A Durable Object reads its own ",[514,1779,1780],{},"storage",[514,1782,1480],{}," by injecting the ",[514,1785,1786],{},"DurableContext"," token — the\nframework-owned handle to that instance's per-object state. Inject it into the object itself, or into a\nprovider the object depends on.",[570,1789,1792],{"className":639,"code":1790,"filename":1791,"language":642,"meta":576,"style":576},"import { DurableContext } from \"@heximon\u002Fdurable\";\n\nexport class CounterRepository {\n  constructor(private readonly context: DurableContext) {}\n\n  public async increment(key: string, by: number): Promise\u003Cnumber> {\n    const current = (await this.context.storage.get\u003Cnumber>(key)) ?? 0;\n    const next = current + by;\n    await this.context.storage.put(key, next);\n    return next;\n  }\n}\n","src\u002Fcounters\u002Fcounter.repository.ts",[514,1793,1794,1815,1819,1829,1850,1854,1892,1942,1960,1990,1998,2002],{"__ignoreMap":576},[580,1795,1796,1798,1800,1803,1805,1807,1809,1811,1813],{"class":582,"line":583},[580,1797,650],{"class":649},[580,1799,678],{"class":660},[580,1801,1802],{"class":653}," DurableContext",[580,1804,684],{"class":660},[580,1806,687],{"class":649},[580,1808,661],{"class":660},[580,1810,982],{"class":589},[580,1812,667],{"class":660},[580,1814,670],{"class":660},[580,1816,1817],{"class":582,"line":673},[580,1818,703],{"emptyLinePlaceholder":702},[580,1820,1821,1823,1825,1827],{"class":582,"line":699},[580,1822,709],{"class":649},[580,1824,1020],{"class":1019},[580,1826,995],{"class":586},[580,1828,1049],{"class":660},[580,1830,1831,1833,1835,1837,1839,1842,1844,1846,1848],{"class":582,"line":706},[580,1832,1054],{"class":1019},[580,1834,718],{"class":660},[580,1836,1059],{"class":1019},[580,1838,1062],{"class":1019},[580,1840,1841],{"class":1065}," context",[580,1843,731],{"class":660},[580,1845,1802],{"class":586},[580,1847,774],{"class":660},[580,1849,1075],{"class":660},[580,1851,1852],{"class":582,"line":724},[580,1853,703],{"emptyLinePlaceholder":702},[580,1855,1856,1858,1860,1862,1864,1867,1869,1872,1874,1876,1878,1880,1882,1884,1886,1888,1890],{"class":582,"line":746},[580,1857,1084],{"class":1019},[580,1859,1087],{"class":1019},[580,1861,1090],{"class":727},[580,1863,718],{"class":660},[580,1865,1866],{"class":1065},"key",[580,1868,731],{"class":660},[580,1870,1871],{"class":586}," string",[580,1873,883],{"class":660},[580,1875,1150],{"class":1065},[580,1877,731],{"class":660},[580,1879,1430],{"class":586},[580,1881,1104],{"class":660},[580,1883,1107],{"class":586},[580,1885,1110],{"class":660},[580,1887,1113],{"class":586},[580,1889,1116],{"class":660},[580,1891,1049],{"class":660},[580,1893,1894,1896,1899,1901,1904,1907,1909,1912,1914,1916,1918,1921,1923,1925,1927,1929,1931,1934,1937,1940],{"class":582,"line":768},[580,1895,1445],{"class":1019},[580,1897,1898],{"class":653}," current",[580,1900,1098],{"class":660},[580,1902,1903],{"class":727}," (",[580,1905,1906],{"class":649},"await",[580,1908,1127],{"class":660},[580,1910,1911],{"class":653},"context",[580,1913,1133],{"class":660},[580,1915,1780],{"class":653},[580,1917,1133],{"class":660},[580,1919,1920],{"class":715},"get",[580,1922,1110],{"class":660},[580,1924,1113],{"class":586},[580,1926,1116],{"class":660},[580,1928,718],{"class":727},[580,1930,1866],{"class":653},[580,1932,1933],{"class":727},")) ",[580,1935,1936],{"class":660},"??",[580,1938,1939],{"class":761}," 0",[580,1941,670],{"class":660},[580,1943,1944,1946,1949,1951,1953,1956,1958],{"class":582,"line":1121},[580,1945,1445],{"class":1019},[580,1947,1948],{"class":653}," next",[580,1950,1098],{"class":660},[580,1952,1898],{"class":653},[580,1954,1955],{"class":660}," +",[580,1957,1150],{"class":653},[580,1959,670],{"class":660},[580,1961,1962,1965,1967,1969,1971,1973,1975,1978,1980,1982,1984,1986,1988],{"class":582,"line":1157},[580,1963,1964],{"class":649},"    await",[580,1966,1127],{"class":660},[580,1968,1911],{"class":653},[580,1970,1133],{"class":660},[580,1972,1780],{"class":653},[580,1974,1133],{"class":660},[580,1976,1977],{"class":715},"put",[580,1979,718],{"class":727},[580,1981,1866],{"class":653},[580,1983,883],{"class":660},[580,1985,1948],{"class":653},[580,1987,774],{"class":727},[580,1989,670],{"class":660},[580,1991,1992,1994,1996],{"class":582,"line":1163},[580,1993,1124],{"class":649},[580,1995,1948],{"class":653},[580,1997,670],{"class":660},[580,1999,2000],{"class":582,"line":1509},[580,2001,1160],{"class":660},[580,2003,2004],{"class":582,"line":1514},[580,2005,1166],{"class":660},[499,2007,2008,2011,2012,2015,2016,2018,2019,2018,2021,2024,2025,2028,2029,2031,2032,2034,2035,2038,2039,2042,2043,2046,2047,2050],{},[514,2009,2010],{},"context.storage"," is the portable ",[514,2013,2014],{},"DurableStorage"," surface — ",[514,2017,1920],{}," \u002F ",[514,2020,1977],{},[514,2022,2023],{},"delete"," and a full ",[514,2026,2027],{},"list()","\nsnapshot — the subset that both Cloudflare's storage and the Node dev shim actually support, so it works the\nsame in ",[514,2030,516],{}," and on Workers. For Cloudflare-only surfaces (",[514,2033,1041],{},", ",[514,2036,2037],{},"transaction",", alarms, or paginated\n",[514,2040,2041],{},"list(options)",") cast to the full ",[514,2044,2045],{},"DurableObjectStorage",", which your app imports from its own\n",[514,2048,2049],{},"@cloudflare\u002Fworkers-types"," dependency:",[570,2052,2054],{"className":639,"code":2053,"language":642,"meta":576,"style":576},"import type { DurableObjectStorage } from \"@cloudflare\u002Fworkers-types\";\n\nconst rows = (this.context.storage as unknown as DurableObjectStorage).sql\n  .exec(\"SELECT * FROM events\")\n  .toArray();\n",[514,2055,2056,2079,2083,2124,2144],{"__ignoreMap":576},[580,2057,2058,2060,2062,2064,2067,2069,2071,2073,2075,2077],{"class":582,"line":583},[580,2059,650],{"class":649},[580,2061,968],{"class":649},[580,2063,678],{"class":660},[580,2065,2066],{"class":653}," DurableObjectStorage",[580,2068,684],{"class":660},[580,2070,687],{"class":649},[580,2072,661],{"class":660},[580,2074,2049],{"class":589},[580,2076,667],{"class":660},[580,2078,670],{"class":660},[580,2080,2081],{"class":582,"line":673},[580,2082,703],{"emptyLinePlaceholder":702},[580,2084,2085,2088,2091,2094,2096,2099,2101,2103,2106,2109,2112,2115,2117,2119,2121],{"class":582,"line":699},[580,2086,2087],{"class":1019},"const",[580,2089,2090],{"class":653}," rows ",[580,2092,2093],{"class":660},"=",[580,2095,1903],{"class":653},[580,2097,2098],{"class":660},"this.",[580,2100,1911],{"class":653},[580,2102,1133],{"class":660},[580,2104,2105],{"class":653},"storage ",[580,2107,2108],{"class":649},"as",[580,2110,2111],{"class":586}," unknown",[580,2113,2114],{"class":649}," as",[580,2116,2066],{"class":586},[580,2118,774],{"class":653},[580,2120,1133],{"class":660},[580,2122,2123],{"class":653},"sql\n",[580,2125,2126,2129,2132,2134,2136,2139,2141],{"class":582,"line":706},[580,2127,2128],{"class":660},"  .",[580,2130,2131],{"class":715},"exec",[580,2133,718],{"class":653},[580,2135,667],{"class":660},[580,2137,2138],{"class":589},"SELECT * FROM events",[580,2140,667],{"class":660},[580,2142,2143],{"class":653},")\n",[580,2145,2146,2148,2151,2153],{"class":582,"line":724},[580,2147,2128],{"class":660},[580,2149,2150],{"class":715},"toArray",[580,2152,880],{"class":653},[580,2154,670],{"class":660},[2156,2157,2159,2160,2163,2164,2167,2168,2170,2171,2174],"callout",{"type":2158},"info","The escape cast is the visible boundary where you leave the portable surface. The Node dev shim does ",[509,2161,2162],{},"not","\nemulate ",[514,2165,2166],{},".sql"," — a ",[514,2169,1172],{},"-backed object reaching for it works under ",[514,2172,2173],{},"wrangler dev"," \u002F Workers but throws on the\nNode shim, where SQLite is not run in-process.",[499,2176,2177,2178,2181,2182,2184,2185,2187,2188,2191],{},"Because Durable Objects are ",[509,2179,2180],{},"lazily constructed"," — the framework never builds a DO in the main app,\nonly in the per-instance bridge that supplies a bound ",[514,2183,1786],{}," — it is safe to read\n",[514,2186,2010],{}," or ",[514,2189,2190],{},"context.id"," directly in a constructor:",[570,2193,2196],{"className":639,"code":2194,"filename":2195,"language":642,"meta":576,"style":576},"import { DurableContext, type DurableObject } from \"@heximon\u002Fdurable\";\n\nexport class Session implements DurableObject\u003C{ storage: \"kv\" }> {\n  public readonly sessionId: string;\n\n  constructor(private readonly context: DurableContext) {\n    this.sessionId = context.id.toString(); \u002F\u002F safe — only the bridge constructs this, never the main app\n  }\n}\n","src\u002Fsessions\u002Fsession.ts",[514,2197,2198,2224,2228,2258,2273,2277,2297,2326,2330],{"__ignoreMap":576},[580,2199,2200,2202,2204,2206,2208,2210,2212,2214,2216,2218,2220,2222],{"class":582,"line":583},[580,2201,650],{"class":649},[580,2203,678],{"class":660},[580,2205,1802],{"class":653},[580,2207,883],{"class":660},[580,2209,968],{"class":649},[580,2211,973],{"class":653},[580,2213,684],{"class":660},[580,2215,687],{"class":649},[580,2217,661],{"class":660},[580,2219,982],{"class":589},[580,2221,667],{"class":660},[580,2223,670],{"class":660},[580,2225,2226],{"class":582,"line":673},[580,2227,703],{"emptyLinePlaceholder":702},[580,2229,2230,2232,2234,2237,2239,2241,2243,2245,2247,2249,2252,2254,2256],{"class":582,"line":699},[580,2231,709],{"class":649},[580,2233,1020],{"class":1019},[580,2235,2236],{"class":586}," Session",[580,2238,1026],{"class":1019},[580,2240,973],{"class":586},[580,2242,1031],{"class":660},[580,2244,1034],{"class":727},[580,2246,731],{"class":660},[580,2248,661],{"class":660},[580,2250,2251],{"class":589},"kv",[580,2253,667],{"class":660},[580,2255,1046],{"class":660},[580,2257,1049],{"class":660},[580,2259,2260,2262,2264,2267,2269,2271],{"class":582,"line":706},[580,2261,1084],{"class":1019},[580,2263,1062],{"class":1019},[580,2265,2266],{"class":727}," sessionId",[580,2268,731],{"class":660},[580,2270,1871],{"class":586},[580,2272,670],{"class":660},[580,2274,2275],{"class":582,"line":724},[580,2276,703],{"emptyLinePlaceholder":702},[580,2278,2279,2281,2283,2285,2287,2289,2291,2293,2295],{"class":582,"line":746},[580,2280,1054],{"class":1019},[580,2282,718],{"class":660},[580,2284,1059],{"class":1019},[580,2286,1062],{"class":1019},[580,2288,1841],{"class":1065},[580,2290,731],{"class":660},[580,2292,1802],{"class":586},[580,2294,774],{"class":660},[580,2296,1049],{"class":660},[580,2298,2299,2302,2305,2307,2309,2311,2313,2315,2318,2320,2323],{"class":582,"line":768},[580,2300,2301],{"class":660},"    this.",[580,2303,2304],{"class":653},"sessionId",[580,2306,1098],{"class":660},[580,2308,1841],{"class":653},[580,2310,1133],{"class":660},[580,2312,1480],{"class":653},[580,2314,1133],{"class":660},[580,2316,2317],{"class":715},"toString",[580,2319,880],{"class":727},[580,2321,2322],{"class":660},";",[580,2324,2325],{"class":1439}," \u002F\u002F safe — only the bridge constructs this, never the main app\n",[580,2327,2328],{"class":582,"line":1121},[580,2329,1160],{"class":660},[580,2331,2332],{"class":582,"line":1157},[580,2333,1166],{"class":660},[2156,2335,2337,2342,2343,2346],{"type":2336},"warning",[509,2338,2339,2341],{},[514,2340,1786],{}," only resolves inside a Durable Object instance."," Inject it into a plain controller\nand the first access throws ",[514,2344,2345],{},"DurableContext is only available inside a Durable Object instance"," — the throw\ncatches a misplaced injection before it reads the wrong object's state. Keep it confined to a Durable\nObject and the providers it owns.",[552,2348,2350],{"id":2349},"run-it-on-node","Run it on Node",[499,2352,2353,2355],{},[514,2354,516],{}," runs a faithful Node shim, not real Durable Objects: Map-backed storage and an in-process\nnamespace that keeps one instance per id. You exercise the full RPC path locally before you ship.",[567,2357,2358,2370,2384,2397],{},[570,2359,2361],{"className":572,"code":2360,"filename":574,"language":575,"meta":576,"style":576},"pnpm dev\n",[514,2362,2363],{"__ignoreMap":576},[580,2364,2365,2367],{"class":582,"line":583},[580,2366,574],{"class":586},[580,2368,2369],{"class":589}," dev\n",[570,2371,2373],{"className":572,"code":2372,"filename":597,"language":575,"meta":576,"style":576},"npm run dev\n",[514,2374,2375],{"__ignoreMap":576},[580,2376,2377,2379,2382],{"class":582,"line":583},[580,2378,597],{"class":586},[580,2380,2381],{"class":589}," run",[580,2383,2369],{"class":589},[570,2385,2387],{"className":572,"code":2386,"filename":612,"language":575,"meta":576,"style":576},"yarn run dev\n",[514,2388,2389],{"__ignoreMap":576},[580,2390,2391,2393,2395],{"class":582,"line":583},[580,2392,612],{"class":586},[580,2394,2381],{"class":589},[580,2396,2369],{"class":589},[570,2398,2400],{"className":572,"code":2399,"filename":626,"language":575,"meta":576,"style":576},"bun run dev\n",[514,2401,2402],{"__ignoreMap":576},[580,2403,2404,2406,2408],{"class":582,"line":583},[580,2405,626],{"class":586},[580,2407,2381],{"class":589},[580,2409,2369],{"class":589},[570,2411,2414],{"className":572,"code":2412,"filename":2413,"language":575,"meta":576,"style":576},"curl -X POST http:\u002F\u002Flocalhost:3000\u002Fcounters\u002Fhello\u002Fbump\n# → { \"count\": 1 }   (call it again → { \"count\": 2 } — same object, persisted state)\n","terminal",[514,2415,2416,2430],{"__ignoreMap":576},[580,2417,2418,2421,2424,2427],{"class":582,"line":583},[580,2419,2420],{"class":586},"curl",[580,2422,2423],{"class":589}," -X",[580,2425,2426],{"class":589}," POST",[580,2428,2429],{"class":589}," http:\u002F\u002Flocalhost:3000\u002Fcounters\u002Fhello\u002Fbump\n",[580,2431,2432],{"class":582,"line":673},[580,2433,2434],{"class":1439},"# → { \"count\": 1 }   (call it again → { \"count\": 2 } — same object, persisted state)\n",[499,2436,2437],{},"The shim runs serially the same way the platform does, so the single-threaded guarantee holds in dev\ntoo. What it can't reproduce is cross-isolate behavior — for that, deploy.",[552,2439,2441],{"id":2440},"configure-the-object","Configure the object",[499,2443,2444,2445,2448],{},"Options are passed as the ",[514,2446,2447],{},"DurableObject\u003C{...}>"," TYPE argument and tune storage and the generated Workers binding.",[2450,2451,2452,2469],"table",{},[2453,2454,2455],"thead",{},[2456,2457,2458,2463,2466],"tr",{},[2459,2460,2462],"th",{"align":2461},"left","Option",[2459,2464,2465],{"align":2461},"Default",[2459,2467,2468],{"align":2461},"What it does",[2470,2471,2472,2491,2504],"tbody",{},[2456,2473,2474,2479,2483],{},[2475,2476,2477],"td",{"align":2461},[514,2478,1780],{},[2475,2480,2481],{"align":2461},[514,2482,1176],{},[2475,2484,2485,2487,2488,2490],{"align":2461},[514,2486,1172],{}," (SQLite) or ",[514,2489,1176],{}," (key-value) backing for the object's persistent state",[2456,2492,2493,2498,2501],{},[2475,2494,2495],{"align":2461},[514,2496,2497],{},"binding",[2475,2499,2500],{"align":2461},"SCREAMING_SNAKE of the class name",[2475,2502,2503],{"align":2461},"The Workers binding name the object is bound under",[2456,2505,2506,2511,2516],{},[2475,2507,2508],{"align":2461},[514,2509,2510],{},"hibernate",[2475,2512,2513],{"align":2461},[514,2514,2515],{},"false",[2475,2517,2518,2519,774],{"align":2461},"Required to host a WebSocket handler in the object via the Hibernation API (see ",[502,2520,267],{"href":268},[552,2522,2524],{"id":2523},"hibernation-keeps-an-idle-room-free","Hibernation keeps an idle room free",[499,2526,2527,2528,2531],{},"Setting ",[514,2529,2530],{},"hibernate: true"," lets Cloudflare evict the object between frames and rehydrate it on the next one, so\na room with no traffic costs nothing while it still holds every live connection for that topic.",[499,2533,2534,2535,2537,2538,2540,2541,2543],{},"This is what makes a Durable Object the cross-isolate broadcast tier for ",[502,2536,267],{"href":268},"\nand ",[502,2539,275],{"href":276},": host the socket or stream inside the object\ninstead of a plain handler, and ",[514,2542,534],{},"\u002Fbroadcast reaches every connection in the room regardless of which\nisolate accepted it.",[552,2545,2547],{"id":2546},"deploy-to-cloudflare-workers","Deploy to Cloudflare Workers",[499,2549,2550,2551,2554,2555,2557,2558,2561,2562,2565,2566,2569,2570,2572],{},"On Cloudflare, each object runs as a real Durable Object, and ",[514,2552,2553],{},"CloudflareWorkerPlugin"," generates the worker\nentry for you — no worker file to hand-write. ",[514,2556,561],{}," also emits the Durable Object bindings and\nmigration ledger into the ",[514,2559,2560],{},"wrangler.json"," the ",[514,2563,2564],{},"CloudflarePlugin"," writes. See\n",[502,2567,307],{"href":2568},"\u002Fdocs\u002Fdeploy\u002Fcloudflare#durable-objects"," for the generated bridge, the ",[514,2571,2560],{}," binding\nrules, and the full Workers deploy.",[499,2574,2575,2576,2579],{},"Adding an object in a later release? Tag it — ",[514,2577,2578],{},"DurableObject\u003C{ migration: \"v2\" }>"," — so Cloudflare registers\nonly the new class in its own ordered migration.",[499,2581,2582,2585,2586,2588,2589,2592,2593,2596,2597,2600,2601,2604],{},[509,2583,2584],{},"Renaming or deleting"," an object names a class that's gone from source, so the compiler can't derive it;\ndeclare those in ",[514,2587,780],{}," under the app-level ",[514,2590,2591],{},"durable.migrations"," override (",[514,2594,2595],{},"renamedClasses"," \u002F\n",[514,2598,2599],{},"deletedClasses",", by generated ",[514,2602,2603],{},"\u003CName>DO"," class name), and they fold into the same ordered ledger:",[570,2606,2608],{"className":639,"code":2607,"filename":780,"language":642,"meta":576,"style":576},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { DurablePlugin } from \"@heximon\u002Fdurable\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new DurablePlugin() \u002F* … *\u002F],\n  durable: {\n    migrations: [\n      { tag: \"v3\", renamedClasses: [{ from: \"ChatRoomDO\", to: \"RoomV2DO\" }] },\n      { tag: \"v4\", deletedClasses: [\"LegacyRoomDO\"] },\n    ],\n  },\n});\n",[514,2609,2610,2630,2650,2654,2666,2689,2697,2707,2767,2802,2809,2814],{"__ignoreMap":576},[580,2611,2612,2614,2616,2618,2620,2622,2624,2626,2628],{"class":582,"line":583},[580,2613,650],{"class":649},[580,2615,678],{"class":660},[580,2617,791],{"class":653},[580,2619,684],{"class":660},[580,2621,687],{"class":649},[580,2623,661],{"class":660},[580,2625,800],{"class":589},[580,2627,667],{"class":660},[580,2629,670],{"class":660},[580,2631,2632,2634,2636,2638,2640,2642,2644,2646,2648],{"class":582,"line":673},[580,2633,650],{"class":649},[580,2635,678],{"class":660},[580,2637,813],{"class":653},[580,2639,684],{"class":660},[580,2641,687],{"class":649},[580,2643,661],{"class":660},[580,2645,822],{"class":589},[580,2647,667],{"class":660},[580,2649,670],{"class":660},[580,2651,2652],{"class":582,"line":699},[580,2653,703],{"emptyLinePlaceholder":702},[580,2655,2656,2658,2660,2662,2664],{"class":582,"line":706},[580,2657,709],{"class":649},[580,2659,712],{"class":649},[580,2661,791],{"class":715},[580,2663,718],{"class":653},[580,2665,721],{"class":660},[580,2667,2668,2670,2672,2674,2676,2678,2681,2684,2687],{"class":582,"line":724},[580,2669,728],{"class":727},[580,2671,731],{"class":660},[580,2673,734],{"class":653},[580,2675,875],{"class":660},[580,2677,813],{"class":715},[580,2679,2680],{"class":653},"() ",[580,2682,2683],{"class":1439},"\u002F* … *\u002F",[580,2685,2686],{"class":653},"]",[580,2688,743],{"class":660},[580,2690,2691,2693,2695],{"class":582,"line":746},[580,2692,1736],{"class":727},[580,2694,731],{"class":660},[580,2696,1049],{"class":660},[580,2698,2699,2702,2704],{"class":582,"line":768},[580,2700,2701],{"class":727},"    migrations",[580,2703,731],{"class":660},[580,2705,2706],{"class":653}," [\n",[580,2708,2709,2712,2715,2717,2719,2722,2724,2726,2729,2731,2733,2735,2737,2739,2741,2744,2746,2748,2751,2753,2755,2758,2760,2762,2765],{"class":582,"line":1121},[580,2710,2711],{"class":660},"      {",[580,2713,2714],{"class":727}," tag",[580,2716,731],{"class":660},[580,2718,661],{"class":660},[580,2720,2721],{"class":589},"v3",[580,2723,667],{"class":660},[580,2725,883],{"class":660},[580,2727,2728],{"class":727}," renamedClasses",[580,2730,731],{"class":660},[580,2732,734],{"class":653},[580,2734,865],{"class":660},[580,2736,687],{"class":727},[580,2738,731],{"class":660},[580,2740,661],{"class":660},[580,2742,2743],{"class":589},"ChatRoomDO",[580,2745,667],{"class":660},[580,2747,883],{"class":660},[580,2749,2750],{"class":727}," to",[580,2752,731],{"class":660},[580,2754,661],{"class":660},[580,2756,2757],{"class":589},"RoomV2DO",[580,2759,667],{"class":660},[580,2761,684],{"class":660},[580,2763,2764],{"class":653},"] ",[580,2766,1731],{"class":660},[580,2768,2769,2771,2773,2775,2777,2780,2782,2784,2787,2789,2791,2793,2796,2798,2800],{"class":582,"line":1157},[580,2770,2711],{"class":660},[580,2772,2714],{"class":727},[580,2774,731],{"class":660},[580,2776,661],{"class":660},[580,2778,2779],{"class":589},"v4",[580,2781,667],{"class":660},[580,2783,883],{"class":660},[580,2785,2786],{"class":727}," deletedClasses",[580,2788,731],{"class":660},[580,2790,734],{"class":653},[580,2792,667],{"class":660},[580,2794,2795],{"class":589},"LegacyRoomDO",[580,2797,667],{"class":660},[580,2799,2764],{"class":653},[580,2801,1731],{"class":660},[580,2803,2804,2807],{"class":582,"line":1163},[580,2805,2806],{"class":653},"    ]",[580,2808,743],{"class":660},[580,2810,2811],{"class":582,"line":1509},[580,2812,2813],{"class":660},"  },\n",[580,2815,2816,2818,2820],{"class":582,"line":1514},[580,2817,771],{"class":660},[580,2819,774],{"class":653},[580,2821,670],{"class":660},[552,2823,2825,2826,774],{"id":2824},"distributed-rate-limiting-heximondurablesecurity","Distributed rate limiting (",[514,2827,2828],{},"@heximon\u002Fdurable\u002Fsecurity",[499,2830,2831,2833],{},[514,2832,2828],{}," ships a turnkey rate-limit tier backed by a Durable Object — one DO per\nrate-limit key — so the sliding-window counter is shared across all isolates.",[499,2835,2836,2837,2840,2841,2844,2845,2848,2849,2852,2853,2856,2857,2859,2860,2862,2863,2034,2865,2867,2868,1133],{},"The package ships the ",[514,2838,2839],{},"RateLimitRoom"," Durable Object, its ",[514,2842,2843],{},"RateLimitRoomFactory"," handle, and the concrete\n",[514,2846,2847],{},"RateLimitRoomStore"," (a transparent drop-in for ",[514,2850,2851],{},"MemoryRateLimitStore","), so the app ",[509,2854,2855],{},"lists"," them with no\nlocal Durable Object shells: ",[514,2858,2839],{}," + ",[514,2861,2843],{}," under ",[514,2864,1558],{},[514,2866,2847],{},"\nunder ",[514,2869,1540],{},[499,2871,2872,2873,2876,2877,2881],{},"The ",[514,2874,2875],{},"RateLimitMiddleware",", its policy, and the controller are unchanged.\nSee ",[502,2878,2880],{"href":2879},"\u002Fdocs\u002Fcapabilities\u002Fsecurity#distributed-rate-limiting","Security hardening → Distributed rate limiting"," for the\nfull wiring pattern.",[552,2883,2885,2886,774],{"id":2884},"strongly-consistent-keyvalue-storage-heximondurablekv","Strongly-consistent key\u002Fvalue storage (",[514,2887,2888],{},"@heximon\u002Fdurable\u002Fkv",[499,2890,2891,2893,2894,2897,2898,2901,2902,2905,2906,2909,2910,2913],{},[514,2892,2888],{}," ships a turnkey ",[514,2895,2896],{},"Storage"," (the ",[502,2899,2900],{"href":166},"key\u002Fvalue port",")\nbacked by a Durable Object. All keys live in one single-threaded room, so every read and write —\nincluding the conditional ",[514,2903,2904],{},"setIfAbsent"," — is strongly consistent and ",[509,2907,2908],{},"atomic"," across all isolates\nand regions. That is exactly what the ",[502,2911,2912],{"href":186},"idempotency guard"," needs on\nCloudflare, where the eventually-consistent Workers KV is the wrong store.",[499,2915,2836,2916,2840,2919,2844,2922,2925,2926,2928,2929,2931],{},[514,2917,2918],{},"KvRoom",[514,2920,2921],{},"KvRoomFactory",[514,2923,2924],{},"KvRoomStorage"," (a satisfier of the ",[514,2927,2896],{}," DI token), so the app ",[509,2930,2855],{}," them with no local\nDurable Object shells:",[570,2933,2935],{"className":639,"code":2934,"language":642,"meta":576,"style":576},"import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { KvRoom, KvRoomFactory, KvRoomStorage } from \"@heximon\u002Fdurable\u002Fkv\";\n\nexport class StorageModule extends Module({\n  providers: [{ provide: Storage, useClass: KvRoomStorage }],\n  durable: {\n    objects: [KvRoom],\n    factories: [KvRoomFactory],\n  },\n  exports: [Storage],\n}) {}\n",[514,2936,2937,2957,2979,3010,3014,3031,3064,3072,3084,3096,3100,3112],{"__ignoreMap":576},[580,2938,2939,2941,2943,2945,2947,2949,2951,2953,2955],{"class":582,"line":583},[580,2940,650],{"class":649},[580,2942,678],{"class":660},[580,2944,1584],{"class":653},[580,2946,684],{"class":660},[580,2948,687],{"class":649},[580,2950,661],{"class":660},[580,2952,1593],{"class":589},[580,2954,667],{"class":660},[580,2956,670],{"class":660},[580,2958,2959,2961,2963,2966,2968,2970,2972,2975,2977],{"class":582,"line":673},[580,2960,650],{"class":649},[580,2962,678],{"class":660},[580,2964,2965],{"class":653}," Storage",[580,2967,684],{"class":660},[580,2969,687],{"class":649},[580,2971,661],{"class":660},[580,2973,2974],{"class":589},"@heximon\u002Fkv",[580,2976,667],{"class":660},[580,2978,670],{"class":660},[580,2980,2981,2983,2985,2988,2990,2993,2995,2998,3000,3002,3004,3006,3008],{"class":582,"line":699},[580,2982,650],{"class":649},[580,2984,678],{"class":660},[580,2986,2987],{"class":653}," KvRoom",[580,2989,883],{"class":660},[580,2991,2992],{"class":653}," KvRoomFactory",[580,2994,883],{"class":660},[580,2996,2997],{"class":653}," KvRoomStorage",[580,2999,684],{"class":660},[580,3001,687],{"class":649},[580,3003,661],{"class":660},[580,3005,2888],{"class":589},[580,3007,667],{"class":660},[580,3009,670],{"class":660},[580,3011,3012],{"class":582,"line":706},[580,3013,703],{"emptyLinePlaceholder":702},[580,3015,3016,3018,3020,3023,3025,3027,3029],{"class":582,"line":724},[580,3017,709],{"class":649},[580,3019,1020],{"class":1019},[580,3021,3022],{"class":586}," StorageModule",[580,3024,1259],{"class":1019},[580,3026,1584],{"class":715},[580,3028,718],{"class":653},[580,3030,721],{"class":660},[580,3032,3033,3035,3037,3039,3041,3044,3046,3048,3050,3053,3055,3058,3060,3062],{"class":582,"line":746},[580,3034,1704],{"class":727},[580,3036,731],{"class":660},[580,3038,734],{"class":653},[580,3040,865],{"class":660},[580,3042,3043],{"class":727}," provide",[580,3045,731],{"class":660},[580,3047,2965],{"class":653},[580,3049,883],{"class":660},[580,3051,3052],{"class":727}," useClass",[580,3054,731],{"class":660},[580,3056,3057],{"class":653}," KvRoomStorage ",[580,3059,771],{"class":660},[580,3061,2686],{"class":653},[580,3063,743],{"class":660},[580,3065,3066,3068,3070],{"class":582,"line":768},[580,3067,1736],{"class":727},[580,3069,731],{"class":660},[580,3071,1049],{"class":660},[580,3073,3074,3077,3079,3082],{"class":582,"line":1121},[580,3075,3076],{"class":727},"    objects",[580,3078,731],{"class":660},[580,3080,3081],{"class":653}," [KvRoom]",[580,3083,743],{"class":660},[580,3085,3086,3089,3091,3094],{"class":582,"line":1157},[580,3087,3088],{"class":727},"    factories",[580,3090,731],{"class":660},[580,3092,3093],{"class":653}," [KvRoomFactory]",[580,3095,743],{"class":660},[580,3097,3098],{"class":582,"line":1163},[580,3099,2813],{"class":660},[580,3101,3102,3105,3107,3110],{"class":582,"line":1509},[580,3103,3104],{"class":727},"  exports",[580,3106,731],{"class":660},[580,3108,3109],{"class":653}," [Storage]",[580,3111,743],{"class":660},[580,3113,3114,3116,3118],{"class":582,"line":1514},[580,3115,771],{"class":660},[580,3117,1767],{"class":653},[580,3119,1770],{"class":660},[499,3121,3122,3123,3129,3130,3133,3134,3137],{},"TTL is honored with lazy expiry inside the room (no alarms). A room sustains ~500–1,000 req\u002Fs —\nplenty for idempotency markers and coordination state, wrong for a high-QPS cache tier (keep\n",[502,3124,3126],{"href":3125},"\u002Fdocs\u002Fcapabilities\u002Fkey-value#cloudflare-workers-kv-heximonkvcloudflare-edge-safe",[514,3127,3128],{},"CloudflareKvStorage","\nthere). For an isolated or hotter keyspace, construct the ",[514,3131,3132],{},"DurableObjectKvStorage"," routing base with\n",[514,3135,3136],{},"{ room, shards }"," — keys hash deterministically onto the fixed shard set, so single-key semantics\nstay exact at any shard count.",[552,3139,3141],{"id":3140},"see-also","See also",[3143,3144,3145,3152,3168,3176,3181,3189],"ul",{},[3146,3147,3148,3151],"li",{},[502,3149,3150],{"href":264},"Realtime overview"," — plain WebSockets and SSE cover most apps with no Durable\nObject at all.",[3146,3153,3154,3157,3158,3161,3162,3164,3165,3167],{},[502,3155,3156],{"href":190},"Security hardening"," — the ",[514,3159,3160],{},"RateLimitStore"," port and how ",[514,3163,2828],{},"\ndrops in for ",[514,3166,2851],{},", plus the distributed rate-limit store wired alongside the body guard\nand security headers.",[3146,3169,3170,3172,3173,3175],{},[502,3171,267],{"href":268}," — host a WebSocket handler inside a Durable Object with\n",[514,3174,2530],{},", for real cross-isolate fan-out via the Hibernation API.",[3146,3177,3178,3180],{},[502,3179,275],{"href":276}," — broadcast typed server-sent events across\nisolates from a Durable Object holding the live streams.",[3146,3182,3183,3185,3186,3188],{},[502,3184,307],{"href":308}," — the generated bridge, ",[514,3187,2560],{}," binding rules, and the full\nWorkers deploy.",[3146,3190,3191,3196,3197,3199,3200,3202],{},[502,3192,3195],{"href":3193,"rel":3194},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fflagship\u002Fapps\u002Fcloudflare",[506],"the flagship Cloudflare app","\n— a ",[514,3198,2530],{}," seat-map room hosting a WebSocket, plus a keyed feed room fanning out SSE across\nisolates, all addressed through ",[514,3201,1536],{}," handles.",[3204,3205,3206],"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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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}",{"title":576,"searchDepth":673,"depth":673,"links":3208},[3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3221,3223],{"id":554,"depth":673,"text":555},{"id":920,"depth":673,"text":921},{"id":940,"depth":673,"text":941},{"id":1180,"depth":673,"text":1181},{"id":1551,"depth":673,"text":1552},{"id":1773,"depth":673,"text":1774},{"id":2349,"depth":673,"text":2350},{"id":2440,"depth":673,"text":2441},{"id":2523,"depth":673,"text":2524},{"id":2546,"depth":673,"text":2547},{"id":2824,"depth":673,"text":3220},"Distributed rate limiting (@heximon\u002Fdurable\u002Fsecurity)",{"id":2884,"depth":673,"text":3222},"Strongly-consistent key\u002Fvalue storage (@heximon\u002Fdurable\u002Fkv)",{"id":3140,"depth":673,"text":3141},"Author a single-threaded stateful actor at the edge with DurableObject and a DI-injected DurableFactory, address it by name, and reach storage through DurableContext.","md",null,{},{"icon":80},{"title":289,"description":3224},"vp6DN1Jx2hwb1T0MWBqI0J6P_d3kkxRswu1dB82a7Pw",[3232,3234],{"title":285,"path":286,"stem":287,"description":3233,"icon":259,"children":-1},"Generate an AsyncAPI 3.1 document from your WebSocket contracts and SSE event maps at runtime with AsyncApiGenerator, serving bidirectional WS send\u002Freceive operations and SSE receive-only operations, with the wire envelope documented at the message level.",{"title":142,"path":299,"stem":300,"description":3235,"icon":6,"children":-1},"PlatformStrategy, heximon.platform, vp build artifacts, feature x platform support matrix, NodeHostStrategy, CloudflareWorkersStrategy, VercelFunctionsStrategy, NetlifyFunctionsStrategy, LambdaStrategy, DenoDeployStrategy, heximon deploy.",1783300761903]