[{"data":1,"prerenderedAt":4557},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-events":493,"-docs-capabilities-events-surround":4552},[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":146,"body":495,"description":4545,"extension":4546,"links":4547,"meta":4548,"navigation":4549,"path":147,"seo":4550,"stem":148,"__hash__":4551},"docs\u002Fdocs\u002F03.capabilities\u002F02.events.md",{"type":496,"value":497,"toc":4526},"minimark",[498,511,514,589,592,597,620,691,698,853,858,868,1093,1135,1139,1161,1388,1415,1419,1429,1682,1690,1694,1713,1833,1842,2037,2041,2051,2486,2509,2513,2530,2902,2916,2920,2958,3199,3203,3229,3235,3365,3369,3386,3538,3542,3570,4019,4025,4029,4041,4245,4260,4397,4409,4413,4424,4437,4441,4444,4467,4477,4481,4522],[499,500,501,502,506,507,510],"p",{},"When one feature has to react to something another feature did — send a welcome email after a sign-up,\nrecord a metric when an order ships — the obvious move is to call straight across: the sign-up code\ninvokes the mail service. Do that a few times and your modules are knotted together; the sign-up\nfeature can't compile without the mail feature, and you can't test either alone. Events break that knot:\na feature ",[503,504,505],"strong",{},"publishes"," what happened and walks away, and any number of features ",[503,508,509],{},"subscribe",". The\npublisher never imports a subscriber — the only thing connecting them is the event's shape.",[499,512,513],{},"Heximon gives you three event tiers, each for a different reach. They build on one another, so pick the\nsmallest one that does the job:",[515,516,517,537],"table",{},[518,519,520],"thead",{},[521,522,523,528,531,534],"tr",{},[524,525,527],"th",{"align":526},"left","Tier",[524,529,530],{"align":526},"Reach",[524,532,533],{"align":526},"Delivery",[524,535,536],{"align":526},"When to use",[538,539,540,557,573],"tbody",{},[521,541,542,548,551,554],{},[543,544,545],"td",{"align":526},[503,546,547],{},"In-process",[543,549,550],{"align":526},"Same app",[543,552,553],{"align":526},"Synchronous, awaited",[543,555,556],{"align":526},"Decouple features in one app — notifications, logging, side effects",[521,558,559,564,567,570],{},[543,560,561],{"align":526},[503,562,563],{},"Domain",[543,565,566],{"align":526},"Same app, after a save",[543,568,569],{"align":526},"Synchronous, flushed on demand",[543,571,572],{"align":526},"React to state changes an aggregate recorded, within one bounded context",[521,574,575,580,583,586],{},[543,576,577],{"align":526},[503,578,579],{},"Integration",[543,581,582],{"align":526},"Across services",[543,584,585],{"align":526},"Async, queue-backed",[543,587,588],{"align":526},"Communicate between bounded contexts or separate services",[499,590,591],{},"The tiers share one substrate, so promoting from one to the next is cheap. Domain events ride the same\nclass-identity dispatch the in-process bus uses; integration events ride the same queue channels raw\nqueue handlers use.",[593,594,596],"h2",{"id":595},"in-process-events","In-process events",[499,598,599,600,604,605,608,609,612,613,608,616,619],{},"The lowest tier is the ",[601,602,603],"code",{},"EventBus",": a publish\u002Fsubscribe bus for decoupling features inside one running\napp. It keys events two ways — by ",[503,606,607],{},"class identity"," (",[601,610,611],{},"emit(new OrderPlacedEvent(...))",") or by a ",[503,614,615],{},"string\nname",[601,617,618],{},"emit(\"shop.order.audited\", payload)",") — and it's a core provider, so you inject it by class\nidentity with no module to import.",[621,622,623,648,663,677],"code-group",{},[624,625,631],"pre",{"className":626,"code":627,"filename":628,"language":629,"meta":630,"style":630},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fevents\n","pnpm","bash","",[601,632,633],{"__ignoreMap":630},[634,635,638,641,645],"span",{"class":636,"line":637},"line",1,[634,639,628],{"class":640},"sBMFI",[634,642,644],{"class":643},"sfazB"," add",[634,646,647],{"class":643}," @heximon\u002Fevents\n",[624,649,652],{"className":626,"code":650,"filename":651,"language":629,"meta":630,"style":630},"npm install @heximon\u002Fevents\n","npm",[601,653,654],{"__ignoreMap":630},[634,655,656,658,661],{"class":636,"line":637},[634,657,651],{"class":640},[634,659,660],{"class":643}," install",[634,662,647],{"class":643},[624,664,667],{"className":626,"code":665,"filename":666,"language":629,"meta":630,"style":630},"yarn add @heximon\u002Fevents\n","yarn",[601,668,669],{"__ignoreMap":630},[634,670,671,673,675],{"class":636,"line":637},[634,672,666],{"class":640},[634,674,644],{"class":643},[634,676,647],{"class":643},[624,678,681],{"className":626,"code":679,"filename":680,"language":629,"meta":630,"style":630},"bun add @heximon\u002Fevents\n","bun",[601,682,683],{"__ignoreMap":630},[634,684,685,687,689],{"class":636,"line":637},[634,686,680],{"class":640},[634,688,644],{"class":643},[634,690,647],{"class":643},[499,692,693,694,697],{},"Register the events compiler plugin alongside the HTTP plugin in ",[601,695,696],{},"heximon.config.ts",":",[624,699,703],{"className":700,"code":701,"filename":696,"language":702,"meta":630,"style":630},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { EventEmitterPlugin } from \"@heximon\u002Fevents\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new HttpPlugin(), new EventEmitterPlugin()],\n});\n","ts",[601,704,705,737,760,783,790,808,842],{"__ignoreMap":630},[634,706,707,711,715,719,722,725,728,731,734],{"class":636,"line":637},[634,708,710],{"class":709},"s7zQu","import",[634,712,714],{"class":713},"sMK4o"," {",[634,716,718],{"class":717},"sTEyZ"," defineHeximonConfig",[634,720,721],{"class":713}," }",[634,723,724],{"class":709}," from",[634,726,727],{"class":713}," \"",[634,729,730],{"class":643},"@heximon\u002Fbuild",[634,732,733],{"class":713},"\"",[634,735,736],{"class":713},";\n",[634,738,740,742,744,747,749,751,753,756,758],{"class":636,"line":739},2,[634,741,710],{"class":709},[634,743,714],{"class":713},[634,745,746],{"class":717}," EventEmitterPlugin",[634,748,721],{"class":713},[634,750,724],{"class":709},[634,752,727],{"class":713},[634,754,755],{"class":643},"@heximon\u002Fevents\u002Fcompiler",[634,757,733],{"class":713},[634,759,736],{"class":713},[634,761,763,765,767,770,772,774,776,779,781],{"class":636,"line":762},3,[634,764,710],{"class":709},[634,766,714],{"class":713},[634,768,769],{"class":717}," HttpPlugin",[634,771,721],{"class":713},[634,773,724],{"class":709},[634,775,727],{"class":713},[634,777,778],{"class":643},"@heximon\u002Fhttp\u002Fcompiler",[634,780,733],{"class":713},[634,782,736],{"class":713},[634,784,786],{"class":636,"line":785},4,[634,787,789],{"emptyLinePlaceholder":788},true,"\n",[634,791,793,796,799,802,805],{"class":636,"line":792},5,[634,794,795],{"class":709},"export",[634,797,798],{"class":709}," default",[634,800,718],{"class":801},"s2Zo4",[634,803,804],{"class":717},"(",[634,806,807],{"class":713},"{\n",[634,809,811,815,817,820,823,825,828,831,834,836,839],{"class":636,"line":810},6,[634,812,814],{"class":813},"swJcz","  plugins",[634,816,697],{"class":713},[634,818,819],{"class":717}," [",[634,821,822],{"class":713},"new",[634,824,769],{"class":801},[634,826,827],{"class":717},"()",[634,829,830],{"class":713},",",[634,832,833],{"class":713}," new",[634,835,746],{"class":801},[634,837,838],{"class":717},"()]",[634,840,841],{"class":713},",\n",[634,843,845,848,851],{"class":636,"line":844},7,[634,846,847],{"class":713},"}",[634,849,850],{"class":717},")",[634,852,736],{"class":713},[854,855,857],"h3",{"id":856},"define-a-class-tier-event","Define a class-tier event",[499,859,860,861,864,865,867],{},"A class-tier event is a plain class whose constructor parameters carry its payload. Its ",[503,862,863],{},"class identity\nis the dispatch token"," — an ",[601,866,611],{}," routes to every handler bound to that\nclass. No string keys, no central registry: the class itself is the contract.",[624,869,872],{"className":700,"code":870,"filename":871,"language":702,"meta":630,"style":630},"import { BaseEvent } from \"@heximon\u002Fevents\";\n\nexport class OrderPlacedEvent extends BaseEvent {\n  constructor(\n    public readonly orderId: string,\n    public readonly customerEmail: string,\n    public readonly lineItems: readonly OrderLineItem[],\n  ) {\n    super();\n  }\n\n  public describe(): string {\n    return `order ${this.orderId} (${this.lineItems.length} item(s)) for ${this.customerEmail}`;\n  }\n}\n","order-events.ts",[601,873,874,896,900,919,927,946,961,982,990,1000,1006,1011,1027,1082,1087],{"__ignoreMap":630},[634,875,876,878,880,883,885,887,889,892,894],{"class":636,"line":637},[634,877,710],{"class":709},[634,879,714],{"class":713},[634,881,882],{"class":717}," BaseEvent",[634,884,721],{"class":713},[634,886,724],{"class":709},[634,888,727],{"class":713},[634,890,891],{"class":643},"@heximon\u002Fevents",[634,893,733],{"class":713},[634,895,736],{"class":713},[634,897,898],{"class":636,"line":739},[634,899,789],{"emptyLinePlaceholder":788},[634,901,902,904,908,911,914,916],{"class":636,"line":762},[634,903,795],{"class":709},[634,905,907],{"class":906},"spNyl"," class",[634,909,910],{"class":640}," OrderPlacedEvent",[634,912,913],{"class":906}," extends",[634,915,882],{"class":640},[634,917,918],{"class":713}," {\n",[634,920,921,924],{"class":636,"line":785},[634,922,923],{"class":906},"  constructor",[634,925,926],{"class":713},"(\n",[634,928,929,932,935,939,941,944],{"class":636,"line":792},[634,930,931],{"class":906},"    public",[634,933,934],{"class":906}," readonly",[634,936,938],{"class":937},"sHdIc"," orderId",[634,940,697],{"class":713},[634,942,943],{"class":640}," string",[634,945,841],{"class":713},[634,947,948,950,952,955,957,959],{"class":636,"line":810},[634,949,931],{"class":906},[634,951,934],{"class":906},[634,953,954],{"class":937}," customerEmail",[634,956,697],{"class":713},[634,958,943],{"class":640},[634,960,841],{"class":713},[634,962,963,965,967,970,972,974,977,980],{"class":636,"line":844},[634,964,931],{"class":906},[634,966,934],{"class":906},[634,968,969],{"class":937}," lineItems",[634,971,697],{"class":713},[634,973,934],{"class":906},[634,975,976],{"class":640}," OrderLineItem",[634,978,979],{"class":717},"[]",[634,981,841],{"class":713},[634,983,985,988],{"class":636,"line":984},8,[634,986,987],{"class":713},"  )",[634,989,918],{"class":713},[634,991,993,996,998],{"class":636,"line":992},9,[634,994,995],{"class":717},"    super",[634,997,827],{"class":813},[634,999,736],{"class":713},[634,1001,1003],{"class":636,"line":1002},10,[634,1004,1005],{"class":713},"  }\n",[634,1007,1009],{"class":636,"line":1008},11,[634,1010,789],{"emptyLinePlaceholder":788},[634,1012,1014,1017,1020,1023,1025],{"class":636,"line":1013},12,[634,1015,1016],{"class":906},"  public",[634,1018,1019],{"class":813}," describe",[634,1021,1022],{"class":713},"():",[634,1024,943],{"class":640},[634,1026,918],{"class":713},[634,1028,1030,1033,1036,1039,1042,1045,1048,1050,1052,1054,1056,1059,1062,1065,1067,1070,1072,1074,1077,1080],{"class":636,"line":1029},13,[634,1031,1032],{"class":709},"    return",[634,1034,1035],{"class":713}," `",[634,1037,1038],{"class":643},"order ",[634,1040,1041],{"class":713},"${",[634,1043,1044],{"class":713},"this.",[634,1046,1047],{"class":717},"orderId",[634,1049,847],{"class":713},[634,1051,608],{"class":643},[634,1053,1041],{"class":713},[634,1055,1044],{"class":713},[634,1057,1058],{"class":717},"lineItems",[634,1060,1061],{"class":713},".",[634,1063,1064],{"class":717},"length",[634,1066,847],{"class":713},[634,1068,1069],{"class":643}," item(s)) for ",[634,1071,1041],{"class":713},[634,1073,1044],{"class":713},[634,1075,1076],{"class":717},"customerEmail",[634,1078,1079],{"class":713},"}`",[634,1081,736],{"class":713},[634,1083,1085],{"class":636,"line":1084},14,[634,1086,1005],{"class":713},[634,1088,1090],{"class":636,"line":1089},15,[634,1091,1092],{"class":713},"}\n",[499,1094,1095,1096,1099,1100,1103,1104,1107,1108,1111,1112,1114,1115,1117,1118,1124,1125,1128,1129,1134],{},"Each event extends ",[601,1097,1098],{},"BaseEvent",", the shipped class-tier base. The bus dispatches by reading\n",[601,1101,1102],{},"event.constructor[\"~eventId\"]",", but TypeScript widens an instance's ",[601,1105,1106],{},"constructor"," to ",[601,1109,1110],{},"Function",", so a\nplain class wouldn't type-check as emittable — ",[601,1113,1098],{}," carries that stamp at the type level so\n",[601,1116,611],{}," needs no cast. An app built on ",[1119,1120,1121],"a",{"href":229},[601,1122,1123],{},"@heximon\u002Fdomain"," gets\nthis for free — its ",[601,1126,1127],{},"DomainEvent"," base ",[503,1130,1131,1132],{},"extends ",[601,1133,1098],{}," — which is exactly why domain events ride\nthis same class tier.",[854,1136,1138],{"id":1137},"handle-a-class-tier-event-serially","Handle a class-tier event serially",[499,1140,1141,1144,1145,1148,1149,1152,1153,1156,1157,1160],{},[601,1142,1143],{},"implements EventHandler\u003COrderPlacedEvent>"," binds a handler to the event ",[503,1146,1147],{},"class",", and ",[601,1150,1151],{},"handle"," receives\nthe typed instance. Serial handlers run ",[503,1154,1155],{},"in declaration order, and a throw stops the rest"," — the\nexception propagates back to the caller that emitted the event, rolling back the originating work. That\nmakes serial handlers the right home for side effects on a request's success path. (",[601,1158,1159],{},"extends EventHandler\u003COrderPlacedEvent>"," binds identically — use it when you want your own base-class hierarchy on\ntop of a handler.)",[624,1162,1165],{"className":700,"code":1163,"filename":1164,"language":702,"meta":630,"style":630},"import type { EventHandler } from \"@heximon\u002Fevents\";\n\u002F\u002F The compiler reads the bound event class from the `EventHandler\u003COrderPlacedEvent>` type argument.\nimport { OrderPlacedEvent } from \"..\u002Fshop\u002Forder-events\";\n\nexport class ConfirmationEmailHandler implements EventHandler\u003COrderPlacedEvent> {\n  constructor(private readonly eventLog: EventLog) {}\n\n  public handle(event: OrderPlacedEvent): void {\n    this.eventLog.record(\n      \"confirmation-email\",\n      event.orderId,\n      `Confirmation email sent to ${event.customerEmail} for ${event.describe()}`,\n    );\n  }\n}\n","confirmation-email.handler.ts",[601,1166,1167,1191,1197,1218,1222,1247,1271,1275,1299,1314,1326,1337,1373,1380,1384],{"__ignoreMap":630},[634,1168,1169,1171,1174,1176,1179,1181,1183,1185,1187,1189],{"class":636,"line":637},[634,1170,710],{"class":709},[634,1172,1173],{"class":709}," type",[634,1175,714],{"class":713},[634,1177,1178],{"class":717}," EventHandler",[634,1180,721],{"class":713},[634,1182,724],{"class":709},[634,1184,727],{"class":713},[634,1186,891],{"class":643},[634,1188,733],{"class":713},[634,1190,736],{"class":713},[634,1192,1193],{"class":636,"line":739},[634,1194,1196],{"class":1195},"sHwdD","\u002F\u002F The compiler reads the bound event class from the `EventHandler\u003COrderPlacedEvent>` type argument.\n",[634,1198,1199,1201,1203,1205,1207,1209,1211,1214,1216],{"class":636,"line":762},[634,1200,710],{"class":709},[634,1202,714],{"class":713},[634,1204,910],{"class":717},[634,1206,721],{"class":713},[634,1208,724],{"class":709},[634,1210,727],{"class":713},[634,1212,1213],{"class":643},"..\u002Fshop\u002Forder-events",[634,1215,733],{"class":713},[634,1217,736],{"class":713},[634,1219,1220],{"class":636,"line":785},[634,1221,789],{"emptyLinePlaceholder":788},[634,1223,1224,1226,1228,1231,1234,1236,1239,1242,1245],{"class":636,"line":792},[634,1225,795],{"class":709},[634,1227,907],{"class":906},[634,1229,1230],{"class":640}," ConfirmationEmailHandler",[634,1232,1233],{"class":906}," implements",[634,1235,1178],{"class":640},[634,1237,1238],{"class":713},"\u003C",[634,1240,1241],{"class":640},"OrderPlacedEvent",[634,1243,1244],{"class":713},">",[634,1246,918],{"class":713},[634,1248,1249,1251,1253,1256,1258,1261,1263,1266,1268],{"class":636,"line":810},[634,1250,923],{"class":906},[634,1252,804],{"class":713},[634,1254,1255],{"class":906},"private",[634,1257,934],{"class":906},[634,1259,1260],{"class":937}," eventLog",[634,1262,697],{"class":713},[634,1264,1265],{"class":640}," EventLog",[634,1267,850],{"class":713},[634,1269,1270],{"class":713}," {}\n",[634,1272,1273],{"class":636,"line":844},[634,1274,789],{"emptyLinePlaceholder":788},[634,1276,1277,1279,1282,1284,1287,1289,1291,1294,1297],{"class":636,"line":984},[634,1278,1016],{"class":906},[634,1280,1281],{"class":813}," handle",[634,1283,804],{"class":713},[634,1285,1286],{"class":937},"event",[634,1288,697],{"class":713},[634,1290,910],{"class":640},[634,1292,1293],{"class":713},"):",[634,1295,1296],{"class":640}," void",[634,1298,918],{"class":713},[634,1300,1301,1304,1307,1309,1312],{"class":636,"line":992},[634,1302,1303],{"class":713},"    this.",[634,1305,1306],{"class":717},"eventLog",[634,1308,1061],{"class":713},[634,1310,1311],{"class":801},"record",[634,1313,926],{"class":813},[634,1315,1316,1319,1322,1324],{"class":636,"line":1002},[634,1317,1318],{"class":713},"      \"",[634,1320,1321],{"class":643},"confirmation-email",[634,1323,733],{"class":713},[634,1325,841],{"class":713},[634,1327,1328,1331,1333,1335],{"class":636,"line":1008},[634,1329,1330],{"class":717},"      event",[634,1332,1061],{"class":713},[634,1334,1047],{"class":717},[634,1336,841],{"class":713},[634,1338,1339,1342,1345,1347,1349,1351,1353,1355,1358,1360,1362,1364,1367,1369,1371],{"class":636,"line":1013},[634,1340,1341],{"class":713},"      `",[634,1343,1344],{"class":643},"Confirmation email sent to ",[634,1346,1041],{"class":713},[634,1348,1286],{"class":717},[634,1350,1061],{"class":713},[634,1352,1076],{"class":717},[634,1354,847],{"class":713},[634,1356,1357],{"class":643}," for ",[634,1359,1041],{"class":713},[634,1361,1286],{"class":717},[634,1363,1061],{"class":713},[634,1365,1366],{"class":801},"describe",[634,1368,827],{"class":717},[634,1370,1079],{"class":713},[634,1372,841],{"class":713},[634,1374,1375,1378],{"class":636,"line":1029},[634,1376,1377],{"class":813},"    )",[634,1379,736],{"class":713},[634,1381,1382],{"class":636,"line":1084},[634,1383,1005],{"class":713},[634,1385,1386],{"class":636,"line":1089},[634,1387,1092],{"class":713},[1389,1390,1392,1399,1400,1402,1403,1406,1407,1410,1411,1414],"callout",{"type":1391},"info",[503,1393,1394,1395,1398],{},"The event class is the ",[601,1396,1397],{},"EventHandler\u003C…>"," type argument."," The compiler reads the binding from the type\nposition — ",[601,1401,1143],{}," — and bakes the routing into generated wiring, so\nboth classes are type-only here. ",[601,1404,1405],{},"import type { EventHandler }"," keeps the marker out of the runtime module\ngraph, and ",[601,1408,1409],{},"import type { OrderPlacedEvent }"," is correct when the event class is used nowhere else as a\nvalue; a plain ",[601,1412,1413],{},"import { OrderPlacedEvent }"," is equally fine.",[854,1416,1418],{"id":1417},"handle-a-class-tier-event-best-effort","Handle a class-tier event best-effort",[499,1420,1421,1424,1425,1428],{},[601,1422,1423],{},"implements NotificationHandler\u003COrderPlacedEvent>"," binds the same way, but flips the execution policy.\nNotification handlers run ",[503,1426,1427],{},"together, after the serial bucket, and their errors are collected rather\nthan thrown"," — one handler failing never rolls back the originating work, or stops its siblings. Reach\nfor these when a side effect must not be allowed to fail the request: metrics, projections,\nfire-and-forget notifications.",[624,1430,1433],{"className":700,"code":1431,"filename":1432,"language":702,"meta":630,"style":630},"import type { NotificationHandler } from \"@heximon\u002Fevents\";\nimport type { OrderPlacedEvent } from \"..\u002Fshop\u002Forder-events\";\n\nexport class OrderMetricsHandler implements NotificationHandler\u003COrderPlacedEvent> {\n  constructor(private readonly eventLog: EventLog) {}\n\n  public async handle(event: OrderPlacedEvent): Promise\u003Cvoid> {\n    const totalUnits = event.lineItems.reduce((sum, item) => sum + item.quantity, 0);\n    this.eventLog.record(\"order-metrics\", event.orderId, `Recorded orders_placed metric (${totalUnits} unit(s))`);\n  }\n}\n","order-metrics.handler.ts",[601,1434,1435,1458,1480,1484,1505,1525,1529,1560,1623,1674,1678],{"__ignoreMap":630},[634,1436,1437,1439,1441,1443,1446,1448,1450,1452,1454,1456],{"class":636,"line":637},[634,1438,710],{"class":709},[634,1440,1173],{"class":709},[634,1442,714],{"class":713},[634,1444,1445],{"class":717}," NotificationHandler",[634,1447,721],{"class":713},[634,1449,724],{"class":709},[634,1451,727],{"class":713},[634,1453,891],{"class":643},[634,1455,733],{"class":713},[634,1457,736],{"class":713},[634,1459,1460,1462,1464,1466,1468,1470,1472,1474,1476,1478],{"class":636,"line":739},[634,1461,710],{"class":709},[634,1463,1173],{"class":709},[634,1465,714],{"class":713},[634,1467,910],{"class":717},[634,1469,721],{"class":713},[634,1471,724],{"class":709},[634,1473,727],{"class":713},[634,1475,1213],{"class":643},[634,1477,733],{"class":713},[634,1479,736],{"class":713},[634,1481,1482],{"class":636,"line":762},[634,1483,789],{"emptyLinePlaceholder":788},[634,1485,1486,1488,1490,1493,1495,1497,1499,1501,1503],{"class":636,"line":785},[634,1487,795],{"class":709},[634,1489,907],{"class":906},[634,1491,1492],{"class":640}," OrderMetricsHandler",[634,1494,1233],{"class":906},[634,1496,1445],{"class":640},[634,1498,1238],{"class":713},[634,1500,1241],{"class":640},[634,1502,1244],{"class":713},[634,1504,918],{"class":713},[634,1506,1507,1509,1511,1513,1515,1517,1519,1521,1523],{"class":636,"line":792},[634,1508,923],{"class":906},[634,1510,804],{"class":713},[634,1512,1255],{"class":906},[634,1514,934],{"class":906},[634,1516,1260],{"class":937},[634,1518,697],{"class":713},[634,1520,1265],{"class":640},[634,1522,850],{"class":713},[634,1524,1270],{"class":713},[634,1526,1527],{"class":636,"line":810},[634,1528,789],{"emptyLinePlaceholder":788},[634,1530,1531,1533,1536,1538,1540,1542,1544,1546,1548,1551,1553,1556,1558],{"class":636,"line":844},[634,1532,1016],{"class":906},[634,1534,1535],{"class":906}," async",[634,1537,1281],{"class":813},[634,1539,804],{"class":713},[634,1541,1286],{"class":937},[634,1543,697],{"class":713},[634,1545,910],{"class":640},[634,1547,1293],{"class":713},[634,1549,1550],{"class":640}," Promise",[634,1552,1238],{"class":713},[634,1554,1555],{"class":640},"void",[634,1557,1244],{"class":713},[634,1559,918],{"class":713},[634,1561,1562,1565,1568,1571,1574,1576,1578,1580,1583,1585,1587,1590,1592,1595,1597,1600,1603,1606,1608,1610,1613,1615,1619,1621],{"class":636,"line":984},[634,1563,1564],{"class":906},"    const",[634,1566,1567],{"class":717}," totalUnits",[634,1569,1570],{"class":713}," =",[634,1572,1573],{"class":717}," event",[634,1575,1061],{"class":713},[634,1577,1058],{"class":717},[634,1579,1061],{"class":713},[634,1581,1582],{"class":801},"reduce",[634,1584,804],{"class":813},[634,1586,804],{"class":713},[634,1588,1589],{"class":937},"sum",[634,1591,830],{"class":713},[634,1593,1594],{"class":937}," item",[634,1596,850],{"class":713},[634,1598,1599],{"class":906}," =>",[634,1601,1602],{"class":717}," sum",[634,1604,1605],{"class":713}," +",[634,1607,1594],{"class":717},[634,1609,1061],{"class":713},[634,1611,1612],{"class":717},"quantity",[634,1614,830],{"class":713},[634,1616,1618],{"class":1617},"sbssI"," 0",[634,1620,850],{"class":813},[634,1622,736],{"class":713},[634,1624,1625,1627,1629,1631,1633,1635,1637,1640,1642,1644,1646,1648,1650,1652,1654,1657,1659,1662,1664,1667,1670,1672],{"class":636,"line":992},[634,1626,1303],{"class":713},[634,1628,1306],{"class":717},[634,1630,1061],{"class":713},[634,1632,1311],{"class":801},[634,1634,804],{"class":813},[634,1636,733],{"class":713},[634,1638,1639],{"class":643},"order-metrics",[634,1641,733],{"class":713},[634,1643,830],{"class":713},[634,1645,1573],{"class":717},[634,1647,1061],{"class":713},[634,1649,1047],{"class":717},[634,1651,830],{"class":713},[634,1653,1035],{"class":713},[634,1655,1656],{"class":643},"Recorded orders_placed metric (",[634,1658,1041],{"class":713},[634,1660,1661],{"class":717},"totalUnits",[634,1663,847],{"class":713},[634,1665,1666],{"class":643}," unit(s))",[634,1668,1669],{"class":713},"`",[634,1671,850],{"class":813},[634,1673,736],{"class":713},[634,1675,1676],{"class":636,"line":1002},[634,1677,1005],{"class":713},[634,1679,1680],{"class":636,"line":1008},[634,1681,1092],{"class":713},[499,1683,1684,1685,1689],{},"That split — serial handlers can fail the request, notification handlers can't — is the whole design.\nA failed confirmation email ",[1686,1687,1688],"em",{},"should"," fail the order; a flaky metrics write should never touch it.",[854,1691,1693],{"id":1692},"subscribe-by-name-instead","Subscribe by name instead",[499,1695,1696,1697,1700,1701,1704,1705,1708,1709,1712],{},"Some events have no single owning class — a cross-cutting audit record for ",[1686,1698,1699],{},"any"," order action, say. For\nthose, key by a ",[503,1702,1703],{},"string name",". Declare the ",[601,1706,1707],{},"name → payload"," mapping by augmenting the framework's\n",[601,1710,1711],{},"EventMap","; that one augmentation types both the publisher and every subscriber.",[624,1714,1717],{"className":700,"code":1715,"filename":1716,"language":702,"meta":630,"style":630},"export interface OrderAuditedEvent {\n  readonly orderId: string;\n  readonly action: string;\n  readonly recordedAt: string;\n}\n\n\u002F\u002F Register the name → payload so both emit() and the handler type-check.\ndeclare module \"@heximon\u002Fevents\" {\n  interface EventMap {\n    \"shop.order.audited\": OrderAuditedEvent;\n  }\n}\n","audit-event.ts",[601,1718,1719,1731,1744,1757,1770,1774,1778,1783,1799,1809,1825,1829],{"__ignoreMap":630},[634,1720,1721,1723,1726,1729],{"class":636,"line":637},[634,1722,795],{"class":709},[634,1724,1725],{"class":906}," interface",[634,1727,1728],{"class":640}," OrderAuditedEvent",[634,1730,918],{"class":713},[634,1732,1733,1736,1738,1740,1742],{"class":636,"line":739},[634,1734,1735],{"class":906},"  readonly",[634,1737,938],{"class":813},[634,1739,697],{"class":713},[634,1741,943],{"class":640},[634,1743,736],{"class":713},[634,1745,1746,1748,1751,1753,1755],{"class":636,"line":762},[634,1747,1735],{"class":906},[634,1749,1750],{"class":813}," action",[634,1752,697],{"class":713},[634,1754,943],{"class":640},[634,1756,736],{"class":713},[634,1758,1759,1761,1764,1766,1768],{"class":636,"line":785},[634,1760,1735],{"class":906},[634,1762,1763],{"class":813}," recordedAt",[634,1765,697],{"class":713},[634,1767,943],{"class":640},[634,1769,736],{"class":713},[634,1771,1772],{"class":636,"line":792},[634,1773,1092],{"class":713},[634,1775,1776],{"class":636,"line":810},[634,1777,789],{"emptyLinePlaceholder":788},[634,1779,1780],{"class":636,"line":844},[634,1781,1782],{"class":1195},"\u002F\u002F Register the name → payload so both emit() and the handler type-check.\n",[634,1784,1785,1788,1791,1793,1795,1797],{"class":636,"line":984},[634,1786,1787],{"class":906},"declare",[634,1789,1790],{"class":906}," module",[634,1792,727],{"class":713},[634,1794,891],{"class":643},[634,1796,733],{"class":713},[634,1798,918],{"class":713},[634,1800,1801,1804,1807],{"class":636,"line":992},[634,1802,1803],{"class":906},"  interface",[634,1805,1806],{"class":640}," EventMap",[634,1808,918],{"class":713},[634,1810,1811,1814,1817,1819,1821,1823],{"class":636,"line":1002},[634,1812,1813],{"class":713},"    \"",[634,1815,1816],{"class":643},"shop.order.audited",[634,1818,733],{"class":713},[634,1820,697],{"class":713},[634,1822,1728],{"class":640},[634,1824,736],{"class":713},[634,1826,1827],{"class":636,"line":1008},[634,1828,1005],{"class":713},[634,1830,1831],{"class":636,"line":1013},[634,1832,1092],{"class":713},[499,1834,1835,1836,1838,1839,1841],{},"A string-tier handler subscribes by name, and its ",[601,1837,1286],{}," parameter is typed straight from the ",[601,1840,1711],{},".\nString-tier handlers always run serially.",[624,1843,1846],{"className":700,"code":1844,"filename":1845,"language":702,"meta":630,"style":630},"import type { EventHandler } from \"@heximon\u002Fevents\";\nimport type { OrderAuditedEvent } from \"..\u002Fshop\u002Faudit-event\";\n\nexport class AuditTrailHandler implements EventHandler\u003C\"shop.order.audited\"> {\n  constructor(private readonly eventLog: EventLog) {}\n\n  public handle(event: OrderAuditedEvent): void {\n    this.eventLog.record(\"audit-trail\", event.orderId, `Audit: order ${event.action} at ${event.recordedAt}`);\n  }\n}\n","audit-trail.handler.ts",[601,1847,1848,1870,1893,1897,1922,1942,1946,1966,2029,2033],{"__ignoreMap":630},[634,1849,1850,1852,1854,1856,1858,1860,1862,1864,1866,1868],{"class":636,"line":637},[634,1851,710],{"class":709},[634,1853,1173],{"class":709},[634,1855,714],{"class":713},[634,1857,1178],{"class":717},[634,1859,721],{"class":713},[634,1861,724],{"class":709},[634,1863,727],{"class":713},[634,1865,891],{"class":643},[634,1867,733],{"class":713},[634,1869,736],{"class":713},[634,1871,1872,1874,1876,1878,1880,1882,1884,1886,1889,1891],{"class":636,"line":739},[634,1873,710],{"class":709},[634,1875,1173],{"class":709},[634,1877,714],{"class":713},[634,1879,1728],{"class":717},[634,1881,721],{"class":713},[634,1883,724],{"class":709},[634,1885,727],{"class":713},[634,1887,1888],{"class":643},"..\u002Fshop\u002Faudit-event",[634,1890,733],{"class":713},[634,1892,736],{"class":713},[634,1894,1895],{"class":636,"line":762},[634,1896,789],{"emptyLinePlaceholder":788},[634,1898,1899,1901,1903,1906,1908,1910,1912,1914,1916,1918,1920],{"class":636,"line":785},[634,1900,795],{"class":709},[634,1902,907],{"class":906},[634,1904,1905],{"class":640}," AuditTrailHandler",[634,1907,1233],{"class":906},[634,1909,1178],{"class":640},[634,1911,1238],{"class":713},[634,1913,733],{"class":713},[634,1915,1816],{"class":643},[634,1917,733],{"class":713},[634,1919,1244],{"class":713},[634,1921,918],{"class":713},[634,1923,1924,1926,1928,1930,1932,1934,1936,1938,1940],{"class":636,"line":792},[634,1925,923],{"class":906},[634,1927,804],{"class":713},[634,1929,1255],{"class":906},[634,1931,934],{"class":906},[634,1933,1260],{"class":937},[634,1935,697],{"class":713},[634,1937,1265],{"class":640},[634,1939,850],{"class":713},[634,1941,1270],{"class":713},[634,1943,1944],{"class":636,"line":810},[634,1945,789],{"emptyLinePlaceholder":788},[634,1947,1948,1950,1952,1954,1956,1958,1960,1962,1964],{"class":636,"line":844},[634,1949,1016],{"class":906},[634,1951,1281],{"class":813},[634,1953,804],{"class":713},[634,1955,1286],{"class":937},[634,1957,697],{"class":713},[634,1959,1728],{"class":640},[634,1961,1293],{"class":713},[634,1963,1296],{"class":640},[634,1965,918],{"class":713},[634,1967,1968,1970,1972,1974,1976,1978,1980,1983,1985,1987,1989,1991,1993,1995,1997,2000,2002,2004,2006,2009,2011,2014,2016,2018,2020,2023,2025,2027],{"class":636,"line":984},[634,1969,1303],{"class":713},[634,1971,1306],{"class":717},[634,1973,1061],{"class":713},[634,1975,1311],{"class":801},[634,1977,804],{"class":813},[634,1979,733],{"class":713},[634,1981,1982],{"class":643},"audit-trail",[634,1984,733],{"class":713},[634,1986,830],{"class":713},[634,1988,1573],{"class":717},[634,1990,1061],{"class":713},[634,1992,1047],{"class":717},[634,1994,830],{"class":713},[634,1996,1035],{"class":713},[634,1998,1999],{"class":643},"Audit: order ",[634,2001,1041],{"class":713},[634,2003,1286],{"class":717},[634,2005,1061],{"class":713},[634,2007,2008],{"class":717},"action",[634,2010,847],{"class":713},[634,2012,2013],{"class":643}," at ",[634,2015,1041],{"class":713},[634,2017,1286],{"class":717},[634,2019,1061],{"class":713},[634,2021,2022],{"class":717},"recordedAt",[634,2024,1079],{"class":713},[634,2026,850],{"class":813},[634,2028,736],{"class":713},[634,2030,2031],{"class":636,"line":992},[634,2032,1005],{"class":713},[634,2034,2035],{"class":636,"line":1002},[634,2036,1092],{"class":713},[854,2038,2040],{"id":2039},"publish-from-anywhere","Publish from anywhere",[499,2042,2043,2044,2046,2047,2050],{},"The publisher injects ",[601,2045,603],{}," by class identity — there's no module to add to ",[601,2048,2049],{},"imports"," — and emits\neither tier. It knows nothing about the handlers reacting; the only coupling is the event shape.",[624,2052,2055],{"className":700,"code":2053,"filename":2054,"language":702,"meta":630,"style":630},"import type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport { EventBus } from \"@heximon\u002Fevents\";\nimport { OrderPlacedEvent } from \".\u002Forder-events\";\n\nexport class ShopController implements Controller\u003C\"\u002Fshop\"> {\n  constructor(private readonly eventBus: EventBus) {}\n\n  public async placeOrder(action: Post\u003C\"\u002Forders\">): Promise\u003C{ orderId: string; status: \"placed\" }> {\n    const body = (await action.request.json()) as PlaceOrderBody;\n    const orderId = ShopController.nextOrderId();\n\n    \u002F\u002F Class tier: fan out to every handler bound to OrderPlacedEvent; emitAsync awaits them.\n    await this.eventBus.emitAsync(new OrderPlacedEvent(orderId, body.customerEmail, body.lineItems));\n\n    \u002F\u002F String tier: name + payload, typed against the augmented EventMap.\n    await this.eventBus.emitAsync(\"shop.order.audited\", {\n      orderId,\n      action: \"placed\",\n      recordedAt: new Date().toISOString(),\n    });\n\n    return { orderId, status: \"placed\" };\n  }\n}\n","shop.controller.ts",[601,2056,2057,2086,2107,2128,2132,2158,2179,2183,2243,2280,2299,2303,2308,2355,2359,2364,2389,2397,2413,2437,2447,2452,2476,2481],{"__ignoreMap":630},[634,2058,2059,2061,2063,2065,2068,2070,2073,2075,2077,2079,2082,2084],{"class":636,"line":637},[634,2060,710],{"class":709},[634,2062,1173],{"class":709},[634,2064,714],{"class":713},[634,2066,2067],{"class":717}," Controller",[634,2069,830],{"class":713},[634,2071,2072],{"class":717}," Post",[634,2074,721],{"class":713},[634,2076,724],{"class":709},[634,2078,727],{"class":713},[634,2080,2081],{"class":643},"@heximon\u002Fhttp",[634,2083,733],{"class":713},[634,2085,736],{"class":713},[634,2087,2088,2090,2092,2095,2097,2099,2101,2103,2105],{"class":636,"line":739},[634,2089,710],{"class":709},[634,2091,714],{"class":713},[634,2093,2094],{"class":717}," EventBus",[634,2096,721],{"class":713},[634,2098,724],{"class":709},[634,2100,727],{"class":713},[634,2102,891],{"class":643},[634,2104,733],{"class":713},[634,2106,736],{"class":713},[634,2108,2109,2111,2113,2115,2117,2119,2121,2124,2126],{"class":636,"line":762},[634,2110,710],{"class":709},[634,2112,714],{"class":713},[634,2114,910],{"class":717},[634,2116,721],{"class":713},[634,2118,724],{"class":709},[634,2120,727],{"class":713},[634,2122,2123],{"class":643},".\u002Forder-events",[634,2125,733],{"class":713},[634,2127,736],{"class":713},[634,2129,2130],{"class":636,"line":785},[634,2131,789],{"emptyLinePlaceholder":788},[634,2133,2134,2136,2138,2141,2143,2145,2147,2149,2152,2154,2156],{"class":636,"line":792},[634,2135,795],{"class":709},[634,2137,907],{"class":906},[634,2139,2140],{"class":640}," ShopController",[634,2142,1233],{"class":906},[634,2144,2067],{"class":640},[634,2146,1238],{"class":713},[634,2148,733],{"class":713},[634,2150,2151],{"class":643},"\u002Fshop",[634,2153,733],{"class":713},[634,2155,1244],{"class":713},[634,2157,918],{"class":713},[634,2159,2160,2162,2164,2166,2168,2171,2173,2175,2177],{"class":636,"line":810},[634,2161,923],{"class":906},[634,2163,804],{"class":713},[634,2165,1255],{"class":906},[634,2167,934],{"class":906},[634,2169,2170],{"class":937}," eventBus",[634,2172,697],{"class":713},[634,2174,2094],{"class":640},[634,2176,850],{"class":713},[634,2178,1270],{"class":713},[634,2180,2181],{"class":636,"line":844},[634,2182,789],{"emptyLinePlaceholder":788},[634,2184,2185,2187,2189,2192,2194,2196,2198,2200,2202,2204,2207,2209,2212,2214,2217,2219,2221,2223,2226,2229,2231,2233,2236,2238,2241],{"class":636,"line":984},[634,2186,1016],{"class":906},[634,2188,1535],{"class":906},[634,2190,2191],{"class":813}," placeOrder",[634,2193,804],{"class":713},[634,2195,2008],{"class":937},[634,2197,697],{"class":713},[634,2199,2072],{"class":640},[634,2201,1238],{"class":713},[634,2203,733],{"class":713},[634,2205,2206],{"class":643},"\u002Forders",[634,2208,733],{"class":713},[634,2210,2211],{"class":713},">):",[634,2213,1550],{"class":640},[634,2215,2216],{"class":713},"\u003C{",[634,2218,938],{"class":813},[634,2220,697],{"class":713},[634,2222,943],{"class":640},[634,2224,2225],{"class":713},";",[634,2227,2228],{"class":813}," status",[634,2230,697],{"class":713},[634,2232,727],{"class":713},[634,2234,2235],{"class":643},"placed",[634,2237,733],{"class":713},[634,2239,2240],{"class":713}," }>",[634,2242,918],{"class":713},[634,2244,2245,2247,2250,2252,2254,2257,2259,2261,2264,2266,2269,2272,2275,2278],{"class":636,"line":992},[634,2246,1564],{"class":906},[634,2248,2249],{"class":717}," body",[634,2251,1570],{"class":713},[634,2253,608],{"class":813},[634,2255,2256],{"class":709},"await",[634,2258,1750],{"class":717},[634,2260,1061],{"class":713},[634,2262,2263],{"class":717},"request",[634,2265,1061],{"class":713},[634,2267,2268],{"class":801},"json",[634,2270,2271],{"class":813},"()) ",[634,2273,2274],{"class":709},"as",[634,2276,2277],{"class":640}," PlaceOrderBody",[634,2279,736],{"class":713},[634,2281,2282,2284,2286,2288,2290,2292,2295,2297],{"class":636,"line":1002},[634,2283,1564],{"class":906},[634,2285,938],{"class":717},[634,2287,1570],{"class":713},[634,2289,2140],{"class":717},[634,2291,1061],{"class":713},[634,2293,2294],{"class":801},"nextOrderId",[634,2296,827],{"class":813},[634,2298,736],{"class":713},[634,2300,2301],{"class":636,"line":1008},[634,2302,789],{"emptyLinePlaceholder":788},[634,2304,2305],{"class":636,"line":1013},[634,2306,2307],{"class":1195},"    \u002F\u002F Class tier: fan out to every handler bound to OrderPlacedEvent; emitAsync awaits them.\n",[634,2309,2310,2313,2316,2319,2321,2324,2326,2328,2330,2332,2334,2336,2338,2340,2342,2344,2346,2348,2350,2353],{"class":636,"line":1029},[634,2311,2312],{"class":709},"    await",[634,2314,2315],{"class":713}," this.",[634,2317,2318],{"class":717},"eventBus",[634,2320,1061],{"class":713},[634,2322,2323],{"class":801},"emitAsync",[634,2325,804],{"class":813},[634,2327,822],{"class":713},[634,2329,910],{"class":801},[634,2331,804],{"class":813},[634,2333,1047],{"class":717},[634,2335,830],{"class":713},[634,2337,2249],{"class":717},[634,2339,1061],{"class":713},[634,2341,1076],{"class":717},[634,2343,830],{"class":713},[634,2345,2249],{"class":717},[634,2347,1061],{"class":713},[634,2349,1058],{"class":717},[634,2351,2352],{"class":813},"))",[634,2354,736],{"class":713},[634,2356,2357],{"class":636,"line":1084},[634,2358,789],{"emptyLinePlaceholder":788},[634,2360,2361],{"class":636,"line":1089},[634,2362,2363],{"class":1195},"    \u002F\u002F String tier: name + payload, typed against the augmented EventMap.\n",[634,2365,2367,2369,2371,2373,2375,2377,2379,2381,2383,2385,2387],{"class":636,"line":2366},16,[634,2368,2312],{"class":709},[634,2370,2315],{"class":713},[634,2372,2318],{"class":717},[634,2374,1061],{"class":713},[634,2376,2323],{"class":801},[634,2378,804],{"class":813},[634,2380,733],{"class":713},[634,2382,1816],{"class":643},[634,2384,733],{"class":713},[634,2386,830],{"class":713},[634,2388,918],{"class":713},[634,2390,2392,2395],{"class":636,"line":2391},17,[634,2393,2394],{"class":717},"      orderId",[634,2396,841],{"class":713},[634,2398,2400,2403,2405,2407,2409,2411],{"class":636,"line":2399},18,[634,2401,2402],{"class":813},"      action",[634,2404,697],{"class":713},[634,2406,727],{"class":713},[634,2408,2235],{"class":643},[634,2410,733],{"class":713},[634,2412,841],{"class":713},[634,2414,2416,2419,2421,2423,2426,2428,2430,2433,2435],{"class":636,"line":2415},19,[634,2417,2418],{"class":813},"      recordedAt",[634,2420,697],{"class":713},[634,2422,833],{"class":713},[634,2424,2425],{"class":801}," Date",[634,2427,827],{"class":813},[634,2429,1061],{"class":713},[634,2431,2432],{"class":801},"toISOString",[634,2434,827],{"class":813},[634,2436,841],{"class":713},[634,2438,2440,2443,2445],{"class":636,"line":2439},20,[634,2441,2442],{"class":713},"    }",[634,2444,850],{"class":813},[634,2446,736],{"class":713},[634,2448,2450],{"class":636,"line":2449},21,[634,2451,789],{"emptyLinePlaceholder":788},[634,2453,2455,2457,2459,2461,2463,2465,2467,2469,2471,2473],{"class":636,"line":2454},22,[634,2456,1032],{"class":709},[634,2458,714],{"class":713},[634,2460,938],{"class":717},[634,2462,830],{"class":713},[634,2464,2228],{"class":813},[634,2466,697],{"class":713},[634,2468,727],{"class":713},[634,2470,2235],{"class":643},[634,2472,733],{"class":713},[634,2474,2475],{"class":713}," };\n",[634,2477,2479],{"class":636,"line":2478},23,[634,2480,1005],{"class":713},[634,2482,2484],{"class":636,"line":2483},24,[634,2485,1092],{"class":713},[499,2487,2488,2490,2491,2494,2495,2498,2499,2501,2502,2504,2505,2508],{},[601,2489,2323],{}," ",[503,2492,2493],{},"awaits"," the fan-out: the serial bucket runs first (a throw surfaces back here), then the\nnotification bucket — the right contract on a request's success path. There's also ",[601,2496,2497],{},"emit",", which is\nfire-and-forget: inside a request it still completes its handler work, but never blocks the response. No\ncast is needed at the publish boundary because ",[601,2500,1241],{}," extends ",[601,2503,1098],{},", which carries the\ndispatch stamp at the type level; a DDD app emits through the ",[601,2506,2507],{},"DomainEvents"," facade, the next tier.",[854,2510,2512],{"id":2511},"intercept-serial-dispatch","Intercept serial dispatch",[499,2514,2515,2518,2519,2522,2523,2525,2526,2529],{},[601,2516,2517],{},"EventInterceptor"," wraps the serial ",[601,2520,2521],{},"EventHandler"," chain — the right home for cross-cutting behavior\nlike tracing, logging, or short-circuiting dispatch. Scope it to one event class (a type argument) or make\nit app-wide (no type argument). Only the serial ",[601,2524,2521],{}," tier is intercepted — ",[601,2527,2528],{},"NotificationHandler","\nruns outside the chain, and string-tier handlers bypass it entirely.",[624,2531,2534],{"className":700,"code":2532,"filename":2533,"language":702,"meta":630,"style":630},"import { EventClassName, EventInterceptor } from \"@heximon\u002Fevents\";\nimport { EventLog } from \".\u002Fevent-log\";\n\nexport class TraceEventsInterceptor extends EventInterceptor {\n  constructor(private readonly eventLog: EventLog) {\n    super();\n  }\n\n  public async intercept(event: object, next: () => Promise\u003Cvoid>): Promise\u003Cvoid> {\n    this.eventLog.record(\n      \"trace-events\",\n      TraceEventsInterceptor.orderIdOf(event),\n      `Traced dispatch of ${EventClassName.of(event)}`,\n    );\n\n    await next();\n  }\n\n  private static orderIdOf(event: object): string {\n    const record = event as Record\u003Cstring, unknown>;\n\n    return typeof record[\"orderId\"] === \"string\" ? record[\"orderId\"] : \"unknown\";\n  }\n}\n","trace-events.interceptor.ts",[601,2535,2536,2562,2583,2587,2602,2622,2630,2634,2638,2686,2698,2709,2727,2751,2757,2761,2771,2775,2779,2804,2834,2838,2894,2898],{"__ignoreMap":630},[634,2537,2538,2540,2542,2545,2547,2550,2552,2554,2556,2558,2560],{"class":636,"line":637},[634,2539,710],{"class":709},[634,2541,714],{"class":713},[634,2543,2544],{"class":717}," EventClassName",[634,2546,830],{"class":713},[634,2548,2549],{"class":717}," EventInterceptor",[634,2551,721],{"class":713},[634,2553,724],{"class":709},[634,2555,727],{"class":713},[634,2557,891],{"class":643},[634,2559,733],{"class":713},[634,2561,736],{"class":713},[634,2563,2564,2566,2568,2570,2572,2574,2576,2579,2581],{"class":636,"line":739},[634,2565,710],{"class":709},[634,2567,714],{"class":713},[634,2569,1265],{"class":717},[634,2571,721],{"class":713},[634,2573,724],{"class":709},[634,2575,727],{"class":713},[634,2577,2578],{"class":643},".\u002Fevent-log",[634,2580,733],{"class":713},[634,2582,736],{"class":713},[634,2584,2585],{"class":636,"line":762},[634,2586,789],{"emptyLinePlaceholder":788},[634,2588,2589,2591,2593,2596,2598,2600],{"class":636,"line":785},[634,2590,795],{"class":709},[634,2592,907],{"class":906},[634,2594,2595],{"class":640}," TraceEventsInterceptor",[634,2597,913],{"class":906},[634,2599,2549],{"class":640},[634,2601,918],{"class":713},[634,2603,2604,2606,2608,2610,2612,2614,2616,2618,2620],{"class":636,"line":792},[634,2605,923],{"class":906},[634,2607,804],{"class":713},[634,2609,1255],{"class":906},[634,2611,934],{"class":906},[634,2613,1260],{"class":937},[634,2615,697],{"class":713},[634,2617,1265],{"class":640},[634,2619,850],{"class":713},[634,2621,918],{"class":713},[634,2623,2624,2626,2628],{"class":636,"line":810},[634,2625,995],{"class":717},[634,2627,827],{"class":813},[634,2629,736],{"class":713},[634,2631,2632],{"class":636,"line":844},[634,2633,1005],{"class":713},[634,2635,2636],{"class":636,"line":984},[634,2637,789],{"emptyLinePlaceholder":788},[634,2639,2640,2642,2644,2647,2649,2651,2653,2656,2658,2661,2663,2666,2668,2670,2672,2674,2676,2678,2680,2682,2684],{"class":636,"line":992},[634,2641,1016],{"class":906},[634,2643,1535],{"class":906},[634,2645,2646],{"class":813}," intercept",[634,2648,804],{"class":713},[634,2650,1286],{"class":937},[634,2652,697],{"class":713},[634,2654,2655],{"class":640}," object",[634,2657,830],{"class":713},[634,2659,2660],{"class":801}," next",[634,2662,697],{"class":713},[634,2664,2665],{"class":713}," ()",[634,2667,1599],{"class":906},[634,2669,1550],{"class":640},[634,2671,1238],{"class":713},[634,2673,1555],{"class":640},[634,2675,2211],{"class":713},[634,2677,1550],{"class":640},[634,2679,1238],{"class":713},[634,2681,1555],{"class":640},[634,2683,1244],{"class":713},[634,2685,918],{"class":713},[634,2687,2688,2690,2692,2694,2696],{"class":636,"line":1002},[634,2689,1303],{"class":713},[634,2691,1306],{"class":717},[634,2693,1061],{"class":713},[634,2695,1311],{"class":801},[634,2697,926],{"class":813},[634,2699,2700,2702,2705,2707],{"class":636,"line":1008},[634,2701,1318],{"class":713},[634,2703,2704],{"class":643},"trace-events",[634,2706,733],{"class":713},[634,2708,841],{"class":713},[634,2710,2711,2714,2716,2719,2721,2723,2725],{"class":636,"line":1013},[634,2712,2713],{"class":717},"      TraceEventsInterceptor",[634,2715,1061],{"class":713},[634,2717,2718],{"class":801},"orderIdOf",[634,2720,804],{"class":813},[634,2722,1286],{"class":717},[634,2724,850],{"class":813},[634,2726,841],{"class":713},[634,2728,2729,2731,2734,2736,2739,2741,2744,2747,2749],{"class":636,"line":1029},[634,2730,1341],{"class":713},[634,2732,2733],{"class":643},"Traced dispatch of ",[634,2735,1041],{"class":713},[634,2737,2738],{"class":717},"EventClassName",[634,2740,1061],{"class":713},[634,2742,2743],{"class":801},"of",[634,2745,2746],{"class":717},"(event)",[634,2748,1079],{"class":713},[634,2750,841],{"class":713},[634,2752,2753,2755],{"class":636,"line":1084},[634,2754,1377],{"class":813},[634,2756,736],{"class":713},[634,2758,2759],{"class":636,"line":1089},[634,2760,789],{"emptyLinePlaceholder":788},[634,2762,2763,2765,2767,2769],{"class":636,"line":2366},[634,2764,2312],{"class":709},[634,2766,2660],{"class":801},[634,2768,827],{"class":813},[634,2770,736],{"class":713},[634,2772,2773],{"class":636,"line":2391},[634,2774,1005],{"class":713},[634,2776,2777],{"class":636,"line":2399},[634,2778,789],{"emptyLinePlaceholder":788},[634,2780,2781,2784,2787,2790,2792,2794,2796,2798,2800,2802],{"class":636,"line":2415},[634,2782,2783],{"class":906},"  private",[634,2785,2786],{"class":906}," static",[634,2788,2789],{"class":813}," orderIdOf",[634,2791,804],{"class":713},[634,2793,1286],{"class":937},[634,2795,697],{"class":713},[634,2797,2655],{"class":640},[634,2799,1293],{"class":713},[634,2801,943],{"class":640},[634,2803,918],{"class":713},[634,2805,2806,2808,2811,2813,2815,2818,2821,2823,2826,2828,2831],{"class":636,"line":2439},[634,2807,1564],{"class":906},[634,2809,2810],{"class":717}," record",[634,2812,1570],{"class":713},[634,2814,1573],{"class":717},[634,2816,2817],{"class":709}," as",[634,2819,2820],{"class":640}," Record",[634,2822,1238],{"class":713},[634,2824,2825],{"class":640},"string",[634,2827,830],{"class":713},[634,2829,2830],{"class":640}," unknown",[634,2832,2833],{"class":713},">;\n",[634,2835,2836],{"class":636,"line":2449},[634,2837,789],{"emptyLinePlaceholder":788},[634,2839,2840,2842,2845,2847,2850,2852,2854,2856,2859,2862,2864,2866,2868,2871,2873,2875,2877,2879,2881,2883,2885,2887,2890,2892],{"class":636,"line":2454},[634,2841,1032],{"class":709},[634,2843,2844],{"class":713}," typeof",[634,2846,2810],{"class":717},[634,2848,2849],{"class":813},"[",[634,2851,733],{"class":713},[634,2853,1047],{"class":643},[634,2855,733],{"class":713},[634,2857,2858],{"class":813},"] ",[634,2860,2861],{"class":713},"===",[634,2863,727],{"class":713},[634,2865,2825],{"class":643},[634,2867,733],{"class":713},[634,2869,2870],{"class":713}," ?",[634,2872,2810],{"class":717},[634,2874,2849],{"class":813},[634,2876,733],{"class":713},[634,2878,1047],{"class":643},[634,2880,733],{"class":713},[634,2882,2858],{"class":813},[634,2884,697],{"class":713},[634,2886,727],{"class":713},[634,2888,2889],{"class":643},"unknown",[634,2891,733],{"class":713},[634,2893,736],{"class":713},[634,2895,2896],{"class":636,"line":2478},[634,2897,1005],{"class":713},[634,2899,2900],{"class":636,"line":2483},[634,2901,1092],{"class":713},[499,2903,2904,2907,2908,2911,2912,2915],{},[601,2905,2906],{},"event.constructor.name"," mangles under production minification — every vendor deploy target ships\nminified — so tracing reads ",[601,2909,2910],{},"EventClassName.of(event)"," instead, the compiler-stamped name that survives it\n(falling back to ",[601,2913,2914],{},"constructor.name"," only for an event with no class-tier handler, which is never stamped).",[854,2917,2919],{"id":2918},"wire-the-handlers","Wire the handlers",[499,2921,2922,2923,2926,2927,2930,2931,2934,2935,2937,2938,2941,2942,2944,2945,2948,2949,2952,2953,2955,2956,1061],{},"Handlers are declared under the module's ",[601,2924,2925],{},"events"," namespace — ",[503,2928,2929],{},"never"," in ",[601,2932,2933],{},"providers",". Serial\n",[601,2936,2521],{},"s go under ",[601,2939,2940],{},"handlers",", best-effort ",[601,2943,2528],{},"s under ",[601,2946,2947],{},"notificationHandlers",",\nand interceptors under ",[601,2950,2951],{},"interceptors",". A handler left in ",[601,2954,2933],{}," is constructed but never wired\ninto dispatch, so it silently never fires. Plain injectables stay in ",[601,2957,2933],{},[624,2959,2962],{"className":700,"code":2960,"filename":2961,"language":702,"meta":630,"style":630},"import { Module } from \"@heximon\u002Fruntime\";\nimport { AuditTrailHandler } from \".\u002Faudit-trail.handler\";\nimport { ConfirmationEmailHandler } from \".\u002Fconfirmation-email.handler\";\nimport { EventLog } from \".\u002Fevent-log\";\nimport { OrderMetricsHandler } from \".\u002Forder-metrics.handler\";\nimport { TraceEventsInterceptor } from \".\u002Ftrace-events.interceptor\";\n\nexport class NotificationsModule extends Module({\n  providers: [EventLog],\n  events: {\n    handlers: [ConfirmationEmailHandler, AuditTrailHandler],\n    notificationHandlers: [OrderMetricsHandler],\n    interceptors: [TraceEventsInterceptor],\n  },\n  exports: [EventLog],\n}) {}\n","notifications.module.ts",[601,2963,2964,2986,3007,3028,3048,3069,3090,3094,3111,3123,3132,3149,3161,3173,3178,3189],{"__ignoreMap":630},[634,2965,2966,2968,2970,2973,2975,2977,2979,2982,2984],{"class":636,"line":637},[634,2967,710],{"class":709},[634,2969,714],{"class":713},[634,2971,2972],{"class":717}," Module",[634,2974,721],{"class":713},[634,2976,724],{"class":709},[634,2978,727],{"class":713},[634,2980,2981],{"class":643},"@heximon\u002Fruntime",[634,2983,733],{"class":713},[634,2985,736],{"class":713},[634,2987,2988,2990,2992,2994,2996,2998,3000,3003,3005],{"class":636,"line":739},[634,2989,710],{"class":709},[634,2991,714],{"class":713},[634,2993,1905],{"class":717},[634,2995,721],{"class":713},[634,2997,724],{"class":709},[634,2999,727],{"class":713},[634,3001,3002],{"class":643},".\u002Faudit-trail.handler",[634,3004,733],{"class":713},[634,3006,736],{"class":713},[634,3008,3009,3011,3013,3015,3017,3019,3021,3024,3026],{"class":636,"line":762},[634,3010,710],{"class":709},[634,3012,714],{"class":713},[634,3014,1230],{"class":717},[634,3016,721],{"class":713},[634,3018,724],{"class":709},[634,3020,727],{"class":713},[634,3022,3023],{"class":643},".\u002Fconfirmation-email.handler",[634,3025,733],{"class":713},[634,3027,736],{"class":713},[634,3029,3030,3032,3034,3036,3038,3040,3042,3044,3046],{"class":636,"line":785},[634,3031,710],{"class":709},[634,3033,714],{"class":713},[634,3035,1265],{"class":717},[634,3037,721],{"class":713},[634,3039,724],{"class":709},[634,3041,727],{"class":713},[634,3043,2578],{"class":643},[634,3045,733],{"class":713},[634,3047,736],{"class":713},[634,3049,3050,3052,3054,3056,3058,3060,3062,3065,3067],{"class":636,"line":792},[634,3051,710],{"class":709},[634,3053,714],{"class":713},[634,3055,1492],{"class":717},[634,3057,721],{"class":713},[634,3059,724],{"class":709},[634,3061,727],{"class":713},[634,3063,3064],{"class":643},".\u002Forder-metrics.handler",[634,3066,733],{"class":713},[634,3068,736],{"class":713},[634,3070,3071,3073,3075,3077,3079,3081,3083,3086,3088],{"class":636,"line":810},[634,3072,710],{"class":709},[634,3074,714],{"class":713},[634,3076,2595],{"class":717},[634,3078,721],{"class":713},[634,3080,724],{"class":709},[634,3082,727],{"class":713},[634,3084,3085],{"class":643},".\u002Ftrace-events.interceptor",[634,3087,733],{"class":713},[634,3089,736],{"class":713},[634,3091,3092],{"class":636,"line":844},[634,3093,789],{"emptyLinePlaceholder":788},[634,3095,3096,3098,3100,3103,3105,3107,3109],{"class":636,"line":984},[634,3097,795],{"class":709},[634,3099,907],{"class":906},[634,3101,3102],{"class":640}," NotificationsModule",[634,3104,913],{"class":906},[634,3106,2972],{"class":801},[634,3108,804],{"class":717},[634,3110,807],{"class":713},[634,3112,3113,3116,3118,3121],{"class":636,"line":992},[634,3114,3115],{"class":813},"  providers",[634,3117,697],{"class":713},[634,3119,3120],{"class":717}," [EventLog]",[634,3122,841],{"class":713},[634,3124,3125,3128,3130],{"class":636,"line":1002},[634,3126,3127],{"class":813},"  events",[634,3129,697],{"class":713},[634,3131,918],{"class":713},[634,3133,3134,3137,3139,3142,3144,3147],{"class":636,"line":1008},[634,3135,3136],{"class":813},"    handlers",[634,3138,697],{"class":713},[634,3140,3141],{"class":717}," [ConfirmationEmailHandler",[634,3143,830],{"class":713},[634,3145,3146],{"class":717}," AuditTrailHandler]",[634,3148,841],{"class":713},[634,3150,3151,3154,3156,3159],{"class":636,"line":1013},[634,3152,3153],{"class":813},"    notificationHandlers",[634,3155,697],{"class":713},[634,3157,3158],{"class":717}," [OrderMetricsHandler]",[634,3160,841],{"class":713},[634,3162,3163,3166,3168,3171],{"class":636,"line":1029},[634,3164,3165],{"class":813},"    interceptors",[634,3167,697],{"class":713},[634,3169,3170],{"class":717}," [TraceEventsInterceptor]",[634,3172,841],{"class":713},[634,3174,3175],{"class":636,"line":1084},[634,3176,3177],{"class":713},"  },\n",[634,3179,3180,3183,3185,3187],{"class":636,"line":1089},[634,3181,3182],{"class":813},"  exports",[634,3184,697],{"class":713},[634,3186,3120],{"class":717},[634,3188,841],{"class":713},[634,3190,3191,3193,3196],{"class":636,"line":2366},[634,3192,847],{"class":713},[634,3194,3195],{"class":717},") ",[634,3197,3198],{"class":713},"{}\n",[593,3200,3202],{"id":3201},"domain-events","Domain events",[499,3204,3205,3206,3208,3209,3212,3213,3216,3217,3220,3221,3224,3225,3228],{},"Once you have aggregates (see ",[1119,3207,228],{"href":229},"), the next tier up is ",[503,3210,3211],{},"domain\nevents",". The difference is ",[1686,3214,3215],{},"when"," they fire: an aggregate ",[503,3218,3219],{},"records"," events as its state changes, you\n",[503,3222,3223],{},"save"," it, and then you ",[503,3226,3227],{},"flush"," the recorded events. That ordering means a handler always runs\nagainst persisted state, never a half-applied change.",[499,3230,3231,3232,3234],{},"A ",[601,3233,1127],{}," is a plain class — same shape as a class-tier event, but its base already carries the\ndispatch stamp, so there's no extra base to declare.",[624,3236,3239],{"className":700,"code":3237,"filename":3238,"language":702,"meta":630,"style":630},"import { DomainEvent } from \"@heximon\u002Fdomain\";\nimport type { OrderId } from \"..\u002Forder.entity\";\n\nexport class OrderShippedDomainEvent extends DomainEvent {\n  public constructor(\n    public readonly orderId: OrderId,\n    public readonly shippedAt: Date,\n  ) {\n    super();\n  }\n}\n","order.events.ts",[601,3240,3241,3262,3286,3290,3305,3314,3328,3343,3349,3357,3361],{"__ignoreMap":630},[634,3242,3243,3245,3247,3250,3252,3254,3256,3258,3260],{"class":636,"line":637},[634,3244,710],{"class":709},[634,3246,714],{"class":713},[634,3248,3249],{"class":717}," DomainEvent",[634,3251,721],{"class":713},[634,3253,724],{"class":709},[634,3255,727],{"class":713},[634,3257,1123],{"class":643},[634,3259,733],{"class":713},[634,3261,736],{"class":713},[634,3263,3264,3266,3268,3270,3273,3275,3277,3279,3282,3284],{"class":636,"line":739},[634,3265,710],{"class":709},[634,3267,1173],{"class":709},[634,3269,714],{"class":713},[634,3271,3272],{"class":717}," OrderId",[634,3274,721],{"class":713},[634,3276,724],{"class":709},[634,3278,727],{"class":713},[634,3280,3281],{"class":643},"..\u002Forder.entity",[634,3283,733],{"class":713},[634,3285,736],{"class":713},[634,3287,3288],{"class":636,"line":762},[634,3289,789],{"emptyLinePlaceholder":788},[634,3291,3292,3294,3296,3299,3301,3303],{"class":636,"line":785},[634,3293,795],{"class":709},[634,3295,907],{"class":906},[634,3297,3298],{"class":640}," OrderShippedDomainEvent",[634,3300,913],{"class":906},[634,3302,3249],{"class":640},[634,3304,918],{"class":713},[634,3306,3307,3309,3312],{"class":636,"line":792},[634,3308,1016],{"class":906},[634,3310,3311],{"class":906}," constructor",[634,3313,926],{"class":713},[634,3315,3316,3318,3320,3322,3324,3326],{"class":636,"line":810},[634,3317,931],{"class":906},[634,3319,934],{"class":906},[634,3321,938],{"class":937},[634,3323,697],{"class":713},[634,3325,3272],{"class":640},[634,3327,841],{"class":713},[634,3329,3330,3332,3334,3337,3339,3341],{"class":636,"line":844},[634,3331,931],{"class":906},[634,3333,934],{"class":906},[634,3335,3336],{"class":937}," shippedAt",[634,3338,697],{"class":713},[634,3340,2425],{"class":640},[634,3342,841],{"class":713},[634,3344,3345,3347],{"class":636,"line":984},[634,3346,987],{"class":713},[634,3348,918],{"class":713},[634,3350,3351,3353,3355],{"class":636,"line":992},[634,3352,995],{"class":717},[634,3354,827],{"class":813},[634,3356,736],{"class":713},[634,3358,3359],{"class":636,"line":1002},[634,3360,1005],{"class":713},[634,3362,3363],{"class":636,"line":1008},[634,3364,1092],{"class":713},[854,3366,3368],{"id":3367},"record-events-on-the-aggregate","Record events on the aggregate",[499,3370,3371,3372,3377,3378,3381,3382,3385],{},"The ",[1119,3373,3374],{"href":229},[601,3375,3376],{},"AggregateRoot"," records events with ",[601,3379,3380],{},"addDomainEvent(...)"," as its state\ntransitions. It buffers them and otherwise does nothing — the aggregate has ",[503,3383,3384],{},"no"," dependency on the\nevent bus, so recording stays decoupled from dispatch and the domain layer stays pure.",[624,3387,3390],{"className":700,"code":3388,"filename":3389,"language":702,"meta":630,"style":630},"public ship(): void {\n  if (this.props.status === \"Shipped\") throw new CannotShipTwiceError();\n  const shippedAt = new Date();\n  this.props.status = \"Shipped\";\n  this.props.shippedAt = shippedAt;\n  this.addDomainEvent(new OrderShippedDomainEvent(this.id, shippedAt)); \u002F\u002F buffered, not yet dispatched\n}\n","order.entity.ts",[601,3391,3392,3407,3448,3465,3486,3503,3534],{"__ignoreMap":630},[634,3393,3394,3397,3400,3403,3405],{"class":636,"line":637},[634,3395,3396],{"class":717},"public ",[634,3398,3399],{"class":801},"ship",[634,3401,3402],{"class":717},"(): ",[634,3404,1555],{"class":713},[634,3406,918],{"class":713},[634,3408,3409,3412,3414,3416,3419,3421,3424,3427,3429,3432,3434,3436,3439,3441,3444,3446],{"class":636,"line":739},[634,3410,3411],{"class":709},"  if",[634,3413,608],{"class":813},[634,3415,1044],{"class":713},[634,3417,3418],{"class":717},"props",[634,3420,1061],{"class":713},[634,3422,3423],{"class":717},"status",[634,3425,3426],{"class":713}," ===",[634,3428,727],{"class":713},[634,3430,3431],{"class":643},"Shipped",[634,3433,733],{"class":713},[634,3435,3195],{"class":813},[634,3437,3438],{"class":709},"throw",[634,3440,833],{"class":713},[634,3442,3443],{"class":801}," CannotShipTwiceError",[634,3445,827],{"class":813},[634,3447,736],{"class":713},[634,3449,3450,3453,3455,3457,3459,3461,3463],{"class":636,"line":762},[634,3451,3452],{"class":906},"  const",[634,3454,3336],{"class":717},[634,3456,1570],{"class":713},[634,3458,833],{"class":713},[634,3460,2425],{"class":801},[634,3462,827],{"class":813},[634,3464,736],{"class":713},[634,3466,3467,3470,3472,3474,3476,3478,3480,3482,3484],{"class":636,"line":785},[634,3468,3469],{"class":713},"  this.",[634,3471,3418],{"class":717},[634,3473,1061],{"class":713},[634,3475,3423],{"class":717},[634,3477,1570],{"class":713},[634,3479,727],{"class":713},[634,3481,3431],{"class":643},[634,3483,733],{"class":713},[634,3485,736],{"class":713},[634,3487,3488,3490,3492,3494,3497,3499,3501],{"class":636,"line":792},[634,3489,3469],{"class":713},[634,3491,3418],{"class":717},[634,3493,1061],{"class":713},[634,3495,3496],{"class":717},"shippedAt",[634,3498,1570],{"class":713},[634,3500,3336],{"class":717},[634,3502,736],{"class":713},[634,3504,3505,3507,3510,3512,3514,3516,3518,3520,3523,3525,3527,3529,3531],{"class":636,"line":810},[634,3506,3469],{"class":713},[634,3508,3509],{"class":801},"addDomainEvent",[634,3511,804],{"class":813},[634,3513,822],{"class":713},[634,3515,3298],{"class":801},[634,3517,804],{"class":813},[634,3519,1044],{"class":713},[634,3521,3522],{"class":717},"id",[634,3524,830],{"class":713},[634,3526,3336],{"class":717},[634,3528,2352],{"class":813},[634,3530,2225],{"class":713},[634,3532,3533],{"class":1195}," \u002F\u002F buffered, not yet dispatched\n",[634,3535,3536],{"class":636,"line":844},[634,3537,1092],{"class":713},[854,3539,3541],{"id":3540},"flush-after-the-save","Flush after the save",[499,3543,3544,3546,3547,3550,3551,3554,3555,3558,3559,3562,3563,3566,3567,3569],{},[601,3545,2507],{}," is the injectable facade — a core provider, injected by constructor parameter type with\nno module import. After persisting the aggregate, drain its buffer with ",[601,3548,3549],{},"domainEvents.emitFrom(order)",".\nThat dispatches each recorded event ",[503,3552,3553],{},"serially, in order"," — a throw stops the remaining events. Under the\nDB-backed command auto-wrap (which wraps ",[601,3556,3557],{},"execute"," + ",[601,3560,3561],{},"emitFrom"," in a single ",[601,3564,3565],{},"Database.runInTransaction",") this\nrolls the SQL write back atomically; a command whose module has no ",[601,3568,77],{}," propagates the throw without a\nrollback.",[624,3571,3574],{"className":700,"code":3572,"filename":3573,"language":702,"meta":630,"style":630},"import { NotFoundError } from \"@heximon\u002Fruntime\u002Ferrors\";\nimport { DomainEvents } from \"@heximon\u002Fdomain\";\nimport type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport type { OrderId } from \".\u002Forder.entity\";\nimport { OrderRepository } from \".\u002Forder.repository\";\n\nexport class OrdersController implements Controller\u003C\"\u002Forders\"> {\n  public constructor(\n    private readonly repository: OrderRepository,\n    private readonly domainEvents: DomainEvents, \u002F\u002F core provider, injected by type\n  ) {}\n\n  public async ship(action: Post\u003C\"\u002F:id\u002Fship\">): Promise\u003C{ id: string; status: string }> {\n    const id = action.request.pathParams.id as OrderId;\n    const order = await this.repository.getById(id);\n    if (!order) throw new NotFoundError(`Order ${id} not found`);\n    order.ship();\n    await this.repository.save(order);\n    await this.domainEvents.emitFrom(order); \u002F\u002F drains the buffer + dispatches the recorded events\n    return { id: order.id, status: order.status };\n  }\n}\n","orders.controller.ts",[601,3575,3576,3598,3619,3645,3668,3690,3694,3719,3727,3743,3761,3767,3771,3822,3851,3881,3924,3937,3957,3981,4011,4015],{"__ignoreMap":630},[634,3577,3578,3580,3582,3585,3587,3589,3591,3594,3596],{"class":636,"line":637},[634,3579,710],{"class":709},[634,3581,714],{"class":713},[634,3583,3584],{"class":717}," NotFoundError",[634,3586,721],{"class":713},[634,3588,724],{"class":709},[634,3590,727],{"class":713},[634,3592,3593],{"class":643},"@heximon\u002Fruntime\u002Ferrors",[634,3595,733],{"class":713},[634,3597,736],{"class":713},[634,3599,3600,3602,3604,3607,3609,3611,3613,3615,3617],{"class":636,"line":739},[634,3601,710],{"class":709},[634,3603,714],{"class":713},[634,3605,3606],{"class":717}," DomainEvents",[634,3608,721],{"class":713},[634,3610,724],{"class":709},[634,3612,727],{"class":713},[634,3614,1123],{"class":643},[634,3616,733],{"class":713},[634,3618,736],{"class":713},[634,3620,3621,3623,3625,3627,3629,3631,3633,3635,3637,3639,3641,3643],{"class":636,"line":762},[634,3622,710],{"class":709},[634,3624,1173],{"class":709},[634,3626,714],{"class":713},[634,3628,2067],{"class":717},[634,3630,830],{"class":713},[634,3632,2072],{"class":717},[634,3634,721],{"class":713},[634,3636,724],{"class":709},[634,3638,727],{"class":713},[634,3640,2081],{"class":643},[634,3642,733],{"class":713},[634,3644,736],{"class":713},[634,3646,3647,3649,3651,3653,3655,3657,3659,3661,3664,3666],{"class":636,"line":785},[634,3648,710],{"class":709},[634,3650,1173],{"class":709},[634,3652,714],{"class":713},[634,3654,3272],{"class":717},[634,3656,721],{"class":713},[634,3658,724],{"class":709},[634,3660,727],{"class":713},[634,3662,3663],{"class":643},".\u002Forder.entity",[634,3665,733],{"class":713},[634,3667,736],{"class":713},[634,3669,3670,3672,3674,3677,3679,3681,3683,3686,3688],{"class":636,"line":792},[634,3671,710],{"class":709},[634,3673,714],{"class":713},[634,3675,3676],{"class":717}," OrderRepository",[634,3678,721],{"class":713},[634,3680,724],{"class":709},[634,3682,727],{"class":713},[634,3684,3685],{"class":643},".\u002Forder.repository",[634,3687,733],{"class":713},[634,3689,736],{"class":713},[634,3691,3692],{"class":636,"line":810},[634,3693,789],{"emptyLinePlaceholder":788},[634,3695,3696,3698,3700,3703,3705,3707,3709,3711,3713,3715,3717],{"class":636,"line":844},[634,3697,795],{"class":709},[634,3699,907],{"class":906},[634,3701,3702],{"class":640}," OrdersController",[634,3704,1233],{"class":906},[634,3706,2067],{"class":640},[634,3708,1238],{"class":713},[634,3710,733],{"class":713},[634,3712,2206],{"class":643},[634,3714,733],{"class":713},[634,3716,1244],{"class":713},[634,3718,918],{"class":713},[634,3720,3721,3723,3725],{"class":636,"line":984},[634,3722,1016],{"class":906},[634,3724,3311],{"class":906},[634,3726,926],{"class":713},[634,3728,3729,3732,3734,3737,3739,3741],{"class":636,"line":992},[634,3730,3731],{"class":906},"    private",[634,3733,934],{"class":906},[634,3735,3736],{"class":937}," repository",[634,3738,697],{"class":713},[634,3740,3676],{"class":640},[634,3742,841],{"class":713},[634,3744,3745,3747,3749,3752,3754,3756,3758],{"class":636,"line":1002},[634,3746,3731],{"class":906},[634,3748,934],{"class":906},[634,3750,3751],{"class":937}," domainEvents",[634,3753,697],{"class":713},[634,3755,3606],{"class":640},[634,3757,830],{"class":713},[634,3759,3760],{"class":1195}," \u002F\u002F core provider, injected by type\n",[634,3762,3763,3765],{"class":636,"line":1008},[634,3764,987],{"class":713},[634,3766,1270],{"class":713},[634,3768,3769],{"class":636,"line":1013},[634,3770,789],{"emptyLinePlaceholder":788},[634,3772,3773,3775,3777,3780,3782,3784,3786,3788,3790,3792,3795,3797,3799,3801,3803,3806,3808,3810,3812,3814,3816,3818,3820],{"class":636,"line":1029},[634,3774,1016],{"class":906},[634,3776,1535],{"class":906},[634,3778,3779],{"class":813}," ship",[634,3781,804],{"class":713},[634,3783,2008],{"class":937},[634,3785,697],{"class":713},[634,3787,2072],{"class":640},[634,3789,1238],{"class":713},[634,3791,733],{"class":713},[634,3793,3794],{"class":643},"\u002F:id\u002Fship",[634,3796,733],{"class":713},[634,3798,2211],{"class":713},[634,3800,1550],{"class":640},[634,3802,2216],{"class":713},[634,3804,3805],{"class":813}," id",[634,3807,697],{"class":713},[634,3809,943],{"class":640},[634,3811,2225],{"class":713},[634,3813,2228],{"class":813},[634,3815,697],{"class":713},[634,3817,943],{"class":640},[634,3819,2240],{"class":713},[634,3821,918],{"class":713},[634,3823,3824,3826,3828,3830,3832,3834,3836,3838,3841,3843,3845,3847,3849],{"class":636,"line":1084},[634,3825,1564],{"class":906},[634,3827,3805],{"class":717},[634,3829,1570],{"class":713},[634,3831,1750],{"class":717},[634,3833,1061],{"class":713},[634,3835,2263],{"class":717},[634,3837,1061],{"class":713},[634,3839,3840],{"class":717},"pathParams",[634,3842,1061],{"class":713},[634,3844,3522],{"class":717},[634,3846,2817],{"class":709},[634,3848,3272],{"class":640},[634,3850,736],{"class":713},[634,3852,3853,3855,3858,3860,3863,3865,3868,3870,3873,3875,3877,3879],{"class":636,"line":1089},[634,3854,1564],{"class":906},[634,3856,3857],{"class":717}," order",[634,3859,1570],{"class":713},[634,3861,3862],{"class":709}," await",[634,3864,2315],{"class":713},[634,3866,3867],{"class":717},"repository",[634,3869,1061],{"class":713},[634,3871,3872],{"class":801},"getById",[634,3874,804],{"class":813},[634,3876,3522],{"class":717},[634,3878,850],{"class":813},[634,3880,736],{"class":713},[634,3882,3883,3886,3888,3891,3894,3896,3898,3900,3902,3904,3906,3909,3911,3913,3915,3918,3920,3922],{"class":636,"line":2366},[634,3884,3885],{"class":709},"    if",[634,3887,608],{"class":813},[634,3889,3890],{"class":713},"!",[634,3892,3893],{"class":717},"order",[634,3895,3195],{"class":813},[634,3897,3438],{"class":709},[634,3899,833],{"class":713},[634,3901,3584],{"class":801},[634,3903,804],{"class":813},[634,3905,1669],{"class":713},[634,3907,3908],{"class":643},"Order ",[634,3910,1041],{"class":713},[634,3912,3522],{"class":717},[634,3914,847],{"class":713},[634,3916,3917],{"class":643}," not found",[634,3919,1669],{"class":713},[634,3921,850],{"class":813},[634,3923,736],{"class":713},[634,3925,3926,3929,3931,3933,3935],{"class":636,"line":2391},[634,3927,3928],{"class":717},"    order",[634,3930,1061],{"class":713},[634,3932,3399],{"class":801},[634,3934,827],{"class":813},[634,3936,736],{"class":713},[634,3938,3939,3941,3943,3945,3947,3949,3951,3953,3955],{"class":636,"line":2399},[634,3940,2312],{"class":709},[634,3942,2315],{"class":713},[634,3944,3867],{"class":717},[634,3946,1061],{"class":713},[634,3948,3223],{"class":801},[634,3950,804],{"class":813},[634,3952,3893],{"class":717},[634,3954,850],{"class":813},[634,3956,736],{"class":713},[634,3958,3959,3961,3963,3966,3968,3970,3972,3974,3976,3978],{"class":636,"line":2415},[634,3960,2312],{"class":709},[634,3962,2315],{"class":713},[634,3964,3965],{"class":717},"domainEvents",[634,3967,1061],{"class":713},[634,3969,3561],{"class":801},[634,3971,804],{"class":813},[634,3973,3893],{"class":717},[634,3975,850],{"class":813},[634,3977,2225],{"class":713},[634,3979,3980],{"class":1195}," \u002F\u002F drains the buffer + dispatches the recorded events\n",[634,3982,3983,3985,3987,3989,3991,3993,3995,3997,3999,4001,4003,4005,4007,4009],{"class":636,"line":2439},[634,3984,1032],{"class":709},[634,3986,714],{"class":713},[634,3988,3805],{"class":813},[634,3990,697],{"class":713},[634,3992,3857],{"class":717},[634,3994,1061],{"class":713},[634,3996,3522],{"class":717},[634,3998,830],{"class":713},[634,4000,2228],{"class":813},[634,4002,697],{"class":713},[634,4004,3857],{"class":717},[634,4006,1061],{"class":713},[634,4008,3423],{"class":717},[634,4010,2475],{"class":713},[634,4012,4013],{"class":636,"line":2449},[634,4014,1005],{"class":713},[634,4016,4017],{"class":636,"line":2454},[634,4018,1092],{"class":713},[499,4020,4021,4022,4024],{},"Nothing dispatches until that explicit ",[601,4023,3561],{}," — no implicit unit-of-work fires events behind your\nback, which keeps the save-then-flush ordering visible and under your control. A second flush is a\nharmless no-op, because draining the buffer clears it.",[854,4026,4028],{"id":4027},"react-to-a-domain-event","React to a domain event",[499,4030,4031,4032,4035,4036,4038,4039,1061],{},"A domain-event handler is ",[601,4033,4034],{},"class X implements DomainEventHandler\u003CEventClass>",". It's discovered through the\nsame class-identity tier as an in-process ",[601,4037,2521],{}," and routed by the event class, and it runs\nserially inside ",[601,4040,3561],{},[624,4042,4045],{"className":700,"code":4043,"filename":4044,"language":702,"meta":630,"style":630},"import type { DomainEventHandler } from \"@heximon\u002Fdomain\";\nimport { OrderShippedDomainEvent } from \"..\u002Forders\u002Fdomain-events\u002Forder.events\";\nimport { ShipmentTracker } from \".\u002Fshipment-tracker.service\";\n\nexport class RecordShipmentHandler implements DomainEventHandler\u003COrderShippedDomainEvent> {\n  public constructor(private readonly tracker: ShipmentTracker) {}\n\n  public handle(event: OrderShippedDomainEvent): void {\n    this.tracker.record({ orderId: event.orderId, shippedAt: event.shippedAt.toISOString() });\n  }\n}\n","record-shipment.handler.ts",[601,4046,4047,4070,4091,4113,4117,4139,4162,4166,4186,4237,4241],{"__ignoreMap":630},[634,4048,4049,4051,4053,4055,4058,4060,4062,4064,4066,4068],{"class":636,"line":637},[634,4050,710],{"class":709},[634,4052,1173],{"class":709},[634,4054,714],{"class":713},[634,4056,4057],{"class":717}," DomainEventHandler",[634,4059,721],{"class":713},[634,4061,724],{"class":709},[634,4063,727],{"class":713},[634,4065,1123],{"class":643},[634,4067,733],{"class":713},[634,4069,736],{"class":713},[634,4071,4072,4074,4076,4078,4080,4082,4084,4087,4089],{"class":636,"line":739},[634,4073,710],{"class":709},[634,4075,714],{"class":713},[634,4077,3298],{"class":717},[634,4079,721],{"class":713},[634,4081,724],{"class":709},[634,4083,727],{"class":713},[634,4085,4086],{"class":643},"..\u002Forders\u002Fdomain-events\u002Forder.events",[634,4088,733],{"class":713},[634,4090,736],{"class":713},[634,4092,4093,4095,4097,4100,4102,4104,4106,4109,4111],{"class":636,"line":762},[634,4094,710],{"class":709},[634,4096,714],{"class":713},[634,4098,4099],{"class":717}," ShipmentTracker",[634,4101,721],{"class":713},[634,4103,724],{"class":709},[634,4105,727],{"class":713},[634,4107,4108],{"class":643},".\u002Fshipment-tracker.service",[634,4110,733],{"class":713},[634,4112,736],{"class":713},[634,4114,4115],{"class":636,"line":785},[634,4116,789],{"emptyLinePlaceholder":788},[634,4118,4119,4121,4123,4126,4128,4130,4132,4135,4137],{"class":636,"line":792},[634,4120,795],{"class":709},[634,4122,907],{"class":906},[634,4124,4125],{"class":640}," RecordShipmentHandler",[634,4127,1233],{"class":906},[634,4129,4057],{"class":640},[634,4131,1238],{"class":713},[634,4133,4134],{"class":640},"OrderShippedDomainEvent",[634,4136,1244],{"class":713},[634,4138,918],{"class":713},[634,4140,4141,4143,4145,4147,4149,4151,4154,4156,4158,4160],{"class":636,"line":810},[634,4142,1016],{"class":906},[634,4144,3311],{"class":906},[634,4146,804],{"class":713},[634,4148,1255],{"class":906},[634,4150,934],{"class":906},[634,4152,4153],{"class":937}," tracker",[634,4155,697],{"class":713},[634,4157,4099],{"class":640},[634,4159,850],{"class":713},[634,4161,1270],{"class":713},[634,4163,4164],{"class":636,"line":844},[634,4165,789],{"emptyLinePlaceholder":788},[634,4167,4168,4170,4172,4174,4176,4178,4180,4182,4184],{"class":636,"line":984},[634,4169,1016],{"class":906},[634,4171,1281],{"class":813},[634,4173,804],{"class":713},[634,4175,1286],{"class":937},[634,4177,697],{"class":713},[634,4179,3298],{"class":640},[634,4181,1293],{"class":713},[634,4183,1296],{"class":640},[634,4185,918],{"class":713},[634,4187,4188,4190,4193,4195,4197,4199,4202,4204,4206,4208,4210,4212,4214,4216,4218,4220,4222,4224,4226,4228,4231,4233,4235],{"class":636,"line":992},[634,4189,1303],{"class":713},[634,4191,4192],{"class":717},"tracker",[634,4194,1061],{"class":713},[634,4196,1311],{"class":801},[634,4198,804],{"class":813},[634,4200,4201],{"class":713},"{",[634,4203,938],{"class":813},[634,4205,697],{"class":713},[634,4207,1573],{"class":717},[634,4209,1061],{"class":713},[634,4211,1047],{"class":717},[634,4213,830],{"class":713},[634,4215,3336],{"class":813},[634,4217,697],{"class":713},[634,4219,1573],{"class":717},[634,4221,1061],{"class":713},[634,4223,3496],{"class":717},[634,4225,1061],{"class":713},[634,4227,2432],{"class":801},[634,4229,4230],{"class":813},"() ",[634,4232,847],{"class":713},[634,4234,850],{"class":813},[634,4236,736],{"class":713},[634,4238,4239],{"class":636,"line":1002},[634,4240,1005],{"class":713},[634,4242,4243],{"class":636,"line":1008},[634,4244,1092],{"class":713},[499,4246,4247,4248,4251,4252,4255,4256,4259],{},"Notice the handler consumes only the flat data the event carries — never the ",[601,4249,4250],{},"Order"," aggregate itself.\nThat's deliberate: the shipping context reacts without reaching into the orders context, so the two stay\ndecoupled. Declare the handler under the module's ",[601,4253,4254],{},"domain"," namespace, in the ",[601,4257,4258],{},"eventHandlers"," sub-key.",[624,4261,4264],{"className":700,"code":4262,"filename":4263,"language":702,"meta":630,"style":630},"import { Module } from \"@heximon\u002Fruntime\";\nimport { RecordShipmentHandler } from \".\u002Frecord-shipment.handler\";\nimport { ShipmentTracker } from \".\u002Fshipment-tracker.service\";\n\nexport class ShippingModule extends Module({\n  providers: [ShipmentTracker],\n  domain: { eventHandlers: [RecordShipmentHandler] },\n  exports: [ShipmentTracker],\n}) {}\n","shipping.module.ts",[601,4265,4266,4286,4307,4327,4331,4348,4359,4379,4389],{"__ignoreMap":630},[634,4267,4268,4270,4272,4274,4276,4278,4280,4282,4284],{"class":636,"line":637},[634,4269,710],{"class":709},[634,4271,714],{"class":713},[634,4273,2972],{"class":717},[634,4275,721],{"class":713},[634,4277,724],{"class":709},[634,4279,727],{"class":713},[634,4281,2981],{"class":643},[634,4283,733],{"class":713},[634,4285,736],{"class":713},[634,4287,4288,4290,4292,4294,4296,4298,4300,4303,4305],{"class":636,"line":739},[634,4289,710],{"class":709},[634,4291,714],{"class":713},[634,4293,4125],{"class":717},[634,4295,721],{"class":713},[634,4297,724],{"class":709},[634,4299,727],{"class":713},[634,4301,4302],{"class":643},".\u002Frecord-shipment.handler",[634,4304,733],{"class":713},[634,4306,736],{"class":713},[634,4308,4309,4311,4313,4315,4317,4319,4321,4323,4325],{"class":636,"line":762},[634,4310,710],{"class":709},[634,4312,714],{"class":713},[634,4314,4099],{"class":717},[634,4316,721],{"class":713},[634,4318,724],{"class":709},[634,4320,727],{"class":713},[634,4322,4108],{"class":643},[634,4324,733],{"class":713},[634,4326,736],{"class":713},[634,4328,4329],{"class":636,"line":785},[634,4330,789],{"emptyLinePlaceholder":788},[634,4332,4333,4335,4337,4340,4342,4344,4346],{"class":636,"line":792},[634,4334,795],{"class":709},[634,4336,907],{"class":906},[634,4338,4339],{"class":640}," ShippingModule",[634,4341,913],{"class":906},[634,4343,2972],{"class":801},[634,4345,804],{"class":717},[634,4347,807],{"class":713},[634,4349,4350,4352,4354,4357],{"class":636,"line":810},[634,4351,3115],{"class":813},[634,4353,697],{"class":713},[634,4355,4356],{"class":717}," [ShipmentTracker]",[634,4358,841],{"class":713},[634,4360,4361,4364,4366,4368,4371,4373,4376],{"class":636,"line":844},[634,4362,4363],{"class":813},"  domain",[634,4365,697],{"class":713},[634,4367,714],{"class":713},[634,4369,4370],{"class":813}," eventHandlers",[634,4372,697],{"class":713},[634,4374,4375],{"class":717}," [RecordShipmentHandler] ",[634,4377,4378],{"class":713},"},\n",[634,4380,4381,4383,4385,4387],{"class":636,"line":984},[634,4382,3182],{"class":813},[634,4384,697],{"class":713},[634,4386,4356],{"class":717},[634,4388,841],{"class":713},[634,4390,4391,4393,4395],{"class":636,"line":992},[634,4392,847],{"class":713},[634,4394,3195],{"class":717},[634,4396,3198],{"class":713},[499,4398,4399,4400,4403,4404,4406,4407,1061],{},"An app using domain events needs ",[601,4401,4402],{},"DomainEventsPlugin",", which wires the ",[601,4405,2507],{}," facade. It requires\nthe events plugin, so the compiler pulls that in automatically — you only list ",[601,4408,4402],{},[593,4410,4412],{"id":4411},"integration-events","Integration events",[499,4414,4415,4416,4419,4420,4423],{},"The two tiers above run in the same process and on the request path. When an event must reach ",[503,4417,4418],{},"another\nbounded context or another service"," — without blocking the request that produced it — promote to\n",[503,4421,4422],{},"integration events",". They're queue-backed: the producer publishes and returns, and the consumer runs later\nwhen the transport delivers.",[499,4425,4426,4427,4430,4431,4434,4435,1061],{},"A typed ",[601,4428,4429],{},"IntegrationEvent\u003C\"name\", Payload>"," producer and an\n",[601,4432,4433],{},"IntegrationEventHandler\u003C\"name\", Payload>"," consumer meet on one channel, with a shared payload type keeping\ndrift between them a compile error rather than a runtime surprise. That tier — the producer\u002Fconsumer walkthrough,\nthe transactional outbox, and the four cross-service fan-out legs (per-service-queue split, Redis Streams\nbroadcast, SNS → SQS, and QStash push for freezing platforms) — has its own page:\n",[1119,4436,243],{"href":244},[593,4438,4440],{"id":4439},"choosing-a-tier","Choosing a tier",[499,4442,4443],{},"Start at the top of this list and move down only when you have to — each tier carries more machinery\nthan the last:",[4445,4446,4447,4453,4462],"ul",{},[4448,4449,4450,4452],"li",{},[503,4451,547],{}," for decoupling features inside one app: notifications, logging, fan-out side effects.\nNo persistence, no infrastructure.",[4448,4454,4455,4457,4458,4461],{},[503,4456,563],{}," once you have aggregates and want to react to state changes ",[1686,4459,4460],{},"after a save",", within a single\nbounded context — same process, flushed explicitly.",[4448,4463,4464,4466],{},[503,4465,579],{}," only when an event genuinely has to cross a process or service boundary. It's the\nasync, queue-backed tier, and it's the most you'll wire.",[499,4468,4469,4470,4472,4473,4476],{},"Promotion is cheap because the substrate is shared: a class-tier ",[601,4471,2521],{}," becomes a\n",[601,4474,4475],{},"DomainEventHandler"," by re-export, and an integration handler reuses the same queue channels.",[593,4478,4480],{"id":4479},"see-also","See also",[4445,4482,4483,4488,4493,4498,4507],{},[4448,4484,4485,4487],{},[1119,4486,228],{"href":229}," — the aggregates that record the domain events you flush\nhere, plus the value objects and errors around them.",[4448,4489,4490,4492],{},[1119,4491,243],{"href":244}," — the queue-backed tier for a cross-context or\ncross-service event: typed producers and handlers, the transactional outbox, and cross-service fan-out.",[4448,4494,4495,4497],{},[1119,4496,233],{"href":234}," — flush an aggregate's events from a command handler after it saves, then\nreact in-process or across services.",[4448,4499,4500,4506],{},[1119,4501,4505],{"href":4502,"rel":4503},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL03-events",[4504],"nofollow","Example L03 — events","\n— a shop module that publishes both class and string tiers, and a fully decoupled notifications module\nof serial and best-effort handlers.",[4448,4508,4509,4514,4515,4517,4518,4521],{},[1119,4510,4513],{"href":4511,"rel":4512},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL06-ddd",[4504],"L06 — DDD","\n— an ",[601,4516,4250],{}," aggregate that records domain events on ",[601,4519,4520],{},"ship()"," and a shipping context that reacts to\nthem across bounded contexts.",[4523,4524,4525],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":630,"searchDepth":739,"depth":739,"links":4527},[4528,4537,4542,4543,4544],{"id":595,"depth":739,"text":596,"children":4529},[4530,4531,4532,4533,4534,4535,4536],{"id":856,"depth":762,"text":857},{"id":1137,"depth":762,"text":1138},{"id":1417,"depth":762,"text":1418},{"id":1692,"depth":762,"text":1693},{"id":2039,"depth":762,"text":2040},{"id":2511,"depth":762,"text":2512},{"id":2918,"depth":762,"text":2919},{"id":3201,"depth":739,"text":3202,"children":4538},[4539,4540,4541],{"id":3367,"depth":762,"text":3368},{"id":3540,"depth":762,"text":3541},{"id":4027,"depth":762,"text":4028},{"id":4411,"depth":739,"text":4412},{"id":4439,"depth":739,"text":4440},{"id":4479,"depth":739,"text":4480},"Decouple features with events across three tiers — the in-process EventBus, EventHandler and NotificationHandler, and domain events on aggregates with DomainEvents.emitFrom.","md",null,{},{"icon":149},{"title":146,"description":4545},"xA3xayKjudLOPwFnGBquW2GC7GTr0eAJvLvKbdu4UJY",[4553,4555],{"title":142,"path":143,"stem":144,"description":4554,"icon":137,"children":-1},"The capability map — every production concern (events, background jobs, cron, caching, storage, health, notifications, idempotency, security, tracing, OpenAPI, MCP, schema, branded ids) and the one config line each one adds.",{"title":151,"path":152,"stem":153,"description":4556,"icon":154,"children":-1},"Move slow work off the request path onto durable channels — the Queue producer port, QueueEventHandler consumers under queue { handlers }, per-handler retry and payload validation, MemoryQueue in dev, and a durable transport per platform.",1783300761903]