[{"data":1,"prerenderedAt":3699},["ShallowReactive",2],{"navigation_docs":3,"-docs-recipes-background-jobs":493,"-docs-recipes-background-jobs-surround":3694},[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":461,"body":495,"description":3687,"extension":3688,"links":3689,"meta":3690,"navigation":3691,"path":462,"seo":3692,"stem":463,"__hash__":3693},"docs\u002Fdocs\u002F09.recipes\u002F09.background-jobs.md",{"type":496,"value":497,"toc":3676},"minimark",[498,512,531,536,547,711,726,730,744,889,900,904,914,1447,1456,1460,1471,1975,1986,1990,2001,2177,2191,2195,2257,2261,2273,2288,2297,2449,2470,2486,3045,3092,3107,3356,3369,3601,3608,3612,3631,3634,3638,3672],[499,500,501,502,506,507,511],"p",{},"Sending a welcome email, regenerating a report, calling a slow third-party API — none of that should\nmake the user wait for their ",[503,504,505],"code",{},"201",". This recipe moves that work off the request path: an endpoint\n",[508,509,510],"strong",{},"publishes"," a typed integration event and returns immediately, and a separate handler does the slow\nwork later, when the transport delivers it.",[499,513,514,515,518,519,522,523,530],{},"By the end you'll have ",[503,516,517],{},"POST \u002Fusers"," that responds in milliseconds and a ",[503,520,521],{},"WelcomeEmailHandler"," that runs\nthe email send afterward. The full app is\n",[524,525,529],"a",{"href":526,"rel":527},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL08-queue",[528],"nofollow","the ladder's L08 — Queue",".",[532,533,535],"h2",{"id":534},"_1-define-the-typed-producer-event","1. Define the typed producer event",[499,537,538,539,542,543,546],{},"The producer and consumer share one statically-checked contract: a payload interface and a typed event\nclass. The event name lives as the ",[508,540,541],{},"first type argument"," of ",[503,544,545],{},"IntegrationEvent\u003C\"name\", Payload>"," — the\ncompiler reads it at build time to derive the dispatch channel and wire the publisher. Define both in one\nfile, centralized so the consumer imports the payload type directly.",[548,549,555],"pre",{"className":550,"code":551,"filename":552,"language":553,"meta":554,"style":554},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { IntegrationEvent } from \"@heximon\u002Fintegration\";\n\nexport interface UserSignedUpPayload {\n  readonly userId: string;\n  readonly name: string;\n  readonly email: string;\n}\n\nexport class UserSignedUp extends IntegrationEvent\u003C\"user.signed-up\", UserSignedUpPayload> {}\n","src\u002Fusers\u002Fevents.ts","ts","",[503,556,557,593,600,617,635,649,663,669,674],{"__ignoreMap":554},[558,559,562,566,570,574,577,580,583,587,590],"span",{"class":560,"line":561},"line",1,[558,563,565],{"class":564},"s7zQu","import",[558,567,569],{"class":568},"sMK4o"," {",[558,571,573],{"class":572},"sTEyZ"," IntegrationEvent",[558,575,576],{"class":568}," }",[558,578,579],{"class":564}," from",[558,581,582],{"class":568}," \"",[558,584,586],{"class":585},"sfazB","@heximon\u002Fintegration",[558,588,589],{"class":568},"\"",[558,591,592],{"class":568},";\n",[558,594,596],{"class":560,"line":595},2,[558,597,599],{"emptyLinePlaceholder":598},true,"\n",[558,601,603,606,610,614],{"class":560,"line":602},3,[558,604,605],{"class":564},"export",[558,607,609],{"class":608},"spNyl"," interface",[558,611,613],{"class":612},"sBMFI"," UserSignedUpPayload",[558,615,616],{"class":568}," {\n",[558,618,620,623,627,630,633],{"class":560,"line":619},4,[558,621,622],{"class":608},"  readonly",[558,624,626],{"class":625},"swJcz"," userId",[558,628,629],{"class":568},":",[558,631,632],{"class":612}," string",[558,634,592],{"class":568},[558,636,638,640,643,645,647],{"class":560,"line":637},5,[558,639,622],{"class":608},[558,641,642],{"class":625}," name",[558,644,629],{"class":568},[558,646,632],{"class":612},[558,648,592],{"class":568},[558,650,652,654,657,659,661],{"class":560,"line":651},6,[558,653,622],{"class":608},[558,655,656],{"class":625}," email",[558,658,629],{"class":568},[558,660,632],{"class":612},[558,662,592],{"class":568},[558,664,666],{"class":560,"line":665},7,[558,667,668],{"class":568},"}\n",[558,670,672],{"class":560,"line":671},8,[558,673,599],{"emptyLinePlaceholder":598},[558,675,677,679,682,685,688,690,693,695,698,700,703,705,708],{"class":560,"line":676},9,[558,678,605],{"class":564},[558,680,681],{"class":608}," class",[558,683,684],{"class":612}," UserSignedUp",[558,686,687],{"class":608}," extends",[558,689,573],{"class":612},[558,691,692],{"class":568},"\u003C",[558,694,589],{"class":568},[558,696,697],{"class":585},"user.signed-up",[558,699,589],{"class":568},[558,701,702],{"class":568},",",[558,704,613],{"class":612},[558,706,707],{"class":568},">",[558,709,710],{"class":568}," {}\n",[499,712,713,714,717,718,721,722,725],{},"The event class is the DI token. The controller injects it by class identity; the compiler wires its\n",[503,715,716],{},"publish"," method over the bound ",[503,719,720],{},"IntegrationEventTransport",". There is no type-map interface to maintain\nand no string channel to keep in sync — the literal ",[503,723,724],{},"\"user.signed-up\""," in the type argument is the\nsingle source of truth for both the producer and the consumer.",[532,727,729],{"id":728},"_2-list-the-producer-in-the-module","2. List the producer in the module",[499,731,732,733,736,737,740,741,530],{},"Declare the typed event under the ",[503,734,735],{},"integration"," namespace's ",[503,738,739],{},"events"," key. That is the list the\ncompiler scans to discover producers — not ",[503,742,743],{},"providers",[548,745,748],{"className":550,"code":746,"filename":747,"language":553,"meta":554,"style":554},"import { Module } from \"@heximon\u002Fruntime\";\nimport { UserSignedUp } from \".\u002Fevents\";\nimport { SignupController } from \".\u002Fsignup.controller\";\n\nexport class UsersModule extends Module({\n  http: { controllers: [SignupController] },\n  integration: { events: [UserSignedUp] },\n}) {}\n","src\u002Fusers\u002Fusers.module.ts",[503,749,750,772,793,815,819,839,859,878],{"__ignoreMap":554},[558,751,752,754,756,759,761,763,765,768,770],{"class":560,"line":561},[558,753,565],{"class":564},[558,755,569],{"class":568},[558,757,758],{"class":572}," Module",[558,760,576],{"class":568},[558,762,579],{"class":564},[558,764,582],{"class":568},[558,766,767],{"class":585},"@heximon\u002Fruntime",[558,769,589],{"class":568},[558,771,592],{"class":568},[558,773,774,776,778,780,782,784,786,789,791],{"class":560,"line":595},[558,775,565],{"class":564},[558,777,569],{"class":568},[558,779,684],{"class":572},[558,781,576],{"class":568},[558,783,579],{"class":564},[558,785,582],{"class":568},[558,787,788],{"class":585},".\u002Fevents",[558,790,589],{"class":568},[558,792,592],{"class":568},[558,794,795,797,799,802,804,806,808,811,813],{"class":560,"line":602},[558,796,565],{"class":564},[558,798,569],{"class":568},[558,800,801],{"class":572}," SignupController",[558,803,576],{"class":568},[558,805,579],{"class":564},[558,807,582],{"class":568},[558,809,810],{"class":585},".\u002Fsignup.controller",[558,812,589],{"class":568},[558,814,592],{"class":568},[558,816,817],{"class":560,"line":619},[558,818,599],{"emptyLinePlaceholder":598},[558,820,821,823,825,828,830,833,836],{"class":560,"line":637},[558,822,605],{"class":564},[558,824,681],{"class":608},[558,826,827],{"class":612}," UsersModule",[558,829,687],{"class":608},[558,831,758],{"class":832},"s2Zo4",[558,834,835],{"class":572},"(",[558,837,838],{"class":568},"{\n",[558,840,841,844,846,848,851,853,856],{"class":560,"line":651},[558,842,843],{"class":625},"  http",[558,845,629],{"class":568},[558,847,569],{"class":568},[558,849,850],{"class":625}," controllers",[558,852,629],{"class":568},[558,854,855],{"class":572}," [SignupController] ",[558,857,858],{"class":568},"},\n",[558,860,861,864,866,868,871,873,876],{"class":560,"line":665},[558,862,863],{"class":625},"  integration",[558,865,629],{"class":568},[558,867,569],{"class":568},[558,869,870],{"class":625}," events",[558,872,629],{"class":568},[558,874,875],{"class":572}," [UserSignedUp] ",[558,877,858],{"class":568},[558,879,880,883,886],{"class":560,"line":671},[558,881,882],{"class":568},"}",[558,884,885],{"class":572},") ",[558,887,888],{"class":568},"{}\n",[499,890,891,892,895,896,899],{},"The in-process ",[503,893,894],{},"MemoryIntegrationEventTransport"," is the default — assembled by the host at boot, bound\nautomatically. There is no transport boilerplate, no ",[503,897,898],{},"QueueModule",", no boot seam to call.",[532,901,903],{"id":902},"_3-publish-from-the-endpoint","3. Publish from the endpoint",[499,905,906,907,910,911,913],{},"The controller receives the typed event as a constructor parameter — class identity is the token, the\ncompiler injects it. Calling ",[503,908,909],{},"await this.userSignedUp.publish(data)"," hands the event off to the\ntransport; the request responds ",[503,912,505],{}," right away.",[548,915,918],{"className":550,"code":916,"filename":917,"language":553,"meta":554,"style":554},"import { uuid } from \"@heximon\u002Fruntime\";\nimport type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport { UserSignedUp } from \".\u002Fevents\";\n\ninterface SignupBody {\n  readonly name: string;\n  readonly email: string;\n}\n\ninterface SignupResult {\n  readonly id: string;\n  readonly email: string;\n}\n\nexport class SignupController implements Controller\u003C\"\u002Fusers\"> {\n  private readonly userSignedUp: UserSignedUp;\n\n  public constructor(userSignedUp: UserSignedUp) {\n    this.userSignedUp = userSignedUp;\n  }\n\n  public async signUp(action: Post\u003C\"\u002F\">): Promise\u003CSignupResult> {\n    const body = (await action.request.json()) as SignupBody;\n    const userId = uuid.v7();\n\n    \u002F\u002F Publish the integration event; the welcome email is sent when the in-process transport\n    \u002F\u002F delivers it on the prefixed channel and the WelcomeEmailHandler runs.\n    await this.userSignedUp.publish({\n      userId,\n      name: body.name,\n      email: body.email,\n    });\n\n    action.response.status = 201;\n    return { id: userId, email: body.email };\n  }\n}\n","src\u002Fusers\u002Fsignup.controller.ts",[503,919,920,941,971,991,995,1005,1017,1029,1033,1037,1047,1061,1074,1079,1084,1111,1129,1134,1158,1173,1179,1184,1228,1268,1289,1294,1301,1307,1326,1335,1352,1369,1379,1384,1408,1437,1442],{"__ignoreMap":554},[558,921,922,924,926,929,931,933,935,937,939],{"class":560,"line":561},[558,923,565],{"class":564},[558,925,569],{"class":568},[558,927,928],{"class":572}," uuid",[558,930,576],{"class":568},[558,932,579],{"class":564},[558,934,582],{"class":568},[558,936,767],{"class":585},[558,938,589],{"class":568},[558,940,592],{"class":568},[558,942,943,945,948,950,953,955,958,960,962,964,967,969],{"class":560,"line":595},[558,944,565],{"class":564},[558,946,947],{"class":564}," type",[558,949,569],{"class":568},[558,951,952],{"class":572}," Controller",[558,954,702],{"class":568},[558,956,957],{"class":572}," Post",[558,959,576],{"class":568},[558,961,579],{"class":564},[558,963,582],{"class":568},[558,965,966],{"class":585},"@heximon\u002Fhttp",[558,968,589],{"class":568},[558,970,592],{"class":568},[558,972,973,975,977,979,981,983,985,987,989],{"class":560,"line":602},[558,974,565],{"class":564},[558,976,569],{"class":568},[558,978,684],{"class":572},[558,980,576],{"class":568},[558,982,579],{"class":564},[558,984,582],{"class":568},[558,986,788],{"class":585},[558,988,589],{"class":568},[558,990,592],{"class":568},[558,992,993],{"class":560,"line":619},[558,994,599],{"emptyLinePlaceholder":598},[558,996,997,1000,1003],{"class":560,"line":637},[558,998,999],{"class":608},"interface",[558,1001,1002],{"class":612}," SignupBody",[558,1004,616],{"class":568},[558,1006,1007,1009,1011,1013,1015],{"class":560,"line":651},[558,1008,622],{"class":608},[558,1010,642],{"class":625},[558,1012,629],{"class":568},[558,1014,632],{"class":612},[558,1016,592],{"class":568},[558,1018,1019,1021,1023,1025,1027],{"class":560,"line":665},[558,1020,622],{"class":608},[558,1022,656],{"class":625},[558,1024,629],{"class":568},[558,1026,632],{"class":612},[558,1028,592],{"class":568},[558,1030,1031],{"class":560,"line":671},[558,1032,668],{"class":568},[558,1034,1035],{"class":560,"line":676},[558,1036,599],{"emptyLinePlaceholder":598},[558,1038,1040,1042,1045],{"class":560,"line":1039},10,[558,1041,999],{"class":608},[558,1043,1044],{"class":612}," SignupResult",[558,1046,616],{"class":568},[558,1048,1050,1052,1055,1057,1059],{"class":560,"line":1049},11,[558,1051,622],{"class":608},[558,1053,1054],{"class":625}," id",[558,1056,629],{"class":568},[558,1058,632],{"class":612},[558,1060,592],{"class":568},[558,1062,1064,1066,1068,1070,1072],{"class":560,"line":1063},12,[558,1065,622],{"class":608},[558,1067,656],{"class":625},[558,1069,629],{"class":568},[558,1071,632],{"class":612},[558,1073,592],{"class":568},[558,1075,1077],{"class":560,"line":1076},13,[558,1078,668],{"class":568},[558,1080,1082],{"class":560,"line":1081},14,[558,1083,599],{"emptyLinePlaceholder":598},[558,1085,1087,1089,1091,1093,1096,1098,1100,1102,1105,1107,1109],{"class":560,"line":1086},15,[558,1088,605],{"class":564},[558,1090,681],{"class":608},[558,1092,801],{"class":612},[558,1094,1095],{"class":608}," implements",[558,1097,952],{"class":612},[558,1099,692],{"class":568},[558,1101,589],{"class":568},[558,1103,1104],{"class":585},"\u002Fusers",[558,1106,589],{"class":568},[558,1108,707],{"class":568},[558,1110,616],{"class":568},[558,1112,1114,1117,1120,1123,1125,1127],{"class":560,"line":1113},16,[558,1115,1116],{"class":608},"  private",[558,1118,1119],{"class":608}," readonly",[558,1121,1122],{"class":625}," userSignedUp",[558,1124,629],{"class":568},[558,1126,684],{"class":612},[558,1128,592],{"class":568},[558,1130,1132],{"class":560,"line":1131},17,[558,1133,599],{"emptyLinePlaceholder":598},[558,1135,1137,1140,1143,1145,1149,1151,1153,1156],{"class":560,"line":1136},18,[558,1138,1139],{"class":608},"  public",[558,1141,1142],{"class":608}," constructor",[558,1144,835],{"class":568},[558,1146,1148],{"class":1147},"sHdIc","userSignedUp",[558,1150,629],{"class":568},[558,1152,684],{"class":612},[558,1154,1155],{"class":568},")",[558,1157,616],{"class":568},[558,1159,1161,1164,1166,1169,1171],{"class":560,"line":1160},19,[558,1162,1163],{"class":568},"    this.",[558,1165,1148],{"class":572},[558,1167,1168],{"class":568}," =",[558,1170,1122],{"class":572},[558,1172,592],{"class":568},[558,1174,1176],{"class":560,"line":1175},20,[558,1177,1178],{"class":568},"  }\n",[558,1180,1182],{"class":560,"line":1181},21,[558,1183,599],{"emptyLinePlaceholder":598},[558,1185,1187,1189,1192,1195,1197,1200,1202,1204,1206,1208,1211,1213,1216,1219,1221,1224,1226],{"class":560,"line":1186},22,[558,1188,1139],{"class":608},[558,1190,1191],{"class":608}," async",[558,1193,1194],{"class":625}," signUp",[558,1196,835],{"class":568},[558,1198,1199],{"class":1147},"action",[558,1201,629],{"class":568},[558,1203,957],{"class":612},[558,1205,692],{"class":568},[558,1207,589],{"class":568},[558,1209,1210],{"class":585},"\u002F",[558,1212,589],{"class":568},[558,1214,1215],{"class":568},">):",[558,1217,1218],{"class":612}," Promise",[558,1220,692],{"class":568},[558,1222,1223],{"class":612},"SignupResult",[558,1225,707],{"class":568},[558,1227,616],{"class":568},[558,1229,1231,1234,1237,1239,1242,1245,1248,1250,1253,1255,1258,1261,1264,1266],{"class":560,"line":1230},23,[558,1232,1233],{"class":608},"    const",[558,1235,1236],{"class":572}," body",[558,1238,1168],{"class":568},[558,1240,1241],{"class":625}," (",[558,1243,1244],{"class":564},"await",[558,1246,1247],{"class":572}," action",[558,1249,530],{"class":568},[558,1251,1252],{"class":572},"request",[558,1254,530],{"class":568},[558,1256,1257],{"class":832},"json",[558,1259,1260],{"class":625},"()) ",[558,1262,1263],{"class":564},"as",[558,1265,1002],{"class":612},[558,1267,592],{"class":568},[558,1269,1271,1273,1275,1277,1279,1281,1284,1287],{"class":560,"line":1270},24,[558,1272,1233],{"class":608},[558,1274,626],{"class":572},[558,1276,1168],{"class":568},[558,1278,928],{"class":572},[558,1280,530],{"class":568},[558,1282,1283],{"class":832},"v7",[558,1285,1286],{"class":625},"()",[558,1288,592],{"class":568},[558,1290,1292],{"class":560,"line":1291},25,[558,1293,599],{"emptyLinePlaceholder":598},[558,1295,1297],{"class":560,"line":1296},26,[558,1298,1300],{"class":1299},"sHwdD","    \u002F\u002F Publish the integration event; the welcome email is sent when the in-process transport\n",[558,1302,1304],{"class":560,"line":1303},27,[558,1305,1306],{"class":1299},"    \u002F\u002F delivers it on the prefixed channel and the WelcomeEmailHandler runs.\n",[558,1308,1310,1313,1316,1318,1320,1322,1324],{"class":560,"line":1309},28,[558,1311,1312],{"class":564},"    await",[558,1314,1315],{"class":568}," this.",[558,1317,1148],{"class":572},[558,1319,530],{"class":568},[558,1321,716],{"class":832},[558,1323,835],{"class":625},[558,1325,838],{"class":568},[558,1327,1329,1332],{"class":560,"line":1328},29,[558,1330,1331],{"class":572},"      userId",[558,1333,1334],{"class":568},",\n",[558,1336,1338,1341,1343,1345,1347,1350],{"class":560,"line":1337},30,[558,1339,1340],{"class":625},"      name",[558,1342,629],{"class":568},[558,1344,1236],{"class":572},[558,1346,530],{"class":568},[558,1348,1349],{"class":572},"name",[558,1351,1334],{"class":568},[558,1353,1355,1358,1360,1362,1364,1367],{"class":560,"line":1354},31,[558,1356,1357],{"class":625},"      email",[558,1359,629],{"class":568},[558,1361,1236],{"class":572},[558,1363,530],{"class":568},[558,1365,1366],{"class":572},"email",[558,1368,1334],{"class":568},[558,1370,1372,1375,1377],{"class":560,"line":1371},32,[558,1373,1374],{"class":568},"    }",[558,1376,1155],{"class":625},[558,1378,592],{"class":568},[558,1380,1382],{"class":560,"line":1381},33,[558,1383,599],{"emptyLinePlaceholder":598},[558,1385,1387,1390,1392,1395,1397,1400,1402,1406],{"class":560,"line":1386},34,[558,1388,1389],{"class":572},"    action",[558,1391,530],{"class":568},[558,1393,1394],{"class":572},"response",[558,1396,530],{"class":568},[558,1398,1399],{"class":572},"status",[558,1401,1168],{"class":568},[558,1403,1405],{"class":1404},"sbssI"," 201",[558,1407,592],{"class":568},[558,1409,1411,1414,1416,1418,1420,1422,1424,1426,1428,1430,1432,1434],{"class":560,"line":1410},35,[558,1412,1413],{"class":564},"    return",[558,1415,569],{"class":568},[558,1417,1054],{"class":625},[558,1419,629],{"class":568},[558,1421,626],{"class":572},[558,1423,702],{"class":568},[558,1425,656],{"class":625},[558,1427,629],{"class":568},[558,1429,1236],{"class":572},[558,1431,530],{"class":568},[558,1433,1366],{"class":572},[558,1435,1436],{"class":568}," };\n",[558,1438,1440],{"class":560,"line":1439},36,[558,1441,1178],{"class":568},[558,1443,1445],{"class":560,"line":1444},37,[558,1446,668],{"class":568},[499,1448,1449,1451,1452,1455],{},[503,1450,716],{}," is fire-and-forget at the business level — it resolves once the work is handed off to the\ntransport. On Node the dispatch rides the request frame's ",[503,1453,1454],{},"waitUntil",", so the response goes out before\nthe email is ever sent.",[532,1457,1459],{"id":1458},"_4-handle-the-work-in-the-background","4. Handle the work in the background",[499,1461,1462,1463,1466,1467,1470],{},"The consumer is one class per event: ",[503,1464,1465],{},"class X implements IntegrationEventHandler\u003C\"user.signed-up\", Payload>",".\nHeximon discovers it from that base — no decorator — and runs its ",[503,1468,1469],{},"handle"," when the transport delivers\nthe event. Its constructor declares dependencies the normal way, so the email transport arrives by class\nidentity.",[548,1472,1475],{"className":550,"code":1473,"filename":1474,"language":553,"meta":554,"style":554},"import type { IntegrationEventHandler } from \"@heximon\u002Fintegration\";\nimport { EmailMessage } from \"@heximon\u002Fnotifications\u002Femail\";\nimport type { UserSignedUpPayload } from \"..\u002Fusers\u002Fevents\";\nimport { CaptureEmailTransport } from \".\u002Fcapture-email-transport\";\n\ntype SignedUpPayload = UserSignedUpPayload;\n\nexport class WelcomeEmailHandler implements IntegrationEventHandler\u003C\n  \"user.signed-up\",\n  SignedUpPayload\n> {\n  private readonly transport: CaptureEmailTransport;\n\n  public constructor(transport: CaptureEmailTransport) {\n    this.transport = transport;\n  }\n\n  public async handle(payload: SignedUpPayload): Promise\u003Cvoid> {\n    const message = new EmailMessage({\n      from: { name: \"Heximon Example\", email: \"noreply@example.com\" },\n      to: { name: payload.name, email: payload.email },\n      subject: \"Welcome aboard!\",\n      content: [\n        \"\u003Cp>Hi {{ name }},\u003C\u002Fp>\",\n        \"\u003Cp>Thanks for signing up. Your account id is \u003Ccode>{{ userId }}\u003C\u002Fcode>.\u003C\u002Fp>\",\n        \"\u003Cp>— The Heximon team\u003C\u002Fp>\",\n      ].join(\"\\n\"),\n      placeholders: {\n        name: payload.name,\n        userId: payload.userId,\n      },\n    });\n\n    await this.transport.send(message);\n  }\n}\n","src\u002Fmail\u002Fwelcome-email.handler.ts",[503,1476,1477,1500,1522,1545,1567,1571,1585,1589,1605,1616,1621,1627,1642,1646,1665,1677,1681,1685,1717,1735,1771,1805,1821,1831,1843,1854,1865,1888,1897,1912,1928,1933,1941,1945,1967,1971],{"__ignoreMap":554},[558,1478,1479,1481,1483,1485,1488,1490,1492,1494,1496,1498],{"class":560,"line":561},[558,1480,565],{"class":564},[558,1482,947],{"class":564},[558,1484,569],{"class":568},[558,1486,1487],{"class":572}," IntegrationEventHandler",[558,1489,576],{"class":568},[558,1491,579],{"class":564},[558,1493,582],{"class":568},[558,1495,586],{"class":585},[558,1497,589],{"class":568},[558,1499,592],{"class":568},[558,1501,1502,1504,1506,1509,1511,1513,1515,1518,1520],{"class":560,"line":595},[558,1503,565],{"class":564},[558,1505,569],{"class":568},[558,1507,1508],{"class":572}," EmailMessage",[558,1510,576],{"class":568},[558,1512,579],{"class":564},[558,1514,582],{"class":568},[558,1516,1517],{"class":585},"@heximon\u002Fnotifications\u002Femail",[558,1519,589],{"class":568},[558,1521,592],{"class":568},[558,1523,1524,1526,1528,1530,1532,1534,1536,1538,1541,1543],{"class":560,"line":602},[558,1525,565],{"class":564},[558,1527,947],{"class":564},[558,1529,569],{"class":568},[558,1531,613],{"class":572},[558,1533,576],{"class":568},[558,1535,579],{"class":564},[558,1537,582],{"class":568},[558,1539,1540],{"class":585},"..\u002Fusers\u002Fevents",[558,1542,589],{"class":568},[558,1544,592],{"class":568},[558,1546,1547,1549,1551,1554,1556,1558,1560,1563,1565],{"class":560,"line":619},[558,1548,565],{"class":564},[558,1550,569],{"class":568},[558,1552,1553],{"class":572}," CaptureEmailTransport",[558,1555,576],{"class":568},[558,1557,579],{"class":564},[558,1559,582],{"class":568},[558,1561,1562],{"class":585},".\u002Fcapture-email-transport",[558,1564,589],{"class":568},[558,1566,592],{"class":568},[558,1568,1569],{"class":560,"line":637},[558,1570,599],{"emptyLinePlaceholder":598},[558,1572,1573,1576,1579,1581,1583],{"class":560,"line":651},[558,1574,1575],{"class":608},"type",[558,1577,1578],{"class":612}," SignedUpPayload",[558,1580,1168],{"class":568},[558,1582,613],{"class":612},[558,1584,592],{"class":568},[558,1586,1587],{"class":560,"line":665},[558,1588,599],{"emptyLinePlaceholder":598},[558,1590,1591,1593,1595,1598,1600,1602],{"class":560,"line":671},[558,1592,605],{"class":564},[558,1594,681],{"class":608},[558,1596,1597],{"class":612}," WelcomeEmailHandler",[558,1599,1095],{"class":608},[558,1601,1487],{"class":612},[558,1603,1604],{"class":568},"\u003C\n",[558,1606,1607,1610,1612,1614],{"class":560,"line":676},[558,1608,1609],{"class":568},"  \"",[558,1611,697],{"class":585},[558,1613,589],{"class":568},[558,1615,1334],{"class":568},[558,1617,1618],{"class":560,"line":1039},[558,1619,1620],{"class":612},"  SignedUpPayload\n",[558,1622,1623,1625],{"class":560,"line":1049},[558,1624,707],{"class":568},[558,1626,616],{"class":568},[558,1628,1629,1631,1633,1636,1638,1640],{"class":560,"line":1063},[558,1630,1116],{"class":608},[558,1632,1119],{"class":608},[558,1634,1635],{"class":625}," transport",[558,1637,629],{"class":568},[558,1639,1553],{"class":612},[558,1641,592],{"class":568},[558,1643,1644],{"class":560,"line":1076},[558,1645,599],{"emptyLinePlaceholder":598},[558,1647,1648,1650,1652,1654,1657,1659,1661,1663],{"class":560,"line":1081},[558,1649,1139],{"class":608},[558,1651,1142],{"class":608},[558,1653,835],{"class":568},[558,1655,1656],{"class":1147},"transport",[558,1658,629],{"class":568},[558,1660,1553],{"class":612},[558,1662,1155],{"class":568},[558,1664,616],{"class":568},[558,1666,1667,1669,1671,1673,1675],{"class":560,"line":1086},[558,1668,1163],{"class":568},[558,1670,1656],{"class":572},[558,1672,1168],{"class":568},[558,1674,1635],{"class":572},[558,1676,592],{"class":568},[558,1678,1679],{"class":560,"line":1113},[558,1680,1178],{"class":568},[558,1682,1683],{"class":560,"line":1131},[558,1684,599],{"emptyLinePlaceholder":598},[558,1686,1687,1689,1691,1694,1696,1699,1701,1703,1706,1708,1710,1713,1715],{"class":560,"line":1136},[558,1688,1139],{"class":608},[558,1690,1191],{"class":608},[558,1692,1693],{"class":625}," handle",[558,1695,835],{"class":568},[558,1697,1698],{"class":1147},"payload",[558,1700,629],{"class":568},[558,1702,1578],{"class":612},[558,1704,1705],{"class":568},"):",[558,1707,1218],{"class":612},[558,1709,692],{"class":568},[558,1711,1712],{"class":612},"void",[558,1714,707],{"class":568},[558,1716,616],{"class":568},[558,1718,1719,1721,1724,1726,1729,1731,1733],{"class":560,"line":1160},[558,1720,1233],{"class":608},[558,1722,1723],{"class":572}," message",[558,1725,1168],{"class":568},[558,1727,1728],{"class":568}," new",[558,1730,1508],{"class":832},[558,1732,835],{"class":625},[558,1734,838],{"class":568},[558,1736,1737,1740,1742,1744,1746,1748,1750,1753,1755,1757,1759,1761,1763,1766,1768],{"class":560,"line":1175},[558,1738,1739],{"class":625},"      from",[558,1741,629],{"class":568},[558,1743,569],{"class":568},[558,1745,642],{"class":625},[558,1747,629],{"class":568},[558,1749,582],{"class":568},[558,1751,1752],{"class":585},"Heximon Example",[558,1754,589],{"class":568},[558,1756,702],{"class":568},[558,1758,656],{"class":625},[558,1760,629],{"class":568},[558,1762,582],{"class":568},[558,1764,1765],{"class":585},"noreply@example.com",[558,1767,589],{"class":568},[558,1769,1770],{"class":568}," },\n",[558,1772,1773,1776,1778,1780,1782,1784,1787,1789,1791,1793,1795,1797,1799,1801,1803],{"class":560,"line":1181},[558,1774,1775],{"class":625},"      to",[558,1777,629],{"class":568},[558,1779,569],{"class":568},[558,1781,642],{"class":625},[558,1783,629],{"class":568},[558,1785,1786],{"class":572}," payload",[558,1788,530],{"class":568},[558,1790,1349],{"class":572},[558,1792,702],{"class":568},[558,1794,656],{"class":625},[558,1796,629],{"class":568},[558,1798,1786],{"class":572},[558,1800,530],{"class":568},[558,1802,1366],{"class":572},[558,1804,1770],{"class":568},[558,1806,1807,1810,1812,1814,1817,1819],{"class":560,"line":1186},[558,1808,1809],{"class":625},"      subject",[558,1811,629],{"class":568},[558,1813,582],{"class":568},[558,1815,1816],{"class":585},"Welcome aboard!",[558,1818,589],{"class":568},[558,1820,1334],{"class":568},[558,1822,1823,1826,1828],{"class":560,"line":1230},[558,1824,1825],{"class":625},"      content",[558,1827,629],{"class":568},[558,1829,1830],{"class":625}," [\n",[558,1832,1833,1836,1839,1841],{"class":560,"line":1270},[558,1834,1835],{"class":568},"        \"",[558,1837,1838],{"class":585},"\u003Cp>Hi {{ name }},\u003C\u002Fp>",[558,1840,589],{"class":568},[558,1842,1334],{"class":568},[558,1844,1845,1847,1850,1852],{"class":560,"line":1291},[558,1846,1835],{"class":568},[558,1848,1849],{"class":585},"\u003Cp>Thanks for signing up. Your account id is \u003Ccode>{{ userId }}\u003C\u002Fcode>.\u003C\u002Fp>",[558,1851,589],{"class":568},[558,1853,1334],{"class":568},[558,1855,1856,1858,1861,1863],{"class":560,"line":1296},[558,1857,1835],{"class":568},[558,1859,1860],{"class":585},"\u003Cp>— The Heximon team\u003C\u002Fp>",[558,1862,589],{"class":568},[558,1864,1334],{"class":568},[558,1866,1867,1870,1872,1875,1877,1879,1882,1884,1886],{"class":560,"line":1303},[558,1868,1869],{"class":625},"      ]",[558,1871,530],{"class":568},[558,1873,1874],{"class":832},"join",[558,1876,835],{"class":625},[558,1878,589],{"class":568},[558,1880,1881],{"class":572},"\\n",[558,1883,589],{"class":568},[558,1885,1155],{"class":625},[558,1887,1334],{"class":568},[558,1889,1890,1893,1895],{"class":560,"line":1309},[558,1891,1892],{"class":625},"      placeholders",[558,1894,629],{"class":568},[558,1896,616],{"class":568},[558,1898,1899,1902,1904,1906,1908,1910],{"class":560,"line":1328},[558,1900,1901],{"class":625},"        name",[558,1903,629],{"class":568},[558,1905,1786],{"class":572},[558,1907,530],{"class":568},[558,1909,1349],{"class":572},[558,1911,1334],{"class":568},[558,1913,1914,1917,1919,1921,1923,1926],{"class":560,"line":1337},[558,1915,1916],{"class":625},"        userId",[558,1918,629],{"class":568},[558,1920,1786],{"class":572},[558,1922,530],{"class":568},[558,1924,1925],{"class":572},"userId",[558,1927,1334],{"class":568},[558,1929,1930],{"class":560,"line":1354},[558,1931,1932],{"class":568},"      },\n",[558,1934,1935,1937,1939],{"class":560,"line":1371},[558,1936,1374],{"class":568},[558,1938,1155],{"class":625},[558,1940,592],{"class":568},[558,1942,1943],{"class":560,"line":1381},[558,1944,599],{"emptyLinePlaceholder":598},[558,1946,1947,1949,1951,1953,1955,1958,1960,1963,1965],{"class":560,"line":1386},[558,1948,1312],{"class":564},[558,1950,1315],{"class":568},[558,1952,1656],{"class":572},[558,1954,530],{"class":568},[558,1956,1957],{"class":832},"send",[558,1959,835],{"class":625},[558,1961,1962],{"class":572},"message",[558,1964,1155],{"class":625},[558,1966,592],{"class":568},[558,1968,1969],{"class":560,"line":1410},[558,1970,1178],{"class":568},[558,1972,1973],{"class":560,"line":1439},[558,1974,668],{"class":568},[499,1976,1977,1978,1981,1982,1985],{},"The event name in the ",[503,1979,1980],{},"IntegrationEventHandler\u003Ctype, Payload>"," type argument must be a ",[508,1983,1984],{},"string literal"," —\nHeximon reads it at build time to route the event here, so it has to be a constant the compiler can see.",[532,1987,1989],{"id":1988},"_5-wire-the-consumer-module","5. Wire the consumer module",[499,1991,1992,1993,736,1995,1998,1999,530],{},"Declare the handler under the ",[503,1994,735],{},[503,1996,1997],{},"eventHandlers"," key — that is the list\nHeximon scans to find it. Its plain dependency, the email transport, stays in ",[503,2000,743],{},[548,2002,2005],{"className":550,"code":2003,"filename":2004,"language":553,"meta":554,"style":554},"import { Module } from \"@heximon\u002Fruntime\";\nimport { CaptureEmailTransport } from \".\u002Fcapture-email-transport\";\nimport { MailController } from \".\u002Fmail.controller\";\nimport { WelcomeEmailHandler } from \".\u002Fwelcome-email.handler\";\n\nexport class MailModule extends Module({\n  providers: [CaptureEmailTransport],\n  http: { controllers: [MailController] },\n  integration: { eventHandlers: [WelcomeEmailHandler] },\n  exports: [CaptureEmailTransport],\n}) {}\n","src\u002Fmail\u002Fmail.module.ts",[503,2006,2007,2027,2047,2069,2090,2094,2111,2123,2140,2158,2169],{"__ignoreMap":554},[558,2008,2009,2011,2013,2015,2017,2019,2021,2023,2025],{"class":560,"line":561},[558,2010,565],{"class":564},[558,2012,569],{"class":568},[558,2014,758],{"class":572},[558,2016,576],{"class":568},[558,2018,579],{"class":564},[558,2020,582],{"class":568},[558,2022,767],{"class":585},[558,2024,589],{"class":568},[558,2026,592],{"class":568},[558,2028,2029,2031,2033,2035,2037,2039,2041,2043,2045],{"class":560,"line":595},[558,2030,565],{"class":564},[558,2032,569],{"class":568},[558,2034,1553],{"class":572},[558,2036,576],{"class":568},[558,2038,579],{"class":564},[558,2040,582],{"class":568},[558,2042,1562],{"class":585},[558,2044,589],{"class":568},[558,2046,592],{"class":568},[558,2048,2049,2051,2053,2056,2058,2060,2062,2065,2067],{"class":560,"line":602},[558,2050,565],{"class":564},[558,2052,569],{"class":568},[558,2054,2055],{"class":572}," MailController",[558,2057,576],{"class":568},[558,2059,579],{"class":564},[558,2061,582],{"class":568},[558,2063,2064],{"class":585},".\u002Fmail.controller",[558,2066,589],{"class":568},[558,2068,592],{"class":568},[558,2070,2071,2073,2075,2077,2079,2081,2083,2086,2088],{"class":560,"line":619},[558,2072,565],{"class":564},[558,2074,569],{"class":568},[558,2076,1597],{"class":572},[558,2078,576],{"class":568},[558,2080,579],{"class":564},[558,2082,582],{"class":568},[558,2084,2085],{"class":585},".\u002Fwelcome-email.handler",[558,2087,589],{"class":568},[558,2089,592],{"class":568},[558,2091,2092],{"class":560,"line":637},[558,2093,599],{"emptyLinePlaceholder":598},[558,2095,2096,2098,2100,2103,2105,2107,2109],{"class":560,"line":651},[558,2097,605],{"class":564},[558,2099,681],{"class":608},[558,2101,2102],{"class":612}," MailModule",[558,2104,687],{"class":608},[558,2106,758],{"class":832},[558,2108,835],{"class":572},[558,2110,838],{"class":568},[558,2112,2113,2116,2118,2121],{"class":560,"line":665},[558,2114,2115],{"class":625},"  providers",[558,2117,629],{"class":568},[558,2119,2120],{"class":572}," [CaptureEmailTransport]",[558,2122,1334],{"class":568},[558,2124,2125,2127,2129,2131,2133,2135,2138],{"class":560,"line":671},[558,2126,843],{"class":625},[558,2128,629],{"class":568},[558,2130,569],{"class":568},[558,2132,850],{"class":625},[558,2134,629],{"class":568},[558,2136,2137],{"class":572}," [MailController] ",[558,2139,858],{"class":568},[558,2141,2142,2144,2146,2148,2151,2153,2156],{"class":560,"line":676},[558,2143,863],{"class":625},[558,2145,629],{"class":568},[558,2147,569],{"class":568},[558,2149,2150],{"class":625}," eventHandlers",[558,2152,629],{"class":568},[558,2154,2155],{"class":572}," [WelcomeEmailHandler] ",[558,2157,858],{"class":568},[558,2159,2160,2163,2165,2167],{"class":560,"line":1039},[558,2161,2162],{"class":625},"  exports",[558,2164,629],{"class":568},[558,2166,2120],{"class":572},[558,2168,1334],{"class":568},[558,2170,2171,2173,2175],{"class":560,"line":1049},[558,2172,882],{"class":568},[558,2174,885],{"class":572},[558,2176,888],{"class":568},[499,2178,2179,2182,2183,2186,2187,2190],{},[503,2180,2181],{},"CaptureEmailTransport"," is a test stand-in that records what it \"sends\" so you can inspect it. Because it\n",[503,2184,2185],{},"extends EmailTransport",", going to production is a one-line change — provide ",[503,2188,2189],{},"ResendTransport"," here\ninstead, and the handler is untouched.",[532,2192,2194],{"id":2193},"_6-run-it","6. Run it",[548,2196,2201],{"className":2197,"code":2198,"filename":2199,"language":2200,"meta":554,"style":554},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl -s -X POST localhost:3010\u002Fusers \\\n  -H 'content-type: application\u002Fjson' \\\n  -d '{\"name\":\"Alice\",\"email\":\"alice@example.com\"}'\n# → 201 immediately; the welcome email is sent when the transport delivers the event, off the request path\n","terminal","bash",[503,2202,2203,2223,2239,2252],{"__ignoreMap":554},[558,2204,2205,2208,2211,2214,2217,2220],{"class":560,"line":561},[558,2206,2207],{"class":612},"curl",[558,2209,2210],{"class":585}," -s",[558,2212,2213],{"class":585}," -X",[558,2215,2216],{"class":585}," POST",[558,2218,2219],{"class":585}," localhost:3010\u002Fusers",[558,2221,2222],{"class":572}," \\\n",[558,2224,2225,2228,2231,2234,2237],{"class":560,"line":595},[558,2226,2227],{"class":585},"  -H",[558,2229,2230],{"class":568}," '",[558,2232,2233],{"class":585},"content-type: application\u002Fjson",[558,2235,2236],{"class":568},"'",[558,2238,2222],{"class":572},[558,2240,2241,2244,2246,2249],{"class":560,"line":602},[558,2242,2243],{"class":585},"  -d",[558,2245,2230],{"class":568},[558,2247,2248],{"class":585},"{\"name\":\"Alice\",\"email\":\"alice@example.com\"}",[558,2250,2251],{"class":568},"'\n",[558,2253,2254],{"class":560,"line":619},[558,2255,2256],{"class":1299},"# → 201 immediately; the welcome email is sent when the transport delivers the event, off the request path\n",[532,2258,2260],{"id":2259},"transactional-outbox-option","Transactional outbox option",[499,2262,2263,2264,2266,2267,2269,2270,2272],{},"The recipe above is fire-and-forget: ",[503,2265,716],{}," hands the event to the in-process transport and the\nhandler runs asynchronously. That works well for low-stakes notifications, but it has a gap — if the\nprocess crashes after ",[503,2268,517],{}," commits the user but before the transport delivers the event, the\n",[503,2271,724],{}," event is lost.",[499,2274,2275,2276,2279,2280,2283,2284,2287],{},"The ",[508,2277,2278],{},"transactional outbox"," closes that gap: the integration event is written to an ",[503,2281,2282],{},"outbox"," table\n",[508,2285,2286],{},"inside the same database transaction"," as the aggregate save. After the commit, a relay drains the\noutbox row and dispatches it to the handler. A crash after the commit replays the rows on boot; a crash\nbefore the commit discards the buffer with the rolled-back write — no ghost deliveries.",[499,2289,2290,2291,2296],{},"This is the pattern in\n",[524,2292,2295],{"href":2293,"rel":2294},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Freliable",[528],"the gap's reliable cross-service example",". The atomic\nwrite-and-publish pattern looks like this in the controller:",[548,2298,2301],{"className":550,"code":2299,"filename":2300,"language":553,"meta":554,"style":554},"await this.repository.runInTransaction(async () => {\n  await this.repository.save(order);             \u002F\u002F aggregate write\n  await this.orderPlaced.publish({               \u002F\u002F buffered → outbox row on onBeforeCommit\n    orderId: order.id,\n    customer: order.customer,\n    totalCents: order.totalCents,\n  });\n});\n\u002F\u002F after the commit the relay schedules; after dispatch the handler runs in the notifications context\n","src\u002Forders\u002Forders.controller.ts",[503,2302,2303,2330,2357,2378,2395,2411,2427,2436,2444],{"__ignoreMap":554},[558,2304,2305,2307,2309,2312,2314,2317,2319,2322,2325,2328],{"class":560,"line":561},[558,2306,1244],{"class":564},[558,2308,1315],{"class":568},[558,2310,2311],{"class":572},"repository",[558,2313,530],{"class":568},[558,2315,2316],{"class":832},"runInTransaction",[558,2318,835],{"class":572},[558,2320,2321],{"class":608},"async",[558,2323,2324],{"class":568}," ()",[558,2326,2327],{"class":608}," =>",[558,2329,616],{"class":568},[558,2331,2332,2335,2337,2339,2341,2344,2346,2349,2351,2354],{"class":560,"line":595},[558,2333,2334],{"class":564},"  await",[558,2336,1315],{"class":568},[558,2338,2311],{"class":572},[558,2340,530],{"class":568},[558,2342,2343],{"class":832},"save",[558,2345,835],{"class":625},[558,2347,2348],{"class":572},"order",[558,2350,1155],{"class":625},[558,2352,2353],{"class":568},";",[558,2355,2356],{"class":1299},"             \u002F\u002F aggregate write\n",[558,2358,2359,2361,2363,2366,2368,2370,2372,2375],{"class":560,"line":602},[558,2360,2334],{"class":564},[558,2362,1315],{"class":568},[558,2364,2365],{"class":572},"orderPlaced",[558,2367,530],{"class":568},[558,2369,716],{"class":832},[558,2371,835],{"class":625},[558,2373,2374],{"class":568},"{",[558,2376,2377],{"class":1299},"               \u002F\u002F buffered → outbox row on onBeforeCommit\n",[558,2379,2380,2383,2385,2388,2390,2393],{"class":560,"line":619},[558,2381,2382],{"class":625},"    orderId",[558,2384,629],{"class":568},[558,2386,2387],{"class":572}," order",[558,2389,530],{"class":568},[558,2391,2392],{"class":572},"id",[558,2394,1334],{"class":568},[558,2396,2397,2400,2402,2404,2406,2409],{"class":560,"line":637},[558,2398,2399],{"class":625},"    customer",[558,2401,629],{"class":568},[558,2403,2387],{"class":572},[558,2405,530],{"class":568},[558,2407,2408],{"class":572},"customer",[558,2410,1334],{"class":568},[558,2412,2413,2416,2418,2420,2422,2425],{"class":560,"line":651},[558,2414,2415],{"class":625},"    totalCents",[558,2417,629],{"class":568},[558,2419,2387],{"class":572},[558,2421,530],{"class":568},[558,2423,2424],{"class":572},"totalCents",[558,2426,1334],{"class":568},[558,2428,2429,2432,2434],{"class":560,"line":665},[558,2430,2431],{"class":568},"  }",[558,2433,1155],{"class":625},[558,2435,592],{"class":568},[558,2437,2438,2440,2442],{"class":560,"line":671},[558,2439,882],{"class":568},[558,2441,1155],{"class":572},[558,2443,592],{"class":568},[558,2445,2446],{"class":560,"line":676},[558,2447,2448],{"class":1299},"\u002F\u002F after the commit the relay schedules; after dispatch the handler runs in the notifications context\n",[499,2450,2275,2451,2454,2455,2458,2459,2462,2463,2465,2466,2469],{},[503,2452,2453],{},"OrderPlaced"," typed producer is the same pattern as ",[503,2456,2457],{},"UserSignedUp"," — an ",[503,2460,2461],{},"IntegrationEvent\u003C\"order.placed\", Payload>"," class the controller injects and calls ",[503,2464,716],{}," on. The only difference is the bound transport: this module provides an ",[503,2467,2468],{},"OutboxIntegrationEventTransport"," satisfier instead of relying on the memory default.",[499,2471,2472,2473,2475,2476,2475,2479,2482,2483,629],{},"To opt in, provide four thin app-local subclasses of the shipped ",[503,2474,735],{}," + ",[503,2477,2478],{},"drizzle",[503,2480,2481],{},"queue"," pieces\nin a shared outbox module. Because each constructor is authored in your source, the compiler reads the\nparameter types as the dependency declaration and injects them directly — no ",[503,2484,2485],{},"useFactory",[548,2487,2490],{"className":550,"code":2488,"filename":2489,"language":553,"meta":554,"style":554},"import { Context, TransactionContext } from \"@heximon\u002Fruntime\";\nimport { OutboxIntegrationEventTransport, OutboxRelay, OutboxStore } from \"@heximon\u002Fintegration\";\nimport { DrizzleOutboxStore } from \"@heximon\u002Fdrizzle\u002Fcore\";\nimport { IntegrationEventTransport, QueueChannelDispatcher } from \"@heximon\u002Fqueue\";\nimport { MemoryIntegrationEventTransport } from \"@heximon\u002Fqueue\u002Fmemory\";\nimport { Database } from \"..\u002Fdatabase\u002Fdatabase\";\nimport { outbox } from \"..\u002Fdatabase\u002Fschema\";\n\n\u002F\u002F Store: the OutboxStore port backed by the app's `outbox` table.\nexport class AppOutboxStore extends DrizzleOutboxStore implements OutboxStore {\n  public constructor(database: Database) { super(database, outbox); }\n}\n\n\u002F\u002F The relay's in-process delivery terminal (bound separately since the producer binds\n\u002F\u002F its own IntegrationEventTransport — the outbox one — which suppresses the memory default).\nexport class AppRelayTransport extends MemoryIntegrationEventTransport {\n  public constructor(dispatcher: QueueChannelDispatcher) { super(dispatcher); }\n}\n\n\u002F\u002F Relay: drains pending rows after commit via AppRelayTransport.\nexport class AppOutboxRelay extends OutboxRelay {\n  public constructor(store: AppOutboxStore, target: AppRelayTransport, context: Context) {\n    super(store, target, context);\n  }\n}\n\n\u002F\u002F Producer transport: buffers each publish, appends to outbox on onBeforeCommit, schedules relay\n\u002F\u002F on onCommit. implements IntegrationEventTransport so the OrderPlaced producer resolves it.\nexport class AppOutboxTransport\n  extends OutboxIntegrationEventTransport\n  implements IntegrationEventTransport\n{\n  public constructor(\n    database: Database,\n    store: AppOutboxStore,\n    relay: AppOutboxRelay,\n    context: Context,\n    transactionContext: TransactionContext,\n  ) {\n    super(database, store, relay, context, transactionContext);\n  }\n}\n","src\u002Foutbox\u002Foutbox.ts",[503,2491,2492,2518,2549,2571,2598,2620,2642,2664,2668,2673,2692,2729,2733,2737,2742,2747,2762,2793,2797,2801,2806,2821,2858,2879,2883,2887,2891,2896,2901,2910,2918,2926,2930,2939,2950,2961,2972,2983,2995,3003,3035,3040],{"__ignoreMap":554},[558,2493,2494,2496,2498,2501,2503,2506,2508,2510,2512,2514,2516],{"class":560,"line":561},[558,2495,565],{"class":564},[558,2497,569],{"class":568},[558,2499,2500],{"class":572}," Context",[558,2502,702],{"class":568},[558,2504,2505],{"class":572}," TransactionContext",[558,2507,576],{"class":568},[558,2509,579],{"class":564},[558,2511,582],{"class":568},[558,2513,767],{"class":585},[558,2515,589],{"class":568},[558,2517,592],{"class":568},[558,2519,2520,2522,2524,2527,2529,2532,2534,2537,2539,2541,2543,2545,2547],{"class":560,"line":595},[558,2521,565],{"class":564},[558,2523,569],{"class":568},[558,2525,2526],{"class":572}," OutboxIntegrationEventTransport",[558,2528,702],{"class":568},[558,2530,2531],{"class":572}," OutboxRelay",[558,2533,702],{"class":568},[558,2535,2536],{"class":572}," OutboxStore",[558,2538,576],{"class":568},[558,2540,579],{"class":564},[558,2542,582],{"class":568},[558,2544,586],{"class":585},[558,2546,589],{"class":568},[558,2548,592],{"class":568},[558,2550,2551,2553,2555,2558,2560,2562,2564,2567,2569],{"class":560,"line":602},[558,2552,565],{"class":564},[558,2554,569],{"class":568},[558,2556,2557],{"class":572}," DrizzleOutboxStore",[558,2559,576],{"class":568},[558,2561,579],{"class":564},[558,2563,582],{"class":568},[558,2565,2566],{"class":585},"@heximon\u002Fdrizzle\u002Fcore",[558,2568,589],{"class":568},[558,2570,592],{"class":568},[558,2572,2573,2575,2577,2580,2582,2585,2587,2589,2591,2594,2596],{"class":560,"line":619},[558,2574,565],{"class":564},[558,2576,569],{"class":568},[558,2578,2579],{"class":572}," IntegrationEventTransport",[558,2581,702],{"class":568},[558,2583,2584],{"class":572}," QueueChannelDispatcher",[558,2586,576],{"class":568},[558,2588,579],{"class":564},[558,2590,582],{"class":568},[558,2592,2593],{"class":585},"@heximon\u002Fqueue",[558,2595,589],{"class":568},[558,2597,592],{"class":568},[558,2599,2600,2602,2604,2607,2609,2611,2613,2616,2618],{"class":560,"line":637},[558,2601,565],{"class":564},[558,2603,569],{"class":568},[558,2605,2606],{"class":572}," MemoryIntegrationEventTransport",[558,2608,576],{"class":568},[558,2610,579],{"class":564},[558,2612,582],{"class":568},[558,2614,2615],{"class":585},"@heximon\u002Fqueue\u002Fmemory",[558,2617,589],{"class":568},[558,2619,592],{"class":568},[558,2621,2622,2624,2626,2629,2631,2633,2635,2638,2640],{"class":560,"line":651},[558,2623,565],{"class":564},[558,2625,569],{"class":568},[558,2627,2628],{"class":572}," Database",[558,2630,576],{"class":568},[558,2632,579],{"class":564},[558,2634,582],{"class":568},[558,2636,2637],{"class":585},"..\u002Fdatabase\u002Fdatabase",[558,2639,589],{"class":568},[558,2641,592],{"class":568},[558,2643,2644,2646,2648,2651,2653,2655,2657,2660,2662],{"class":560,"line":665},[558,2645,565],{"class":564},[558,2647,569],{"class":568},[558,2649,2650],{"class":572}," outbox",[558,2652,576],{"class":568},[558,2654,579],{"class":564},[558,2656,582],{"class":568},[558,2658,2659],{"class":585},"..\u002Fdatabase\u002Fschema",[558,2661,589],{"class":568},[558,2663,592],{"class":568},[558,2665,2666],{"class":560,"line":671},[558,2667,599],{"emptyLinePlaceholder":598},[558,2669,2670],{"class":560,"line":676},[558,2671,2672],{"class":1299},"\u002F\u002F Store: the OutboxStore port backed by the app's `outbox` table.\n",[558,2674,2675,2677,2679,2682,2684,2686,2688,2690],{"class":560,"line":1039},[558,2676,605],{"class":564},[558,2678,681],{"class":608},[558,2680,2681],{"class":612}," AppOutboxStore",[558,2683,687],{"class":608},[558,2685,2557],{"class":612},[558,2687,1095],{"class":608},[558,2689,2536],{"class":612},[558,2691,616],{"class":568},[558,2693,2694,2696,2698,2700,2703,2705,2707,2709,2711,2714,2716,2718,2720,2722,2724,2726],{"class":560,"line":1049},[558,2695,1139],{"class":608},[558,2697,1142],{"class":608},[558,2699,835],{"class":568},[558,2701,2702],{"class":1147},"database",[558,2704,629],{"class":568},[558,2706,2628],{"class":612},[558,2708,1155],{"class":568},[558,2710,569],{"class":568},[558,2712,2713],{"class":572}," super",[558,2715,835],{"class":625},[558,2717,2702],{"class":572},[558,2719,702],{"class":568},[558,2721,2650],{"class":572},[558,2723,1155],{"class":625},[558,2725,2353],{"class":568},[558,2727,2728],{"class":568}," }\n",[558,2730,2731],{"class":560,"line":1063},[558,2732,668],{"class":568},[558,2734,2735],{"class":560,"line":1076},[558,2736,599],{"emptyLinePlaceholder":598},[558,2738,2739],{"class":560,"line":1081},[558,2740,2741],{"class":1299},"\u002F\u002F The relay's in-process delivery terminal (bound separately since the producer binds\n",[558,2743,2744],{"class":560,"line":1086},[558,2745,2746],{"class":1299},"\u002F\u002F its own IntegrationEventTransport — the outbox one — which suppresses the memory default).\n",[558,2748,2749,2751,2753,2756,2758,2760],{"class":560,"line":1113},[558,2750,605],{"class":564},[558,2752,681],{"class":608},[558,2754,2755],{"class":612}," AppRelayTransport",[558,2757,687],{"class":608},[558,2759,2606],{"class":612},[558,2761,616],{"class":568},[558,2763,2764,2766,2768,2770,2773,2775,2777,2779,2781,2783,2785,2787,2789,2791],{"class":560,"line":1131},[558,2765,1139],{"class":608},[558,2767,1142],{"class":608},[558,2769,835],{"class":568},[558,2771,2772],{"class":1147},"dispatcher",[558,2774,629],{"class":568},[558,2776,2584],{"class":612},[558,2778,1155],{"class":568},[558,2780,569],{"class":568},[558,2782,2713],{"class":572},[558,2784,835],{"class":625},[558,2786,2772],{"class":572},[558,2788,1155],{"class":625},[558,2790,2353],{"class":568},[558,2792,2728],{"class":568},[558,2794,2795],{"class":560,"line":1136},[558,2796,668],{"class":568},[558,2798,2799],{"class":560,"line":1160},[558,2800,599],{"emptyLinePlaceholder":598},[558,2802,2803],{"class":560,"line":1175},[558,2804,2805],{"class":1299},"\u002F\u002F Relay: drains pending rows after commit via AppRelayTransport.\n",[558,2807,2808,2810,2812,2815,2817,2819],{"class":560,"line":1181},[558,2809,605],{"class":564},[558,2811,681],{"class":608},[558,2813,2814],{"class":612}," AppOutboxRelay",[558,2816,687],{"class":608},[558,2818,2531],{"class":612},[558,2820,616],{"class":568},[558,2822,2823,2825,2827,2829,2832,2834,2836,2838,2841,2843,2845,2847,2850,2852,2854,2856],{"class":560,"line":1186},[558,2824,1139],{"class":608},[558,2826,1142],{"class":608},[558,2828,835],{"class":568},[558,2830,2831],{"class":1147},"store",[558,2833,629],{"class":568},[558,2835,2681],{"class":612},[558,2837,702],{"class":568},[558,2839,2840],{"class":1147}," target",[558,2842,629],{"class":568},[558,2844,2755],{"class":612},[558,2846,702],{"class":568},[558,2848,2849],{"class":1147}," context",[558,2851,629],{"class":568},[558,2853,2500],{"class":612},[558,2855,1155],{"class":568},[558,2857,616],{"class":568},[558,2859,2860,2863,2865,2867,2869,2871,2873,2875,2877],{"class":560,"line":1230},[558,2861,2862],{"class":572},"    super",[558,2864,835],{"class":625},[558,2866,2831],{"class":572},[558,2868,702],{"class":568},[558,2870,2840],{"class":572},[558,2872,702],{"class":568},[558,2874,2849],{"class":572},[558,2876,1155],{"class":625},[558,2878,592],{"class":568},[558,2880,2881],{"class":560,"line":1270},[558,2882,1178],{"class":568},[558,2884,2885],{"class":560,"line":1291},[558,2886,668],{"class":568},[558,2888,2889],{"class":560,"line":1296},[558,2890,599],{"emptyLinePlaceholder":598},[558,2892,2893],{"class":560,"line":1303},[558,2894,2895],{"class":1299},"\u002F\u002F Producer transport: buffers each publish, appends to outbox on onBeforeCommit, schedules relay\n",[558,2897,2898],{"class":560,"line":1309},[558,2899,2900],{"class":1299},"\u002F\u002F on onCommit. implements IntegrationEventTransport so the OrderPlaced producer resolves it.\n",[558,2902,2903,2905,2907],{"class":560,"line":1328},[558,2904,605],{"class":564},[558,2906,681],{"class":608},[558,2908,2909],{"class":612}," AppOutboxTransport\n",[558,2911,2912,2915],{"class":560,"line":1337},[558,2913,2914],{"class":608},"  extends",[558,2916,2917],{"class":612}," OutboxIntegrationEventTransport\n",[558,2919,2920,2923],{"class":560,"line":1354},[558,2921,2922],{"class":608},"  implements",[558,2924,2925],{"class":612}," IntegrationEventTransport\n",[558,2927,2928],{"class":560,"line":1371},[558,2929,838],{"class":568},[558,2931,2932,2934,2936],{"class":560,"line":1381},[558,2933,1139],{"class":608},[558,2935,1142],{"class":608},[558,2937,2938],{"class":568},"(\n",[558,2940,2941,2944,2946,2948],{"class":560,"line":1386},[558,2942,2943],{"class":1147},"    database",[558,2945,629],{"class":568},[558,2947,2628],{"class":612},[558,2949,1334],{"class":568},[558,2951,2952,2955,2957,2959],{"class":560,"line":1410},[558,2953,2954],{"class":1147},"    store",[558,2956,629],{"class":568},[558,2958,2681],{"class":612},[558,2960,1334],{"class":568},[558,2962,2963,2966,2968,2970],{"class":560,"line":1439},[558,2964,2965],{"class":1147},"    relay",[558,2967,629],{"class":568},[558,2969,2814],{"class":612},[558,2971,1334],{"class":568},[558,2973,2974,2977,2979,2981],{"class":560,"line":1444},[558,2975,2976],{"class":1147},"    context",[558,2978,629],{"class":568},[558,2980,2500],{"class":612},[558,2982,1334],{"class":568},[558,2984,2986,2989,2991,2993],{"class":560,"line":2985},38,[558,2987,2988],{"class":1147},"    transactionContext",[558,2990,629],{"class":568},[558,2992,2505],{"class":612},[558,2994,1334],{"class":568},[558,2996,2998,3001],{"class":560,"line":2997},39,[558,2999,3000],{"class":568},"  )",[558,3002,616],{"class":568},[558,3004,3006,3008,3010,3012,3014,3017,3019,3022,3024,3026,3028,3031,3033],{"class":560,"line":3005},40,[558,3007,2862],{"class":572},[558,3009,835],{"class":625},[558,3011,2702],{"class":572},[558,3013,702],{"class":568},[558,3015,3016],{"class":572}," store",[558,3018,702],{"class":568},[558,3020,3021],{"class":572}," relay",[558,3023,702],{"class":568},[558,3025,2849],{"class":572},[558,3027,702],{"class":568},[558,3029,3030],{"class":572}," transactionContext",[558,3032,1155],{"class":625},[558,3034,592],{"class":568},[558,3036,3038],{"class":560,"line":3037},41,[558,3039,1178],{"class":568},[558,3041,3043],{"class":560,"line":3042},42,[558,3044,668],{"class":568},[499,3046,3047,3048,3051,3052,3054,3055,3057,3058,3061,3062,3051,3065,3068,3069,3072,3073,3076,3077,3080,3081,3084,3085,3088,3089,3091],{},"Then list them all in a shared ",[503,3049,3050],{},"OutboxModule","'s ",[503,3053,743],{}," — every constructor above is authored in app\nsource, so the compiler reads its parameter types directly and injects it, bare, no ",[503,3056,2485],{}," needed\neven for ",[503,3059,3060],{},"AppOutboxRelay",". ",[503,3063,3064],{},"OutboxRelay",[503,3066,3067],{},"OnBootstrap"," hook (the crash-recovery boot replay) is inherited,\nnot redeclared, and still runs automatically. A bare ",[503,3070,3071],{},"TransactionContext"," provider (its constructor is\nalready a plain DI token — just the app ",[503,3074,3075],{},"Context",") and a ",[503,3078,3079],{},"useExisting"," alias round it out: both\n",[503,3082,3083],{},"AppOutboxTransport"," and ",[503,3086,3087],{},"AppRelayTransport"," satisfy the abstract ",[503,3090,720],{},", so the alias\nmakes every producer's injection resolve to the outbox transport, never the relay's terminal.",[499,3093,3094,3095,3097,3098,3100,3101,3103,3104,3106],{},"That disambiguation is also why ",[503,3096,3060],{},"'s own constructor asks for ",[503,3099,3087],{}," by its\nconcrete class instead of the abstract ",[503,3102,720],{}," — this module binds that abstract token\nto ",[503,3105,3083],{},", so injecting the exact terminal class sidesteps the ambiguity instead of tripping\nover the same alias:",[548,3108,3111],{"className":550,"code":3109,"filename":3110,"language":553,"meta":554,"style":554},"import { Module, TransactionContext } from \"@heximon\u002Fruntime\";\nimport { IntegrationEventTransport } from \"@heximon\u002Fqueue\";\nimport { DatabaseModule } from \"..\u002Fdatabase\u002Fdatabase.module\";\nimport { AppOutboxRelay, AppOutboxStore, AppOutboxTransport, AppRelayTransport } from \".\u002Foutbox\";\n\nexport class OutboxModule extends Module({\n  imports: [DatabaseModule],\n  providers: [\n    AppOutboxStore,\n    AppRelayTransport,\n    AppOutboxRelay,\n    AppOutboxTransport,\n    { provide: IntegrationEventTransport, useExisting: AppOutboxTransport },\n    TransactionContext,\n  ],\n  exports: [AppOutboxStore, AppRelayTransport, AppOutboxRelay, AppOutboxTransport, IntegrationEventTransport],\n}) {}\n","src\u002Foutbox\u002Foutbox.module.ts",[503,3112,3113,3137,3157,3179,3213,3217,3234,3246,3254,3261,3268,3275,3282,3306,3313,3320,3348],{"__ignoreMap":554},[558,3114,3115,3117,3119,3121,3123,3125,3127,3129,3131,3133,3135],{"class":560,"line":561},[558,3116,565],{"class":564},[558,3118,569],{"class":568},[558,3120,758],{"class":572},[558,3122,702],{"class":568},[558,3124,2505],{"class":572},[558,3126,576],{"class":568},[558,3128,579],{"class":564},[558,3130,582],{"class":568},[558,3132,767],{"class":585},[558,3134,589],{"class":568},[558,3136,592],{"class":568},[558,3138,3139,3141,3143,3145,3147,3149,3151,3153,3155],{"class":560,"line":595},[558,3140,565],{"class":564},[558,3142,569],{"class":568},[558,3144,2579],{"class":572},[558,3146,576],{"class":568},[558,3148,579],{"class":564},[558,3150,582],{"class":568},[558,3152,2593],{"class":585},[558,3154,589],{"class":568},[558,3156,592],{"class":568},[558,3158,3159,3161,3163,3166,3168,3170,3172,3175,3177],{"class":560,"line":602},[558,3160,565],{"class":564},[558,3162,569],{"class":568},[558,3164,3165],{"class":572}," DatabaseModule",[558,3167,576],{"class":568},[558,3169,579],{"class":564},[558,3171,582],{"class":568},[558,3173,3174],{"class":585},"..\u002Fdatabase\u002Fdatabase.module",[558,3176,589],{"class":568},[558,3178,592],{"class":568},[558,3180,3181,3183,3185,3187,3189,3191,3193,3196,3198,3200,3202,3204,3206,3209,3211],{"class":560,"line":619},[558,3182,565],{"class":564},[558,3184,569],{"class":568},[558,3186,2814],{"class":572},[558,3188,702],{"class":568},[558,3190,2681],{"class":572},[558,3192,702],{"class":568},[558,3194,3195],{"class":572}," AppOutboxTransport",[558,3197,702],{"class":568},[558,3199,2755],{"class":572},[558,3201,576],{"class":568},[558,3203,579],{"class":564},[558,3205,582],{"class":568},[558,3207,3208],{"class":585},".\u002Foutbox",[558,3210,589],{"class":568},[558,3212,592],{"class":568},[558,3214,3215],{"class":560,"line":637},[558,3216,599],{"emptyLinePlaceholder":598},[558,3218,3219,3221,3223,3226,3228,3230,3232],{"class":560,"line":651},[558,3220,605],{"class":564},[558,3222,681],{"class":608},[558,3224,3225],{"class":612}," OutboxModule",[558,3227,687],{"class":608},[558,3229,758],{"class":832},[558,3231,835],{"class":572},[558,3233,838],{"class":568},[558,3235,3236,3239,3241,3244],{"class":560,"line":665},[558,3237,3238],{"class":625},"  imports",[558,3240,629],{"class":568},[558,3242,3243],{"class":572}," [DatabaseModule]",[558,3245,1334],{"class":568},[558,3247,3248,3250,3252],{"class":560,"line":671},[558,3249,2115],{"class":625},[558,3251,629],{"class":568},[558,3253,1830],{"class":572},[558,3255,3256,3259],{"class":560,"line":676},[558,3257,3258],{"class":572},"    AppOutboxStore",[558,3260,1334],{"class":568},[558,3262,3263,3266],{"class":560,"line":1039},[558,3264,3265],{"class":572},"    AppRelayTransport",[558,3267,1334],{"class":568},[558,3269,3270,3273],{"class":560,"line":1049},[558,3271,3272],{"class":572},"    AppOutboxRelay",[558,3274,1334],{"class":568},[558,3276,3277,3280],{"class":560,"line":1063},[558,3278,3279],{"class":572},"    AppOutboxTransport",[558,3281,1334],{"class":568},[558,3283,3284,3287,3290,3292,3294,3296,3299,3301,3304],{"class":560,"line":1076},[558,3285,3286],{"class":568},"    {",[558,3288,3289],{"class":625}," provide",[558,3291,629],{"class":568},[558,3293,2579],{"class":572},[558,3295,702],{"class":568},[558,3297,3298],{"class":625}," useExisting",[558,3300,629],{"class":568},[558,3302,3303],{"class":572}," AppOutboxTransport ",[558,3305,858],{"class":568},[558,3307,3308,3311],{"class":560,"line":1081},[558,3309,3310],{"class":572},"    TransactionContext",[558,3312,1334],{"class":568},[558,3314,3315,3318],{"class":560,"line":1086},[558,3316,3317],{"class":572},"  ]",[558,3319,1334],{"class":568},[558,3321,3322,3324,3326,3329,3331,3333,3335,3337,3339,3341,3343,3346],{"class":560,"line":1113},[558,3323,2162],{"class":625},[558,3325,629],{"class":568},[558,3327,3328],{"class":572}," [AppOutboxStore",[558,3330,702],{"class":568},[558,3332,2755],{"class":572},[558,3334,702],{"class":568},[558,3336,2814],{"class":572},[558,3338,702],{"class":568},[558,3340,3195],{"class":572},[558,3342,702],{"class":568},[558,3344,3345],{"class":572}," IntegrationEventTransport]",[558,3347,1334],{"class":568},[558,3349,3350,3352,3354],{"class":560,"line":1131},[558,3351,882],{"class":568},[558,3353,885],{"class":572},[558,3355,888],{"class":568},[499,3357,3358,3359,3361,3362,3365,3366,3368],{},"The producer module imports ",[503,3360,3050],{}," and lists its own typed event under ",[503,3363,3364],{},"integration: { events }"," —\nno other change is needed; the producer's ",[503,3367,716],{}," now routes through the shared outbox transport:",[548,3370,3373],{"className":550,"code":3371,"filename":3372,"language":553,"meta":554,"style":554},"import { Module } from \"@heximon\u002Fruntime\";\nimport { DatabaseModule } from \"..\u002Fdatabase\u002Fdatabase.module\";\nimport { OrderPlaced } from \".\u002Fevents\";\nimport { OrderRepository } from \".\u002Forder.repository\";\nimport { OrdersController } from \".\u002Forders.controller\";\nimport { OutboxModule } from \"..\u002Foutbox\u002Foutbox.module\";\n\nexport class OrdersModule extends Module({\n  imports: [DatabaseModule, OutboxModule],\n  providers: [OrderRepository],\n  http: { controllers: [OrdersController] },\n  integration: { events: [OrderPlaced] },\n  exports: [OrderRepository],\n}) {}\n","src\u002Forders\u002Forders.module.ts",[503,3374,3375,3395,3415,3436,3458,3480,3501,3505,3522,3538,3549,3566,3583,3593],{"__ignoreMap":554},[558,3376,3377,3379,3381,3383,3385,3387,3389,3391,3393],{"class":560,"line":561},[558,3378,565],{"class":564},[558,3380,569],{"class":568},[558,3382,758],{"class":572},[558,3384,576],{"class":568},[558,3386,579],{"class":564},[558,3388,582],{"class":568},[558,3390,767],{"class":585},[558,3392,589],{"class":568},[558,3394,592],{"class":568},[558,3396,3397,3399,3401,3403,3405,3407,3409,3411,3413],{"class":560,"line":595},[558,3398,565],{"class":564},[558,3400,569],{"class":568},[558,3402,3165],{"class":572},[558,3404,576],{"class":568},[558,3406,579],{"class":564},[558,3408,582],{"class":568},[558,3410,3174],{"class":585},[558,3412,589],{"class":568},[558,3414,592],{"class":568},[558,3416,3417,3419,3421,3424,3426,3428,3430,3432,3434],{"class":560,"line":602},[558,3418,565],{"class":564},[558,3420,569],{"class":568},[558,3422,3423],{"class":572}," OrderPlaced",[558,3425,576],{"class":568},[558,3427,579],{"class":564},[558,3429,582],{"class":568},[558,3431,788],{"class":585},[558,3433,589],{"class":568},[558,3435,592],{"class":568},[558,3437,3438,3440,3442,3445,3447,3449,3451,3454,3456],{"class":560,"line":619},[558,3439,565],{"class":564},[558,3441,569],{"class":568},[558,3443,3444],{"class":572}," OrderRepository",[558,3446,576],{"class":568},[558,3448,579],{"class":564},[558,3450,582],{"class":568},[558,3452,3453],{"class":585},".\u002Forder.repository",[558,3455,589],{"class":568},[558,3457,592],{"class":568},[558,3459,3460,3462,3464,3467,3469,3471,3473,3476,3478],{"class":560,"line":637},[558,3461,565],{"class":564},[558,3463,569],{"class":568},[558,3465,3466],{"class":572}," OrdersController",[558,3468,576],{"class":568},[558,3470,579],{"class":564},[558,3472,582],{"class":568},[558,3474,3475],{"class":585},".\u002Forders.controller",[558,3477,589],{"class":568},[558,3479,592],{"class":568},[558,3481,3482,3484,3486,3488,3490,3492,3494,3497,3499],{"class":560,"line":651},[558,3483,565],{"class":564},[558,3485,569],{"class":568},[558,3487,3225],{"class":572},[558,3489,576],{"class":568},[558,3491,579],{"class":564},[558,3493,582],{"class":568},[558,3495,3496],{"class":585},"..\u002Foutbox\u002Foutbox.module",[558,3498,589],{"class":568},[558,3500,592],{"class":568},[558,3502,3503],{"class":560,"line":665},[558,3504,599],{"emptyLinePlaceholder":598},[558,3506,3507,3509,3511,3514,3516,3518,3520],{"class":560,"line":671},[558,3508,605],{"class":564},[558,3510,681],{"class":608},[558,3512,3513],{"class":612}," OrdersModule",[558,3515,687],{"class":608},[558,3517,758],{"class":832},[558,3519,835],{"class":572},[558,3521,838],{"class":568},[558,3523,3524,3526,3528,3531,3533,3536],{"class":560,"line":676},[558,3525,3238],{"class":625},[558,3527,629],{"class":568},[558,3529,3530],{"class":572}," [DatabaseModule",[558,3532,702],{"class":568},[558,3534,3535],{"class":572}," OutboxModule]",[558,3537,1334],{"class":568},[558,3539,3540,3542,3544,3547],{"class":560,"line":1039},[558,3541,2115],{"class":625},[558,3543,629],{"class":568},[558,3545,3546],{"class":572}," [OrderRepository]",[558,3548,1334],{"class":568},[558,3550,3551,3553,3555,3557,3559,3561,3564],{"class":560,"line":1049},[558,3552,843],{"class":625},[558,3554,629],{"class":568},[558,3556,569],{"class":568},[558,3558,850],{"class":625},[558,3560,629],{"class":568},[558,3562,3563],{"class":572}," [OrdersController] ",[558,3565,858],{"class":568},[558,3567,3568,3570,3572,3574,3576,3578,3581],{"class":560,"line":1063},[558,3569,863],{"class":625},[558,3571,629],{"class":568},[558,3573,569],{"class":568},[558,3575,870],{"class":625},[558,3577,629],{"class":568},[558,3579,3580],{"class":572}," [OrderPlaced] ",[558,3582,858],{"class":568},[558,3584,3585,3587,3589,3591],{"class":560,"line":1076},[558,3586,2162],{"class":625},[558,3588,629],{"class":568},[558,3590,3546],{"class":572},[558,3592,1334],{"class":568},[558,3594,3595,3597,3599],{"class":560,"line":1081},[558,3596,882],{"class":568},[558,3598,885],{"class":572},[558,3600,888],{"class":568},[499,3602,3603,3604,3607],{},"Delivery is ",[508,3605,3606],{},"at-least-once"," (a crash between dispatch and row deletion can re-deliver), so handlers\nshould be idempotent — dedup on the event id or the aggregate id before acting.",[532,3609,3611],{"id":3610},"swap-to-cloudflare-queue-in-production","Swap to Cloudflare Queue in production",[499,3613,3614,3615,3618,3619,3622,3623,3626,3627,3630],{},"The handler is bound to the event name, not to a transport, so the only thing that changes is the\ntransport the producer publishes through. Bind ",[503,3616,3617],{},"CloudflareQueueIntegrationEventTransport","\n(",[503,3620,3621],{},"@heximon\u002Fqueue\u002Fcloudflare",") instead of relying on the in-process memory default, and let\n",[503,3624,3625],{},"CloudflareQueueConsumer"," drain each batch in the worker's ",[503,3628,3629],{},"queue(batch, env, ctx)"," hook onto\nthe same handlers you already wired.",[499,3632,3633],{},"The split is the point: your business logic — the typed event, the handler, the email — is identical in\ndev and production, so you develop with zero infrastructure and deploy without rewriting the work.",[532,3635,3637],{"id":3636},"see-also","See also",[3639,3640,3641,3647,3652,3657,3666],"ul",{},[3642,3643,3644,3646],"li",{},[524,3645,151],{"href":152}," — the base transport, channel dispatch, and the memory and Cloudflare\nadapters in depth.",[3642,3648,3649,3651],{},[524,3650,146],{"href":147}," — decouple features in-process with the event bus when the work stays\ninside one request and one context, with no queue.",[3642,3653,3654,3656],{},[524,3655,228],{"href":229}," — model the aggregates and domain events that integration\nevents are published from.",[3642,3658,3659,3662,3663,3665],{},[524,3660,529],{"href":526,"rel":3661},[528],"\n— the full runnable app this recipe is drawn from: the sign-up endpoint, the welcome-email handler, a\nswappable email transport, and a test that drives ",[503,3664,517],{}," → transport delivery → captured email\nend-to-end.",[3642,3667,3668,3671],{},[524,3669,2295],{"href":2293,"rel":3670},[528],"\n— the reliable integration tier end to end: an order controller that saves the aggregate and publishes\nthe typed event in one transaction, an outbox relay that drains and dispatches after the commit, and a\ntest proving that a rolled-back order delivers no event.",[3673,3674,3675],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":554,"searchDepth":595,"depth":595,"links":3677},[3678,3679,3680,3681,3682,3683,3684,3685,3686],{"id":534,"depth":595,"text":535},{"id":728,"depth":595,"text":729},{"id":902,"depth":595,"text":903},{"id":1458,"depth":595,"text":1459},{"id":1988,"depth":595,"text":1989},{"id":2193,"depth":595,"text":2194},{"id":2259,"depth":595,"text":2260},{"id":3610,"depth":595,"text":3611},{"id":3636,"depth":595,"text":3637},"Move work off the request path with a typed IntegrationEvent producer, an IntegrationEventHandler consumer, an in-process MemoryIntegrationEventTransport default, and an optional transactional-outbox tier for at-least-once delivery.","md",null,{},{"icon":464},{"title":461,"description":3687},"m_F8YsSHXkJfn-kSPTFB2NHJL9RyDztw0aIQLbXhyM0",[3695,3697],{"title":457,"path":458,"stem":459,"description":3696,"icon":100,"children":-1},"Protect routes end-to-end with IdentityKeyPair, JWTFactory, JWTVerifier, PasswordHashingAlgorithm, AuthContext, JWTAuthMiddleware, and scope guards — register, login, and a scope-guarded endpoint.",{"title":466,"path":467,"stem":468,"description":3698,"icon":149,"children":-1},"Wire an event-driven module with EventBus, EventHandler and NotificationHandler, the events namespace, DomainEvents, and IntegrationEventHandler across the in-process, domain, and integration tiers.",1783300761903]