[{"data":1,"prerenderedAt":4125},["ShallowReactive",2],{"navigation_docs":3,"-docs-architecture-ddd":493,"-docs-architecture-ddd-surround":4120},[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":228,"body":495,"description":4113,"extension":4114,"links":4115,"meta":4116,"navigation":4117,"path":229,"seo":4118,"stem":230,"__hash__":4119},"docs\u002Fdocs\u002F04.architecture\u002F02.ddd.md",{"type":496,"value":497,"toc":4102},"minimark",[498,507,512,524,544,550,572,579,589,1288,1315,1329,1353,1357,1374,2093,2111,2132,2136,2154,2161,2232,2235,2239,2262,2269,2535,2552,2556,2570,2693,2700,2704,2710,2898,2909,3382,3392,3406,3412,3622,3628,3632,3635,3702,3711,3715,3729,3871,3880,3891,4013,4017,4098],[499,500,501,502,506],"p",{},"You may never need this — see the ",[503,504,505],"a",{"href":225},"Architecture overview"," for the signals that say\nyou've earned it. Reach for it when a rule like \"can't ship twice\" or \"can't ship empty\" starts\ngetting checked in more than one controller, because that's the first sign the rule lives in the\nwrong place.",[508,509,511],"h2",{"id":510},"the-failure-mode-this-fixes","The failure mode this fixes",[499,513,514,515,519,520,523],{},"An ",[516,517,518],"code",{},"Order"," has a rule: it can't ship if it's already shipped, and it can't ship with no items. Left as\nplain rows, that rule gets checked wherever a route touches the order — the ",[516,521,522],{},"POST \u002F:id\u002Fship"," handler\ntoday, a bulk-fulfillment job next month, an admin action after that. Each call site re-derives the\ncheck from the same two columns. Miss one, and an order ships twice.",[499,525,526,527,531,532,535,536,539,540,543],{},"Two symptoms compound it: ",[528,529,530],"strong",{},"write-skew",", where two requests load the same row, each computes a\nvalid-looking update from what they read, and the second write silently clobbers the first with no\nerror; and ",[528,533,534],{},"anemic rows",", where the data is just a bag of fields (",[516,537,538],{},"status: string",", ",[516,541,542],{},"items: unknown[]",") that nothing stops a caller from setting directly, skipping the rule entirely.",[499,545,546,547,549],{},"Domain-driven design's fix is to make the rule a property of the data, not of the caller: the only way\nto mutate an ",[516,548,518],{}," is through a method that enforces the invariant, a version check makes a stale\nwrite fail loud instead of silently losing data, and a fact worth reacting to — \"this order shipped\" —\nbecomes a recorded event instead of something a second query has to re-derive.",[499,551,552,553,556,557,539,560,563,564,567,568,571],{},"Three building blocks get you there. A ",[528,554,555],{},"value object"," is compared by its contents, not an identity —\n",[516,558,559],{},"Money",[516,561,562],{},"Email",". An ",[528,565,566],{},"entity"," has identity that persists across changes — you mutate it, and it works\nout what changed. An ",[528,569,570],{},"aggregate root"," is the entity at the top of a cluster: the consistency boundary\nthat guards every invariant and records what happened.",[499,573,574,575,578],{},"All three are plain classes that ",[516,576,577],{},"extend"," a typed base — equality, dirty tracking, and rehydration come\nfree.",[499,580,581,582,585,586,588],{},"The ",[503,583,584],{"href":471},"ddd-aggregate recipe"," builds exactly this — an ",[516,587,518],{}," that can't\nship twice or empty — end to end; treat this page as the reference and that one as the walkthrough.",[590,591,597],"pre",{"className":592,"code":593,"filename":594,"language":595,"meta":596,"style":596},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { ValueObject } from \"@heximon\u002Fdomain\";\n\ninterface MoneyValue {\n  readonly amountCents: number;\n  readonly currency: string;\n}\n\nexport class Money extends ValueObject\u003CMoneyValue> {\n  private static readonly currencyPattern = \u002F^[A-Z]{3}$\u002F;\n\n  public static create(amountCents: number, currency: string): Money {\n    if (!Number.isInteger(amountCents) || amountCents \u003C 0) {\n      throw new RangeError(`Invalid money amount: ${amountCents}`);\n    }\n    if (!Money.currencyPattern.test(currency)) {\n      throw new TypeError(`Invalid currency: ${currency}`);\n    }\n    return new Money({ amountCents, currency });\n  }\n\n  public get amountCents(): number {\n    return this.getInternalValue().amountCents;\n  }\n\n  public get currency(): string {\n    return this.getInternalValue().currency;\n  }\n\n  public add(other: Money): Money {\n    if (other.currency !== this.currency) {\n      throw new TypeError(\"Currency mismatch\");\n    }\n    return Money.create(this.amountCents + other.amountCents, this.currency);\n  }\n\n  public multiply(factor: number): Money {\n    return Money.create(Math.round(this.amountCents * factor), this.currency);\n  }\n}\n","src\u002Forders\u002Fmoney.value.ts","ts","",[516,598,599,635,642,656,674,689,695,700,728,769,774,812,858,891,897,928,955,960,987,993,998,1015,1035,1040,1045,1060,1077,1082,1087,1110,1134,1156,1161,1200,1205,1210,1233,1278,1283],{"__ignoreMap":596},[600,601,604,608,612,616,619,622,625,629,632],"span",{"class":602,"line":603},"line",1,[600,605,607],{"class":606},"s7zQu","import",[600,609,611],{"class":610},"sMK4o"," {",[600,613,615],{"class":614},"sTEyZ"," ValueObject",[600,617,618],{"class":610}," }",[600,620,621],{"class":606}," from",[600,623,624],{"class":610}," \"",[600,626,628],{"class":627},"sfazB","@heximon\u002Fdomain",[600,630,631],{"class":610},"\"",[600,633,634],{"class":610},";\n",[600,636,638],{"class":602,"line":637},2,[600,639,641],{"emptyLinePlaceholder":640},true,"\n",[600,643,645,649,653],{"class":602,"line":644},3,[600,646,648],{"class":647},"spNyl","interface",[600,650,652],{"class":651},"sBMFI"," MoneyValue",[600,654,655],{"class":610}," {\n",[600,657,659,662,666,669,672],{"class":602,"line":658},4,[600,660,661],{"class":647},"  readonly",[600,663,665],{"class":664},"swJcz"," amountCents",[600,667,668],{"class":610},":",[600,670,671],{"class":651}," number",[600,673,634],{"class":610},[600,675,677,679,682,684,687],{"class":602,"line":676},5,[600,678,661],{"class":647},[600,680,681],{"class":664}," currency",[600,683,668],{"class":610},[600,685,686],{"class":651}," string",[600,688,634],{"class":610},[600,690,692],{"class":602,"line":691},6,[600,693,694],{"class":610},"}\n",[600,696,698],{"class":602,"line":697},7,[600,699,641],{"emptyLinePlaceholder":640},[600,701,703,706,709,712,715,717,720,723,726],{"class":602,"line":702},8,[600,704,705],{"class":606},"export",[600,707,708],{"class":647}," class",[600,710,711],{"class":651}," Money",[600,713,714],{"class":647}," extends",[600,716,615],{"class":651},[600,718,719],{"class":610},"\u003C",[600,721,722],{"class":651},"MoneyValue",[600,724,725],{"class":610},">",[600,727,655],{"class":610},[600,729,731,734,737,740,743,746,749,752,755,758,761,764,767],{"class":602,"line":730},9,[600,732,733],{"class":647},"  private",[600,735,736],{"class":647}," static",[600,738,739],{"class":647}," readonly",[600,741,742],{"class":664}," currencyPattern",[600,744,745],{"class":610}," =",[600,747,748],{"class":610}," \u002F",[600,750,751],{"class":606},"^",[600,753,754],{"class":610},"[",[600,756,757],{"class":627},"A-Z",[600,759,760],{"class":610},"]{3}",[600,762,763],{"class":606},"$",[600,765,766],{"class":610},"\u002F",[600,768,634],{"class":610},[600,770,772],{"class":602,"line":771},10,[600,773,641],{"emptyLinePlaceholder":640},[600,775,777,780,782,785,788,792,794,796,799,801,803,805,808,810],{"class":602,"line":776},11,[600,778,779],{"class":647},"  public",[600,781,736],{"class":647},[600,783,784],{"class":664}," create",[600,786,787],{"class":610},"(",[600,789,791],{"class":790},"sHdIc","amountCents",[600,793,668],{"class":610},[600,795,671],{"class":651},[600,797,798],{"class":610},",",[600,800,681],{"class":790},[600,802,668],{"class":610},[600,804,686],{"class":651},[600,806,807],{"class":610},"):",[600,809,711],{"class":651},[600,811,655],{"class":610},[600,813,815,818,821,824,827,830,834,836,838,841,844,846,849,853,855],{"class":602,"line":814},12,[600,816,817],{"class":606},"    if",[600,819,820],{"class":664}," (",[600,822,823],{"class":610},"!",[600,825,826],{"class":614},"Number",[600,828,829],{"class":610},".",[600,831,833],{"class":832},"s2Zo4","isInteger",[600,835,787],{"class":664},[600,837,791],{"class":614},[600,839,840],{"class":664},") ",[600,842,843],{"class":610},"||",[600,845,665],{"class":614},[600,847,848],{"class":610}," \u003C",[600,850,852],{"class":851},"sbssI"," 0",[600,854,840],{"class":664},[600,856,857],{"class":610},"{\n",[600,859,861,864,867,870,872,875,878,881,883,886,889],{"class":602,"line":860},13,[600,862,863],{"class":606},"      throw",[600,865,866],{"class":610}," new",[600,868,869],{"class":832}," RangeError",[600,871,787],{"class":664},[600,873,874],{"class":610},"`",[600,876,877],{"class":627},"Invalid money amount: ",[600,879,880],{"class":610},"${",[600,882,791],{"class":614},[600,884,885],{"class":610},"}`",[600,887,888],{"class":664},")",[600,890,634],{"class":610},[600,892,894],{"class":602,"line":893},14,[600,895,896],{"class":610},"    }\n",[600,898,900,902,904,906,908,910,913,915,918,920,923,926],{"class":602,"line":899},15,[600,901,817],{"class":606},[600,903,820],{"class":664},[600,905,823],{"class":610},[600,907,559],{"class":614},[600,909,829],{"class":610},[600,911,912],{"class":614},"currencyPattern",[600,914,829],{"class":610},[600,916,917],{"class":832},"test",[600,919,787],{"class":664},[600,921,922],{"class":614},"currency",[600,924,925],{"class":664},")) ",[600,927,857],{"class":610},[600,929,931,933,935,938,940,942,945,947,949,951,953],{"class":602,"line":930},16,[600,932,863],{"class":606},[600,934,866],{"class":610},[600,936,937],{"class":832}," TypeError",[600,939,787],{"class":664},[600,941,874],{"class":610},[600,943,944],{"class":627},"Invalid currency: ",[600,946,880],{"class":610},[600,948,922],{"class":614},[600,950,885],{"class":610},[600,952,888],{"class":664},[600,954,634],{"class":610},[600,956,958],{"class":602,"line":957},17,[600,959,896],{"class":610},[600,961,963,966,968,970,972,975,977,979,981,983,985],{"class":602,"line":962},18,[600,964,965],{"class":606},"    return",[600,967,866],{"class":610},[600,969,711],{"class":832},[600,971,787],{"class":664},[600,973,974],{"class":610},"{",[600,976,665],{"class":614},[600,978,798],{"class":610},[600,980,681],{"class":614},[600,982,618],{"class":610},[600,984,888],{"class":664},[600,986,634],{"class":610},[600,988,990],{"class":602,"line":989},19,[600,991,992],{"class":610},"  }\n",[600,994,996],{"class":602,"line":995},20,[600,997,641],{"emptyLinePlaceholder":640},[600,999,1001,1003,1006,1008,1011,1013],{"class":602,"line":1000},21,[600,1002,779],{"class":647},[600,1004,1005],{"class":647}," get",[600,1007,665],{"class":664},[600,1009,1010],{"class":610},"():",[600,1012,671],{"class":651},[600,1014,655],{"class":610},[600,1016,1018,1020,1023,1026,1029,1031,1033],{"class":602,"line":1017},22,[600,1019,965],{"class":606},[600,1021,1022],{"class":610}," this.",[600,1024,1025],{"class":832},"getInternalValue",[600,1027,1028],{"class":664},"()",[600,1030,829],{"class":610},[600,1032,791],{"class":614},[600,1034,634],{"class":610},[600,1036,1038],{"class":602,"line":1037},23,[600,1039,992],{"class":610},[600,1041,1043],{"class":602,"line":1042},24,[600,1044,641],{"emptyLinePlaceholder":640},[600,1046,1048,1050,1052,1054,1056,1058],{"class":602,"line":1047},25,[600,1049,779],{"class":647},[600,1051,1005],{"class":647},[600,1053,681],{"class":664},[600,1055,1010],{"class":610},[600,1057,686],{"class":651},[600,1059,655],{"class":610},[600,1061,1063,1065,1067,1069,1071,1073,1075],{"class":602,"line":1062},26,[600,1064,965],{"class":606},[600,1066,1022],{"class":610},[600,1068,1025],{"class":832},[600,1070,1028],{"class":664},[600,1072,829],{"class":610},[600,1074,922],{"class":614},[600,1076,634],{"class":610},[600,1078,1080],{"class":602,"line":1079},27,[600,1081,992],{"class":610},[600,1083,1085],{"class":602,"line":1084},28,[600,1086,641],{"emptyLinePlaceholder":640},[600,1088,1090,1092,1095,1097,1100,1102,1104,1106,1108],{"class":602,"line":1089},29,[600,1091,779],{"class":647},[600,1093,1094],{"class":664}," add",[600,1096,787],{"class":610},[600,1098,1099],{"class":790},"other",[600,1101,668],{"class":610},[600,1103,711],{"class":651},[600,1105,807],{"class":610},[600,1107,711],{"class":651},[600,1109,655],{"class":610},[600,1111,1113,1115,1117,1119,1121,1123,1126,1128,1130,1132],{"class":602,"line":1112},30,[600,1114,817],{"class":606},[600,1116,820],{"class":664},[600,1118,1099],{"class":614},[600,1120,829],{"class":610},[600,1122,922],{"class":614},[600,1124,1125],{"class":610}," !==",[600,1127,1022],{"class":610},[600,1129,922],{"class":614},[600,1131,840],{"class":664},[600,1133,857],{"class":610},[600,1135,1137,1139,1141,1143,1145,1147,1150,1152,1154],{"class":602,"line":1136},31,[600,1138,863],{"class":606},[600,1140,866],{"class":610},[600,1142,937],{"class":832},[600,1144,787],{"class":664},[600,1146,631],{"class":610},[600,1148,1149],{"class":627},"Currency mismatch",[600,1151,631],{"class":610},[600,1153,888],{"class":664},[600,1155,634],{"class":610},[600,1157,1159],{"class":602,"line":1158},32,[600,1160,896],{"class":610},[600,1162,1164,1166,1168,1170,1173,1175,1178,1180,1183,1186,1188,1190,1192,1194,1196,1198],{"class":602,"line":1163},33,[600,1165,965],{"class":606},[600,1167,711],{"class":614},[600,1169,829],{"class":610},[600,1171,1172],{"class":832},"create",[600,1174,787],{"class":664},[600,1176,1177],{"class":610},"this.",[600,1179,791],{"class":614},[600,1181,1182],{"class":610}," +",[600,1184,1185],{"class":614}," other",[600,1187,829],{"class":610},[600,1189,791],{"class":614},[600,1191,798],{"class":610},[600,1193,1022],{"class":610},[600,1195,922],{"class":614},[600,1197,888],{"class":664},[600,1199,634],{"class":610},[600,1201,1203],{"class":602,"line":1202},34,[600,1204,992],{"class":610},[600,1206,1208],{"class":602,"line":1207},35,[600,1209,641],{"emptyLinePlaceholder":640},[600,1211,1213,1215,1218,1220,1223,1225,1227,1229,1231],{"class":602,"line":1212},36,[600,1214,779],{"class":647},[600,1216,1217],{"class":664}," multiply",[600,1219,787],{"class":610},[600,1221,1222],{"class":790},"factor",[600,1224,668],{"class":610},[600,1226,671],{"class":651},[600,1228,807],{"class":610},[600,1230,711],{"class":651},[600,1232,655],{"class":610},[600,1234,1236,1238,1240,1242,1244,1246,1249,1251,1254,1256,1258,1260,1263,1266,1268,1270,1272,1274,1276],{"class":602,"line":1235},37,[600,1237,965],{"class":606},[600,1239,711],{"class":614},[600,1241,829],{"class":610},[600,1243,1172],{"class":832},[600,1245,787],{"class":664},[600,1247,1248],{"class":614},"Math",[600,1250,829],{"class":610},[600,1252,1253],{"class":832},"round",[600,1255,787],{"class":664},[600,1257,1177],{"class":610},[600,1259,791],{"class":614},[600,1261,1262],{"class":610}," *",[600,1264,1265],{"class":614}," factor",[600,1267,888],{"class":664},[600,1269,798],{"class":610},[600,1271,1022],{"class":610},[600,1273,922],{"class":614},[600,1275,888],{"class":664},[600,1277,634],{"class":610},[600,1279,1281],{"class":602,"line":1280},38,[600,1282,992],{"class":610},[600,1284,1286],{"class":602,"line":1285},39,[600,1287,694],{"class":610},[499,1289,1290,1292,1293,1297,1298,1301,1302,1304,1305,1308,1309,1311,1312,1314],{},[516,1291,559],{}," has no id — it ",[1294,1295,1296],"em",{},"is"," its amount and currency, so two with the same value are ",[516,1299,1300],{},"equals",". The value is\nfrozen on construction, so every operation returns a new ",[516,1303,559],{}," (read back through ",[516,1306,1307],{},"getInternalValue()","),\nand the ",[516,1310,1172],{}," factory holds the invariant so a ",[516,1313,559],{}," is always valid.",[499,1316,1317,1318,1324,1325,1328],{},"To skip the manual checks, hand the base a ",[503,1319,1323],{"href":1320,"rel":1321},"https:\u002F\u002Fstandardschema.dev",[1322],"nofollow","Standard Schema"," validator:\n",[516,1326,1327],{},"class BirthDate extends ValueObject(schema) {}"," validates on construction and throws HTTP 400 on bad\ninput — use a synchronous one.",[499,1330,1331,1332,1335,1336,1339,1340,1342,1343,1345,1346,1348,1349,1352],{},"Value objects nest, and equality recurses all the way down — you never write the comparison, and it stays\ncorrect as the shape grows. An ",[516,1333,1334],{},"OrderItem"," (a branded ",[516,1337,1338],{},"ProductId",", a ",[516,1341,559],{}," unit price, a quantity) wraps\na nested ",[516,1344,559],{}," the same way, and two ",[516,1347,1334],{},"s are equal only when their unit prices are too. See the\n",[503,1350,584],{"href":1351},"\u002Fdocs\u002Frecipes\u002Fddd-aggregate#model-the-value-objects"," for that full definition.",[508,1354,1356],{"id":1355},"model-an-aggregate-root","Model an aggregate root",[499,1358,514,1359,1362,1363,1366,1367,1369,1370,1373],{},[516,1360,1361],{},"AggregateRoot"," is the entity at the top of a cluster — the ",[528,1364,1365],{},"consistency boundary"," for everything\ninside it. Invariants live in its methods, so an ",[516,1368,518],{}," is the only thing that may change its own status\nor items, and can never reach an invalid state from outside. As it changes it ",[528,1371,1372],{},"records domain events"," —\nfacts about what happened, buffered for later dispatch.",[590,1375,1378],{"className":592,"code":1376,"filename":1377,"language":595,"meta":596,"style":596},"import type { Branded } from \"@heximon\u002Fprimitives\";\nimport { AggregateRoot } from \"@heximon\u002Fdomain\";\nimport { OrderCreatedDomainEvent, OrderShippedDomainEvent } from \".\u002Fdomain-events\u002Forder.events\";\nimport { CannotShipTwiceError } from \".\u002Forder-errors\";\nimport type { OrderItem } from \".\u002Forder-item.value\";\n\nexport type OrderId = Branded\u003Cstring, \"OrderId\">;\n\nexport const OrderStatus = { Draft: \"Draft\", Shipped: \"Shipped\" } as const;\nexport type OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];\n\ninterface OrderProps extends Record\u003Cstring, unknown> {\n  items: OrderItem[];\n  status: OrderStatus;\n  shippedAt: Date | undefined;\n}\n\nexport class Order extends AggregateRoot\u003COrderProps, OrderId> {\n  public static create(id: OrderId, items: OrderItem[]): Order {\n    const order = new Order(id, { items: [...items], status: OrderStatus.Draft, shippedAt: undefined });\n    order.addDomainEvent(new OrderCreatedDomainEvent(id)); \u002F\u002F buffered, flushed later\n    return order;\n  }\n\n  public ship(): void {\n    if (this.props.status === OrderStatus.Shipped) {\n      throw new CannotShipTwiceError();\n    }\n    this.props.status = OrderStatus.Shipped;\n    this.props.shippedAt = new Date();\n    this.addDomainEvent(new OrderShippedDomainEvent(this.id, this.props.shippedAt));\n  }\n\n  public hasShipped(): boolean {\n    return this.props.status === OrderStatus.Shipped;\n  }\n\n  public get status(): OrderStatus {\n    return this.props.status;\n  }\n}\n","src\u002Forders\u002Forder.entity.ts",[516,1379,1380,1405,1426,1453,1475,1499,1503,1533,1537,1587,1617,1621,1646,1660,1671,1689,1693,1697,1723,1757,1823,1854,1862,1866,1870,1884,1913,1925,1929,1950,1971,2003,2007,2011,2025,2047,2051,2055,2069,2083,2088],{"__ignoreMap":596},[600,1381,1382,1384,1387,1389,1392,1394,1396,1398,1401,1403],{"class":602,"line":603},[600,1383,607],{"class":606},[600,1385,1386],{"class":606}," type",[600,1388,611],{"class":610},[600,1390,1391],{"class":614}," Branded",[600,1393,618],{"class":610},[600,1395,621],{"class":606},[600,1397,624],{"class":610},[600,1399,1400],{"class":627},"@heximon\u002Fprimitives",[600,1402,631],{"class":610},[600,1404,634],{"class":610},[600,1406,1407,1409,1411,1414,1416,1418,1420,1422,1424],{"class":602,"line":637},[600,1408,607],{"class":606},[600,1410,611],{"class":610},[600,1412,1413],{"class":614}," AggregateRoot",[600,1415,618],{"class":610},[600,1417,621],{"class":606},[600,1419,624],{"class":610},[600,1421,628],{"class":627},[600,1423,631],{"class":610},[600,1425,634],{"class":610},[600,1427,1428,1430,1432,1435,1437,1440,1442,1444,1446,1449,1451],{"class":602,"line":644},[600,1429,607],{"class":606},[600,1431,611],{"class":610},[600,1433,1434],{"class":614}," OrderCreatedDomainEvent",[600,1436,798],{"class":610},[600,1438,1439],{"class":614}," OrderShippedDomainEvent",[600,1441,618],{"class":610},[600,1443,621],{"class":606},[600,1445,624],{"class":610},[600,1447,1448],{"class":627},".\u002Fdomain-events\u002Forder.events",[600,1450,631],{"class":610},[600,1452,634],{"class":610},[600,1454,1455,1457,1459,1462,1464,1466,1468,1471,1473],{"class":602,"line":658},[600,1456,607],{"class":606},[600,1458,611],{"class":610},[600,1460,1461],{"class":614}," CannotShipTwiceError",[600,1463,618],{"class":610},[600,1465,621],{"class":606},[600,1467,624],{"class":610},[600,1469,1470],{"class":627},".\u002Forder-errors",[600,1472,631],{"class":610},[600,1474,634],{"class":610},[600,1476,1477,1479,1481,1483,1486,1488,1490,1492,1495,1497],{"class":602,"line":676},[600,1478,607],{"class":606},[600,1480,1386],{"class":606},[600,1482,611],{"class":610},[600,1484,1485],{"class":614}," OrderItem",[600,1487,618],{"class":610},[600,1489,621],{"class":606},[600,1491,624],{"class":610},[600,1493,1494],{"class":627},".\u002Forder-item.value",[600,1496,631],{"class":610},[600,1498,634],{"class":610},[600,1500,1501],{"class":602,"line":691},[600,1502,641],{"emptyLinePlaceholder":640},[600,1504,1505,1507,1509,1512,1514,1516,1518,1521,1523,1525,1528,1530],{"class":602,"line":697},[600,1506,705],{"class":606},[600,1508,1386],{"class":647},[600,1510,1511],{"class":651}," OrderId",[600,1513,745],{"class":610},[600,1515,1391],{"class":651},[600,1517,719],{"class":610},[600,1519,1520],{"class":651},"string",[600,1522,798],{"class":610},[600,1524,624],{"class":610},[600,1526,1527],{"class":627},"OrderId",[600,1529,631],{"class":610},[600,1531,1532],{"class":610},">;\n",[600,1534,1535],{"class":602,"line":702},[600,1536,641],{"emptyLinePlaceholder":640},[600,1538,1539,1541,1544,1547,1550,1552,1555,1557,1559,1562,1564,1566,1569,1571,1573,1576,1578,1580,1583,1585],{"class":602,"line":730},[600,1540,705],{"class":606},[600,1542,1543],{"class":647}," const",[600,1545,1546],{"class":614}," OrderStatus ",[600,1548,1549],{"class":610},"=",[600,1551,611],{"class":610},[600,1553,1554],{"class":664}," Draft",[600,1556,668],{"class":610},[600,1558,624],{"class":610},[600,1560,1561],{"class":627},"Draft",[600,1563,631],{"class":610},[600,1565,798],{"class":610},[600,1567,1568],{"class":664}," Shipped",[600,1570,668],{"class":610},[600,1572,624],{"class":610},[600,1574,1575],{"class":627},"Shipped",[600,1577,631],{"class":610},[600,1579,618],{"class":610},[600,1581,1582],{"class":606}," as",[600,1584,1543],{"class":647},[600,1586,634],{"class":610},[600,1588,1589,1591,1593,1596,1598,1600,1603,1606,1609,1612,1615],{"class":602,"line":771},[600,1590,705],{"class":606},[600,1592,1386],{"class":647},[600,1594,1595],{"class":651}," OrderStatus",[600,1597,745],{"class":610},[600,1599,820],{"class":614},[600,1601,1602],{"class":610},"typeof",[600,1604,1605],{"class":614}," OrderStatus)[",[600,1607,1608],{"class":610},"keyof",[600,1610,1611],{"class":610}," typeof",[600,1613,1614],{"class":614}," OrderStatus]",[600,1616,634],{"class":610},[600,1618,1619],{"class":602,"line":776},[600,1620,641],{"emptyLinePlaceholder":640},[600,1622,1623,1625,1628,1630,1633,1635,1637,1639,1642,1644],{"class":602,"line":814},[600,1624,648],{"class":647},[600,1626,1627],{"class":651}," OrderProps",[600,1629,714],{"class":647},[600,1631,1632],{"class":651}," Record",[600,1634,719],{"class":610},[600,1636,1520],{"class":651},[600,1638,798],{"class":610},[600,1640,1641],{"class":651}," unknown",[600,1643,725],{"class":610},[600,1645,655],{"class":610},[600,1647,1648,1651,1653,1655,1658],{"class":602,"line":860},[600,1649,1650],{"class":664},"  items",[600,1652,668],{"class":610},[600,1654,1485],{"class":651},[600,1656,1657],{"class":614},"[]",[600,1659,634],{"class":610},[600,1661,1662,1665,1667,1669],{"class":602,"line":893},[600,1663,1664],{"class":664},"  status",[600,1666,668],{"class":610},[600,1668,1595],{"class":651},[600,1670,634],{"class":610},[600,1672,1673,1676,1678,1681,1684,1687],{"class":602,"line":899},[600,1674,1675],{"class":664},"  shippedAt",[600,1677,668],{"class":610},[600,1679,1680],{"class":651}," Date",[600,1682,1683],{"class":610}," |",[600,1685,1686],{"class":651}," undefined",[600,1688,634],{"class":610},[600,1690,1691],{"class":602,"line":930},[600,1692,694],{"class":610},[600,1694,1695],{"class":602,"line":957},[600,1696,641],{"emptyLinePlaceholder":640},[600,1698,1699,1701,1703,1706,1708,1710,1712,1715,1717,1719,1721],{"class":602,"line":962},[600,1700,705],{"class":606},[600,1702,708],{"class":647},[600,1704,1705],{"class":651}," Order",[600,1707,714],{"class":647},[600,1709,1413],{"class":651},[600,1711,719],{"class":610},[600,1713,1714],{"class":651},"OrderProps",[600,1716,798],{"class":610},[600,1718,1511],{"class":651},[600,1720,725],{"class":610},[600,1722,655],{"class":610},[600,1724,1725,1727,1729,1731,1733,1736,1738,1740,1742,1745,1747,1749,1751,1753,1755],{"class":602,"line":989},[600,1726,779],{"class":647},[600,1728,736],{"class":647},[600,1730,784],{"class":664},[600,1732,787],{"class":610},[600,1734,1735],{"class":790},"id",[600,1737,668],{"class":610},[600,1739,1511],{"class":651},[600,1741,798],{"class":610},[600,1743,1744],{"class":790}," items",[600,1746,668],{"class":610},[600,1748,1485],{"class":651},[600,1750,1657],{"class":614},[600,1752,807],{"class":610},[600,1754,1705],{"class":651},[600,1756,655],{"class":610},[600,1758,1759,1762,1765,1767,1769,1771,1773,1775,1777,1779,1781,1783,1786,1789,1792,1795,1797,1800,1802,1804,1806,1808,1810,1813,1815,1817,1819,1821],{"class":602,"line":995},[600,1760,1761],{"class":647},"    const",[600,1763,1764],{"class":614}," order",[600,1766,745],{"class":610},[600,1768,866],{"class":610},[600,1770,1705],{"class":832},[600,1772,787],{"class":664},[600,1774,1735],{"class":614},[600,1776,798],{"class":610},[600,1778,611],{"class":610},[600,1780,1744],{"class":664},[600,1782,668],{"class":610},[600,1784,1785],{"class":664}," [",[600,1787,1788],{"class":610},"...",[600,1790,1791],{"class":614},"items",[600,1793,1794],{"class":664},"]",[600,1796,798],{"class":610},[600,1798,1799],{"class":664}," status",[600,1801,668],{"class":610},[600,1803,1595],{"class":614},[600,1805,829],{"class":610},[600,1807,1561],{"class":614},[600,1809,798],{"class":610},[600,1811,1812],{"class":664}," shippedAt",[600,1814,668],{"class":610},[600,1816,1686],{"class":610},[600,1818,618],{"class":610},[600,1820,888],{"class":664},[600,1822,634],{"class":610},[600,1824,1825,1828,1830,1833,1835,1838,1840,1842,1844,1847,1850],{"class":602,"line":1000},[600,1826,1827],{"class":614},"    order",[600,1829,829],{"class":610},[600,1831,1832],{"class":832},"addDomainEvent",[600,1834,787],{"class":664},[600,1836,1837],{"class":610},"new",[600,1839,1434],{"class":832},[600,1841,787],{"class":664},[600,1843,1735],{"class":614},[600,1845,1846],{"class":664},"))",[600,1848,1849],{"class":610},";",[600,1851,1853],{"class":1852},"sHwdD"," \u002F\u002F buffered, flushed later\n",[600,1855,1856,1858,1860],{"class":602,"line":1017},[600,1857,965],{"class":606},[600,1859,1764],{"class":614},[600,1861,634],{"class":610},[600,1863,1864],{"class":602,"line":1037},[600,1865,992],{"class":610},[600,1867,1868],{"class":602,"line":1042},[600,1869,641],{"emptyLinePlaceholder":640},[600,1871,1872,1874,1877,1879,1882],{"class":602,"line":1047},[600,1873,779],{"class":647},[600,1875,1876],{"class":664}," ship",[600,1878,1010],{"class":610},[600,1880,1881],{"class":651}," void",[600,1883,655],{"class":610},[600,1885,1886,1888,1890,1892,1895,1897,1900,1903,1905,1907,1909,1911],{"class":602,"line":1062},[600,1887,817],{"class":606},[600,1889,820],{"class":664},[600,1891,1177],{"class":610},[600,1893,1894],{"class":614},"props",[600,1896,829],{"class":610},[600,1898,1899],{"class":614},"status",[600,1901,1902],{"class":610}," ===",[600,1904,1595],{"class":614},[600,1906,829],{"class":610},[600,1908,1575],{"class":614},[600,1910,840],{"class":664},[600,1912,857],{"class":610},[600,1914,1915,1917,1919,1921,1923],{"class":602,"line":1079},[600,1916,863],{"class":606},[600,1918,866],{"class":610},[600,1920,1461],{"class":832},[600,1922,1028],{"class":664},[600,1924,634],{"class":610},[600,1926,1927],{"class":602,"line":1084},[600,1928,896],{"class":610},[600,1930,1931,1934,1936,1938,1940,1942,1944,1946,1948],{"class":602,"line":1089},[600,1932,1933],{"class":610},"    this.",[600,1935,1894],{"class":614},[600,1937,829],{"class":610},[600,1939,1899],{"class":614},[600,1941,745],{"class":610},[600,1943,1595],{"class":614},[600,1945,829],{"class":610},[600,1947,1575],{"class":614},[600,1949,634],{"class":610},[600,1951,1952,1954,1956,1958,1961,1963,1965,1967,1969],{"class":602,"line":1112},[600,1953,1933],{"class":610},[600,1955,1894],{"class":614},[600,1957,829],{"class":610},[600,1959,1960],{"class":614},"shippedAt",[600,1962,745],{"class":610},[600,1964,866],{"class":610},[600,1966,1680],{"class":832},[600,1968,1028],{"class":664},[600,1970,634],{"class":610},[600,1972,1973,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999,2001],{"class":602,"line":1136},[600,1974,1933],{"class":610},[600,1976,1832],{"class":832},[600,1978,787],{"class":664},[600,1980,1837],{"class":610},[600,1982,1439],{"class":832},[600,1984,787],{"class":664},[600,1986,1177],{"class":610},[600,1988,1735],{"class":614},[600,1990,798],{"class":610},[600,1992,1022],{"class":610},[600,1994,1894],{"class":614},[600,1996,829],{"class":610},[600,1998,1960],{"class":614},[600,2000,1846],{"class":664},[600,2002,634],{"class":610},[600,2004,2005],{"class":602,"line":1158},[600,2006,992],{"class":610},[600,2008,2009],{"class":602,"line":1163},[600,2010,641],{"emptyLinePlaceholder":640},[600,2012,2013,2015,2018,2020,2023],{"class":602,"line":1202},[600,2014,779],{"class":647},[600,2016,2017],{"class":664}," hasShipped",[600,2019,1010],{"class":610},[600,2021,2022],{"class":651}," boolean",[600,2024,655],{"class":610},[600,2026,2027,2029,2031,2033,2035,2037,2039,2041,2043,2045],{"class":602,"line":1207},[600,2028,965],{"class":606},[600,2030,1022],{"class":610},[600,2032,1894],{"class":614},[600,2034,829],{"class":610},[600,2036,1899],{"class":614},[600,2038,1902],{"class":610},[600,2040,1595],{"class":614},[600,2042,829],{"class":610},[600,2044,1575],{"class":614},[600,2046,634],{"class":610},[600,2048,2049],{"class":602,"line":1212},[600,2050,992],{"class":610},[600,2052,2053],{"class":602,"line":1235},[600,2054,641],{"emptyLinePlaceholder":640},[600,2056,2057,2059,2061,2063,2065,2067],{"class":602,"line":1280},[600,2058,779],{"class":647},[600,2060,1005],{"class":647},[600,2062,1799],{"class":664},[600,2064,1010],{"class":610},[600,2066,1595],{"class":651},[600,2068,655],{"class":610},[600,2070,2071,2073,2075,2077,2079,2081],{"class":602,"line":1285},[600,2072,965],{"class":606},[600,2074,1022],{"class":610},[600,2076,1894],{"class":614},[600,2078,829],{"class":610},[600,2080,1899],{"class":614},[600,2082,634],{"class":610},[600,2084,2086],{"class":602,"line":2085},40,[600,2087,992],{"class":610},[600,2089,2091],{"class":602,"line":2090},41,[600,2092,694],{"class":610},[499,2094,2095,2096,2099,2100,2103,2104,2106,2107,2110],{},"The aggregate has ",[528,2097,2098],{},"no dependency on the event bus"," — ",[516,2101,2102],{},"addDomainEvent(...)"," just buffers, and a caller\ndrains it after the save. That keeps ",[516,2105,518],{}," a pure domain object you can unit-test, and leaves ",[1294,2108,2109],{},"when","\nevents fire to the application.",[499,2112,2113,2115,2116,2099,2119,2122,2123,2125,2126,2128,2129,2131],{},[516,2114,1527],{}," is a ",[528,2117,2118],{},"branded type",[516,2120,2121],{},"Branded\u003Cstring, \"OrderId\">"," from ",[516,2124,1400],{},". It\ninterchanges freely with a plain ",[516,2127,1520],{},", but the compiler rejects passing one where a differently\nbranded id (a ",[516,2130,1338],{},") is expected — a type-level guard with zero runtime cost, so your domain methods\ncan't cross identifiers.",[508,2133,2135],{"id":2134},"know-what-an-entity-changed","Know what an entity changed",[499,2137,514,2138,2141,2142,2144,2145,2147,2148,2150,2151,2153],{},[516,2139,2140],{},"Entity"," (and ",[516,2143,1361],{},", which extends it) has identity: two are ",[516,2146,1300],{}," when they share an\n",[516,2149,1735],{},". You mutate its ",[516,2152,1894],{}," as plain fields, and the entity works out what changed by diffing a snapshot\ntaken when it was loaded or last saved — no proxy, no per-field tracking call to remember.",[499,2155,2156,2157,2160],{},"That diff drives a ",[516,2158,2159],{},"DirtyState"," marker, which a repository reads to pick the right write — so partial\nupdates are free, with no dirty flag of your own:",[2162,2163,2164,2184],"table",{},[2165,2166,2167],"thead",{},[2168,2169,2170,2175,2178],"tr",{},[2171,2172,2174],"th",{"align":2173},"left","State",[2171,2176,2177],{"align":2173},"Meaning",[2171,2179,2180,2181],{"align":2173},"Write on ",[516,2182,2183],{},"save()",[2185,2186,2187,2203,2216],"tbody",{},[2168,2188,2189,2195,2198],{},[2190,2191,2192],"td",{"align":2173},[516,2193,2194],{},"Detached",[2190,2196,2197],{"align":2173},"Newly created, never persisted",[2190,2199,2200],{"align":2173},[516,2201,2202],{},"INSERT",[2168,2204,2205,2210,2213],{},[2190,2206,2207],{"align":2173},[516,2208,2209],{},"Persistent",[2190,2211,2212],{"align":2173},"In sync with the store",[2190,2214,2215],{"align":2173},"No-op",[2168,2217,2218,2223,2226],{},[2190,2219,2220],{"align":2173},[516,2221,2222],{},"Transient",[2190,2224,2225],{"align":2173},"Persisted, then mutated",[2190,2227,2228,2231],{"align":2173},[516,2229,2230],{},"UPDATE"," (changed columns only)",[499,2233,2234],{},"That same diff is what makes the write-skew failure mode from the top of this page fail loud instead of\nsilently losing data — see the next section.",[508,2236,2238],{"id":2237},"stop-write-skew-with-optimistic-concurrency","Stop write-skew with optimistic concurrency",[499,2240,2241,2242,2244,2245,2248,2249,2251,2252,2254,2255,2257,2258,2261],{},"Every ",[516,2243,2140],{}," carries a monotonically increasing ",[516,2246,2247],{},"version",", bumped whenever a ",[516,2250,2209],{}," entity goes\n",[516,2253,2222],{},". A repository's ",[516,2256,2183],{}," issues a version-guarded write — ",[516,2259,2260],{},"UPDATE … WHERE version = \u003Cexpected>","\n— and treats \"zero rows updated\" as a conflict, not a silent no-op.",[499,2263,2264,2265,2268],{},"That's what turns the two-workers-load-the-same-row scenario from the top of this page into a loud\n",[516,2266,2267],{},"ConcurrencyError"," for the loser, instead of a silently clobbered write:",[590,2270,2273],{"className":592,"code":2271,"filename":2272,"language":595,"meta":596,"style":596},"\u002F\u002F Two independent reads simulate two workers loading the same row at the same version.\nconst first = await repository.getById(carol.id);\nconst second = await repository.getById(carol.id);\n\nfirst.rename(\"Carol A\");\nawait repository.save(first);\n\n\u002F\u002F The second worker's in-memory version is now stale: its version-guarded UPDATE matches zero rows.\nsecond.rename(\"Carol B\");\nawait expect(repository.save(second)).rejects.toBeInstanceOf(ConcurrencyError);\n\n\u002F\u002F The first writer won; the row is at version 2 with its name.\nconst reloaded = await repository.getById(carol.id);\nexpect(reloaded?.name).toBe(\"Carol A\");\nexpect(reloaded?.getVersion()).toBe(2);\n","examples\u002Fladder\u002FL06-ddd\u002Ftest\u002Fusers.test.ts",[516,2274,2275,2280,2311,2336,2340,2363,2380,2384,2389,2411,2443,2447,2452,2477,2508],{"__ignoreMap":596},[600,2276,2277],{"class":602,"line":603},[600,2278,2279],{"class":1852},"\u002F\u002F Two independent reads simulate two workers loading the same row at the same version.\n",[600,2281,2282,2285,2288,2290,2293,2296,2298,2301,2304,2306,2309],{"class":602,"line":637},[600,2283,2284],{"class":647},"const",[600,2286,2287],{"class":614}," first ",[600,2289,1549],{"class":610},[600,2291,2292],{"class":606}," await",[600,2294,2295],{"class":614}," repository",[600,2297,829],{"class":610},[600,2299,2300],{"class":832},"getById",[600,2302,2303],{"class":614},"(carol",[600,2305,829],{"class":610},[600,2307,2308],{"class":614},"id)",[600,2310,634],{"class":610},[600,2312,2313,2315,2318,2320,2322,2324,2326,2328,2330,2332,2334],{"class":602,"line":644},[600,2314,2284],{"class":647},[600,2316,2317],{"class":614}," second ",[600,2319,1549],{"class":610},[600,2321,2292],{"class":606},[600,2323,2295],{"class":614},[600,2325,829],{"class":610},[600,2327,2300],{"class":832},[600,2329,2303],{"class":614},[600,2331,829],{"class":610},[600,2333,2308],{"class":614},[600,2335,634],{"class":610},[600,2337,2338],{"class":602,"line":658},[600,2339,641],{"emptyLinePlaceholder":640},[600,2341,2342,2345,2347,2350,2352,2354,2357,2359,2361],{"class":602,"line":676},[600,2343,2344],{"class":614},"first",[600,2346,829],{"class":610},[600,2348,2349],{"class":832},"rename",[600,2351,787],{"class":614},[600,2353,631],{"class":610},[600,2355,2356],{"class":627},"Carol A",[600,2358,631],{"class":610},[600,2360,888],{"class":614},[600,2362,634],{"class":610},[600,2364,2365,2368,2370,2372,2375,2378],{"class":602,"line":691},[600,2366,2367],{"class":606},"await",[600,2369,2295],{"class":614},[600,2371,829],{"class":610},[600,2373,2374],{"class":832},"save",[600,2376,2377],{"class":614},"(first)",[600,2379,634],{"class":610},[600,2381,2382],{"class":602,"line":697},[600,2383,641],{"emptyLinePlaceholder":640},[600,2385,2386],{"class":602,"line":702},[600,2387,2388],{"class":1852},"\u002F\u002F The second worker's in-memory version is now stale: its version-guarded UPDATE matches zero rows.\n",[600,2390,2391,2394,2396,2398,2400,2402,2405,2407,2409],{"class":602,"line":730},[600,2392,2393],{"class":614},"second",[600,2395,829],{"class":610},[600,2397,2349],{"class":832},[600,2399,787],{"class":614},[600,2401,631],{"class":610},[600,2403,2404],{"class":627},"Carol B",[600,2406,631],{"class":610},[600,2408,888],{"class":614},[600,2410,634],{"class":610},[600,2412,2413,2415,2418,2421,2423,2425,2428,2430,2433,2435,2438,2441],{"class":602,"line":771},[600,2414,2367],{"class":606},[600,2416,2417],{"class":832}," expect",[600,2419,2420],{"class":614},"(repository",[600,2422,829],{"class":610},[600,2424,2374],{"class":832},[600,2426,2427],{"class":614},"(second))",[600,2429,829],{"class":610},[600,2431,2432],{"class":614},"rejects",[600,2434,829],{"class":610},[600,2436,2437],{"class":832},"toBeInstanceOf",[600,2439,2440],{"class":614},"(ConcurrencyError)",[600,2442,634],{"class":610},[600,2444,2445],{"class":602,"line":776},[600,2446,641],{"emptyLinePlaceholder":640},[600,2448,2449],{"class":602,"line":814},[600,2450,2451],{"class":1852},"\u002F\u002F The first writer won; the row is at version 2 with its name.\n",[600,2453,2454,2456,2459,2461,2463,2465,2467,2469,2471,2473,2475],{"class":602,"line":860},[600,2455,2284],{"class":647},[600,2457,2458],{"class":614}," reloaded ",[600,2460,1549],{"class":610},[600,2462,2292],{"class":606},[600,2464,2295],{"class":614},[600,2466,829],{"class":610},[600,2468,2300],{"class":832},[600,2470,2303],{"class":614},[600,2472,829],{"class":610},[600,2474,2308],{"class":614},[600,2476,634],{"class":610},[600,2478,2479,2482,2485,2488,2491,2493,2496,2498,2500,2502,2504,2506],{"class":602,"line":893},[600,2480,2481],{"class":832},"expect",[600,2483,2484],{"class":614},"(reloaded",[600,2486,2487],{"class":610},"?.",[600,2489,2490],{"class":614},"name)",[600,2492,829],{"class":610},[600,2494,2495],{"class":832},"toBe",[600,2497,787],{"class":614},[600,2499,631],{"class":610},[600,2501,2356],{"class":627},[600,2503,631],{"class":610},[600,2505,888],{"class":614},[600,2507,634],{"class":610},[600,2509,2510,2512,2514,2516,2519,2522,2524,2526,2528,2531,2533],{"class":602,"line":899},[600,2511,2481],{"class":832},[600,2513,2484],{"class":614},[600,2515,2487],{"class":610},[600,2517,2518],{"class":832},"getVersion",[600,2520,2521],{"class":614},"())",[600,2523,829],{"class":610},[600,2525,2495],{"class":832},[600,2527,787],{"class":614},[600,2529,2530],{"class":851},"2",[600,2532,888],{"class":614},[600,2534,634],{"class":610},[499,2536,2537,2538,2540,2541,2543,2544,2548,2549,2551],{},"The loser gets a ",[516,2539,2267],{}," to retry against fresh state instead of a lost update — no row locks\nheld across the request, just a version check at write time. This is the same ",[516,2542,2267],{},"\nhierarchy every dialect implements; see ",[503,2545,2547],{"href":2546},"\u002Fdocs\u002Fessentials\u002Fpersistence#optimistic-concurrency","Persistence → optimistic\nconcurrency"," for the underlying contract, and note\nthat ",[503,2550,233],{"href":234},"'s command bus already retries on it automatically.",[508,2553,2555],{"id":2554},"raise-domain-errors","Raise domain errors",[499,2557,2558,2559,2562,2563,2566,2567,829],{},"A ",[516,2560,2561],{},"DomainError"," extends the core ",[516,2564,2565],{},"HeximonError",", so throwing one from any handler renders as a well-formed\nRFC 9457 problem response with the right HTTP status — no error-mapping layer in between. Set it with the\nstatic ",[516,2568,2569],{},"statusCode",[590,2571,2574],{"className":592,"code":2572,"filename":2573,"language":595,"meta":596,"style":596},"import { DomainError } from \"@heximon\u002Fdomain\";\n\nexport class CannotShipTwiceError extends DomainError {\n  public static override readonly statusCode = 409;\n\n  public constructor() {\n    super(\"Order has already shipped\");\n    this.statusCode = CannotShipTwiceError.statusCode;\n  }\n}\n","src\u002Forders\u002Forder-errors.ts",[516,2575,2576,2597,2601,2615,2636,2640,2651,2669,2685,2689],{"__ignoreMap":596},[600,2577,2578,2580,2582,2585,2587,2589,2591,2593,2595],{"class":602,"line":603},[600,2579,607],{"class":606},[600,2581,611],{"class":610},[600,2583,2584],{"class":614}," DomainError",[600,2586,618],{"class":610},[600,2588,621],{"class":606},[600,2590,624],{"class":610},[600,2592,628],{"class":627},[600,2594,631],{"class":610},[600,2596,634],{"class":610},[600,2598,2599],{"class":602,"line":637},[600,2600,641],{"emptyLinePlaceholder":640},[600,2602,2603,2605,2607,2609,2611,2613],{"class":602,"line":644},[600,2604,705],{"class":606},[600,2606,708],{"class":647},[600,2608,1461],{"class":651},[600,2610,714],{"class":647},[600,2612,2584],{"class":651},[600,2614,655],{"class":610},[600,2616,2617,2619,2621,2624,2626,2629,2631,2634],{"class":602,"line":658},[600,2618,779],{"class":647},[600,2620,736],{"class":647},[600,2622,2623],{"class":647}," override",[600,2625,739],{"class":647},[600,2627,2628],{"class":664}," statusCode",[600,2630,745],{"class":610},[600,2632,2633],{"class":851}," 409",[600,2635,634],{"class":610},[600,2637,2638],{"class":602,"line":676},[600,2639,641],{"emptyLinePlaceholder":640},[600,2641,2642,2644,2647,2649],{"class":602,"line":691},[600,2643,779],{"class":647},[600,2645,2646],{"class":647}," constructor",[600,2648,1028],{"class":610},[600,2650,655],{"class":610},[600,2652,2653,2656,2658,2660,2663,2665,2667],{"class":602,"line":697},[600,2654,2655],{"class":614},"    super",[600,2657,787],{"class":664},[600,2659,631],{"class":610},[600,2661,2662],{"class":627},"Order has already shipped",[600,2664,631],{"class":610},[600,2666,888],{"class":664},[600,2668,634],{"class":610},[600,2670,2671,2673,2675,2677,2679,2681,2683],{"class":602,"line":702},[600,2672,1933],{"class":610},[600,2674,2569],{"class":614},[600,2676,745],{"class":610},[600,2678,1461],{"class":614},[600,2680,829],{"class":610},[600,2682,2569],{"class":614},[600,2684,634],{"class":610},[600,2686,2687],{"class":602,"line":730},[600,2688,992],{"class":610},[600,2690,2691],{"class":602,"line":771},[600,2692,694],{"class":610},[499,2694,2695,2696,2699],{},"A forbidden transition is a domain fact, not an HTTP concern — so the rule lives on the aggregate, and the\nframework turns the throw into a ",[516,2697,2698],{},"409"," at the boundary.",[508,2701,2703],{"id":2702},"record-and-flush-domain-events","Record and flush domain events",[499,2705,2558,2706,2709],{},[516,2707,2708],{},"DomainEvent"," is a plain class whose constructor parameters carry its payload. The aggregate records it\non a state change; nothing dispatches until you flush.",[590,2711,2714],{"className":592,"code":2712,"filename":2713,"language":595,"meta":596,"style":596},"import { DomainEvent } from \"@heximon\u002Fdomain\";\nimport type { OrderId } from \"..\u002Forder.entity\";\n\nexport class OrderCreatedDomainEvent extends DomainEvent {\n  public constructor(public readonly orderId: OrderId) {\n    super();\n  }\n}\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","src\u002Forders\u002Fdomain-events\u002Forder.events.ts",[516,2715,2716,2737,2760,2764,2778,2802,2810,2814,2818,2822,2836,2845,2861,2875,2882,2890,2894],{"__ignoreMap":596},[600,2717,2718,2720,2722,2725,2727,2729,2731,2733,2735],{"class":602,"line":603},[600,2719,607],{"class":606},[600,2721,611],{"class":610},[600,2723,2724],{"class":614}," DomainEvent",[600,2726,618],{"class":610},[600,2728,621],{"class":606},[600,2730,624],{"class":610},[600,2732,628],{"class":627},[600,2734,631],{"class":610},[600,2736,634],{"class":610},[600,2738,2739,2741,2743,2745,2747,2749,2751,2753,2756,2758],{"class":602,"line":637},[600,2740,607],{"class":606},[600,2742,1386],{"class":606},[600,2744,611],{"class":610},[600,2746,1511],{"class":614},[600,2748,618],{"class":610},[600,2750,621],{"class":606},[600,2752,624],{"class":610},[600,2754,2755],{"class":627},"..\u002Forder.entity",[600,2757,631],{"class":610},[600,2759,634],{"class":610},[600,2761,2762],{"class":602,"line":644},[600,2763,641],{"emptyLinePlaceholder":640},[600,2765,2766,2768,2770,2772,2774,2776],{"class":602,"line":658},[600,2767,705],{"class":606},[600,2769,708],{"class":647},[600,2771,1434],{"class":651},[600,2773,714],{"class":647},[600,2775,2724],{"class":651},[600,2777,655],{"class":610},[600,2779,2780,2782,2784,2786,2789,2791,2794,2796,2798,2800],{"class":602,"line":676},[600,2781,779],{"class":647},[600,2783,2646],{"class":647},[600,2785,787],{"class":610},[600,2787,2788],{"class":647},"public",[600,2790,739],{"class":647},[600,2792,2793],{"class":790}," orderId",[600,2795,668],{"class":610},[600,2797,1511],{"class":651},[600,2799,888],{"class":610},[600,2801,655],{"class":610},[600,2803,2804,2806,2808],{"class":602,"line":691},[600,2805,2655],{"class":614},[600,2807,1028],{"class":664},[600,2809,634],{"class":610},[600,2811,2812],{"class":602,"line":697},[600,2813,992],{"class":610},[600,2815,2816],{"class":602,"line":702},[600,2817,694],{"class":610},[600,2819,2820],{"class":602,"line":730},[600,2821,641],{"emptyLinePlaceholder":640},[600,2823,2824,2826,2828,2830,2832,2834],{"class":602,"line":771},[600,2825,705],{"class":606},[600,2827,708],{"class":647},[600,2829,1439],{"class":651},[600,2831,714],{"class":647},[600,2833,2724],{"class":651},[600,2835,655],{"class":610},[600,2837,2838,2840,2842],{"class":602,"line":776},[600,2839,779],{"class":647},[600,2841,2646],{"class":647},[600,2843,2844],{"class":610},"(\n",[600,2846,2847,2850,2852,2854,2856,2858],{"class":602,"line":814},[600,2848,2849],{"class":647},"    public",[600,2851,739],{"class":647},[600,2853,2793],{"class":790},[600,2855,668],{"class":610},[600,2857,1511],{"class":651},[600,2859,2860],{"class":610},",\n",[600,2862,2863,2865,2867,2869,2871,2873],{"class":602,"line":860},[600,2864,2849],{"class":647},[600,2866,739],{"class":647},[600,2868,1812],{"class":790},[600,2870,668],{"class":610},[600,2872,1680],{"class":651},[600,2874,2860],{"class":610},[600,2876,2877,2880],{"class":602,"line":893},[600,2878,2879],{"class":610},"  )",[600,2881,655],{"class":610},[600,2883,2884,2886,2888],{"class":602,"line":899},[600,2885,2655],{"class":614},[600,2887,1028],{"class":664},[600,2889,634],{"class":610},[600,2891,2892],{"class":602,"line":930},[600,2893,992],{"class":610},[600,2895,2896],{"class":602,"line":957},[600,2897,694],{"class":610},[499,2899,2900,2901,2904,2905,2908],{},"Inject the ",[516,2902,2903],{},"DomainEvents"," facade — a core provider the DDD plugin contributes app-wide. After\n",[516,2906,2907],{},"repository.save(order)",", flush the buffered events with one explicit call:",[590,2910,2913],{"className":592,"code":2911,"filename":2912,"language":595,"meta":596,"style":596},"import type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport { DomainEvents } from \"@heximon\u002Fdomain\";\nimport { NotFoundError } from \"@heximon\u002Fruntime\u002Ferrors\";\nimport { Order, 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,\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\n    order.ship(); \u002F\u002F enforces invariants, records OrderShippedDomainEvent\n    await this.repository.save(order);\n    await this.domainEvents.emitFrom(order); \u002F\u002F drain + dispatch, serial, in order\n\n    return { id: order.id, status: order.status };\n  }\n}\n","src\u002Forders\u002Forders.controller.ts",[516,2914,2915,2944,2965,2987,3014,3036,3040,3067,3075,3090,3105,3112,3116,3172,3203,3230,3273,3277,3293,3314,3339,3343,3374,3378],{"__ignoreMap":596},[600,2916,2917,2919,2921,2923,2926,2928,2931,2933,2935,2937,2940,2942],{"class":602,"line":603},[600,2918,607],{"class":606},[600,2920,1386],{"class":606},[600,2922,611],{"class":610},[600,2924,2925],{"class":614}," Controller",[600,2927,798],{"class":610},[600,2929,2930],{"class":614}," Post",[600,2932,618],{"class":610},[600,2934,621],{"class":606},[600,2936,624],{"class":610},[600,2938,2939],{"class":627},"@heximon\u002Fhttp",[600,2941,631],{"class":610},[600,2943,634],{"class":610},[600,2945,2946,2948,2950,2953,2955,2957,2959,2961,2963],{"class":602,"line":637},[600,2947,607],{"class":606},[600,2949,611],{"class":610},[600,2951,2952],{"class":614}," DomainEvents",[600,2954,618],{"class":610},[600,2956,621],{"class":606},[600,2958,624],{"class":610},[600,2960,628],{"class":627},[600,2962,631],{"class":610},[600,2964,634],{"class":610},[600,2966,2967,2969,2971,2974,2976,2978,2980,2983,2985],{"class":602,"line":644},[600,2968,607],{"class":606},[600,2970,611],{"class":610},[600,2972,2973],{"class":614}," NotFoundError",[600,2975,618],{"class":610},[600,2977,621],{"class":606},[600,2979,624],{"class":610},[600,2981,2982],{"class":627},"@heximon\u002Fruntime\u002Ferrors",[600,2984,631],{"class":610},[600,2986,634],{"class":610},[600,2988,2989,2991,2993,2995,2997,2999,3001,3003,3005,3007,3010,3012],{"class":602,"line":658},[600,2990,607],{"class":606},[600,2992,611],{"class":610},[600,2994,1705],{"class":614},[600,2996,798],{"class":610},[600,2998,1386],{"class":606},[600,3000,1511],{"class":614},[600,3002,618],{"class":610},[600,3004,621],{"class":606},[600,3006,624],{"class":610},[600,3008,3009],{"class":627},".\u002Forder.entity",[600,3011,631],{"class":610},[600,3013,634],{"class":610},[600,3015,3016,3018,3020,3023,3025,3027,3029,3032,3034],{"class":602,"line":676},[600,3017,607],{"class":606},[600,3019,611],{"class":610},[600,3021,3022],{"class":614}," OrderRepository",[600,3024,618],{"class":610},[600,3026,621],{"class":606},[600,3028,624],{"class":610},[600,3030,3031],{"class":627},".\u002Forder.repository",[600,3033,631],{"class":610},[600,3035,634],{"class":610},[600,3037,3038],{"class":602,"line":691},[600,3039,641],{"emptyLinePlaceholder":640},[600,3041,3042,3044,3046,3049,3052,3054,3056,3058,3061,3063,3065],{"class":602,"line":697},[600,3043,705],{"class":606},[600,3045,708],{"class":647},[600,3047,3048],{"class":651}," OrdersController",[600,3050,3051],{"class":647}," implements",[600,3053,2925],{"class":651},[600,3055,719],{"class":610},[600,3057,631],{"class":610},[600,3059,3060],{"class":627},"\u002Forders",[600,3062,631],{"class":610},[600,3064,725],{"class":610},[600,3066,655],{"class":610},[600,3068,3069,3071,3073],{"class":602,"line":702},[600,3070,779],{"class":647},[600,3072,2646],{"class":647},[600,3074,2844],{"class":610},[600,3076,3077,3080,3082,3084,3086,3088],{"class":602,"line":730},[600,3078,3079],{"class":647},"    private",[600,3081,739],{"class":647},[600,3083,2295],{"class":790},[600,3085,668],{"class":610},[600,3087,3022],{"class":651},[600,3089,2860],{"class":610},[600,3091,3092,3094,3096,3099,3101,3103],{"class":602,"line":771},[600,3093,3079],{"class":647},[600,3095,739],{"class":647},[600,3097,3098],{"class":790}," domainEvents",[600,3100,668],{"class":610},[600,3102,2952],{"class":651},[600,3104,2860],{"class":610},[600,3106,3107,3109],{"class":602,"line":776},[600,3108,2879],{"class":610},[600,3110,3111],{"class":610}," {}\n",[600,3113,3114],{"class":602,"line":814},[600,3115,641],{"emptyLinePlaceholder":640},[600,3117,3118,3120,3123,3125,3127,3130,3132,3134,3136,3138,3141,3143,3146,3149,3152,3155,3157,3159,3161,3163,3165,3167,3170],{"class":602,"line":860},[600,3119,779],{"class":647},[600,3121,3122],{"class":647}," async",[600,3124,1876],{"class":664},[600,3126,787],{"class":610},[600,3128,3129],{"class":790},"action",[600,3131,668],{"class":610},[600,3133,2930],{"class":651},[600,3135,719],{"class":610},[600,3137,631],{"class":610},[600,3139,3140],{"class":627},"\u002F:id\u002Fship",[600,3142,631],{"class":610},[600,3144,3145],{"class":610},">):",[600,3147,3148],{"class":651}," Promise",[600,3150,3151],{"class":610},"\u003C{",[600,3153,3154],{"class":664}," id",[600,3156,668],{"class":610},[600,3158,686],{"class":651},[600,3160,1849],{"class":610},[600,3162,1799],{"class":664},[600,3164,668],{"class":610},[600,3166,686],{"class":651},[600,3168,3169],{"class":610}," }>",[600,3171,655],{"class":610},[600,3173,3174,3176,3178,3180,3183,3185,3188,3190,3193,3195,3197,3199,3201],{"class":602,"line":893},[600,3175,1761],{"class":647},[600,3177,3154],{"class":614},[600,3179,745],{"class":610},[600,3181,3182],{"class":614}," action",[600,3184,829],{"class":610},[600,3186,3187],{"class":614},"request",[600,3189,829],{"class":610},[600,3191,3192],{"class":614},"pathParams",[600,3194,829],{"class":610},[600,3196,1735],{"class":614},[600,3198,1582],{"class":606},[600,3200,1511],{"class":651},[600,3202,634],{"class":610},[600,3204,3205,3207,3209,3211,3213,3215,3218,3220,3222,3224,3226,3228],{"class":602,"line":899},[600,3206,1761],{"class":647},[600,3208,1764],{"class":614},[600,3210,745],{"class":610},[600,3212,2292],{"class":606},[600,3214,1022],{"class":610},[600,3216,3217],{"class":614},"repository",[600,3219,829],{"class":610},[600,3221,2300],{"class":832},[600,3223,787],{"class":664},[600,3225,1735],{"class":614},[600,3227,888],{"class":664},[600,3229,634],{"class":610},[600,3231,3232,3234,3236,3238,3241,3243,3246,3248,3250,3252,3254,3257,3259,3261,3264,3267,3269,3271],{"class":602,"line":930},[600,3233,817],{"class":606},[600,3235,820],{"class":664},[600,3237,823],{"class":610},[600,3239,3240],{"class":614},"order",[600,3242,840],{"class":664},[600,3244,3245],{"class":606},"throw",[600,3247,866],{"class":610},[600,3249,2973],{"class":832},[600,3251,787],{"class":664},[600,3253,874],{"class":610},[600,3255,3256],{"class":627},"Order ",[600,3258,880],{"class":610},[600,3260,1735],{"class":614},[600,3262,3263],{"class":610},"}",[600,3265,3266],{"class":627}," not found",[600,3268,874],{"class":610},[600,3270,888],{"class":664},[600,3272,634],{"class":610},[600,3274,3275],{"class":602,"line":957},[600,3276,641],{"emptyLinePlaceholder":640},[600,3278,3279,3281,3283,3286,3288,3290],{"class":602,"line":962},[600,3280,1827],{"class":614},[600,3282,829],{"class":610},[600,3284,3285],{"class":832},"ship",[600,3287,1028],{"class":664},[600,3289,1849],{"class":610},[600,3291,3292],{"class":1852}," \u002F\u002F enforces invariants, records OrderShippedDomainEvent\n",[600,3294,3295,3298,3300,3302,3304,3306,3308,3310,3312],{"class":602,"line":989},[600,3296,3297],{"class":606},"    await",[600,3299,1022],{"class":610},[600,3301,3217],{"class":614},[600,3303,829],{"class":610},[600,3305,2374],{"class":832},[600,3307,787],{"class":664},[600,3309,3240],{"class":614},[600,3311,888],{"class":664},[600,3313,634],{"class":610},[600,3315,3316,3318,3320,3323,3325,3328,3330,3332,3334,3336],{"class":602,"line":995},[600,3317,3297],{"class":606},[600,3319,1022],{"class":610},[600,3321,3322],{"class":614},"domainEvents",[600,3324,829],{"class":610},[600,3326,3327],{"class":832},"emitFrom",[600,3329,787],{"class":664},[600,3331,3240],{"class":614},[600,3333,888],{"class":664},[600,3335,1849],{"class":610},[600,3337,3338],{"class":1852}," \u002F\u002F drain + dispatch, serial, in order\n",[600,3340,3341],{"class":602,"line":1000},[600,3342,641],{"emptyLinePlaceholder":640},[600,3344,3345,3347,3349,3351,3353,3355,3357,3359,3361,3363,3365,3367,3369,3371],{"class":602,"line":1017},[600,3346,965],{"class":606},[600,3348,611],{"class":610},[600,3350,3154],{"class":664},[600,3352,668],{"class":610},[600,3354,1764],{"class":614},[600,3356,829],{"class":610},[600,3358,1735],{"class":614},[600,3360,798],{"class":610},[600,3362,1799],{"class":664},[600,3364,668],{"class":610},[600,3366,1764],{"class":614},[600,3368,829],{"class":610},[600,3370,1899],{"class":614},[600,3372,3373],{"class":610}," };\n",[600,3375,3376],{"class":602,"line":1037},[600,3377,992],{"class":610},[600,3379,3380],{"class":602,"line":1042},[600,3381,694],{"class":610},[499,3383,3384,3385,3388,3389,3391],{},"The flush is explicit on purpose: events fire ",[528,3386,3387],{},"after"," the save succeeds, in order, inside the same command\ntransaction — so a handler throw rolls the whole write back atomically instead of leaving a\nrecorded-but-unreacted event. (A command whose owning module has no ",[516,3390,77],{}," in scope receives no\ntransaction wrapper, so the throw simply propagates without a rollback.)",[499,3393,3394,3395,3397,3398,3401,3402,829],{},"When a module binds more than one ",[516,3396,77],{},", the wrap target is ambiguous and you select it — or opt out —\nwith the ",[516,3399,3400],{},"{ database }"," type option; see ",[503,3403,3405],{"href":3404},"\u002Fdocs\u002Farchitecture\u002Fcqrs#command-transaction-wrap","CQRS → command transaction wrap",[499,3407,2558,3408,3411],{},[516,3409,3410],{},"DomainEventHandler"," reacts to one event class, linked by the event you pass to the base, with its\nconstructor declaring its dependencies:",[590,3413,3416],{"className":592,"code":3414,"filename":3415,"language":595,"meta":596,"style":596},"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","src\u002Fshipments\u002Frecord-shipment.handler.ts",[516,3417,3418,3441,3462,3484,3488,3510,3534,3538,3560,3614,3618],{"__ignoreMap":596},[600,3419,3420,3422,3424,3426,3429,3431,3433,3435,3437,3439],{"class":602,"line":603},[600,3421,607],{"class":606},[600,3423,1386],{"class":606},[600,3425,611],{"class":610},[600,3427,3428],{"class":614}," DomainEventHandler",[600,3430,618],{"class":610},[600,3432,621],{"class":606},[600,3434,624],{"class":610},[600,3436,628],{"class":627},[600,3438,631],{"class":610},[600,3440,634],{"class":610},[600,3442,3443,3445,3447,3449,3451,3453,3455,3458,3460],{"class":602,"line":637},[600,3444,607],{"class":606},[600,3446,611],{"class":610},[600,3448,1439],{"class":614},[600,3450,618],{"class":610},[600,3452,621],{"class":606},[600,3454,624],{"class":610},[600,3456,3457],{"class":627},"..\u002Forders\u002Fdomain-events\u002Forder.events",[600,3459,631],{"class":610},[600,3461,634],{"class":610},[600,3463,3464,3466,3468,3471,3473,3475,3477,3480,3482],{"class":602,"line":644},[600,3465,607],{"class":606},[600,3467,611],{"class":610},[600,3469,3470],{"class":614}," ShipmentTracker",[600,3472,618],{"class":610},[600,3474,621],{"class":606},[600,3476,624],{"class":610},[600,3478,3479],{"class":627},".\u002Fshipment-tracker.service",[600,3481,631],{"class":610},[600,3483,634],{"class":610},[600,3485,3486],{"class":602,"line":658},[600,3487,641],{"emptyLinePlaceholder":640},[600,3489,3490,3492,3494,3497,3499,3501,3503,3506,3508],{"class":602,"line":676},[600,3491,705],{"class":606},[600,3493,708],{"class":647},[600,3495,3496],{"class":651}," RecordShipmentHandler",[600,3498,3051],{"class":647},[600,3500,3428],{"class":651},[600,3502,719],{"class":610},[600,3504,3505],{"class":651},"OrderShippedDomainEvent",[600,3507,725],{"class":610},[600,3509,655],{"class":610},[600,3511,3512,3514,3516,3518,3521,3523,3526,3528,3530,3532],{"class":602,"line":691},[600,3513,779],{"class":647},[600,3515,2646],{"class":647},[600,3517,787],{"class":610},[600,3519,3520],{"class":647},"private",[600,3522,739],{"class":647},[600,3524,3525],{"class":790}," tracker",[600,3527,668],{"class":610},[600,3529,3470],{"class":651},[600,3531,888],{"class":610},[600,3533,3111],{"class":610},[600,3535,3536],{"class":602,"line":697},[600,3537,641],{"emptyLinePlaceholder":640},[600,3539,3540,3542,3545,3547,3550,3552,3554,3556,3558],{"class":602,"line":702},[600,3541,779],{"class":647},[600,3543,3544],{"class":664}," handle",[600,3546,787],{"class":610},[600,3548,3549],{"class":790},"event",[600,3551,668],{"class":610},[600,3553,1439],{"class":651},[600,3555,807],{"class":610},[600,3557,1881],{"class":651},[600,3559,655],{"class":610},[600,3561,3562,3564,3567,3569,3572,3574,3576,3578,3580,3583,3585,3588,3590,3592,3594,3596,3598,3600,3602,3605,3608,3610,3612],{"class":602,"line":730},[600,3563,1933],{"class":610},[600,3565,3566],{"class":614},"tracker",[600,3568,829],{"class":610},[600,3570,3571],{"class":832},"record",[600,3573,787],{"class":664},[600,3575,974],{"class":610},[600,3577,2793],{"class":664},[600,3579,668],{"class":610},[600,3581,3582],{"class":614}," event",[600,3584,829],{"class":610},[600,3586,3587],{"class":614},"orderId",[600,3589,798],{"class":610},[600,3591,1812],{"class":664},[600,3593,668],{"class":610},[600,3595,3582],{"class":614},[600,3597,829],{"class":610},[600,3599,1960],{"class":614},[600,3601,829],{"class":610},[600,3603,3604],{"class":832},"toISOString",[600,3606,3607],{"class":664},"() ",[600,3609,3263],{"class":610},[600,3611,888],{"class":664},[600,3613,634],{"class":610},[600,3615,3616],{"class":602,"line":771},[600,3617,992],{"class":610},[600,3619,3620],{"class":602,"line":776},[600,3621,694],{"class":610},[499,3623,3624,3625,3627],{},"The handler consumes only the flat data on the event — never the ",[516,3626,518],{}," aggregate — so a domain event is\na seam between bounded contexts: one side records a fact, the other reacts, neither imports the other.",[508,3629,3631],{"id":3630},"map-between-domain-and-the-outside-world","Map between domain and the outside world",[499,3633,3634],{},"Aggregates aren't your API shape or your table shape, so DDD ships three mapper contracts — each an\nabstract class a handler injects by contract, wired to whichever subclass extends it:",[2162,3636,3637,3650],{},[2165,3638,3639],{},[2168,3640,3641,3644,3647],{},[2171,3642,3643],{"align":2173},"Contract",[2171,3645,3646],{"align":2173},"Direction",[2171,3648,3649],{"align":2173},"Method",[2185,3651,3652,3667,3686],{},[2168,3653,3654,3659,3662],{},[2190,3655,3656],{"align":2173},[516,3657,3658],{},"ResponseMapper\u003CT>",[2190,3660,3661],{"align":2173},"domain object → response DTO",[2190,3663,3664],{"align":2173},[516,3665,3666],{},"toResponse",[2168,3668,3669,3674,3677],{},[2190,3670,3671],{"align":2173},[516,3672,3673],{},"PersistenceMapper",[2190,3675,3676],{"align":2173},"domain ↔ persisted record",[2190,3678,3679,3682,3683],{"align":2173},[516,3680,3681],{},"toDomain"," \u002F ",[516,3684,3685],{},"toPersistence",[2168,3687,3688,3693,3696],{},[2190,3689,3690],{"align":2173},[516,3691,3692],{},"EntityPersistenceMapper",[2190,3694,3695],{"align":2173},"entity ↔ row, rehydrating through the base",[2190,3697,3698,3682,3700],{"align":2173},[516,3699,3681],{},[516,3701,3685],{},[499,3703,3704,3705,3707,3708,829],{},"For Drizzle-backed repositories you don't write a ",[516,3706,3673],{}," by hand — the entity definition\nderives it, rehydrating with the right snapshot so dirty tracking starts clean; see\n",[503,3709,3710],{"href":83},"Drizzle",[508,3712,3714],{"id":3713},"wire-the-module","Wire the module",[499,3716,3717,3718,3721,3722,3725,3726,3728],{},"Domain-event handlers go under the ",[516,3719,3720],{},"domain"," namespace — never in ",[516,3723,3724],{},"providers",", because the compiler routes\nthem onto the event tier instead of constructing them as plain injectables. Repositories, services, and\nmappers are ordinary providers; the ",[516,3727,2903],{}," facade is contributed by the plugin, never listed.",[590,3730,3733],{"className":592,"code":3731,"filename":3732,"language":595,"meta":596,"style":596},"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","src\u002Fshipments\u002Fshipping.module.ts",[516,3734,3735,3757,3778,3798,3802,3819,3831,3851,3862],{"__ignoreMap":596},[600,3736,3737,3739,3741,3744,3746,3748,3750,3753,3755],{"class":602,"line":603},[600,3738,607],{"class":606},[600,3740,611],{"class":610},[600,3742,3743],{"class":614}," Module",[600,3745,618],{"class":610},[600,3747,621],{"class":606},[600,3749,624],{"class":610},[600,3751,3752],{"class":627},"@heximon\u002Fruntime",[600,3754,631],{"class":610},[600,3756,634],{"class":610},[600,3758,3759,3761,3763,3765,3767,3769,3771,3774,3776],{"class":602,"line":637},[600,3760,607],{"class":606},[600,3762,611],{"class":610},[600,3764,3496],{"class":614},[600,3766,618],{"class":610},[600,3768,621],{"class":606},[600,3770,624],{"class":610},[600,3772,3773],{"class":627},".\u002Frecord-shipment.handler",[600,3775,631],{"class":610},[600,3777,634],{"class":610},[600,3779,3780,3782,3784,3786,3788,3790,3792,3794,3796],{"class":602,"line":644},[600,3781,607],{"class":606},[600,3783,611],{"class":610},[600,3785,3470],{"class":614},[600,3787,618],{"class":610},[600,3789,621],{"class":606},[600,3791,624],{"class":610},[600,3793,3479],{"class":627},[600,3795,631],{"class":610},[600,3797,634],{"class":610},[600,3799,3800],{"class":602,"line":658},[600,3801,641],{"emptyLinePlaceholder":640},[600,3803,3804,3806,3808,3811,3813,3815,3817],{"class":602,"line":676},[600,3805,705],{"class":606},[600,3807,708],{"class":647},[600,3809,3810],{"class":651}," ShippingModule",[600,3812,714],{"class":647},[600,3814,3743],{"class":832},[600,3816,787],{"class":614},[600,3818,857],{"class":610},[600,3820,3821,3824,3826,3829],{"class":602,"line":691},[600,3822,3823],{"class":664},"  providers",[600,3825,668],{"class":610},[600,3827,3828],{"class":614}," [ShipmentTracker]",[600,3830,2860],{"class":610},[600,3832,3833,3836,3838,3840,3843,3845,3848],{"class":602,"line":697},[600,3834,3835],{"class":664},"  domain",[600,3837,668],{"class":610},[600,3839,611],{"class":610},[600,3841,3842],{"class":664}," eventHandlers",[600,3844,668],{"class":610},[600,3846,3847],{"class":614}," [RecordShipmentHandler] ",[600,3849,3850],{"class":610},"},\n",[600,3852,3853,3856,3858,3860],{"class":602,"line":702},[600,3854,3855],{"class":664},"  exports",[600,3857,668],{"class":610},[600,3859,3828],{"class":614},[600,3861,2860],{"class":610},[600,3863,3864,3866,3868],{"class":602,"line":730},[600,3865,3263],{"class":610},[600,3867,840],{"class":614},[600,3869,3870],{"class":610},"{}\n",[499,3872,3873,3874,3876,3877,3879],{},"Each bounded context is its own module: orders owns the ",[516,3875,518],{}," aggregate, shipping owns the handler that\nreacts to ",[516,3878,3505],{},", and neither depends on the other's providers — only on the shared\nevent tier. That is the point of modelling contexts as separate modules.",[499,3881,3882,3883,3886,3887,3890],{},"Finally, register the DDD compiler plugin alongside the HTTP plugin in the ",[516,3884,3885],{},"heximon.config.ts"," config file.\n",[516,3888,3889],{},"DomainEventsPlugin"," wires the facade and pulls in the events plugin domain events dispatch through, so you\ndon't list that one yourself.",[590,3892,3894],{"className":592,"code":3893,"filename":3885,"language":595,"meta":596,"style":596},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { DomainEventsPlugin } from \"@heximon\u002Fdomain\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new HttpPlugin(), new DomainEventsPlugin()],\n});\n",[516,3895,3896,3918,3940,3962,3966,3979,4005],{"__ignoreMap":596},[600,3897,3898,3900,3902,3905,3907,3909,3911,3914,3916],{"class":602,"line":603},[600,3899,607],{"class":606},[600,3901,611],{"class":610},[600,3903,3904],{"class":614}," defineHeximonConfig",[600,3906,618],{"class":610},[600,3908,621],{"class":606},[600,3910,624],{"class":610},[600,3912,3913],{"class":627},"@heximon\u002Fbuild",[600,3915,631],{"class":610},[600,3917,634],{"class":610},[600,3919,3920,3922,3924,3927,3929,3931,3933,3936,3938],{"class":602,"line":637},[600,3921,607],{"class":606},[600,3923,611],{"class":610},[600,3925,3926],{"class":614}," DomainEventsPlugin",[600,3928,618],{"class":610},[600,3930,621],{"class":606},[600,3932,624],{"class":610},[600,3934,3935],{"class":627},"@heximon\u002Fdomain\u002Fcompiler",[600,3937,631],{"class":610},[600,3939,634],{"class":610},[600,3941,3942,3944,3946,3949,3951,3953,3955,3958,3960],{"class":602,"line":644},[600,3943,607],{"class":606},[600,3945,611],{"class":610},[600,3947,3948],{"class":614}," HttpPlugin",[600,3950,618],{"class":610},[600,3952,621],{"class":606},[600,3954,624],{"class":610},[600,3956,3957],{"class":627},"@heximon\u002Fhttp\u002Fcompiler",[600,3959,631],{"class":610},[600,3961,634],{"class":610},[600,3963,3964],{"class":602,"line":658},[600,3965,641],{"emptyLinePlaceholder":640},[600,3967,3968,3970,3973,3975,3977],{"class":602,"line":676},[600,3969,705],{"class":606},[600,3971,3972],{"class":606}," default",[600,3974,3904],{"class":832},[600,3976,787],{"class":614},[600,3978,857],{"class":610},[600,3980,3981,3984,3986,3988,3990,3992,3994,3996,3998,4000,4003],{"class":602,"line":691},[600,3982,3983],{"class":664},"  plugins",[600,3985,668],{"class":610},[600,3987,1785],{"class":614},[600,3989,1837],{"class":610},[600,3991,3948],{"class":832},[600,3993,1028],{"class":614},[600,3995,798],{"class":610},[600,3997,866],{"class":610},[600,3999,3926],{"class":832},[600,4001,4002],{"class":614},"()]",[600,4004,2860],{"class":610},[600,4006,4007,4009,4011],{"class":602,"line":697},[600,4008,3263],{"class":610},[600,4010,888],{"class":614},[600,4012,634],{"class":610},[508,4014,4016],{"id":4015},"see-also","See also",[4018,4019,4020,4030,4043,4048,4057,4068,4073],"ul",{},[4021,4022,4023,4025,4026,4029],"li",{},[503,4024,470],{"href":471}," — the full worked walkthrough of everything on this\npage: branded ids, value objects, invariants, optimistic concurrency, and a cross-context domain-event\nhandler, built up file by file with a runnable ",[516,4027,4028],{},"curl"," sequence.",[4021,4031,4032,4034,4035,4038,4039,4042],{},[503,4033,233],{"href":234}," — drive aggregate writes through a ",[516,4036,4037],{},"CommandBus"," and reads through a\n",[516,4040,4041],{},"QueryBus",", with concurrency retry and around-chain interceptors.",[4021,4044,4045,4047],{},[503,4046,146],{"href":147}," — the in-process and cross-context event tiers, including the\nintegration-event channel for reacting across services.",[4021,4049,4050,4052,4053,4056],{},[503,4051,238],{"href":239}," — persist aggregates behind a typed\n",[516,4054,4055],{},"Repository",", with changed-column saves and optimistic concurrency.",[4021,4058,4059,4062,4063,4065,4066,829],{},[503,4060,4061],{"href":88},"Persistence"," — the ",[516,4064,2267],{}," hierarchy and how a dialect enforces\nthe version guard underneath ",[516,4067,2183],{},[4021,4069,4070,4072],{},[503,4071,57],{"href":58}," — the HTTP surface that turns requests into aggregate operations\nand flushes their events.",[4021,4074,4075,4082,4083,4086,4087,4089,4090,4093,4094,4097],{},[503,4076,4079],{"href":4077,"rel":4078},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL06-ddd",[1322],[528,4080,4081],{},"L06 — DDD","\n— a runnable ",[516,4084,4085],{},"User"," aggregate with an ",[516,4088,562],{}," value object, a branded ",[516,4091,4092],{},"UserId",", optimistic-concurrency\nversioning, and a ",[516,4095,4096],{},"UserRegisteredDomainEvent"," flushed across to a decoupled onboarding context.",[4099,4100,4101],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":596,"searchDepth":637,"depth":637,"links":4103},[4104,4105,4106,4107,4108,4109,4110,4111,4112],{"id":510,"depth":637,"text":511},{"id":1355,"depth":637,"text":1356},{"id":2134,"depth":637,"text":2135},{"id":2237,"depth":637,"text":2238},{"id":2554,"depth":637,"text":2555},{"id":2702,"depth":637,"text":2703},{"id":3630,"depth":637,"text":3631},{"id":3713,"depth":637,"text":3714},{"id":4015,"depth":637,"text":4016},"Model your domain with the Entity, ValueObject, and AggregateRoot bases — value equality, dirty tracking, optimistic concurrency, and domain events.","md",null,{},{"icon":231},{"title":228,"description":4113},"P-Qovrbd6GFBDGu_ob5qMOOJSqZ30Lc3cOsqofoK19c",[4121,4123],{"title":142,"path":225,"stem":226,"description":4122,"icon":220,"children":-1},"When to reach for CQRS, Domain-Driven Design, the repository pattern, integration events, sagas, and workflows — and when a plain controller and a plain provider are still the right call.",{"title":233,"path":234,"stem":235,"description":4124,"icon":236,"children":-1},"Split writes from reads with a typed CommandBus and QueryBus, one handler per message, around-chain interceptors, and automatic ConcurrencyError retry.",1783300761903]