[{"data":1,"prerenderedAt":2759},["ShallowReactive",2],{"navigation_docs":3,"-docs-deploy-cross-service-events":493,"-docs-deploy-cross-service-events-surround":2754},[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":351,"body":495,"description":2747,"extension":2748,"links":2749,"meta":2750,"navigation":2751,"path":352,"seo":2752,"stem":353,"__hash__":2753},"docs\u002Fdocs\u002F06.deploy\u002F12.cross-service-events.md",{"type":496,"value":497,"toc":2735},"minimark",[498,537,542,708,734,924,930,935,956,1042,1054,1058,1077,1087,1158,1182,1186,1215,1388,1406,1421,1445,1449,1473,1642,1652,1677,1681,1691,1891,1925,1951,1955,1973,2141,2172,2576,2613,2617,2627,2687,2698,2702,2731],[499,500,501,502,506,507,511,512,516,517,520,521,524,525,528,529,532,533,536],"p",{},"When the producer and the subscribers of an ",[503,504,505],"a",{"href":244},"integration event"," are\n",[508,509,510],"strong",{},"separate deploys"," — ",[513,514,515],"code",{},"orders"," publishes ",[513,518,519],{},"order.placed",", a separately deployed ",[513,522,523],{},"billing"," service reacts — you\npublish once, from ",[513,526,527],{},"heximon.config.ts","'s ",[513,530,531],{},"crossService.transport",", and every subscribed service gets its own copy.\nThe producer's ",[513,534,535],{},"publish()"," call is identical to the single-deploy case; only the transport underneath it changes,\nand that's a deploy-time choice, not an app-code change.",[538,539,541],"h2",{"id":540},"choosing-a-leg","Choosing a leg",[543,544,545,568],"table",{},[546,547,548],"thead",{},[549,550,551,556,559,562,565],"tr",{},[552,553,555],"th",{"align":554},"left","Leg",[552,557,558],{"align":554},"Delivery",[552,560,561],{"align":554},"Runs on",[552,563,564],{"align":554},"Use when",[552,566,567],{"align":554},"Example",[569,570,571,599,628,655,683],"tbody",{},[549,572,573,580,583,586,589],{},[574,575,576,579],"td",{"align":554},[508,577,578],{},"Per-service-queue split"," (default)",[574,581,582],{"align":554},"N enqueues, one per subscriber",[574,584,585],{"align":554},"Any queue transport",[574,587,588],{"align":554},"No native broker, or you want the simplest mental model",[574,590,591],{"align":554},[503,592,596],{"href":593,"rel":594},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Ffanout",[595],"nofollow",[513,597,598],{},"fanout",[549,600,601,606,613,616,619],{},[574,602,603],{"align":554},[508,604,605],{},"Redis Streams broadcast",[574,607,608,609,612],{"align":554},"1 ",[513,610,611],{},"XADD",", N consumer groups",[574,614,615],{"align":554},"Node\u002FBun\u002FDeno subscriber",[574,617,618],{"align":554},"Already on Redis\u002FUpstash and want producer-side savings",[574,620,621],{"align":554},[503,622,625],{"href":623,"rel":624},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Fbroadcast",[595],[513,626,627],{},"broadcast",[549,629,630,635,641,643,646],{},[574,631,632],{"align":554},[508,633,634],{},"SNS → SQS broadcast",[574,636,608,637,640],{"align":554},[513,638,639],{},"Publish",", N SQS queues",[574,642,615],{"align":554},[574,644,645],{"align":554},"AWS-native deploy",[574,647,648],{"align":554},[503,649,652],{"href":650,"rel":651},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Fsns",[595],[513,653,654],{},"sns",[549,656,657,662,668,671,674],{},[574,658,659],{"align":554},[508,660,661],{},"Cloudflare DO router",[574,663,608,664,667],{"align":554},[513,665,666],{},"publish",", router fans out",[574,669,670],{"align":554},"Cloudflare Workers",[574,672,673],{"align":554},"No native CF broker; want producer-blindness",[574,675,676],{"align":554},[503,677,680],{"href":678,"rel":679},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fflagship\u002Fapps\u002Fnotify-split",[595],[513,681,682],{},"notify-split",[549,684,685,690,693,696,699],{},[574,686,687],{"align":554},[508,688,689],{},"QStash push",[574,691,692],{"align":554},"1 HTTP POST, N pushed deliveries",[574,694,695],{"align":554},"Any platform, incl. freezing functions",[574,697,698],{"align":554},"Subscriber is Vercel \u002F Netlify \u002F Lambda",[574,700,701],{"align":554},[503,702,705],{"href":703,"rel":704},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fgap\u002Fcross-service-transports\u002Fqstash",[595],[513,706,707],{},"qstash",[499,709,710,711,714,715,718,719,722,723,726,727,729,730,733],{},"Every service joins the fabric the same way — ",[513,712,713],{},"service: \"\u003Cid>\""," names its own deploy identity, and ",[513,716,717],{},"crossService","\nopts it in. On ",[513,720,721],{},"vp build"," \u002F ",[513,724,725],{},"vp dev",", the host reads ",[513,728,717],{},", discovers who subscribes to what by scanning\nthe workspace (by default, walking up to the nearest ",[513,731,732],{},"pnpm-workspace.yaml","), and threads that topology into the\ncompile — the producer's build bakes the distributor, the subscriber's build bakes the consumer, with no boot\nseam in either service:",[735,736,742],"pre",{"className":737,"code":738,"filename":739,"language":740,"meta":741,"style":741},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { IntegrationEventsPlugin } from \"@heximon\u002Fintegration\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: {},\n});\n","services\u002Forders\u002Fheximon.config.ts","ts","",[513,743,744,780,803,826,833,851,886,902,913],{"__ignoreMap":741},[745,746,749,753,757,761,764,767,770,774,777],"span",{"class":747,"line":748},"line",1,[745,750,752],{"class":751},"s7zQu","import",[745,754,756],{"class":755},"sMK4o"," {",[745,758,760],{"class":759},"sTEyZ"," defineHeximonConfig",[745,762,763],{"class":755}," }",[745,765,766],{"class":751}," from",[745,768,769],{"class":755}," \"",[745,771,773],{"class":772},"sfazB","@heximon\u002Fbuild",[745,775,776],{"class":755},"\"",[745,778,779],{"class":755},";\n",[745,781,783,785,787,790,792,794,796,799,801],{"class":747,"line":782},2,[745,784,752],{"class":751},[745,786,756],{"class":755},[745,788,789],{"class":759}," IntegrationEventsPlugin",[745,791,763],{"class":755},[745,793,766],{"class":751},[745,795,769],{"class":755},[745,797,798],{"class":772},"@heximon\u002Fintegration\u002Fcompiler",[745,800,776],{"class":755},[745,802,779],{"class":755},[745,804,806,808,810,813,815,817,819,822,824],{"class":747,"line":805},3,[745,807,752],{"class":751},[745,809,756],{"class":755},[745,811,812],{"class":759}," HttpPlugin",[745,814,763],{"class":755},[745,816,766],{"class":751},[745,818,769],{"class":755},[745,820,821],{"class":772},"@heximon\u002Fhttp\u002Fcompiler",[745,823,776],{"class":755},[745,825,779],{"class":755},[745,827,829],{"class":747,"line":828},4,[745,830,832],{"emptyLinePlaceholder":831},true,"\n",[745,834,836,839,842,845,848],{"class":747,"line":835},5,[745,837,838],{"class":751},"export",[745,840,841],{"class":751}," default",[745,843,760],{"class":844},"s2Zo4",[745,846,847],{"class":759},"(",[745,849,850],{"class":755},"{\n",[745,852,854,858,861,864,867,869,872,875,878,880,883],{"class":747,"line":853},6,[745,855,857],{"class":856},"swJcz","  plugins",[745,859,860],{"class":755},":",[745,862,863],{"class":759}," [",[745,865,866],{"class":755},"new",[745,868,789],{"class":844},[745,870,871],{"class":759},"()",[745,873,874],{"class":755},",",[745,876,877],{"class":755}," new",[745,879,812],{"class":844},[745,881,882],{"class":759},"()]",[745,884,885],{"class":755},",\n",[745,887,889,892,894,896,898,900],{"class":747,"line":888},7,[745,890,891],{"class":856},"  service",[745,893,860],{"class":755},[745,895,769],{"class":755},[745,897,515],{"class":772},[745,899,776],{"class":755},[745,901,885],{"class":755},[745,903,905,908,910],{"class":747,"line":904},8,[745,906,907],{"class":856},"  crossService",[745,909,860],{"class":755},[745,911,912],{"class":755}," {},\n",[745,914,916,919,922],{"class":747,"line":915},9,[745,917,918],{"class":755},"}",[745,920,921],{"class":759},")",[745,923,779],{"class":755},[499,925,926,927,929],{},"Renaming a service's ",[513,928,713],{}," orphans its queue, so change it deliberately.",[931,932,934],"h3",{"id":933},"scanning-a-nested-services-directory","Scanning a nested services directory",[499,936,937,938,940,941,944,945,948,949,952,953,955],{},"The default scan only reaches as far as the nearest ",[513,939,732],{}," — fine when your services already sit\nat the workspace root. When they're nested a level deeper — siblings under their own ",[513,942,943],{},"services\u002F"," directory inside\na larger monorepo — point the scan there explicitly with ",[513,946,947],{},"workspaceRoot",". Heximon's own gap examples lay every\ncross-service leg out exactly this way (",[513,950,951],{},"examples\u002Fgap\u002Fcross-service-transports\u002F\u003Cleg>\u002Fservices\u002F\u003Cname>\u002Fheximon.config.ts","),\nso each service's config overrides the scan to start one level up, at its ",[513,954,943],{}," parent:",[735,957,959],{"className":737,"code":958,"filename":739,"language":740,"meta":741,"style":741},"export default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: { workspaceRoot: \"..\" },\n});\n",[513,960,961,973,997,1011,1034],{"__ignoreMap":741},[745,962,963,965,967,969,971],{"class":747,"line":748},[745,964,838],{"class":751},[745,966,841],{"class":751},[745,968,760],{"class":844},[745,970,847],{"class":759},[745,972,850],{"class":755},[745,974,975,977,979,981,983,985,987,989,991,993,995],{"class":747,"line":782},[745,976,857],{"class":856},[745,978,860],{"class":755},[745,980,863],{"class":759},[745,982,866],{"class":755},[745,984,789],{"class":844},[745,986,871],{"class":759},[745,988,874],{"class":755},[745,990,877],{"class":755},[745,992,812],{"class":844},[745,994,882],{"class":759},[745,996,885],{"class":755},[745,998,999,1001,1003,1005,1007,1009],{"class":747,"line":805},[745,1000,891],{"class":856},[745,1002,860],{"class":755},[745,1004,769],{"class":755},[745,1006,515],{"class":772},[745,1008,776],{"class":755},[745,1010,885],{"class":755},[745,1012,1013,1015,1017,1019,1022,1024,1026,1029,1031],{"class":747,"line":828},[745,1014,907],{"class":856},[745,1016,860],{"class":755},[745,1018,756],{"class":755},[745,1020,1021],{"class":856}," workspaceRoot",[745,1023,860],{"class":755},[745,1025,769],{"class":755},[745,1027,1028],{"class":772},"..",[745,1030,776],{"class":755},[745,1032,1033],{"class":755}," },\n",[745,1035,1036,1038,1040],{"class":747,"line":835},[745,1037,918],{"class":755},[745,1039,921],{"class":759},[745,1041,779],{"class":755},[499,1043,1044,1046,1047,1050,1051,1053],{},[513,1045,947],{}," is relative to the service's own root (or absolute); ",[513,1048,1049],{},"\"..\""," here means \"scan my parent directory's\nchildren\" — every sibling under ",[513,1052,943],{}," — instead of walking up further and picking up every unrelated app in\nthe outer monorepo.",[538,1055,1057],{"id":1056},"per-service-queue-split-the-default","Per-service-queue split (the default)",[499,1059,1060,1061,1064,1065,1068,1069,1072,1073,1076],{},"With no native broker to fan a single write to every subscriber, the producer ",[508,1062,1063],{},"splits",": at build time it learns\nwhich services subscribe to each event, and fans ",[508,1066,1067],{},"one copy per subscriber"," into that subscriber's own durable\nqueue, ",[513,1070,1071],{},"heximon-ie-\u003Cservice>",". Over a SQL transport this is a shared-store story — both deploys point at one\ndatabase, and the producer's distributor writes into the same ",[513,1074,1075],{},"queue_messages"," table the subscriber's consumer\ndrains. A platform with a native per-service queue (Cloudflare Queues) routes the split through that instead.",[499,1078,1079,1080,1083,1084,1086],{},"No ",[513,1081,1082],{},"transport"," is declared for this leg — it's the fallback when ",[513,1085,717],{}," opts in with no emitter:",[735,1088,1090],{"className":737,"code":1089,"filename":739,"language":740,"meta":741,"style":741},"export default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: {},\n});\n",[513,1091,1092,1104,1128,1142,1150],{"__ignoreMap":741},[745,1093,1094,1096,1098,1100,1102],{"class":747,"line":748},[745,1095,838],{"class":751},[745,1097,841],{"class":751},[745,1099,760],{"class":844},[745,1101,847],{"class":759},[745,1103,850],{"class":755},[745,1105,1106,1108,1110,1112,1114,1116,1118,1120,1122,1124,1126],{"class":747,"line":782},[745,1107,857],{"class":856},[745,1109,860],{"class":755},[745,1111,863],{"class":759},[745,1113,866],{"class":755},[745,1115,789],{"class":844},[745,1117,871],{"class":759},[745,1119,874],{"class":755},[745,1121,877],{"class":755},[745,1123,812],{"class":844},[745,1125,882],{"class":759},[745,1127,885],{"class":755},[745,1129,1130,1132,1134,1136,1138,1140],{"class":747,"line":805},[745,1131,891],{"class":856},[745,1133,860],{"class":755},[745,1135,769],{"class":755},[745,1137,515],{"class":772},[745,1139,776],{"class":755},[745,1141,885],{"class":755},[745,1143,1144,1146,1148],{"class":747,"line":828},[745,1145,907],{"class":856},[745,1147,860],{"class":755},[745,1149,912],{"class":755},[745,1151,1152,1154,1156],{"class":747,"line":835},[745,1153,918],{"class":755},[745,1155,921],{"class":759},[745,1157,779],{"class":755},[499,1159,1160,1164,1165,1167,1168,1170,1171,1174,1175,1177,1178,1181],{},[503,1161,1163],{"href":593,"rel":1162},[595],"The gap's fanout example","\nis the runnable split baseline: an ",[513,1166,515],{}," producer, a ",[513,1169,523],{}," subscriber, and an end-to-end test that boots\nboth services and drives ",[513,1172,1173],{},"POST \u002Forders"," through the shared ",[513,1176,1075],{}," table to ",[513,1179,1180],{},"OnOrderPlaced.handle",".",[538,1183,1185],{"id":1184},"native-broadcast-redis-streams","Native broadcast — Redis Streams",[499,1187,1188,1189,1192,1193,1195,1196,1200,1201,1203,1204,1206,1207,1210,1211,1214],{},"A broker with native pub\u002Fsub does not need to split: the producer writes ",[508,1190,1191],{},"once",", and every subscriber reads its\nown copy. On Redis Streams that's one ",[513,1194,611],{}," to a single shared stream plus one ",[1197,1198,1199],"em",{},"consumer group"," per subscribing\nservice (",[513,1202,1071],{},") — Redis fans the one entry to every group. Select it with a distributor-emitter\ninstance on ",[513,1205,531],{}," and bind the ",[513,1208,1209],{},"@upstash\u002Fredis"," client to the ",[513,1212,1213],{},"RedisStreamClient"," token:",[735,1216,1218],{"className":737,"code":1217,"filename":739,"language":740,"meta":741,"style":741},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { IntegrationEventsPlugin } from \"@heximon\u002Fintegration\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\nimport { RedisStreamsFanout } from \"@heximon\u002Fqueue\u002Fupstash\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: { transport: new RedisStreamsFanout() },\n});\n",[513,1219,1220,1240,1260,1280,1302,1306,1318,1342,1356,1379],{"__ignoreMap":741},[745,1221,1222,1224,1226,1228,1230,1232,1234,1236,1238],{"class":747,"line":748},[745,1223,752],{"class":751},[745,1225,756],{"class":755},[745,1227,760],{"class":759},[745,1229,763],{"class":755},[745,1231,766],{"class":751},[745,1233,769],{"class":755},[745,1235,773],{"class":772},[745,1237,776],{"class":755},[745,1239,779],{"class":755},[745,1241,1242,1244,1246,1248,1250,1252,1254,1256,1258],{"class":747,"line":782},[745,1243,752],{"class":751},[745,1245,756],{"class":755},[745,1247,789],{"class":759},[745,1249,763],{"class":755},[745,1251,766],{"class":751},[745,1253,769],{"class":755},[745,1255,798],{"class":772},[745,1257,776],{"class":755},[745,1259,779],{"class":755},[745,1261,1262,1264,1266,1268,1270,1272,1274,1276,1278],{"class":747,"line":805},[745,1263,752],{"class":751},[745,1265,756],{"class":755},[745,1267,812],{"class":759},[745,1269,763],{"class":755},[745,1271,766],{"class":751},[745,1273,769],{"class":755},[745,1275,821],{"class":772},[745,1277,776],{"class":755},[745,1279,779],{"class":755},[745,1281,1282,1284,1286,1289,1291,1293,1295,1298,1300],{"class":747,"line":828},[745,1283,752],{"class":751},[745,1285,756],{"class":755},[745,1287,1288],{"class":759}," RedisStreamsFanout",[745,1290,763],{"class":755},[745,1292,766],{"class":751},[745,1294,769],{"class":755},[745,1296,1297],{"class":772},"@heximon\u002Fqueue\u002Fupstash\u002Fcompiler",[745,1299,776],{"class":755},[745,1301,779],{"class":755},[745,1303,1304],{"class":747,"line":835},[745,1305,832],{"emptyLinePlaceholder":831},[745,1307,1308,1310,1312,1314,1316],{"class":747,"line":853},[745,1309,838],{"class":751},[745,1311,841],{"class":751},[745,1313,760],{"class":844},[745,1315,847],{"class":759},[745,1317,850],{"class":755},[745,1319,1320,1322,1324,1326,1328,1330,1332,1334,1336,1338,1340],{"class":747,"line":888},[745,1321,857],{"class":856},[745,1323,860],{"class":755},[745,1325,863],{"class":759},[745,1327,866],{"class":755},[745,1329,789],{"class":844},[745,1331,871],{"class":759},[745,1333,874],{"class":755},[745,1335,877],{"class":755},[745,1337,812],{"class":844},[745,1339,882],{"class":759},[745,1341,885],{"class":755},[745,1343,1344,1346,1348,1350,1352,1354],{"class":747,"line":904},[745,1345,891],{"class":856},[745,1347,860],{"class":755},[745,1349,769],{"class":755},[745,1351,515],{"class":772},[745,1353,776],{"class":755},[745,1355,885],{"class":755},[745,1357,1358,1360,1362,1364,1367,1369,1371,1373,1376],{"class":747,"line":915},[745,1359,907],{"class":856},[745,1361,860],{"class":755},[745,1363,756],{"class":755},[745,1365,1366],{"class":856}," transport",[745,1368,860],{"class":755},[745,1370,877],{"class":755},[745,1372,1288],{"class":844},[745,1374,1375],{"class":759},"() ",[745,1377,1378],{"class":755},"},\n",[745,1380,1382,1384,1386],{"class":747,"line":1381},10,[745,1383,918],{"class":755},[745,1385,921],{"class":759},[745,1387,779],{"class":755},[499,1389,1390,1391,1394,1395,1397,1398,1401,1402,1405],{},"It sits behind the same ",[513,1392,1393],{},"IntegrationEventTransport"," port, so only the producer write (1 ",[513,1396,611],{}," instead of N\nenqueues) and the read (a consumer group per service) change — the outbox\u002Frelay path is untouched. Because several\nproducers can share one stream, each event carries its producing-service ",[513,1399,1400],{},"source",", which the subscriber folds\ninto its idempotency key (",[513,1403,1404],{},"idempotency:queue:\u003Csubscriber>:\u003Csource>:\u003Cid>",") so two producers minting the same id\nnever collide.",[499,1407,1408,1409,1412,1413,1416,1417,1420],{},"A native broker is also immune to ",[508,1410,1411],{},"late-subscriber starvation",": with the split leg, a producer\nfans only to subscribers it knew about at build time, but the stream ",[508,1414,1415],{},"retains"," entries, so a subscriber that\njoins later reads the backlog it missed. The Redis Streams consumer is a long-lived poll loop, so this leg runs on\na Node\u002FBun\u002FDeno deploy, not a freezing function — and bounding the shared stream needs ",[508,1418,1419],{},"Redis 8.2+ (or Upstash)","\nfor its ACK-aware trim, which only reclaims entries every consumer group has acknowledged.",[499,1422,1423,1427,1428,1430,1431,1434,1435,1437,1438,1441,1442,1444],{},[503,1424,1426],{"href":623,"rel":1425},[595],"The gap's broadcast example","\nis the runnable flagship for this leg: an ",[513,1429,515],{}," producer + ",[508,1432,1433],{},"two"," subscribers (",[513,1436,523],{},", ",[513,1439,1440],{},"analytics","), with an\nend-to-end test that proves the defining property — one ",[513,1443,611],{}," reaches every subscriber's consumer group.",[538,1446,1448],{"id":1447},"native-broadcast-aws-sns-to-sqs","Native broadcast — AWS SNS to SQS",[499,1450,1451,1452,1455,1456,1459,1460,1463,1464,1466,1467,1469,1470,1181],{},"The AWS counterpart of Redis Streams: select ",[513,1453,1454],{},"crossService.transport: new SnsFanout()"," and bind an ",[513,1457,1458],{},"SnsClient","\n(producer) + ",[513,1461,1462],{},"SqsClient"," (each subscriber). The producer does one ",[513,1465,639],{}," to a shared SNS topic; SNS fans the\nmessage to one SQS queue per subscribing service (",[513,1468,1071],{},"), each drained by the reused\n",[513,1471,1472],{},"SqsQueueConsumer",[735,1474,1476],{"className":737,"code":1475,"filename":739,"language":740,"meta":741,"style":741},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { IntegrationEventsPlugin } from \"@heximon\u002Fintegration\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\nimport { SnsFanout } from \"@heximon\u002Fqueue\u002Fsns\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: { transport: new SnsFanout() },\n});\n",[513,1477,1478,1498,1518,1538,1560,1564,1576,1600,1614,1634],{"__ignoreMap":741},[745,1479,1480,1482,1484,1486,1488,1490,1492,1494,1496],{"class":747,"line":748},[745,1481,752],{"class":751},[745,1483,756],{"class":755},[745,1485,760],{"class":759},[745,1487,763],{"class":755},[745,1489,766],{"class":751},[745,1491,769],{"class":755},[745,1493,773],{"class":772},[745,1495,776],{"class":755},[745,1497,779],{"class":755},[745,1499,1500,1502,1504,1506,1508,1510,1512,1514,1516],{"class":747,"line":782},[745,1501,752],{"class":751},[745,1503,756],{"class":755},[745,1505,789],{"class":759},[745,1507,763],{"class":755},[745,1509,766],{"class":751},[745,1511,769],{"class":755},[745,1513,798],{"class":772},[745,1515,776],{"class":755},[745,1517,779],{"class":755},[745,1519,1520,1522,1524,1526,1528,1530,1532,1534,1536],{"class":747,"line":805},[745,1521,752],{"class":751},[745,1523,756],{"class":755},[745,1525,812],{"class":759},[745,1527,763],{"class":755},[745,1529,766],{"class":751},[745,1531,769],{"class":755},[745,1533,821],{"class":772},[745,1535,776],{"class":755},[745,1537,779],{"class":755},[745,1539,1540,1542,1544,1547,1549,1551,1553,1556,1558],{"class":747,"line":828},[745,1541,752],{"class":751},[745,1543,756],{"class":755},[745,1545,1546],{"class":759}," SnsFanout",[745,1548,763],{"class":755},[745,1550,766],{"class":751},[745,1552,769],{"class":755},[745,1554,1555],{"class":772},"@heximon\u002Fqueue\u002Fsns\u002Fcompiler",[745,1557,776],{"class":755},[745,1559,779],{"class":755},[745,1561,1562],{"class":747,"line":835},[745,1563,832],{"emptyLinePlaceholder":831},[745,1565,1566,1568,1570,1572,1574],{"class":747,"line":853},[745,1567,838],{"class":751},[745,1569,841],{"class":751},[745,1571,760],{"class":844},[745,1573,847],{"class":759},[745,1575,850],{"class":755},[745,1577,1578,1580,1582,1584,1586,1588,1590,1592,1594,1596,1598],{"class":747,"line":888},[745,1579,857],{"class":856},[745,1581,860],{"class":755},[745,1583,863],{"class":759},[745,1585,866],{"class":755},[745,1587,789],{"class":844},[745,1589,871],{"class":759},[745,1591,874],{"class":755},[745,1593,877],{"class":755},[745,1595,812],{"class":844},[745,1597,882],{"class":759},[745,1599,885],{"class":755},[745,1601,1602,1604,1606,1608,1610,1612],{"class":747,"line":904},[745,1603,891],{"class":856},[745,1605,860],{"class":755},[745,1607,769],{"class":755},[745,1609,515],{"class":772},[745,1611,776],{"class":755},[745,1613,885],{"class":755},[745,1615,1616,1618,1620,1622,1624,1626,1628,1630,1632],{"class":747,"line":915},[745,1617,907],{"class":856},[745,1619,860],{"class":755},[745,1621,756],{"class":755},[745,1623,1366],{"class":856},[745,1625,860],{"class":755},[745,1627,877],{"class":755},[745,1629,1546],{"class":844},[745,1631,1375],{"class":759},[745,1633,1378],{"class":755},[745,1635,1636,1638,1640],{"class":747,"line":1381},[745,1637,918],{"class":755},[745,1639,921],{"class":759},[745,1641,779],{"class":755},[499,1643,1644,1645,1648,1649,1651],{},"The topic, the per-service queues, and the topic-to-queue subscriptions are deploy-provisioned (Terraform \u002F\nCloudFormation), and each subscription ",[508,1646,1647],{},"must enable raw message delivery"," — without it, SNS wraps the body in a\nJSON envelope before depositing it into SQS, and the ",[513,1650,1472],{},", which decodes the raw published body,\nwould fail.",[499,1653,1654,1655,1663,1664,1668,1669,1672,1673,1676],{},"The topic ARN and each service's own queue URL are read from the environment at runtime — see the\n",[503,1656,1659,1662],{"href":1657,"rel":1658},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fpackages\u002Farchitecture\u002Fqueue#native-cross-service-broadcast--snsfanout-heximonqueuesns",[595],[513,1660,1661],{},"@heximon\u002Fqueue\u002Fsns"," README","\nfor the full env-variable contract. ",[503,1665,1667],{"href":650,"rel":1666},[595],"The gap's SNS example","\nships the Terraform ",[513,1670,1671],{},"infra\u002F"," and a ",[513,1674,1675],{},"DEPLOY.md"," for the live AWS round-trip.",[538,1678,1680],{"id":1679},"cloudflare-escape-hatch-the-do-router","Cloudflare escape hatch — the DO router",[499,1682,1683,1684,1687,1688,860],{},"Cloudflare has no native broadcast product (Pub\u002FSub was retired), so on Workers the router ",[508,1685,1686],{},"is"," the hub: a\nsingle Durable Object holds a runtime subscription registry and fans out itself. Select it with\n",[513,1689,1690],{},"crossService.transport: new CloudflareDoRouterFanout()",[735,1692,1694],{"className":737,"code":1693,"filename":739,"language":740,"meta":741,"style":741},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { IntegrationEventsPlugin } from \"@heximon\u002Fintegration\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\nimport { DurablePlugin } from \"@heximon\u002Fdurable\u002Fcompiler\";\nimport { CloudflareDoRouterFanout } from \"@heximon\u002Fcloudflare\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin(), new DurablePlugin()],\n  service: \"orders\",\n  crossService: { transport: new CloudflareDoRouterFanout() },\n});\n",[513,1695,1696,1716,1736,1756,1778,1800,1804,1816,1848,1862,1882],{"__ignoreMap":741},[745,1697,1698,1700,1702,1704,1706,1708,1710,1712,1714],{"class":747,"line":748},[745,1699,752],{"class":751},[745,1701,756],{"class":755},[745,1703,760],{"class":759},[745,1705,763],{"class":755},[745,1707,766],{"class":751},[745,1709,769],{"class":755},[745,1711,773],{"class":772},[745,1713,776],{"class":755},[745,1715,779],{"class":755},[745,1717,1718,1720,1722,1724,1726,1728,1730,1732,1734],{"class":747,"line":782},[745,1719,752],{"class":751},[745,1721,756],{"class":755},[745,1723,789],{"class":759},[745,1725,763],{"class":755},[745,1727,766],{"class":751},[745,1729,769],{"class":755},[745,1731,798],{"class":772},[745,1733,776],{"class":755},[745,1735,779],{"class":755},[745,1737,1738,1740,1742,1744,1746,1748,1750,1752,1754],{"class":747,"line":805},[745,1739,752],{"class":751},[745,1741,756],{"class":755},[745,1743,812],{"class":759},[745,1745,763],{"class":755},[745,1747,766],{"class":751},[745,1749,769],{"class":755},[745,1751,821],{"class":772},[745,1753,776],{"class":755},[745,1755,779],{"class":755},[745,1757,1758,1760,1762,1765,1767,1769,1771,1774,1776],{"class":747,"line":828},[745,1759,752],{"class":751},[745,1761,756],{"class":755},[745,1763,1764],{"class":759}," DurablePlugin",[745,1766,763],{"class":755},[745,1768,766],{"class":751},[745,1770,769],{"class":755},[745,1772,1773],{"class":772},"@heximon\u002Fdurable\u002Fcompiler",[745,1775,776],{"class":755},[745,1777,779],{"class":755},[745,1779,1780,1782,1784,1787,1789,1791,1793,1796,1798],{"class":747,"line":835},[745,1781,752],{"class":751},[745,1783,756],{"class":755},[745,1785,1786],{"class":759}," CloudflareDoRouterFanout",[745,1788,763],{"class":755},[745,1790,766],{"class":751},[745,1792,769],{"class":755},[745,1794,1795],{"class":772},"@heximon\u002Fcloudflare\u002Fcompiler",[745,1797,776],{"class":755},[745,1799,779],{"class":755},[745,1801,1802],{"class":747,"line":853},[745,1803,832],{"emptyLinePlaceholder":831},[745,1805,1806,1808,1810,1812,1814],{"class":747,"line":888},[745,1807,838],{"class":751},[745,1809,841],{"class":751},[745,1811,760],{"class":844},[745,1813,847],{"class":759},[745,1815,850],{"class":755},[745,1817,1818,1820,1822,1824,1826,1828,1830,1832,1834,1836,1838,1840,1842,1844,1846],{"class":747,"line":904},[745,1819,857],{"class":856},[745,1821,860],{"class":755},[745,1823,863],{"class":759},[745,1825,866],{"class":755},[745,1827,789],{"class":844},[745,1829,871],{"class":759},[745,1831,874],{"class":755},[745,1833,877],{"class":755},[745,1835,812],{"class":844},[745,1837,871],{"class":759},[745,1839,874],{"class":755},[745,1841,877],{"class":755},[745,1843,1764],{"class":844},[745,1845,882],{"class":759},[745,1847,885],{"class":755},[745,1849,1850,1852,1854,1856,1858,1860],{"class":747,"line":915},[745,1851,891],{"class":856},[745,1853,860],{"class":755},[745,1855,769],{"class":755},[745,1857,515],{"class":772},[745,1859,776],{"class":755},[745,1861,885],{"class":755},[745,1863,1864,1866,1868,1870,1872,1874,1876,1878,1880],{"class":747,"line":1381},[745,1865,907],{"class":856},[745,1867,860],{"class":755},[745,1869,756],{"class":755},[745,1871,1366],{"class":856},[745,1873,860],{"class":755},[745,1875,877],{"class":755},[745,1877,1786],{"class":844},[745,1879,1375],{"class":759},[745,1881,1378],{"class":755},[745,1883,1885,1887,1889],{"class":747,"line":1884},11,[745,1886,918],{"class":755},[745,1888,921],{"class":759},[745,1890,779],{"class":755},[499,1892,1893,1894,1896,1897,1900,1901,1904,1905,1908,1909,1912,1913,1916,1917,1920,1921,1924],{},"The producer does ONE ",[513,1895,666],{}," to the router and never names a subscriber. Each subscriber ",[508,1898,1899],{},"self-registers its\ndelivery queue with the router at runtime",", so the registry — not the producer's build — is the authoritative\nsubscriber set; the router fans every event onto each subscriber's own queue, drained by the reused\n",[513,1902,1903],{},"CloudflareQueueConsumer",". That buys ",[508,1906,1907],{},"producer-blindness",": add a subscriber in a new repo without rebuilding the\nproducer. It costs for it: the single router DO is a per-topic SPOF with a ~1000 req\u002Fs ceiling, and the fan-out is\n",[513,1910,1911],{},"(2N+1)"," queue ops plus DO compute — ",[1197,1914,1915],{},"more"," than the split's ",[513,1918,1919],{},"~3N",". So the router is a documented ",[508,1922,1923],{},"opt-in escape\nhatch",", and the per-service-queue split stays the Cloudflare default.",[499,1926,1927,1928,1931,1932,1935,1936,1940,1941,1944,1945,1947,1948,1950],{},"The router host lists the shipped DO under ",[513,1929,1930],{},"durable","; a subscriber lists none — it reaches the router\ncross-worker through a ",[513,1933,1934],{},"script_name"," Durable Object namespace binding. ",[503,1937,1939],{"href":678,"rel":1938},[595],"The flagship notify-split app","\nis the runnable DO-router example — the flagship's real ",[513,1942,1943],{},"@ticketing\u002Fnotifications"," context redeployed as its own\nCloudflare Worker, fed only by the cross-service event, with a ",[513,1946,1675],{}," multi-worker recipe (provision queues →\nset the host's Queues REST credentials → ",[513,1949,721],{}," each service → deploy host-first → verify).",[538,1952,1954],{"id":1953},"push-broadcast-for-freezing-platforms-upstash-qstash","Push broadcast for freezing platforms — Upstash QStash",[499,1956,1957,1958,1961,1962,1965,1966,1969,1970,860],{},"Every leg above needs a subscriber that can run a long-lived poll loop (SQL \u002F Redis \u002F SQS) or that is a Cloudflare\nWorker. A Vercel \u002F Netlify \u002F AWS Lambda ",[508,1959,1960],{},"function"," freezes between invocations and can host neither — the only\ndelivery it accepts is an HTTP request the platform wakes it for. So the producer publishes to an external ",[508,1963,1964],{},"push\nbroker"," that POSTs each event to the subscriber's own route. Select ",[513,1967,1968],{},"crossService.transport: new QStashFanout()","\nand bind a ",[513,1971,1972],{},"QStashClient",[735,1974,1976],{"className":737,"code":1975,"filename":739,"language":740,"meta":741,"style":741},"import { defineHeximonConfig } from \"@heximon\u002Fbuild\";\nimport { IntegrationEventsPlugin } from \"@heximon\u002Fintegration\u002Fcompiler\";\nimport { HttpPlugin } from \"@heximon\u002Fhttp\u002Fcompiler\";\nimport { QStashFanout } from \"@heximon\u002Fqueue\u002Fupstash\u002Fcompiler\";\n\nexport default defineHeximonConfig({\n  plugins: [new IntegrationEventsPlugin(), new HttpPlugin()],\n  service: \"orders\",\n  crossService: { transport: new QStashFanout() },\n});\n",[513,1977,1978,1998,2018,2038,2059,2063,2075,2099,2113,2133],{"__ignoreMap":741},[745,1979,1980,1982,1984,1986,1988,1990,1992,1994,1996],{"class":747,"line":748},[745,1981,752],{"class":751},[745,1983,756],{"class":755},[745,1985,760],{"class":759},[745,1987,763],{"class":755},[745,1989,766],{"class":751},[745,1991,769],{"class":755},[745,1993,773],{"class":772},[745,1995,776],{"class":755},[745,1997,779],{"class":755},[745,1999,2000,2002,2004,2006,2008,2010,2012,2014,2016],{"class":747,"line":782},[745,2001,752],{"class":751},[745,2003,756],{"class":755},[745,2005,789],{"class":759},[745,2007,763],{"class":755},[745,2009,766],{"class":751},[745,2011,769],{"class":755},[745,2013,798],{"class":772},[745,2015,776],{"class":755},[745,2017,779],{"class":755},[745,2019,2020,2022,2024,2026,2028,2030,2032,2034,2036],{"class":747,"line":805},[745,2021,752],{"class":751},[745,2023,756],{"class":755},[745,2025,812],{"class":759},[745,2027,763],{"class":755},[745,2029,766],{"class":751},[745,2031,769],{"class":755},[745,2033,821],{"class":772},[745,2035,776],{"class":755},[745,2037,779],{"class":755},[745,2039,2040,2042,2044,2047,2049,2051,2053,2055,2057],{"class":747,"line":828},[745,2041,752],{"class":751},[745,2043,756],{"class":755},[745,2045,2046],{"class":759}," QStashFanout",[745,2048,763],{"class":755},[745,2050,766],{"class":751},[745,2052,769],{"class":755},[745,2054,1297],{"class":772},[745,2056,776],{"class":755},[745,2058,779],{"class":755},[745,2060,2061],{"class":747,"line":835},[745,2062,832],{"emptyLinePlaceholder":831},[745,2064,2065,2067,2069,2071,2073],{"class":747,"line":853},[745,2066,838],{"class":751},[745,2068,841],{"class":751},[745,2070,760],{"class":844},[745,2072,847],{"class":759},[745,2074,850],{"class":755},[745,2076,2077,2079,2081,2083,2085,2087,2089,2091,2093,2095,2097],{"class":747,"line":888},[745,2078,857],{"class":856},[745,2080,860],{"class":755},[745,2082,863],{"class":759},[745,2084,866],{"class":755},[745,2086,789],{"class":844},[745,2088,871],{"class":759},[745,2090,874],{"class":755},[745,2092,877],{"class":755},[745,2094,812],{"class":844},[745,2096,882],{"class":759},[745,2098,885],{"class":755},[745,2100,2101,2103,2105,2107,2109,2111],{"class":747,"line":904},[745,2102,891],{"class":856},[745,2104,860],{"class":755},[745,2106,769],{"class":755},[745,2108,515],{"class":772},[745,2110,776],{"class":755},[745,2112,885],{"class":755},[745,2114,2115,2117,2119,2121,2123,2125,2127,2129,2131],{"class":747,"line":915},[745,2116,907],{"class":856},[745,2118,860],{"class":755},[745,2120,756],{"class":755},[745,2122,1366],{"class":856},[745,2124,860],{"class":755},[745,2126,877],{"class":755},[745,2128,2046],{"class":844},[745,2130,1375],{"class":759},[745,2132,1378],{"class":755},[745,2134,2135,2137,2139],{"class":747,"line":1381},[745,2136,918],{"class":755},[745,2138,921],{"class":759},[745,2140,779],{"class":755},[499,2142,2143,2144,2147,2148,2151,2152,2155,2156,2159,2160,2163,2164,2167,2168,2171],{},"The producer does ",[508,2145,2146],{},"one"," HTTP POST per event to a QStash ",[508,2149,2150],{},"URL Group",", which pushes the message to every\nendpoint registered under it (a subscriber's HTTPS route) — broadcast, producer-blind. The subscriber side is the\none leg with ",[508,2153,2154],{},"no generated consumer",": the app writes its ",[508,2157,2158],{},"own"," controller and delegates to the injectable\n",[513,2161,2162],{},"QStashReceiver",", which verifies the ",[513,2165,2166],{},"Upstash-Signature"," (self-contained WebCrypto HMAC, no SDK) and dispatches\nthe decoded envelope into the same ",[513,2169,2170],{},"queue:channel"," tier:",[735,2173,2176],{"className":737,"code":2174,"filename":2175,"language":740,"meta":741,"style":741},"import type { Controller, Post } from \"@heximon\u002Fhttp\";\nimport { QStashReceiver } from \"@heximon\u002Fqueue\u002Fupstash\";\n\nexport class IntegrationEventsController implements Controller\u003C\"\u002Fintegration-events\"> {\n  public constructor(private readonly receiver: QStashReceiver) {}\n\n  public async receive(action: Post\u003C\"\u002F\">): Promise\u003C{ ok: boolean }> {\n    const rawBody = await action.request.text();\n    const signature = action.request.headers.get(\"Upstash-Signature\") ?? \"\";\n\n    if (!(await this.receiver.verify(rawBody, signature))) {\n      action.response.status = 401;\n      return { ok: false };\n    }\n\n    await this.receiver.dispatch(rawBody);\n    return { ok: true };\n  }\n}\n","services\u002Fbilling\u002Fsrc\u002Fintegration-events.controller.ts",[513,2177,2178,2208,2230,2234,2267,2296,2300,2350,2381,2425,2429,2470,2494,2513,2519,2524,2547,2564,2570],{"__ignoreMap":741},[745,2179,2180,2182,2185,2187,2190,2192,2195,2197,2199,2201,2204,2206],{"class":747,"line":748},[745,2181,752],{"class":751},[745,2183,2184],{"class":751}," type",[745,2186,756],{"class":755},[745,2188,2189],{"class":759}," Controller",[745,2191,874],{"class":755},[745,2193,2194],{"class":759}," Post",[745,2196,763],{"class":755},[745,2198,766],{"class":751},[745,2200,769],{"class":755},[745,2202,2203],{"class":772},"@heximon\u002Fhttp",[745,2205,776],{"class":755},[745,2207,779],{"class":755},[745,2209,2210,2212,2214,2217,2219,2221,2223,2226,2228],{"class":747,"line":782},[745,2211,752],{"class":751},[745,2213,756],{"class":755},[745,2215,2216],{"class":759}," QStashReceiver",[745,2218,763],{"class":755},[745,2220,766],{"class":751},[745,2222,769],{"class":755},[745,2224,2225],{"class":772},"@heximon\u002Fqueue\u002Fupstash",[745,2227,776],{"class":755},[745,2229,779],{"class":755},[745,2231,2232],{"class":747,"line":805},[745,2233,832],{"emptyLinePlaceholder":831},[745,2235,2236,2238,2242,2246,2249,2251,2254,2256,2259,2261,2264],{"class":747,"line":828},[745,2237,838],{"class":751},[745,2239,2241],{"class":2240},"spNyl"," class",[745,2243,2245],{"class":2244},"sBMFI"," IntegrationEventsController",[745,2247,2248],{"class":2240}," implements",[745,2250,2189],{"class":2244},[745,2252,2253],{"class":755},"\u003C",[745,2255,776],{"class":755},[745,2257,2258],{"class":772},"\u002Fintegration-events",[745,2260,776],{"class":755},[745,2262,2263],{"class":755},">",[745,2265,2266],{"class":755}," {\n",[745,2268,2269,2272,2275,2277,2280,2283,2287,2289,2291,2293],{"class":747,"line":835},[745,2270,2271],{"class":2240},"  public",[745,2273,2274],{"class":2240}," constructor",[745,2276,847],{"class":755},[745,2278,2279],{"class":2240},"private",[745,2281,2282],{"class":2240}," readonly",[745,2284,2286],{"class":2285},"sHdIc"," receiver",[745,2288,860],{"class":755},[745,2290,2216],{"class":2244},[745,2292,921],{"class":755},[745,2294,2295],{"class":755}," {}\n",[745,2297,2298],{"class":747,"line":853},[745,2299,832],{"emptyLinePlaceholder":831},[745,2301,2302,2304,2307,2310,2312,2315,2317,2319,2321,2323,2326,2328,2331,2334,2337,2340,2342,2345,2348],{"class":747,"line":888},[745,2303,2271],{"class":2240},[745,2305,2306],{"class":2240}," async",[745,2308,2309],{"class":856}," receive",[745,2311,847],{"class":755},[745,2313,2314],{"class":2285},"action",[745,2316,860],{"class":755},[745,2318,2194],{"class":2244},[745,2320,2253],{"class":755},[745,2322,776],{"class":755},[745,2324,2325],{"class":772},"\u002F",[745,2327,776],{"class":755},[745,2329,2330],{"class":755},">):",[745,2332,2333],{"class":2244}," Promise",[745,2335,2336],{"class":755},"\u003C{",[745,2338,2339],{"class":856}," ok",[745,2341,860],{"class":755},[745,2343,2344],{"class":2244}," boolean",[745,2346,2347],{"class":755}," }>",[745,2349,2266],{"class":755},[745,2351,2352,2355,2358,2361,2364,2367,2369,2372,2374,2377,2379],{"class":747,"line":904},[745,2353,2354],{"class":2240},"    const",[745,2356,2357],{"class":759}," rawBody",[745,2359,2360],{"class":755}," =",[745,2362,2363],{"class":751}," await",[745,2365,2366],{"class":759}," action",[745,2368,1181],{"class":755},[745,2370,2371],{"class":759},"request",[745,2373,1181],{"class":755},[745,2375,2376],{"class":844},"text",[745,2378,871],{"class":856},[745,2380,779],{"class":755},[745,2382,2383,2385,2388,2390,2392,2394,2396,2398,2401,2403,2406,2408,2410,2412,2414,2417,2420,2423],{"class":747,"line":915},[745,2384,2354],{"class":2240},[745,2386,2387],{"class":759}," signature",[745,2389,2360],{"class":755},[745,2391,2366],{"class":759},[745,2393,1181],{"class":755},[745,2395,2371],{"class":759},[745,2397,1181],{"class":755},[745,2399,2400],{"class":759},"headers",[745,2402,1181],{"class":755},[745,2404,2405],{"class":844},"get",[745,2407,847],{"class":856},[745,2409,776],{"class":755},[745,2411,2166],{"class":772},[745,2413,776],{"class":755},[745,2415,2416],{"class":856},") ",[745,2418,2419],{"class":755},"??",[745,2421,2422],{"class":755}," \"\"",[745,2424,779],{"class":755},[745,2426,2427],{"class":747,"line":1381},[745,2428,832],{"emptyLinePlaceholder":831},[745,2430,2431,2434,2437,2440,2442,2445,2448,2451,2453,2456,2458,2461,2463,2465,2468],{"class":747,"line":1884},[745,2432,2433],{"class":751},"    if",[745,2435,2436],{"class":856}," (",[745,2438,2439],{"class":755},"!",[745,2441,847],{"class":856},[745,2443,2444],{"class":751},"await",[745,2446,2447],{"class":755}," this.",[745,2449,2450],{"class":759},"receiver",[745,2452,1181],{"class":755},[745,2454,2455],{"class":844},"verify",[745,2457,847],{"class":856},[745,2459,2460],{"class":759},"rawBody",[745,2462,874],{"class":755},[745,2464,2387],{"class":759},[745,2466,2467],{"class":856},"))) ",[745,2469,850],{"class":755},[745,2471,2473,2476,2478,2481,2483,2486,2488,2492],{"class":747,"line":2472},12,[745,2474,2475],{"class":759},"      action",[745,2477,1181],{"class":755},[745,2479,2480],{"class":759},"response",[745,2482,1181],{"class":755},[745,2484,2485],{"class":759},"status",[745,2487,2360],{"class":755},[745,2489,2491],{"class":2490},"sbssI"," 401",[745,2493,779],{"class":755},[745,2495,2497,2500,2502,2504,2506,2510],{"class":747,"line":2496},13,[745,2498,2499],{"class":751},"      return",[745,2501,756],{"class":755},[745,2503,2339],{"class":856},[745,2505,860],{"class":755},[745,2507,2509],{"class":2508},"sfNiH"," false",[745,2511,2512],{"class":755}," };\n",[745,2514,2516],{"class":747,"line":2515},14,[745,2517,2518],{"class":755},"    }\n",[745,2520,2522],{"class":747,"line":2521},15,[745,2523,832],{"emptyLinePlaceholder":831},[745,2525,2527,2530,2532,2534,2536,2539,2541,2543,2545],{"class":747,"line":2526},16,[745,2528,2529],{"class":751},"    await",[745,2531,2447],{"class":755},[745,2533,2450],{"class":759},[745,2535,1181],{"class":755},[745,2537,2538],{"class":844},"dispatch",[745,2540,847],{"class":856},[745,2542,2460],{"class":759},[745,2544,921],{"class":856},[745,2546,779],{"class":755},[745,2548,2550,2553,2555,2557,2559,2562],{"class":747,"line":2549},17,[745,2551,2552],{"class":751},"    return",[745,2554,756],{"class":755},[745,2556,2339],{"class":856},[745,2558,860],{"class":755},[745,2560,2561],{"class":2508}," true",[745,2563,2512],{"class":755},[745,2565,2567],{"class":747,"line":2566},18,[745,2568,2569],{"class":755},"  }\n",[745,2571,2573],{"class":747,"line":2572},19,[745,2574,2575],{"class":755},"}\n",[499,2577,1390,2578,2580,2581,2584,2585,2588,2589,2592,2593,2596,2597,2600,2601,2605,2606,2609,2610,1181],{},[513,2579,1393],{}," port, and because the publish runs over plain ",[513,2582,2583],{},"fetch"," from any\nruntime, the build accepts a QStash producer on a freezing platform too — the fan-out gate is transport-aware. The\nURL Group, its endpoints, and the signing keys are deploy-provisioned (the QStash REST API or dashboard); the\nproducer reads ",[513,2586,2587],{},"HEXIMON_QSTASH_URL_GROUP"," + ",[513,2590,2591],{},"QSTASH_TOKEN",", each subscriber reads ",[513,2594,2595],{},"QSTASH_CURRENT_SIGNING_KEY"," \u002F\n",[513,2598,2599],{},"QSTASH_NEXT_SIGNING_KEY",". ",[503,2602,2604],{"href":703,"rel":2603},[595],"The gap's QStash example","\nis the runnable push leg — an in-process ",[513,2607,2608],{},"QStashSimulator"," proves one publish reaches every subscriber, plus a\nforged-signature ",[513,2611,2612],{},"401",[538,2614,2616],{"id":2615},"verification-status","Verification status",[499,2618,2619,2620,2623,2624,2626],{},"Every leg above is proven in-process (",[513,2621,2622],{},"createTestApp"," booting the real services side by side over a shared\nfake\u002Fsimulator) and against real ",[513,2625,721],{}," output. A live multi-service deploy is verified for one leg only —\neverything else is the documented, expected-but-unverified next step:",[2628,2629,2630,2650,2658,2671],"ul",{},[2631,2632,2633,2635,2636,2639,2640,2642,2643,2645,2646,2649],"li",{},[508,2634,661],{}," — no live multi-worker ",[513,2637,2638],{},"wrangler deploy"," yet; the flagship ",[513,2641,682],{}," app's\n",[513,2644,1675],{}," is the recipe, and the router's own registry + fan-out logic is unit-tested against the real\n",[513,2647,2648],{},"IntegrationEventRouterRoom"," Durable Object.",[2631,2651,2652,2654,2655,2657],{},[508,2653,605],{}," — verified with an in-process fake + real ",[513,2656,721],{}," artifacts; no live multi-service\nrun yet.",[2631,2659,2660,2654,2662,2664,2665,2667,2668,2670],{},[508,2661,634],{},[513,2663,721],{}," artifacts; the live AWS round-trip\nis the ",[513,2666,654],{}," example's ",[513,2669,1675],{}," (Terraform-provisioned topic + queues).",[2631,2672,2673,2676,2677,2679,2680,2682,2683,2667,2685,1181],{},[508,2674,2675],{},"QStash push broadcast"," — verified with the in-process ",[513,2678,2608],{}," + real ",[513,2681,721],{}," artifacts; the live\nVercel\u002FNetlify round-trip is the ",[513,2684,707],{},[513,2686,1675],{},[499,2688,2689,2690,2697],{},"See ",[503,2691,2694],{"href":2692,"rel":2693},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Fblob\u002Fmain\u002Fdocs\u002Flive-deploy-verification.md",[595],[513,2695,2696],{},"docs\u002Flive-deploy-verification.md","\nfor the dated ledger behind every \"verified\" claim in these docs.",[538,2699,2701],{"id":2700},"see-also","See also",[2628,2703,2704,2717,2722],{},[2631,2705,2706,2708,2709,2712,2713,2716],{},[503,2707,243],{"href":244}," — the typed ",[513,2710,2711],{},"IntegrationEvent"," producer, the\n",[513,2714,2715],{},"IntegrationEventHandler"," consumer, and the transactional outbox these fan-out legs build on.",[2631,2718,2719,2721],{},[503,2720,151],{"href":152}," — the durable Drizzle\u002FSQS\u002FUpstash transports and the polling-consumer\nmodel the split and broadcast legs are built from.",[2631,2723,2724,2726,2727,2730],{},[503,2725,307],{"href":308}," — Durable Objects, ",[513,2728,2729],{},"wrangler.json"," generation, and the platform the DO\nrouter runs on.",[2732,2733,2734],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .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 .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":741,"searchDepth":782,"depth":782,"links":2736},[2737,2740,2741,2742,2743,2744,2745,2746],{"id":540,"depth":782,"text":541,"children":2738},[2739],{"id":933,"depth":805,"text":934},{"id":1056,"depth":782,"text":1057},{"id":1184,"depth":782,"text":1185},{"id":1447,"depth":782,"text":1448},{"id":1679,"depth":782,"text":1680},{"id":1953,"depth":782,"text":1954},{"id":2615,"depth":782,"text":2616},{"id":2700,"depth":782,"text":2701},"Fan an integration event out to independently deployed services — the per-service-queue split, Redis Streams and SNS-to-SQS native broadcast, the Cloudflare DO-router escape hatch, and QStash push broadcast for freezing platforms — selected via crossService.transport.","md",null,{},{"icon":354},{"title":351,"description":2747},"uUHiL0kLTPF8JwmxaWb4wGTC624kAgMJ-H_beiFtSBU",[2755,2757],{"title":346,"path":347,"stem":348,"description":2756,"icon":349,"children":-1},"Where a Heximon app's fetch server lives — the heximon() Vite dev server, standalone Node\u002FBun\u002FDeno, Nitro, Nuxt, unplugin for other bundlers, library mode, and the mixed-runtime split.",{"title":362,"path":363,"stem":364,"description":2758,"icon":357,"children":-1},"heximon create, deploy, provision, and migrations — the commands the unscoped heximon package ships, scaffolding new apps, resolving credentials, running vp build, and shelling the vendor CLI for you.",1783300761903]