[{"data":1,"prerenderedAt":2685},["ShallowReactive",2],{"navigation_docs":3,"-docs-recipes-reactive-choreography":493,"-docs-recipes-reactive-choreography-surround":2680},[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":485,"body":495,"description":2673,"extension":2674,"links":2675,"meta":2676,"navigation":2677,"path":486,"seo":2678,"stem":487,"__hash__":2679},"docs\u002Fdocs\u002F09.recipes\u002F14.reactive-choreography.md",{"type":496,"value":497,"toc":2664},"minimark",[498,507,518,533,538,554,565,575,583,589,600,604,611,1068,1189,1205,1209,1218,1779,1794,1812,1818,1822,1829,1870,1892,1896,1909,2173,2191,2195,2222,2568,2601,2605,2660],[499,500,501,502,506],"p",{},"A multi-step business flow — place an order, reserve inventory, take payment — must either complete fully or\nundo itself fully: a failed payment should release the reservation and cancel the order. A ",[503,504,505],"strong",{},"saga orchestrator","\ndoes this with a central coordinator that holds the state and issues commands.",[499,508,509,512,513,517],{},[503,510,511],{},"Reactive choreography"," does it with ",[514,515,516],"em",{},"no"," coordinator: each context reacts to the events it cares about\nand emits the next one. The flow organizes itself, and the only thing connecting the contexts is the shape\nof the events they exchange.",[499,519,520,521,528,529,532],{},"This recipe builds the three-context flow in\n",[522,523,527],"a",{"href":524,"rel":525},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fworkflow-compensation",[526],"nofollow","the gap's workflow compensation example",". It stands on the\n",[522,530,531],{"href":481},"transactional outbox"," — that is what makes each step durable.",[534,535,537],"h2",{"id":536},"the-flow-first","The flow, first",[499,539,540,541,544,545,548,549,553],{},"Two paths, decided by whether payment succeeds. Each step ",[503,542,543],{},"reacts"," to one event and ",[503,546,547],{},"emits"," the next; the\nindentation shows that causation. Every emit rides the outbox (see ",[522,550,552],{"href":551},"#each-step-is-an-atomic-write-and-emit","the next section",").",[499,555,556,559,560,564],{},[503,557,558],{},"Happy path"," — ",[561,562,563],"code",{},"POST \u002Forders\u002Fplace { \"failPayment\": false }",":",[566,567,572],"pre",{"className":568,"code":570,"language":571},[569],"language-text","Orders      save Order(pending)      ──▶ order.placed\n└─ Inventory   save Reservation       ──▶ inventory.reserved\n   └─ Payment     save Payment(ok)     ──▶ payment.processed\n      └─ Orders      mark Order(paid)            ✓ done\n","text",[561,573,570],{"__ignoreMap":574},"",[499,576,577,559,580,564],{},[503,578,579],{},"Compensation path",[561,581,582],{},"POST \u002Forders\u002Fplace { \"failPayment\": true }",[566,584,587],{"className":585,"code":586,"language":571},[569],"Orders      save Order(pending)      ──▶ order.placed\n└─ Inventory   save Reservation       ──▶ inventory.reserved\n   └─ Payment     save Payment(failed) ──▶ payment.failed\n      └─ Inventory    release Reservation ──▶ reservation.released\n         └─ Payment      (no write)        ──▶ order.cancelled\n            └─ Orders       mark Order(cancelled)  ✓ done\n",[561,588,586],{"__ignoreMap":574},[499,590,591,592,595,596,599],{},"No context imports another. The ",[561,593,594],{},"failPayment"," flag rides the payloads from ",[561,597,598],{},"order.placed"," down to the payment\nstep, where it deterministically picks the branch — so a test can drive both paths with no real gateway.",[534,601,603],{"id":602},"the-only-coupling-one-shared-event-file","The only coupling: one shared event file",[499,605,606,607,610],{},"Because the contexts never call each other, the ",[503,608,609],{},"event classes and their payload interfaces are the entire\ncontract",". They live in one statically-checked file every producer and consumer imports — inject an unknown\nevent class, or one with the wrong payload, and it is a compile error.",[566,612,617],{"className":613,"code":614,"filename":615,"language":616,"meta":574,"style":574},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { IntegrationEvent } from \"@heximon\u002Fintegration\";\n\nexport interface OrderPlacedPayload {\n  readonly orderId: string;\n  readonly failPayment: boolean;\n}\nexport interface InventoryReservedPayload {\n  readonly orderId: string;\n  readonly failPayment: boolean;\n}\nexport interface PaymentProcessedPayload { readonly orderId: string; }\nexport interface PaymentFailedPayload    { readonly orderId: string; }\nexport interface ReservationReleasedPayload { readonly orderId: string; }\nexport interface OrderCancelledPayload   { readonly orderId: string; }\n\nexport class OrderPlaced      extends IntegrationEvent\u003C\"order.placed\",         OrderPlacedPayload>      {}\nexport class InventoryReserved extends IntegrationEvent\u003C\"inventory.reserved\",  InventoryReservedPayload> {}\nexport class PaymentProcessed extends IntegrationEvent\u003C\"payment.processed\",    PaymentProcessedPayload> {}\nexport class PaymentFailed    extends IntegrationEvent\u003C\"payment.failed\",       PaymentFailedPayload>    {}\nexport class ReservationReleased extends IntegrationEvent\u003C\"reservation.released\", ReservationReleasedPayload> {}\nexport class OrderCancelled   extends IntegrationEvent\u003C\"order.cancelled\",      OrderCancelledPayload>   {}\n","src\u002Fevents.ts","ts",[561,618,619,655,662,679,696,711,717,729,742,755,760,787,812,836,861,866,903,937,969,1003,1034],{"__ignoreMap":574},[620,621,624,628,632,636,639,642,645,649,652],"span",{"class":622,"line":623},"line",1,[620,625,627],{"class":626},"s7zQu","import",[620,629,631],{"class":630},"sMK4o"," {",[620,633,635],{"class":634},"sTEyZ"," IntegrationEvent",[620,637,638],{"class":630}," }",[620,640,641],{"class":626}," from",[620,643,644],{"class":630}," \"",[620,646,648],{"class":647},"sfazB","@heximon\u002Fintegration",[620,650,651],{"class":630},"\"",[620,653,654],{"class":630},";\n",[620,656,658],{"class":622,"line":657},2,[620,659,661],{"emptyLinePlaceholder":660},true,"\n",[620,663,665,668,672,676],{"class":622,"line":664},3,[620,666,667],{"class":626},"export",[620,669,671],{"class":670},"spNyl"," interface",[620,673,675],{"class":674},"sBMFI"," OrderPlacedPayload",[620,677,678],{"class":630}," {\n",[620,680,682,685,689,691,694],{"class":622,"line":681},4,[620,683,684],{"class":670},"  readonly",[620,686,688],{"class":687},"swJcz"," orderId",[620,690,564],{"class":630},[620,692,693],{"class":674}," string",[620,695,654],{"class":630},[620,697,699,701,704,706,709],{"class":622,"line":698},5,[620,700,684],{"class":670},[620,702,703],{"class":687}," failPayment",[620,705,564],{"class":630},[620,707,708],{"class":674}," boolean",[620,710,654],{"class":630},[620,712,714],{"class":622,"line":713},6,[620,715,716],{"class":630},"}\n",[620,718,720,722,724,727],{"class":622,"line":719},7,[620,721,667],{"class":626},[620,723,671],{"class":670},[620,725,726],{"class":674}," InventoryReservedPayload",[620,728,678],{"class":630},[620,730,732,734,736,738,740],{"class":622,"line":731},8,[620,733,684],{"class":670},[620,735,688],{"class":687},[620,737,564],{"class":630},[620,739,693],{"class":674},[620,741,654],{"class":630},[620,743,745,747,749,751,753],{"class":622,"line":744},9,[620,746,684],{"class":670},[620,748,703],{"class":687},[620,750,564],{"class":630},[620,752,708],{"class":674},[620,754,654],{"class":630},[620,756,758],{"class":622,"line":757},10,[620,759,716],{"class":630},[620,761,763,765,767,770,772,775,777,779,781,784],{"class":622,"line":762},11,[620,764,667],{"class":626},[620,766,671],{"class":670},[620,768,769],{"class":674}," PaymentProcessedPayload",[620,771,631],{"class":630},[620,773,774],{"class":670}," readonly",[620,776,688],{"class":687},[620,778,564],{"class":630},[620,780,693],{"class":674},[620,782,783],{"class":630},";",[620,785,786],{"class":630}," }\n",[620,788,790,792,794,797,800,802,804,806,808,810],{"class":622,"line":789},12,[620,791,667],{"class":626},[620,793,671],{"class":670},[620,795,796],{"class":674}," PaymentFailedPayload",[620,798,799],{"class":630},"    {",[620,801,774],{"class":670},[620,803,688],{"class":687},[620,805,564],{"class":630},[620,807,693],{"class":674},[620,809,783],{"class":630},[620,811,786],{"class":630},[620,813,815,817,819,822,824,826,828,830,832,834],{"class":622,"line":814},13,[620,816,667],{"class":626},[620,818,671],{"class":670},[620,820,821],{"class":674}," ReservationReleasedPayload",[620,823,631],{"class":630},[620,825,774],{"class":670},[620,827,688],{"class":687},[620,829,564],{"class":630},[620,831,693],{"class":674},[620,833,783],{"class":630},[620,835,786],{"class":630},[620,837,839,841,843,846,849,851,853,855,857,859],{"class":622,"line":838},14,[620,840,667],{"class":626},[620,842,671],{"class":670},[620,844,845],{"class":674}," OrderCancelledPayload",[620,847,848],{"class":630},"   {",[620,850,774],{"class":670},[620,852,688],{"class":687},[620,854,564],{"class":630},[620,856,693],{"class":674},[620,858,783],{"class":630},[620,860,786],{"class":630},[620,862,864],{"class":622,"line":863},15,[620,865,661],{"emptyLinePlaceholder":660},[620,867,869,871,874,877,880,882,885,887,889,891,894,897,900],{"class":622,"line":868},16,[620,870,667],{"class":626},[620,872,873],{"class":670}," class",[620,875,876],{"class":674}," OrderPlaced",[620,878,879],{"class":670},"      extends",[620,881,635],{"class":674},[620,883,884],{"class":630},"\u003C",[620,886,651],{"class":630},[620,888,598],{"class":647},[620,890,651],{"class":630},[620,892,893],{"class":630},",",[620,895,896],{"class":674},"         OrderPlacedPayload",[620,898,899],{"class":630},">",[620,901,902],{"class":630},"      {}\n",[620,904,906,908,910,913,916,918,920,922,925,927,929,932,934],{"class":622,"line":905},17,[620,907,667],{"class":626},[620,909,873],{"class":670},[620,911,912],{"class":674}," InventoryReserved",[620,914,915],{"class":670}," extends",[620,917,635],{"class":674},[620,919,884],{"class":630},[620,921,651],{"class":630},[620,923,924],{"class":647},"inventory.reserved",[620,926,651],{"class":630},[620,928,893],{"class":630},[620,930,931],{"class":674},"  InventoryReservedPayload",[620,933,899],{"class":630},[620,935,936],{"class":630}," {}\n",[620,938,940,942,944,947,949,951,953,955,958,960,962,965,967],{"class":622,"line":939},18,[620,941,667],{"class":626},[620,943,873],{"class":670},[620,945,946],{"class":674}," PaymentProcessed",[620,948,915],{"class":670},[620,950,635],{"class":674},[620,952,884],{"class":630},[620,954,651],{"class":630},[620,956,957],{"class":647},"payment.processed",[620,959,651],{"class":630},[620,961,893],{"class":630},[620,963,964],{"class":674},"    PaymentProcessedPayload",[620,966,899],{"class":630},[620,968,936],{"class":630},[620,970,972,974,976,979,982,984,986,988,991,993,995,998,1000],{"class":622,"line":971},19,[620,973,667],{"class":626},[620,975,873],{"class":670},[620,977,978],{"class":674}," PaymentFailed",[620,980,981],{"class":670},"    extends",[620,983,635],{"class":674},[620,985,884],{"class":630},[620,987,651],{"class":630},[620,989,990],{"class":647},"payment.failed",[620,992,651],{"class":630},[620,994,893],{"class":630},[620,996,997],{"class":674},"       PaymentFailedPayload",[620,999,899],{"class":630},[620,1001,1002],{"class":630},"    {}\n",[620,1004,1006,1008,1010,1013,1015,1017,1019,1021,1024,1026,1028,1030,1032],{"class":622,"line":1005},20,[620,1007,667],{"class":626},[620,1009,873],{"class":670},[620,1011,1012],{"class":674}," ReservationReleased",[620,1014,915],{"class":670},[620,1016,635],{"class":674},[620,1018,884],{"class":630},[620,1020,651],{"class":630},[620,1022,1023],{"class":647},"reservation.released",[620,1025,651],{"class":630},[620,1027,893],{"class":630},[620,1029,821],{"class":674},[620,1031,899],{"class":630},[620,1033,936],{"class":630},[620,1035,1037,1039,1041,1044,1047,1049,1051,1053,1056,1058,1060,1063,1065],{"class":622,"line":1036},21,[620,1038,667],{"class":626},[620,1040,873],{"class":670},[620,1042,1043],{"class":674}," OrderCancelled",[620,1045,1046],{"class":670},"   extends",[620,1048,635],{"class":674},[620,1050,884],{"class":630},[620,1052,651],{"class":630},[620,1054,1055],{"class":647},"order.cancelled",[620,1057,651],{"class":630},[620,1059,893],{"class":630},[620,1061,1062],{"class":674},"      OrderCancelledPayload",[620,1064,899],{"class":630},[620,1066,1067],{"class":630},"   {}\n",[1069,1070,1071,1091],"table",{},[1072,1073,1074],"thead",{},[1075,1076,1077,1082,1085,1088],"tr",{},[1078,1079,1081],"th",{"align":1080},"left","Event",[1078,1083,1084],{"align":1080},"Emitted by",[1078,1086,1087],{"align":1080},"Consumed by",[1078,1089,1090],{"align":1080},"Carries",[1092,1093,1094,1115,1132,1147,1161,1175],"tbody",{},[1075,1095,1096,1101,1104,1107],{},[1097,1098,1099],"td",{"align":1080},[561,1100,598],{},[1097,1102,1103],{"align":1080},"Orders",[1097,1105,1106],{"align":1080},"Inventory",[1097,1108,1109,1112,1113],{"align":1080},[561,1110,1111],{},"orderId",", ",[561,1114,594],{},[1075,1116,1117,1121,1123,1126],{},[1097,1118,1119],{"align":1080},[561,1120,924],{},[1097,1122,1106],{"align":1080},[1097,1124,1125],{"align":1080},"Orders, Payment",[1097,1127,1128,1112,1130],{"align":1080},[561,1129,1111],{},[561,1131,594],{},[1075,1133,1134,1138,1141,1143],{},[1097,1135,1136],{"align":1080},[561,1137,957],{},[1097,1139,1140],{"align":1080},"Payment",[1097,1142,1103],{"align":1080},[1097,1144,1145],{"align":1080},[561,1146,1111],{},[1075,1148,1149,1153,1155,1157],{},[1097,1150,1151],{"align":1080},[561,1152,990],{},[1097,1154,1140],{"align":1080},[1097,1156,1106],{"align":1080},[1097,1158,1159],{"align":1080},[561,1160,1111],{},[1075,1162,1163,1167,1169,1171],{},[1097,1164,1165],{"align":1080},[561,1166,1023],{},[1097,1168,1106],{"align":1080},[1097,1170,1140],{"align":1080},[1097,1172,1173],{"align":1080},[561,1174,1111],{},[1075,1176,1177,1181,1183,1185],{},[1097,1178,1179],{"align":1080},[561,1180,1055],{},[1097,1182,1140],{"align":1080},[1097,1184,1103],{"align":1080},[1097,1186,1187],{"align":1080},[561,1188,1111],{},[499,1190,1191,1193,1194,1196,1197,1200,1201,1204],{},[561,1192,1111],{}," threads the correlation through every hop, so each handler finds its own aggregate without a\ncoordinator. Note ",[561,1195,924],{}," has ",[503,1198,1199],{},"two"," consumers — the transport fans an event out to every\n",[561,1202,1203],{},"IntegrationEventHandler"," registered for that type.",[534,1206,1208],{"id":1207},"each-step-is-an-atomic-write-and-emit","Each step is an atomic write-and-emit",[499,1210,1211,1212,1215,1216,564],{},"Every step has the same shape: ",[503,1213,1214],{},"react → guard → write the aggregate and emit the next event, atomically.","\nHere is the inventory context reacting to ",[561,1217,598],{},[566,1219,1222],{"className":613,"code":1220,"filename":1221,"language":616,"meta":574,"style":574},"import { uuid } from \"@heximon\u002Fruntime\";\nimport type { IntegrationEventHandler } from \"@heximon\u002Fintegration\";\nimport { InventoryReserved, type OrderPlacedPayload } from \"..\u002Fevents\";\nimport { InventoryReservation, type ReservationId } from \".\u002Finventory-reservation.entity\";\nimport { InventoryReservationRepository } from \".\u002Finventory-reservation.repository\";\n\nexport class OrderPlacedHandler implements IntegrationEventHandler\u003C\n  \"order.placed\",\n  OrderPlacedPayload\n> {\n  public constructor(\n    private readonly repository: InventoryReservationRepository,\n    private readonly inventoryReserved: InventoryReserved,\n  ) {}\n\n  public handle(payload: OrderPlacedPayload): Promise\u003Cvoid> {\n    return this.repository.runInTransaction(async () => {\n      \u002F\u002F Idempotency guard: skip if a reservation already exists for this order.\n      const existing = await this.repository.getByOrderId(payload.orderId);\n\n      if (existing !== undefined) {\n        return;\n      }\n\n      const reservation = InventoryReservation.create(uuid.v7() as ReservationId, payload.orderId);\n\n      \u002F\u002F 1) The aggregate write.\n      await this.repository.save(reservation);\n\n      \u002F\u002F 2) The integration event — buffered now, appended to the outbox on this transaction's commit\n      \u002F\u002F    hook, so the event is durable iff the reservation aggregate write is.\n      await this.inventoryReserved.publish({\n        orderId: payload.orderId,\n        failPayment: payload.failPayment,\n      });\n    });\n  }\n}\n","src\u002Finventory\u002Forder-placed.handler.ts",[561,1223,1224,1246,1270,1297,1326,1348,1352,1369,1381,1386,1392,1403,1420,1435,1442,1446,1478,1509,1515,1551,1555,1578,1586,1592,1597,1645,1650,1656,1680,1685,1691,1697,1716,1732,1748,1758,1768,1774],{"__ignoreMap":574},[620,1225,1226,1228,1230,1233,1235,1237,1239,1242,1244],{"class":622,"line":623},[620,1227,627],{"class":626},[620,1229,631],{"class":630},[620,1231,1232],{"class":634}," uuid",[620,1234,638],{"class":630},[620,1236,641],{"class":626},[620,1238,644],{"class":630},[620,1240,1241],{"class":647},"@heximon\u002Fruntime",[620,1243,651],{"class":630},[620,1245,654],{"class":630},[620,1247,1248,1250,1253,1255,1258,1260,1262,1264,1266,1268],{"class":622,"line":657},[620,1249,627],{"class":626},[620,1251,1252],{"class":626}," type",[620,1254,631],{"class":630},[620,1256,1257],{"class":634}," IntegrationEventHandler",[620,1259,638],{"class":630},[620,1261,641],{"class":626},[620,1263,644],{"class":630},[620,1265,648],{"class":647},[620,1267,651],{"class":630},[620,1269,654],{"class":630},[620,1271,1272,1274,1276,1278,1280,1282,1284,1286,1288,1290,1293,1295],{"class":622,"line":664},[620,1273,627],{"class":626},[620,1275,631],{"class":630},[620,1277,912],{"class":634},[620,1279,893],{"class":630},[620,1281,1252],{"class":626},[620,1283,675],{"class":634},[620,1285,638],{"class":630},[620,1287,641],{"class":626},[620,1289,644],{"class":630},[620,1291,1292],{"class":647},"..\u002Fevents",[620,1294,651],{"class":630},[620,1296,654],{"class":630},[620,1298,1299,1301,1303,1306,1308,1310,1313,1315,1317,1319,1322,1324],{"class":622,"line":681},[620,1300,627],{"class":626},[620,1302,631],{"class":630},[620,1304,1305],{"class":634}," InventoryReservation",[620,1307,893],{"class":630},[620,1309,1252],{"class":626},[620,1311,1312],{"class":634}," ReservationId",[620,1314,638],{"class":630},[620,1316,641],{"class":626},[620,1318,644],{"class":630},[620,1320,1321],{"class":647},".\u002Finventory-reservation.entity",[620,1323,651],{"class":630},[620,1325,654],{"class":630},[620,1327,1328,1330,1332,1335,1337,1339,1341,1344,1346],{"class":622,"line":698},[620,1329,627],{"class":626},[620,1331,631],{"class":630},[620,1333,1334],{"class":634}," InventoryReservationRepository",[620,1336,638],{"class":630},[620,1338,641],{"class":626},[620,1340,644],{"class":630},[620,1342,1343],{"class":647},".\u002Finventory-reservation.repository",[620,1345,651],{"class":630},[620,1347,654],{"class":630},[620,1349,1350],{"class":622,"line":713},[620,1351,661],{"emptyLinePlaceholder":660},[620,1353,1354,1356,1358,1361,1364,1366],{"class":622,"line":719},[620,1355,667],{"class":626},[620,1357,873],{"class":670},[620,1359,1360],{"class":674}," OrderPlacedHandler",[620,1362,1363],{"class":670}," implements",[620,1365,1257],{"class":674},[620,1367,1368],{"class":630},"\u003C\n",[620,1370,1371,1374,1376,1378],{"class":622,"line":731},[620,1372,1373],{"class":630},"  \"",[620,1375,598],{"class":647},[620,1377,651],{"class":630},[620,1379,1380],{"class":630},",\n",[620,1382,1383],{"class":622,"line":744},[620,1384,1385],{"class":674},"  OrderPlacedPayload\n",[620,1387,1388,1390],{"class":622,"line":757},[620,1389,899],{"class":630},[620,1391,678],{"class":630},[620,1393,1394,1397,1400],{"class":622,"line":762},[620,1395,1396],{"class":670},"  public",[620,1398,1399],{"class":670}," constructor",[620,1401,1402],{"class":630},"(\n",[620,1404,1405,1408,1410,1414,1416,1418],{"class":622,"line":789},[620,1406,1407],{"class":670},"    private",[620,1409,774],{"class":670},[620,1411,1413],{"class":1412},"sHdIc"," repository",[620,1415,564],{"class":630},[620,1417,1334],{"class":674},[620,1419,1380],{"class":630},[620,1421,1422,1424,1426,1429,1431,1433],{"class":622,"line":814},[620,1423,1407],{"class":670},[620,1425,774],{"class":670},[620,1427,1428],{"class":1412}," inventoryReserved",[620,1430,564],{"class":630},[620,1432,912],{"class":674},[620,1434,1380],{"class":630},[620,1436,1437,1440],{"class":622,"line":838},[620,1438,1439],{"class":630},"  )",[620,1441,936],{"class":630},[620,1443,1444],{"class":622,"line":863},[620,1445,661],{"emptyLinePlaceholder":660},[620,1447,1448,1450,1453,1456,1459,1461,1463,1466,1469,1471,1474,1476],{"class":622,"line":868},[620,1449,1396],{"class":670},[620,1451,1452],{"class":687}," handle",[620,1454,1455],{"class":630},"(",[620,1457,1458],{"class":1412},"payload",[620,1460,564],{"class":630},[620,1462,675],{"class":674},[620,1464,1465],{"class":630},"):",[620,1467,1468],{"class":674}," Promise",[620,1470,884],{"class":630},[620,1472,1473],{"class":674},"void",[620,1475,899],{"class":630},[620,1477,678],{"class":630},[620,1479,1480,1483,1486,1489,1492,1496,1498,1501,1504,1507],{"class":622,"line":905},[620,1481,1482],{"class":626},"    return",[620,1484,1485],{"class":630}," this.",[620,1487,1488],{"class":634},"repository",[620,1490,1491],{"class":630},".",[620,1493,1495],{"class":1494},"s2Zo4","runInTransaction",[620,1497,1455],{"class":687},[620,1499,1500],{"class":670},"async",[620,1502,1503],{"class":630}," ()",[620,1505,1506],{"class":670}," =>",[620,1508,678],{"class":630},[620,1510,1511],{"class":622,"line":939},[620,1512,1514],{"class":1513},"sHwdD","      \u002F\u002F Idempotency guard: skip if a reservation already exists for this order.\n",[620,1516,1517,1520,1523,1526,1529,1531,1533,1535,1538,1540,1542,1544,1546,1549],{"class":622,"line":971},[620,1518,1519],{"class":670},"      const",[620,1521,1522],{"class":634}," existing",[620,1524,1525],{"class":630}," =",[620,1527,1528],{"class":626}," await",[620,1530,1485],{"class":630},[620,1532,1488],{"class":634},[620,1534,1491],{"class":630},[620,1536,1537],{"class":1494},"getByOrderId",[620,1539,1455],{"class":687},[620,1541,1458],{"class":634},[620,1543,1491],{"class":630},[620,1545,1111],{"class":634},[620,1547,1548],{"class":687},")",[620,1550,654],{"class":630},[620,1552,1553],{"class":622,"line":1005},[620,1554,661],{"emptyLinePlaceholder":660},[620,1556,1557,1560,1563,1566,1569,1572,1575],{"class":622,"line":1036},[620,1558,1559],{"class":626},"      if",[620,1561,1562],{"class":687}," (",[620,1564,1565],{"class":634},"existing",[620,1567,1568],{"class":630}," !==",[620,1570,1571],{"class":630}," undefined",[620,1573,1574],{"class":687},") ",[620,1576,1577],{"class":630},"{\n",[620,1579,1581,1584],{"class":622,"line":1580},22,[620,1582,1583],{"class":626},"        return",[620,1585,654],{"class":630},[620,1587,1589],{"class":622,"line":1588},23,[620,1590,1591],{"class":630},"      }\n",[620,1593,1595],{"class":622,"line":1594},24,[620,1596,661],{"emptyLinePlaceholder":660},[620,1598,1600,1602,1605,1607,1609,1611,1614,1616,1619,1621,1624,1627,1630,1632,1634,1637,1639,1641,1643],{"class":622,"line":1599},25,[620,1601,1519],{"class":670},[620,1603,1604],{"class":634}," reservation",[620,1606,1525],{"class":630},[620,1608,1305],{"class":634},[620,1610,1491],{"class":630},[620,1612,1613],{"class":1494},"create",[620,1615,1455],{"class":687},[620,1617,1618],{"class":634},"uuid",[620,1620,1491],{"class":630},[620,1622,1623],{"class":1494},"v7",[620,1625,1626],{"class":687},"() ",[620,1628,1629],{"class":626},"as",[620,1631,1312],{"class":674},[620,1633,893],{"class":630},[620,1635,1636],{"class":634}," payload",[620,1638,1491],{"class":630},[620,1640,1111],{"class":634},[620,1642,1548],{"class":687},[620,1644,654],{"class":630},[620,1646,1648],{"class":622,"line":1647},26,[620,1649,661],{"emptyLinePlaceholder":660},[620,1651,1653],{"class":622,"line":1652},27,[620,1654,1655],{"class":1513},"      \u002F\u002F 1) The aggregate write.\n",[620,1657,1659,1662,1664,1666,1668,1671,1673,1676,1678],{"class":622,"line":1658},28,[620,1660,1661],{"class":626},"      await",[620,1663,1485],{"class":630},[620,1665,1488],{"class":634},[620,1667,1491],{"class":630},[620,1669,1670],{"class":1494},"save",[620,1672,1455],{"class":687},[620,1674,1675],{"class":634},"reservation",[620,1677,1548],{"class":687},[620,1679,654],{"class":630},[620,1681,1683],{"class":622,"line":1682},29,[620,1684,661],{"emptyLinePlaceholder":660},[620,1686,1688],{"class":622,"line":1687},30,[620,1689,1690],{"class":1513},"      \u002F\u002F 2) The integration event — buffered now, appended to the outbox on this transaction's commit\n",[620,1692,1694],{"class":622,"line":1693},31,[620,1695,1696],{"class":1513},"      \u002F\u002F    hook, so the event is durable iff the reservation aggregate write is.\n",[620,1698,1700,1702,1704,1707,1709,1712,1714],{"class":622,"line":1699},32,[620,1701,1661],{"class":626},[620,1703,1485],{"class":630},[620,1705,1706],{"class":634},"inventoryReserved",[620,1708,1491],{"class":630},[620,1710,1711],{"class":1494},"publish",[620,1713,1455],{"class":687},[620,1715,1577],{"class":630},[620,1717,1719,1722,1724,1726,1728,1730],{"class":622,"line":1718},33,[620,1720,1721],{"class":687},"        orderId",[620,1723,564],{"class":630},[620,1725,1636],{"class":634},[620,1727,1491],{"class":630},[620,1729,1111],{"class":634},[620,1731,1380],{"class":630},[620,1733,1735,1738,1740,1742,1744,1746],{"class":622,"line":1734},34,[620,1736,1737],{"class":687},"        failPayment",[620,1739,564],{"class":630},[620,1741,1636],{"class":634},[620,1743,1491],{"class":630},[620,1745,594],{"class":634},[620,1747,1380],{"class":630},[620,1749,1751,1754,1756],{"class":622,"line":1750},35,[620,1752,1753],{"class":630},"      }",[620,1755,1548],{"class":687},[620,1757,654],{"class":630},[620,1759,1761,1764,1766],{"class":622,"line":1760},36,[620,1762,1763],{"class":630},"    }",[620,1765,1548],{"class":687},[620,1767,654],{"class":630},[620,1769,1771],{"class":622,"line":1770},37,[620,1772,1773],{"class":630},"  }\n",[620,1775,1777],{"class":622,"line":1776},38,[620,1778,716],{"class":630},[499,1780,1781,1782,1785,1786,1789,1790,1793],{},"The typed producer ",[561,1783,1784],{},"InventoryReserved"," is a class that ",[561,1787,1788],{},"extends IntegrationEvent\u003C\"inventory.reserved\", InventoryReservedPayload>"," — injected by class identity, listed under ",[561,1791,1792],{},"integration: { events }"," in the inventory module. The load-bearing part is the transaction body:",[499,1795,1796,1799,1800,1803,1804,1807,1808,1811],{},[561,1797,1798],{},"inventoryReserved.publish"," routes through the bound ",[561,1801,1802],{},"IntegrationEventTransport",". When the outbox transport\nis bound, publish ",[503,1805,1806],{},"buffers"," the event — the outbox row is appended on the transaction's ",[561,1809,1810],{},"onBeforeCommit","\nhook, inside the same transaction as the aggregate. So the aggregate row and the event row commit together:\na rollback drops both; a crash after commit keeps both.",[499,1813,1814,1815,1491],{},"The next step can't run unless this step durably happened, and this step can't durably happen without\nenqueuing the next one. That is the transactional-outbox guarantee — covered in the\n",[522,1816,1817],{"href":481},"outbox recipe",[534,1819,1821],{"id":1820},"at-least-once-every-handler-is-idempotent","At-least-once → every handler is idempotent",[499,1823,1824,1825,1828],{},"The relay re-delivers an event if the process crashes after dispatching it but before deleting its outbox row.\nSo each writing handler checks for the work it would do ",[503,1826,1827],{},"before"," doing it:",[566,1830,1832],{"className":613,"code":1831,"language":616,"meta":574,"style":574},"if (await this.repository.getByOrderId(payload.orderId)) return;\n\u002F\u002F a reservation already exists → a previous delivery wrote the correct state → skip\n",[561,1833,1834,1865],{"__ignoreMap":574},[620,1835,1836,1839,1841,1844,1846,1848,1850,1852,1855,1857,1860,1863],{"class":622,"line":623},[620,1837,1838],{"class":626},"if",[620,1840,1562],{"class":634},[620,1842,1843],{"class":626},"await",[620,1845,1485],{"class":630},[620,1847,1488],{"class":634},[620,1849,1491],{"class":630},[620,1851,1537],{"class":1494},[620,1853,1854],{"class":634},"(payload",[620,1856,1491],{"class":630},[620,1858,1859],{"class":634},"orderId)) ",[620,1861,1862],{"class":626},"return",[620,1864,654],{"class":630},[620,1866,1867],{"class":622,"line":657},[620,1868,1869],{"class":1513},"\u002F\u002F a reservation already exists → a previous delivery wrote the correct state → skip\n",[499,1871,1872,1873,1876,1877,1880,1881,1883,1884,1886,1887,1889,1890,1491],{},"The orders-context handlers check the order's ",[514,1874,1875],{},"status"," instead (already ",[561,1878,1879],{},"paid","? skip). An emit-only handler\n(like the one that turns ",[561,1882,1023],{}," into ",[561,1885,1055],{},") needs no guard of its own, because its\nconsumer has one. For framework-level dedup that rejects re-deliveries ",[514,1888,1827],{}," the handler runs, see\n",[522,1891,185],{"href":186},[534,1893,1895],{"id":1894},"wiring-one-module-per-context","Wiring: one module per context",[499,1897,1898,1899,1902,1903,1905,1906,1908],{},"Each bounded context is a module; they share the outbox through ",[561,1900,1901],{},"imports",". A module that emits events lists\neach typed producer class under ",[561,1904,1792],{}," — the compiler wires its publisher over the\nbound ",[561,1907,1802],{}," and makes it injectable by class identity. No satisfier class, no boot seam:",[566,1910,1913],{"className":613,"code":1911,"filename":1912,"language":616,"meta":574,"style":574},"import { Module } from \"@heximon\u002Fruntime\";\nimport { DatabaseModule } from \"..\u002Fdatabase\u002Fdatabase.module\";\nimport { InventoryReserved, ReservationReleased } from \"..\u002Fevents\";\nimport { OutboxModule } from \"..\u002Foutbox\u002Foutbox.module\";\nimport { InventoryReservationRepository } from \".\u002Finventory-reservation.repository\";\nimport { OrderPlacedHandler } from \".\u002Forder-placed.handler\";\nimport { PaymentFailedHandler } from \".\u002Fpayment-failed.handler\";\n\nexport class InventoryModule extends Module({\n  imports: [DatabaseModule, OutboxModule],\n  providers: [InventoryReservationRepository],\n  integration: { events: [InventoryReserved, ReservationReleased],\n    eventHandlers: [OrderPlacedHandler, PaymentFailedHandler],\n  },\n}) {}\n","src\u002Finventory\u002Finventory.module.ts",[561,1914,1915,1936,1958,1982,2004,2024,2045,2067,2071,2088,2105,2117,2141,2158,2163],{"__ignoreMap":574},[620,1916,1917,1919,1921,1924,1926,1928,1930,1932,1934],{"class":622,"line":623},[620,1918,627],{"class":626},[620,1920,631],{"class":630},[620,1922,1923],{"class":634}," Module",[620,1925,638],{"class":630},[620,1927,641],{"class":626},[620,1929,644],{"class":630},[620,1931,1241],{"class":647},[620,1933,651],{"class":630},[620,1935,654],{"class":630},[620,1937,1938,1940,1942,1945,1947,1949,1951,1954,1956],{"class":622,"line":657},[620,1939,627],{"class":626},[620,1941,631],{"class":630},[620,1943,1944],{"class":634}," DatabaseModule",[620,1946,638],{"class":630},[620,1948,641],{"class":626},[620,1950,644],{"class":630},[620,1952,1953],{"class":647},"..\u002Fdatabase\u002Fdatabase.module",[620,1955,651],{"class":630},[620,1957,654],{"class":630},[620,1959,1960,1962,1964,1966,1968,1970,1972,1974,1976,1978,1980],{"class":622,"line":664},[620,1961,627],{"class":626},[620,1963,631],{"class":630},[620,1965,912],{"class":634},[620,1967,893],{"class":630},[620,1969,1012],{"class":634},[620,1971,638],{"class":630},[620,1973,641],{"class":626},[620,1975,644],{"class":630},[620,1977,1292],{"class":647},[620,1979,651],{"class":630},[620,1981,654],{"class":630},[620,1983,1984,1986,1988,1991,1993,1995,1997,2000,2002],{"class":622,"line":681},[620,1985,627],{"class":626},[620,1987,631],{"class":630},[620,1989,1990],{"class":634}," OutboxModule",[620,1992,638],{"class":630},[620,1994,641],{"class":626},[620,1996,644],{"class":630},[620,1998,1999],{"class":647},"..\u002Foutbox\u002Foutbox.module",[620,2001,651],{"class":630},[620,2003,654],{"class":630},[620,2005,2006,2008,2010,2012,2014,2016,2018,2020,2022],{"class":622,"line":698},[620,2007,627],{"class":626},[620,2009,631],{"class":630},[620,2011,1334],{"class":634},[620,2013,638],{"class":630},[620,2015,641],{"class":626},[620,2017,644],{"class":630},[620,2019,1343],{"class":647},[620,2021,651],{"class":630},[620,2023,654],{"class":630},[620,2025,2026,2028,2030,2032,2034,2036,2038,2041,2043],{"class":622,"line":713},[620,2027,627],{"class":626},[620,2029,631],{"class":630},[620,2031,1360],{"class":634},[620,2033,638],{"class":630},[620,2035,641],{"class":626},[620,2037,644],{"class":630},[620,2039,2040],{"class":647},".\u002Forder-placed.handler",[620,2042,651],{"class":630},[620,2044,654],{"class":630},[620,2046,2047,2049,2051,2054,2056,2058,2060,2063,2065],{"class":622,"line":719},[620,2048,627],{"class":626},[620,2050,631],{"class":630},[620,2052,2053],{"class":634}," PaymentFailedHandler",[620,2055,638],{"class":630},[620,2057,641],{"class":626},[620,2059,644],{"class":630},[620,2061,2062],{"class":647},".\u002Fpayment-failed.handler",[620,2064,651],{"class":630},[620,2066,654],{"class":630},[620,2068,2069],{"class":622,"line":731},[620,2070,661],{"emptyLinePlaceholder":660},[620,2072,2073,2075,2077,2080,2082,2084,2086],{"class":622,"line":744},[620,2074,667],{"class":626},[620,2076,873],{"class":670},[620,2078,2079],{"class":674}," InventoryModule",[620,2081,915],{"class":670},[620,2083,1923],{"class":1494},[620,2085,1455],{"class":634},[620,2087,1577],{"class":630},[620,2089,2090,2093,2095,2098,2100,2103],{"class":622,"line":757},[620,2091,2092],{"class":687},"  imports",[620,2094,564],{"class":630},[620,2096,2097],{"class":634}," [DatabaseModule",[620,2099,893],{"class":630},[620,2101,2102],{"class":634}," OutboxModule]",[620,2104,1380],{"class":630},[620,2106,2107,2110,2112,2115],{"class":622,"line":762},[620,2108,2109],{"class":687},"  providers",[620,2111,564],{"class":630},[620,2113,2114],{"class":634}," [InventoryReservationRepository]",[620,2116,1380],{"class":630},[620,2118,2119,2122,2124,2126,2129,2131,2134,2136,2139],{"class":622,"line":789},[620,2120,2121],{"class":687},"  integration",[620,2123,564],{"class":630},[620,2125,631],{"class":630},[620,2127,2128],{"class":687}," events",[620,2130,564],{"class":630},[620,2132,2133],{"class":634}," [InventoryReserved",[620,2135,893],{"class":630},[620,2137,2138],{"class":634}," ReservationReleased]",[620,2140,1380],{"class":630},[620,2142,2143,2146,2148,2151,2153,2156],{"class":622,"line":814},[620,2144,2145],{"class":687},"    eventHandlers",[620,2147,564],{"class":630},[620,2149,2150],{"class":634}," [OrderPlacedHandler",[620,2152,893],{"class":630},[620,2154,2155],{"class":634}," PaymentFailedHandler]",[620,2157,1380],{"class":630},[620,2159,2160],{"class":622,"line":838},[620,2161,2162],{"class":630},"  },\n",[620,2164,2165,2168,2170],{"class":622,"line":863},[620,2166,2167],{"class":630},"}",[620,2169,1574],{"class":634},[620,2171,2172],{"class":630},"{}\n",[499,2174,2175,2176,2179,2180,2183,2184,2187,2188,2190],{},"The in-process ",[561,2177,2178],{},"MemoryIntegrationEventTransport"," is the default — assembled by the host at boot with no\napp boilerplate. Upgrading a context to at-least-once, transactional delivery means binding the\n",[561,2181,2182],{},"OutboxIntegrationEventTransport"," satisfier in that module's ",[561,2185,2186],{},"providers"," (see the\n",[522,2189,1817],{"href":481},"); every other context that only receives events keeps\nthe memory default and needs no change.",[534,2192,2194],{"id":2193},"verify-both-paths-in-process","Verify both paths in-process",[499,2196,2197,2198,2201,2202,2205,2206,2209,2210,2213,2214,2217,2218,2221],{},"The example's e2e test boots the app in-process with ",[561,2199,2200],{},"createTestApp"," and drives both flows through an\nin-process HTTP client (",[561,2203,2204],{},"createTestClient","). On Node there is no platform ",[561,2207,2208],{},"waitUntil"," sink, so the relay\ndrain is ",[503,2211,2212],{},"awaited at the request frame's teardown"," — by the time ",[561,2215,2216],{},"POST \u002Forders\u002Fplace"," returns the whole\nchain has already run, and a follow-up ",[561,2219,2220],{},"GET"," reflects the terminal status with no polling or sleeps:",[566,2223,2226],{"className":613,"code":2224,"filename":2225,"language":616,"meta":574,"style":574},"const app = await createTestApp();   \u002F\u002F boots a fresh isolated app (reads heximon.config.ts)\nconst client = createTestClient(app);\n\n\u002F\u002F happy path → paid\nlet res = await request(\"POST\", \"\u002Forders\u002Fplace\", { failPayment: false });\nlet order = await request(\"GET\", `\u002Forders\u002F${(await res.json()).id}`);\nexpect((await order.json()).status).toBe(\"paid\");\n\n\u002F\u002F compensation path → cancelled\nres = await request(\"POST\", \"\u002Forders\u002Fplace\", { failPayment: true });\norder = await request(\"GET\", `\u002Forders\u002F${(await res.json()).id}`);\nexpect((await order.json()).status).toBe(\"cancelled\");\n","test\u002Fworkflow-compensation.test.ts",[561,2227,2228,2252,2269,2273,2278,2329,2388,2429,2433,2438,2482,2531],{"__ignoreMap":574},[620,2229,2230,2233,2236,2239,2241,2244,2247,2249],{"class":622,"line":623},[620,2231,2232],{"class":670},"const",[620,2234,2235],{"class":634}," app ",[620,2237,2238],{"class":630},"=",[620,2240,1528],{"class":626},[620,2242,2243],{"class":1494}," createTestApp",[620,2245,2246],{"class":634},"()",[620,2248,783],{"class":630},[620,2250,2251],{"class":1513},"   \u002F\u002F boots a fresh isolated app (reads heximon.config.ts)\n",[620,2253,2254,2256,2259,2261,2264,2267],{"class":622,"line":657},[620,2255,2232],{"class":670},[620,2257,2258],{"class":634}," client ",[620,2260,2238],{"class":630},[620,2262,2263],{"class":1494}," createTestClient",[620,2265,2266],{"class":634},"(app)",[620,2268,654],{"class":630},[620,2270,2271],{"class":622,"line":664},[620,2272,661],{"emptyLinePlaceholder":660},[620,2274,2275],{"class":622,"line":681},[620,2276,2277],{"class":1513},"\u002F\u002F happy path → paid\n",[620,2279,2280,2283,2286,2288,2290,2293,2295,2297,2300,2302,2304,2306,2309,2311,2313,2315,2317,2319,2323,2325,2327],{"class":622,"line":698},[620,2281,2282],{"class":670},"let",[620,2284,2285],{"class":634}," res ",[620,2287,2238],{"class":630},[620,2289,1528],{"class":626},[620,2291,2292],{"class":1494}," request",[620,2294,1455],{"class":634},[620,2296,651],{"class":630},[620,2298,2299],{"class":647},"POST",[620,2301,651],{"class":630},[620,2303,893],{"class":630},[620,2305,644],{"class":630},[620,2307,2308],{"class":647},"\u002Forders\u002Fplace",[620,2310,651],{"class":630},[620,2312,893],{"class":630},[620,2314,631],{"class":630},[620,2316,703],{"class":687},[620,2318,564],{"class":630},[620,2320,2322],{"class":2321},"sfNiH"," false",[620,2324,638],{"class":630},[620,2326,1548],{"class":634},[620,2328,654],{"class":630},[620,2330,2331,2333,2336,2338,2340,2342,2344,2346,2348,2350,2352,2355,2358,2361,2363,2365,2368,2370,2373,2376,2378,2381,2384,2386],{"class":622,"line":713},[620,2332,2282],{"class":670},[620,2334,2335],{"class":634}," order ",[620,2337,2238],{"class":630},[620,2339,1528],{"class":626},[620,2341,2292],{"class":1494},[620,2343,1455],{"class":634},[620,2345,651],{"class":630},[620,2347,2220],{"class":647},[620,2349,651],{"class":630},[620,2351,893],{"class":630},[620,2353,2354],{"class":630}," `",[620,2356,2357],{"class":647},"\u002Forders\u002F",[620,2359,2360],{"class":630},"${",[620,2362,1455],{"class":634},[620,2364,1843],{"class":626},[620,2366,2367],{"class":634}," res",[620,2369,1491],{"class":630},[620,2371,2372],{"class":1494},"json",[620,2374,2375],{"class":634},"())",[620,2377,1491],{"class":630},[620,2379,2380],{"class":634},"id",[620,2382,2383],{"class":630},"}`",[620,2385,1548],{"class":634},[620,2387,654],{"class":630},[620,2389,2390,2393,2396,2398,2401,2403,2405,2407,2409,2412,2414,2417,2419,2421,2423,2425,2427],{"class":622,"line":719},[620,2391,2392],{"class":1494},"expect",[620,2394,2395],{"class":634},"((",[620,2397,1843],{"class":626},[620,2399,2400],{"class":634}," order",[620,2402,1491],{"class":630},[620,2404,2372],{"class":1494},[620,2406,2375],{"class":634},[620,2408,1491],{"class":630},[620,2410,2411],{"class":634},"status)",[620,2413,1491],{"class":630},[620,2415,2416],{"class":1494},"toBe",[620,2418,1455],{"class":634},[620,2420,651],{"class":630},[620,2422,1879],{"class":647},[620,2424,651],{"class":630},[620,2426,1548],{"class":634},[620,2428,654],{"class":630},[620,2430,2431],{"class":622,"line":731},[620,2432,661],{"emptyLinePlaceholder":660},[620,2434,2435],{"class":622,"line":744},[620,2436,2437],{"class":1513},"\u002F\u002F compensation path → cancelled\n",[620,2439,2440,2443,2445,2447,2449,2451,2453,2455,2457,2459,2461,2463,2465,2467,2469,2471,2473,2476,2478,2480],{"class":622,"line":757},[620,2441,2442],{"class":634},"res ",[620,2444,2238],{"class":630},[620,2446,1528],{"class":626},[620,2448,2292],{"class":1494},[620,2450,1455],{"class":634},[620,2452,651],{"class":630},[620,2454,2299],{"class":647},[620,2456,651],{"class":630},[620,2458,893],{"class":630},[620,2460,644],{"class":630},[620,2462,2308],{"class":647},[620,2464,651],{"class":630},[620,2466,893],{"class":630},[620,2468,631],{"class":630},[620,2470,703],{"class":687},[620,2472,564],{"class":630},[620,2474,2475],{"class":2321}," true",[620,2477,638],{"class":630},[620,2479,1548],{"class":634},[620,2481,654],{"class":630},[620,2483,2484,2487,2489,2491,2493,2495,2497,2499,2501,2503,2505,2507,2509,2511,2513,2515,2517,2519,2521,2523,2525,2527,2529],{"class":622,"line":762},[620,2485,2486],{"class":634},"order ",[620,2488,2238],{"class":630},[620,2490,1528],{"class":626},[620,2492,2292],{"class":1494},[620,2494,1455],{"class":634},[620,2496,651],{"class":630},[620,2498,2220],{"class":647},[620,2500,651],{"class":630},[620,2502,893],{"class":630},[620,2504,2354],{"class":630},[620,2506,2357],{"class":647},[620,2508,2360],{"class":630},[620,2510,1455],{"class":634},[620,2512,1843],{"class":626},[620,2514,2367],{"class":634},[620,2516,1491],{"class":630},[620,2518,2372],{"class":1494},[620,2520,2375],{"class":634},[620,2522,1491],{"class":630},[620,2524,2380],{"class":634},[620,2526,2383],{"class":630},[620,2528,1548],{"class":634},[620,2530,654],{"class":630},[620,2532,2533,2535,2537,2539,2541,2543,2545,2547,2549,2551,2553,2555,2557,2559,2562,2564,2566],{"class":622,"line":789},[620,2534,2392],{"class":1494},[620,2536,2395],{"class":634},[620,2538,1843],{"class":626},[620,2540,2400],{"class":634},[620,2542,1491],{"class":630},[620,2544,2372],{"class":1494},[620,2546,2375],{"class":634},[620,2548,1491],{"class":630},[620,2550,2411],{"class":634},[620,2552,1491],{"class":630},[620,2554,2416],{"class":1494},[620,2556,1455],{"class":634},[620,2558,651],{"class":630},[620,2560,2561],{"class":647},"cancelled",[620,2563,651],{"class":630},[620,2565,1548],{"class":634},[620,2567,654],{"class":630},[499,2569,2570,2571,2574,2575,2578,2579,2582,2583,2586,2587,2590,2591,2593,2594,2600],{},"(The full harness — ",[561,2572,2573],{},"createTestApp()"," reads the example's ",[561,2576,2577],{},"heximon.config.ts"," for ",[561,2580,2581],{},"HttpPlugin"," +\n",[561,2584,2585],{},"QueuePlugin"," + ",[561,2588,2589],{},"IntegrationEventsPlugin",", and ",[561,2592,2204],{}," drives the booted app — is in the example's\n",[522,2595,2598],{"href":2596,"rel":2597},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fworkflow-compensation\u002Ftest\u002Fworkflow-compensation.test.ts",[526],[561,2599,2225],{},".)",[534,2602,2604],{"id":2603},"see-also","See also",[2606,2607,2608,2614,2623,2635,2651],"ul",{},[2609,2610,2611,2613],"li",{},[522,2612,480],{"href":481}," — the transactional outbox this builds on.",[2609,2615,2616,2618,2619,2622],{},[522,2617,185],{"href":186}," — framework-level ",[561,2620,2621],{},"eventId"," dedup on top of each handler's own guard.",[2609,2624,2625,2627,2628,2631,2632,2634],{},[522,2626,243],{"href":244}," — the ",[561,2629,2630],{},"IntegrationEvent"," producer base and the ",[561,2633,1203],{}," consumer base.",[2609,2636,2637,2639,2640,2586,2643,2646,2647,2650],{},[522,2638,248],{"href":249}," — when choreography needs a clock: a process-state ",[561,2641,2642],{},"AggregateRoot",[561,2644,2645],{},"DurableTimer"," deadlines + ",[561,2648,2649],{},"TimeoutHandler"," compensation.",[2609,2652,2653,2659],{},[522,2654,2656],{"href":524,"rel":2655},[526],[503,2657,2658],{},"Workflow Compensation","\n— the complete, runnable three-context app with happy and compensation paths and an in-process e2e test.",[2661,2662,2663],"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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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 .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":574,"searchDepth":657,"depth":657,"links":2665},[2666,2667,2668,2669,2670,2671,2672],{"id":536,"depth":657,"text":537},{"id":602,"depth":657,"text":603},{"id":1207,"depth":657,"text":1208},{"id":1820,"depth":657,"text":1821},{"id":1894,"depth":657,"text":1895},{"id":2193,"depth":657,"text":2194},{"id":2603,"depth":657,"text":2604},"A multi-step saga that compensates itself, with no central coordinator — each bounded context reacts to integration events over the transactional outbox and emits the next, with at-least-once delivery and per-handler idempotency.","md",null,{},{"icon":95},{"title":485,"description":2673},"pLVHg9NHk3eHq3s6bdr7kQEVDWttadmoTinGKBEjSBM",[2681,2683],{"title":480,"path":481,"stem":482,"description":2682,"icon":483,"children":-1},"Transactional outbox pattern for at-least-once integration event delivery — OutboxStore, OutboxIntegrationEventTransport, OutboxRelay, fire-and-forget tradeoff, the fire-and-forget compiler warning and its suppressDiagnostics opt-out.",{"title":489,"path":490,"stem":491,"description":2684,"icon":492,"children":-1},"The full best-practice CRUD chain — a shared Contract + typed self-client, QuerySchema\u002FPaginatedResponseSchema pagination, CQRS command\u002Fquery handlers, and a Drizzle aggregate repository behind an EntityQuery mapper.",1783300761903]