[{"data":1,"prerenderedAt":1182},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-idempotency":493,"-docs-capabilities-idempotency-surround":1177},[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":185,"body":495,"description":1170,"extension":1171,"links":1172,"meta":1173,"navigation":1174,"path":186,"seo":1175,"stem":187,"__hash__":1176},"docs\u002Fdocs\u002F03.capabilities\u002F10.idempotency.md",{"type":496,"value":497,"toc":1165},"minimark",[498,502,534,539,558,804,847,869,931,935,941,1056,1080,1084,1161],[499,500,501],"p",{},"Replaying a message that already succeeded should be a no-op, not a duplicate side effect. Heximon provides\nopt-in idempotency guards across three dispatch tiers — domain events, queue channels, and HTTP commands —\nso you can re-deliver safely under at-least-once delivery without writing the guard yourself.",[499,503,504,505,509,510,513,514,517,518,522,523,529,530,533],{},"All three tiers share the same contract: no key means no dedup; entering the gate ",[506,507,508],"strong",{},"claims"," the key\n(dropping a duplicate that is already claimed or processed), success ",[506,511,512],{},"confirms"," it, and a throwing handler\n",[506,515,516],{},"releases"," its claim so the retry runs. There is no ",[519,520,521],"code",{},"@heximon\u002Fidempotency"," package — each\ninterceptor ships as an ",[506,524,525,528],{},[519,526,527],{},".\u002Fidempotency"," subpath of the tier package it guards",", so you import it from a\npackage you already depend on, and a tier you don't use never pulls the guard in. Every shipped interceptor\nextends its interceptor base directly, so it's ",[506,531,532],{},"directly listable"," under the owning module's namespace key —\nno app-authored wrapper is needed.",[535,536,538],"h2",{"id":537},"worked-example-the-queue-tier","Worked example — the queue tier",[499,540,541,542,545,546,549,550,553,554,557],{},"The queue tier has the clearest dedup key: every queued message carries a stable envelope ",[519,543,544],{},"id"," — a UUIDv7 the\nproducer mints once and that survives redelivery. ",[519,547,548],{},"QueueIdempotencyInterceptor"," (",[519,551,552],{},"@heximon\u002Fqueue\u002Fidempotency",")\nreads that id, checks it against a ",[519,555,556],{},"Storage"," marker, and skips the handler when it's already been seen:",[559,560,566],"pre",{"className":561,"code":562,"filename":563,"language":564,"meta":565,"style":565},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Module } from \"@heximon\u002Fruntime\";\nimport { Storage } from \"@heximon\u002Fkv\";\nimport { MemoryStorage } from \"@heximon\u002Fkv\u002Fmemory\";\nimport { QueueIdempotencyInterceptor } from \"@heximon\u002Fqueue\u002Fidempotency\";\n\nexport class AppModule extends Module({\n  providers: [\n    QueueIdempotencyInterceptor,                          \u002F\u002F its ctor injects Context + Storage\n    { provide: Storage, useClass: MemoryStorage },        \u002F\u002F a strongly consistent Storage in production\n  ],\n  queue: { interceptors: [QueueIdempotencyInterceptor] }, \u002F\u002F listed directly — no wrapper\n}) {}\n","src\u002Fapp.module.ts","ts","",[519,567,568,604,627,650,672,679,705,718,731,760,769,792],{"__ignoreMap":565},[569,570,573,577,581,585,588,591,594,598,601],"span",{"class":571,"line":572},"line",1,[569,574,576],{"class":575},"s7zQu","import",[569,578,580],{"class":579},"sMK4o"," {",[569,582,584],{"class":583},"sTEyZ"," Module",[569,586,587],{"class":579}," }",[569,589,590],{"class":575}," from",[569,592,593],{"class":579}," \"",[569,595,597],{"class":596},"sfazB","@heximon\u002Fruntime",[569,599,600],{"class":579},"\"",[569,602,603],{"class":579},";\n",[569,605,607,609,611,614,616,618,620,623,625],{"class":571,"line":606},2,[569,608,576],{"class":575},[569,610,580],{"class":579},[569,612,613],{"class":583}," Storage",[569,615,587],{"class":579},[569,617,590],{"class":575},[569,619,593],{"class":579},[569,621,622],{"class":596},"@heximon\u002Fkv",[569,624,600],{"class":579},[569,626,603],{"class":579},[569,628,630,632,634,637,639,641,643,646,648],{"class":571,"line":629},3,[569,631,576],{"class":575},[569,633,580],{"class":579},[569,635,636],{"class":583}," MemoryStorage",[569,638,587],{"class":579},[569,640,590],{"class":575},[569,642,593],{"class":579},[569,644,645],{"class":596},"@heximon\u002Fkv\u002Fmemory",[569,647,600],{"class":579},[569,649,603],{"class":579},[569,651,653,655,657,660,662,664,666,668,670],{"class":571,"line":652},4,[569,654,576],{"class":575},[569,656,580],{"class":579},[569,658,659],{"class":583}," QueueIdempotencyInterceptor",[569,661,587],{"class":579},[569,663,590],{"class":575},[569,665,593],{"class":579},[569,667,552],{"class":596},[569,669,600],{"class":579},[569,671,603],{"class":579},[569,673,675],{"class":571,"line":674},5,[569,676,678],{"emptyLinePlaceholder":677},true,"\n",[569,680,682,685,689,693,696,699,702],{"class":571,"line":681},6,[569,683,684],{"class":575},"export",[569,686,688],{"class":687},"spNyl"," class",[569,690,692],{"class":691},"sBMFI"," AppModule",[569,694,695],{"class":687}," extends",[569,697,584],{"class":698},"s2Zo4",[569,700,701],{"class":583},"(",[569,703,704],{"class":579},"{\n",[569,706,708,712,715],{"class":571,"line":707},7,[569,709,711],{"class":710},"swJcz","  providers",[569,713,714],{"class":579},":",[569,716,717],{"class":583}," [\n",[569,719,721,724,727],{"class":571,"line":720},8,[569,722,723],{"class":583},"    QueueIdempotencyInterceptor",[569,725,726],{"class":579},",",[569,728,730],{"class":729},"sHwdD","                          \u002F\u002F its ctor injects Context + Storage\n",[569,732,734,737,740,742,744,746,749,751,754,757],{"class":571,"line":733},9,[569,735,736],{"class":579},"    {",[569,738,739],{"class":710}," provide",[569,741,714],{"class":579},[569,743,613],{"class":583},[569,745,726],{"class":579},[569,747,748],{"class":710}," useClass",[569,750,714],{"class":579},[569,752,753],{"class":583}," MemoryStorage ",[569,755,756],{"class":579},"},",[569,758,759],{"class":729},"        \u002F\u002F a strongly consistent Storage in production\n",[569,761,763,766],{"class":571,"line":762},10,[569,764,765],{"class":583},"  ]",[569,767,768],{"class":579},",\n",[569,770,772,775,777,779,782,784,787,789],{"class":571,"line":771},11,[569,773,774],{"class":710},"  queue",[569,776,714],{"class":579},[569,778,580],{"class":579},[569,780,781],{"class":710}," interceptors",[569,783,714],{"class":579},[569,785,786],{"class":583}," [QueueIdempotencyInterceptor] ",[569,788,756],{"class":579},[569,790,791],{"class":729}," \u002F\u002F listed directly — no wrapper\n",[569,793,795,798,801],{"class":571,"line":794},12,[569,796,797],{"class":579},"}",[569,799,800],{"class":583},") ",[569,802,803],{"class":579},"{}\n",[499,805,806,807,809,810,812,813,815,816,819,820,823,824,827,828,831,832,835,836,839,840,843,844,846],{},"The interceptor injects the ",[519,808,556],{}," DI token from ",[519,811,622],{}," (an optional peer, pulled in only when you\nuse the ",[519,814,527],{}," subpath) — bind ",[519,817,818],{},"MemoryStorage"," for dev, a strongly consistent networked backend in\nproduction. The guard is a ",[506,821,822],{},"claim \u002F confirm \u002F release"," protocol: entering the gate claims the key with\n",[519,825,826],{},"setIfAbsent"," under a bounded TTL (a redelivery of a claimed or processed id is dropped), success overwrites\nthe claim with a processed marker, and a throwing handler releases its claim so the next redelivery retries\nimmediately — a crash instead unblocks when the claim TTL lapses. Both windows are tunable via the optional\ntrailing constructor options: ",[519,829,830],{},"claimTtlSeconds"," (default ",[519,833,834],{},"300"," — keep it comfortably above your slowest\nhandler) and ",[519,837,838],{},"retentionTtlSeconds"," (how long the processed marker keeps deduping; omitted = indefinitely).\nThe stored key is prefixed ",[519,841,842],{},"idempotency:queue:\u003Cid>","\nso it never collides with the event or command tiers sharing the same ",[519,845,556],{},".",[499,848,849,850,853,854,857,858,861,862,865,866,868],{},"For ",[506,851,852],{},"cross-service"," fan-out, where subscribing services may share one networked store, the queue key gains\nnamespace segments so copies never collide: a per-subscriber segment (",[519,855,856],{},"idempotency:queue:\u003CsubscriberService>:\u003Cid>","),\nand — when the event arrives over a native broadcast (a shared stream several producers write to) — a\nper-producer ",[519,859,860],{},"source"," segment (",[519,863,864],{},"idempotency:queue:\u003CsubscriberService>:\u003Csource>:\u003Cid>","). A single-service app\nkeeps the flat ",[519,867,842],{}," key.",[870,871,873,908,919],"callout",{"type":872},"warning",[499,874,875,880,881,884,885,888,889,896,897,900,901,904,905,907],{},[506,876,877,878,846],{},"The guard is exactly as strong as your backend's ",[519,879,826],{}," On a backend with an atomic conditional\nwrite — Redis via ",[519,882,883],{},"@heximon\u002Fkv\u002Fredis"," (Node-only), Upstash via ",[519,886,887],{},"@heximon\u002Fkv\u002Fupstash"," (edge-safe), or the\nDurable-Object-backed\n",[890,891,893],"a",{"href":892},"\u002Fdocs\u002Frealtime\u002Fdurable-objects#strongly-consistent-keyvalue-storage-heximondurablekv",[519,894,895],{},"KvRoomStorage"," from\n",[519,898,899],{},"@heximon\u002Fdurable\u002Fkv"," on Cloudflare — truly-concurrent deliveries of the same id admit ",[506,902,903],{},"exactly one"," handler\nrun. On a check-then-set backend the claim degrades to best-effort, and ",[519,906,818],{}," is per-isolate — on\nWorkers with multiple isolates, one isolate's claim is invisible to another.",[499,909,910,913,914,918],{},[506,911,912],{},"Never Cloudflare Workers KV for this guard."," It's eventually consistent (up to ~60 s global propagation), so a\nstale read across regions can let a retried request slip straight past the dedup check it exists to enforce — see\n",[890,915,917],{"href":916},"\u002Fdocs\u002Fcapabilities\u002Fkey-value#first-class-networked-adapters","Key\u002FValue storage"," for the same warning on the\nadapter itself.",[499,920,921,924,925,927,928,930],{},[506,922,923],{},"Mind the claim TTL."," A handler that outlives its claim (",[519,926,830],{},", default 300) lets a concurrent\nredelivery re-claim the id mid-run — size it comfortably above your slowest handler. Set ",[519,929,838],{},"\nto keep the processed-marker set from growing unbounded (each marker then expires with its dedup window).",[535,932,934],{"id":933},"the-other-two-tiers","The other two tiers",[499,936,937,938,940],{},"Same contract, same ",[519,939,527],{}," subpath pattern, different dedup key:",[942,943,944,967],"table",{},[945,946,947],"thead",{},[948,949,950,955,958,961,964],"tr",{},[951,952,954],"th",{"align":953},"left","Tier",[951,956,957],{"align":953},"Import from",[951,959,960],{"align":953},"Dedup key",[951,962,963],{"align":953},"Handler scope",[951,965,966],{"align":953},"Covered on",[968,969,970,1004,1032],"tbody",{},[948,971,972,978,983,989,1000],{},[973,974,975],"td",{"align":953},[506,976,977],{},"Event",[973,979,980],{"align":953},[519,981,982],{},"@heximon\u002Fevents\u002Fidempotency",[973,984,985,988],{"align":953},[519,986,987],{},"event.eventId"," (UUIDv7, per-occurrence)",[973,990,991,992,995,996,999],{"align":953},"Serial ",[519,993,994],{},"EventHandler"," dispatch only — the parallel-absorb ",[519,997,998],{},"NotificationHandler"," bucket bypasses the interceptor chain by design",[973,1001,1002],{"align":953},[890,1003,146],{"href":147},[948,1005,1006,1011,1016,1025,1028],{},[973,1007,1008],{"align":953},[506,1009,1010],{},"Command",[973,1012,1013],{"align":953},[519,1014,1015],{},"@heximon\u002Fcqrs\u002Fidempotency",[973,1017,1018,1021,1022],{"align":953},[519,1019,1020],{},"Idempotency-Key"," HTTP header → ",[519,1023,1024],{},"context.get(\"idempotencyKey\")",[973,1026,1027],{"align":953},"HTTP-dispatched commands only; a command dispatched without the header (or outside an HTTP context) carries no key and falls through unconditionally",[973,1029,1030],{"align":953},[890,1031,233],{"href":234},[948,1033,1034,1038,1042,1048,1051],{},[973,1035,1036],{"align":953},[506,1037,151],{},[973,1039,1040],{"align":953},[519,1041,552],{},[973,1043,1044,1045,1047],{"align":953},"Envelope ",[519,1046,544],{}," (stable UUIDv7 across redeliveries)",[973,1049,1050],{"align":953},"Queue channel dispatch",[973,1052,1053],{"align":953},[890,1054,1055],{"href":152},"Queue & Integration Events",[499,1057,1058,1059,1062,1063,1066,1067,1069,1070,768,1073,1076,1077,1079],{},"Wiring either follows the same shape as the queue example above — swap the import, the interceptor class, and\nthe namespace key (",[519,1060,1061],{},"events: { interceptors: [...] }"," \u002F ",[519,1064,1065],{},"cqrs: { commandInterceptors: [...] }","). All three tiers\ncan share one ",[519,1068,556],{}," instance; each uses a distinct key prefix (",[519,1071,1072],{},"idempotency:event:\u003CeventId>",[519,1074,1075],{},"idempotency:command:\u003Ckey>",", ",[519,1078,842],{},") so the keys never collide.",[535,1081,1083],{"id":1082},"see-also","See also",[1085,1086,1087,1096,1107,1122,1130,1135,1140,1151],"ul",{},[1088,1089,1090,1092,1093,1095],"li",{},[890,1091,1055],{"href":152}," — the queue tier and channel dispatch the\n",[519,1094,548],{}," guards.",[1088,1097,1098,1100,1101,1103,1104,1095],{},[890,1099,146],{"href":147}," — the serial ",[519,1102,994],{}," dispatch the ",[519,1105,1106],{},"EventIdempotencyInterceptor",[1088,1108,1109,1111,1112,1103,1115,1118,1119,1121],{},[890,1110,233],{"href":234}," — the ",[519,1113,1114],{},"CommandBus",[519,1116,1117],{},"CommandIdempotencyInterceptor"," guards, and where\nthe ",[519,1120,1020],{}," header flows from.",[1088,1123,1124,1111,1127,1129],{},[890,1125,1126],{"href":166},"Key-value storage",[519,1128,556],{}," DI token every interceptor injects, the\nfirst-class Redis adapters, and why Cloudflare Workers KV is the wrong backend for a dedup guard.",[1088,1131,1132,1134],{},[890,1133,480],{"href":481}," — the transactional outbox pattern that\nmakes integration events durable before dedup matters.",[1088,1136,1137,1139],{},[890,1138,485],{"href":486}," — multi-step compensation over the durable outbox,\nwith idempotency guards at each hop.",[1088,1141,1142,1150],{},[890,1143,1147],{"href":1144,"rel":1145},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Freliable",[1146],"nofollow",[506,1148,1149],{},"the gap's reliable cross-service example","\n— the durable outbox that makes integration events safe to redeliver, where idempotency guards become necessary.",[1088,1152,1153,1160],{},[890,1154,1157],{"href":1155,"rel":1156},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fworkflow-compensation",[1146],[506,1158,1159],{},"the gap's workflow compensation example","\n— multi-hop choreography with per-handler idempotency checks on each step.",[1162,1163,1164],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .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 .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":565,"searchDepth":606,"depth":606,"links":1166},[1167,1168,1169],{"id":537,"depth":606,"text":538},{"id":933,"depth":606,"text":934},{"id":1082,"depth":606,"text":1083},"Idempotency tiers for event, queue, and command dispatch — EventIdempotencyInterceptor, CommandIdempotencyInterceptor, QueueIdempotencyInterceptor, Idempotency-Key header, ContextData.idempotencyKey, Storage port, best-effort dedup.","md",null,{},{"icon":65},{"title":185,"description":1170},"fkxnxPPD-lJ7qDqVk5V5J0t_KOOMcVMtrbeAXPv0rrM",[1178,1180],{"title":180,"path":181,"stem":182,"description":1179,"icon":183,"children":-1},"Multi-channel notifications behind one Message \u002F MessageTransport contract — email (Resend, unemail), SMS (Twilio), push (OneSignal, FCM, Web Push), TemplateRenderer, SuppressionService, and the NotificationDispatcher.",{"title":189,"path":190,"stem":191,"description":1181,"icon":192,"children":-1},"Body-size guard (content-length, 413 RFC-9457), SecurityHeaders (nosniff\u002FDENY\u002Fno-referrer\u002FHSTS), RateLimitStore port, MemoryRateLimitStore, RateLimitMiddleware, @heximon\u002Fhttp\u002Fsecurity, bearer-only CSRF posture.",1783300761903]