[{"data":1,"prerenderedAt":2729},["ShallowReactive",2],{"navigation_docs":3,"-docs-capabilities-security":493,"-docs-capabilities-security-surround":2724},[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":189,"body":495,"description":2717,"extension":2718,"links":2719,"meta":2720,"navigation":2721,"path":190,"seo":2722,"stem":191,"__hash__":2723},"docs\u002Fdocs\u002F03.capabilities\u002F11.security.md",{"type":496,"value":497,"toc":2700},"minimark",[498,502,507,535,667,673,692,799,802,806,809,920,923,930,935,1001,1024,1031,1041,1103,1111,1120,1127,1146,1570,1580,1715,1823,1836,1843,1863,1909,2207,2218,2243,2250,2255,2271,2590,2611,2617,2635,2639,2650,2657,2661,2696],[499,500,501],"p",{},"A few defaults go a long way: cap the request body so a client cannot exhaust memory, add defensive response\nheaders so browsers enforce content-type sniffing and framing policies, and optionally layer a rate limiter on\ntop. Heximon applies the first two automatically at the dispatch seam — before any handler runs — and ships\nthe rate-limit tier as an opt-in subpath.",[503,504,506],"h2",{"id":505},"body-size-guard","Body-size guard",[499,508,509,510,514,515,519,520,523,530,531,534],{},"Every incoming request is checked against a maximum body size ",[511,512,513],"strong",{},"before any handler or validator reads the\nbody",". A request that declares a ",[516,517,518],"code",{},"Content-Length"," header exceeding the limit is rejected with a ",[516,521,522],{},"413",[524,525,529],"a",{"href":526,"rel":527},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9457",[528],"nofollow","RFC 9457"," ",[516,532,533],{},"problem+json"," response:",[536,537,542],"pre",{"className":538,"code":539,"language":540,"meta":541,"style":541},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"type\": \"tag:api.example.com,2026-07-05:BodySizeExceededError\",\n  \"status\": 413,\n  \"title\": \"Payload Too Large\",\n  \"detail\": \"Request body size 2097152 bytes exceeds the 1048576 byte limit.\",\n  \"instance\": \"\u002Fupload\"\n}\n","json","",[516,543,544,553,581,599,620,641,661],{"__ignoreMap":541},[545,546,549],"span",{"class":547,"line":548},"line",1,[545,550,552],{"class":551},"sMK4o","{\n",[545,554,556,559,563,566,569,572,576,578],{"class":547,"line":555},2,[545,557,558],{"class":551},"  \"",[545,560,562],{"class":561},"spNyl","type",[545,564,565],{"class":551},"\"",[545,567,568],{"class":551},":",[545,570,571],{"class":551}," \"",[545,573,575],{"class":574},"sfazB","tag:api.example.com,2026-07-05:BodySizeExceededError",[545,577,565],{"class":551},[545,579,580],{"class":551},",\n",[545,582,584,586,589,591,593,597],{"class":547,"line":583},3,[545,585,558],{"class":551},[545,587,588],{"class":561},"status",[545,590,565],{"class":551},[545,592,568],{"class":551},[545,594,596],{"class":595},"sbssI"," 413",[545,598,580],{"class":551},[545,600,602,604,607,609,611,613,616,618],{"class":547,"line":601},4,[545,603,558],{"class":551},[545,605,606],{"class":561},"title",[545,608,565],{"class":551},[545,610,568],{"class":551},[545,612,571],{"class":551},[545,614,615],{"class":574},"Payload Too Large",[545,617,565],{"class":551},[545,619,580],{"class":551},[545,621,623,625,628,630,632,634,637,639],{"class":547,"line":622},5,[545,624,558],{"class":551},[545,626,627],{"class":561},"detail",[545,629,565],{"class":551},[545,631,568],{"class":551},[545,633,571],{"class":551},[545,635,636],{"class":574},"Request body size 2097152 bytes exceeds the 1048576 byte limit.",[545,638,565],{"class":551},[545,640,580],{"class":551},[545,642,644,646,649,651,653,655,658],{"class":547,"line":643},6,[545,645,558],{"class":551},[545,647,648],{"class":561},"instance",[545,650,565],{"class":551},[545,652,568],{"class":551},[545,654,571],{"class":551},[545,656,657],{"class":574},"\u002Fupload",[545,659,660],{"class":551},"\"\n",[545,662,664],{"class":547,"line":663},7,[545,665,666],{"class":551},"}\n",[499,668,669,670,672],{},"(The ",[516,671,562],{}," tag carries your API's host + the error's class name — the same envelope every framework\nerror renders through.)",[499,674,675,676,679,680,683,684,687,688,691],{},"The default limit is ",[511,677,678],{},"1 MiB",". Adjust it by setting ",[516,681,682],{},"http.maxBodyBytes"," in ",[516,685,686],{},"CoreConfig"," — the host\nboot prelude wires the value into ",[516,689,690],{},"RequestDispatcher.configure"," automatically (no app-side call needed):",[536,693,697],{"className":694,"code":695,"language":696,"meta":541,"style":541},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F In your app config layering — e.g. an AppConfig that maps env into CoreConfig:\nconst app = await createApp({\n  CoreConfig: new CoreConfig({ http: { maxBodyBytes: 5 * 1024 * 1024 } }), \u002F\u002F 5 MiB\n});\n","ts",[516,698,699,705,730,789],{"__ignoreMap":541},[545,700,701],{"class":547,"line":548},[545,702,704],{"class":703},"sHwdD","\u002F\u002F In your app config layering — e.g. an AppConfig that maps env into CoreConfig:\n",[545,706,707,710,714,717,721,725,728],{"class":547,"line":555},[545,708,709],{"class":561},"const",[545,711,713],{"class":712},"sTEyZ"," app ",[545,715,716],{"class":551},"=",[545,718,720],{"class":719},"s7zQu"," await",[545,722,724],{"class":723},"s2Zo4"," createApp",[545,726,727],{"class":712},"(",[545,729,552],{"class":551},[545,731,732,736,738,741,744,746,749,752,754,757,760,762,765,768,771,773,775,778,780,783,786],{"class":547,"line":583},[545,733,735],{"class":734},"swJcz","  CoreConfig",[545,737,568],{"class":551},[545,739,740],{"class":551}," new",[545,742,743],{"class":723}," CoreConfig",[545,745,727],{"class":712},[545,747,748],{"class":551},"{",[545,750,751],{"class":734}," http",[545,753,568],{"class":551},[545,755,756],{"class":551}," {",[545,758,759],{"class":734}," maxBodyBytes",[545,761,568],{"class":551},[545,763,764],{"class":595}," 5",[545,766,767],{"class":551}," *",[545,769,770],{"class":595}," 1024",[545,772,767],{"class":551},[545,774,770],{"class":595},[545,776,777],{"class":551}," }",[545,779,777],{"class":551},[545,781,782],{"class":712},")",[545,784,785],{"class":551},",",[545,787,788],{"class":703}," \u002F\u002F 5 MiB\n",[545,790,791,794,796],{"class":547,"line":601},[545,792,793],{"class":551},"}",[545,795,782],{"class":712},[545,797,798],{"class":551},";\n",[499,800,801],{},"The guard covers both inline and contract-mode controller binding — it sits at the shared dispatch seam,\nnot at the per-route level, so every route is protected automatically.",[503,803,805],{"id":804},"security-response-headers","Security response headers",[499,807,808],{},"Every response carries a conservative set of security headers, applied at the same dispatch seam so no\nroute can accidentally omit them:",[810,811,812,829],"table",{},[813,814,815],"thead",{},[816,817,818,823,826],"tr",{},[819,820,822],"th",{"align":821},"left","Header",[819,824,825],{"align":821},"Value",[819,827,828],{"align":821},"Effect",[830,831,832,848,867,886,901],"tbody",{},[816,833,834,840,845],{},[835,836,837],"td",{"align":821},[516,838,839],{},"X-Content-Type-Options",[835,841,842],{"align":821},[516,843,844],{},"nosniff",[835,846,847],{"align":821},"Prevents browsers from MIME-sniffing a response away from the declared content type.",[816,849,850,855,860],{},[835,851,852],{"align":821},[516,853,854],{},"X-Frame-Options",[835,856,857],{"align":821},[516,858,859],{},"DENY",[835,861,862,863,866],{"align":821},"Blocks the page from being embedded in any ",[516,864,865],{},"\u003Ciframe>"," — prevents clickjacking.",[816,868,869,874,879],{},[835,870,871],{"align":821},[516,872,873],{},"Referrer-Policy",[835,875,876],{"align":821},[516,877,878],{},"no-referrer",[835,880,881,882,885],{"align":821},"Sends no ",[516,883,884],{},"Referer"," header on outbound navigations — avoids leaking your URL.",[816,887,888,893,898],{},[835,889,890],{"align":821},[516,891,892],{},"X-DNS-Prefetch-Control",[835,894,895],{"align":821},[516,896,897],{},"off",[835,899,900],{"align":821},"Disables browser DNS prefetching, which can leak visited URLs to DNS resolvers.",[816,902,903,908,913],{},[835,904,905],{"align":821},[516,906,907],{},"Strict-Transport-Security",[835,909,910],{"align":821},[516,911,912],{},"max-age=31536000; includeSubDomains",[835,914,915,916,919],{"align":821},"Enforced ",[511,917,918],{},"only over HTTPS",". Tells browsers to always use HTTPS for one year and all subdomains.",[499,921,922],{},"HSTS is conditional — it is only emitted when the request arrived over HTTPS, because sending it over HTTP\nis counterproductive and some environments serve localhost over plain HTTP. The other four headers apply\nunconditionally.",[499,924,925,926,929],{},"The header set is applied via ",[516,927,928],{},"SecurityHeadersPolicy",", an overridable DI token — bind your own implementation\nto replace the defaults.",[499,931,932,933,568],{},"To skip the pass entirely — for an app that sets these headers at the edge\u002FCDN (Vercel\u002FNetlify\u002FCloudflare\nheader config) rather than per response — turn it off in ",[516,934,686],{},[536,936,938],{"className":694,"code":937,"language":696,"meta":541,"style":541},"const app = await createApp({\n  CoreConfig: new CoreConfig({ http: { securityHeaders: false } }),\n});\n",[516,939,940,956,993],{"__ignoreMap":541},[545,941,942,944,946,948,950,952,954],{"class":547,"line":548},[545,943,709],{"class":561},[545,945,713],{"class":712},[545,947,716],{"class":551},[545,949,720],{"class":719},[545,951,724],{"class":723},[545,953,727],{"class":712},[545,955,552],{"class":551},[545,957,958,960,962,964,966,968,970,972,974,976,979,981,985,987,989,991],{"class":547,"line":555},[545,959,735],{"class":734},[545,961,568],{"class":551},[545,963,740],{"class":551},[545,965,743],{"class":723},[545,967,727],{"class":712},[545,969,748],{"class":551},[545,971,751],{"class":734},[545,973,568],{"class":551},[545,975,756],{"class":551},[545,977,978],{"class":734}," securityHeaders",[545,980,568],{"class":551},[545,982,984],{"class":983},"sfNiH"," false",[545,986,777],{"class":551},[545,988,777],{"class":551},[545,990,782],{"class":712},[545,992,580],{"class":551},[545,994,995,997,999],{"class":547,"line":583},[545,996,793],{"class":551},[545,998,782],{"class":712},[545,1000,798],{"class":551},[499,1002,1003,1004,1006,1007,1011,1012,1015,1016,1019,1020,1023],{},"The overridable ",[516,1005,928],{}," still governs ",[1008,1009,1010],"em",{},"which"," headers apply while on; this toggle is the\nseparate \"apply them at all\" switch (default on — secure by default). A sibling ",[516,1013,1014],{},"http"," toggle turns off other\nper-request work the same way: ",[516,1017,1018],{},"requestId: false"," skips the ",[516,1021,1022],{},"x-request-id"," derivation + echo, for apps where\ncorrelation ids are assigned upstream (load balancer \u002F API gateway).",[503,1025,1027,1028],{"id":1026},"rate-limiting-heximonhttpsecurity","Rate limiting — ",[516,1029,1030],{},"@heximon\u002Fhttp\u002Fsecurity",[499,1032,1033,1034,1036,1037,1040],{},"The rate-limit tier is opt-in and lives in the ",[516,1035,1030],{}," subpath. It is designed for\n",[511,1038,1039],{},"per-isolate"," limiting — correct for a single-process Node app, but not distributed across multiple\nCloudflare Workers isolates:",[536,1042,1044],{"className":694,"code":1043,"language":696,"meta":541,"style":541},"import { RateLimitMiddleware, RateLimitStore, type RateLimitPolicy } from \"@heximon\u002Fhttp\u002Fsecurity\";\nimport { MemoryRateLimitStore } from \"@heximon\u002Fhttp\u002Fsecurity\";\n",[516,1045,1046,1082],{"__ignoreMap":541},[545,1047,1048,1051,1053,1056,1058,1061,1063,1066,1069,1071,1074,1076,1078,1080],{"class":547,"line":548},[545,1049,1050],{"class":719},"import",[545,1052,756],{"class":551},[545,1054,1055],{"class":712}," RateLimitMiddleware",[545,1057,785],{"class":551},[545,1059,1060],{"class":712}," RateLimitStore",[545,1062,785],{"class":551},[545,1064,1065],{"class":719}," type",[545,1067,1068],{"class":712}," RateLimitPolicy",[545,1070,777],{"class":551},[545,1072,1073],{"class":719}," from",[545,1075,571],{"class":551},[545,1077,1030],{"class":574},[545,1079,565],{"class":551},[545,1081,798],{"class":551},[545,1083,1084,1086,1088,1091,1093,1095,1097,1099,1101],{"class":547,"line":555},[545,1085,1050],{"class":719},[545,1087,756],{"class":551},[545,1089,1090],{"class":712}," MemoryRateLimitStore",[545,1092,777],{"class":551},[545,1094,1073],{"class":719},[545,1096,571],{"class":551},[545,1098,1030],{"class":574},[545,1100,565],{"class":551},[545,1102,798],{"class":551},[1104,1105,1107,1110],"h3",{"id":1106},"ratelimitstore-the-port",[516,1108,1109],{},"RateLimitStore"," — the port",[499,1112,1113,1115,1116,1119],{},[516,1114,1109],{}," is the abstract DI token. A concrete implementation owns the window algorithm and its\nown atomicity. The built-in ",[516,1117,1118],{},"MemoryRateLimitStore"," uses an in-memory sliding window — suitable for\ndevelopment and single-process production deployments.",[1104,1121,1123,1126],{"id":1122},"ratelimitmiddleware-a-local-delegating-wrapper",[516,1124,1125],{},"RateLimitMiddleware"," — a local delegating wrapper",[499,1128,1129,1131,1132,1134,1135,1138,1139,1142,1143,1145],{},[516,1130,1125],{}," is not itself discovered as a middleware — it's a plain class you construct\ndirectly with a ",[516,1133,1109],{}," and a ",[516,1136,1137],{},"RateLimitPolicy",", then delegate to from a local ",[516,1140,1141],{},"implements Middleware"," wrapper the HTTP compiler plugin can discover by its own ",[516,1144,1141],{}," declaration.\nThis is the pattern the flagship app's own rate-limit demo uses:",[536,1147,1150],{"className":694,"code":1148,"filename":1149,"language":696,"meta":541,"style":541},"import { type HttpAction, type Middleware, type Next } from \"@heximon\u002Fhttp\";\nimport { MemoryRateLimitStore, RateLimitMiddleware } from \"@heximon\u002Fhttp\u002Fsecurity\";\nimport { TimeSpan } from \"@heximon\u002Fprimitives\";\n\n\u002F**\n * A per-route rate-limit gate — a discovered `implements Middleware` that delegates to the shipped\n * {@link RateLimitMiddleware} over its own in-memory store, throttling to 5 requests \u002F 30 s per client IP\n * (the shipped default key: `x-forwarded-for`).\n *\u002F\nexport class SecurityRateLimitMiddleware implements Middleware {\n  \u002F** The shipped rate-limit middleware, built over a dedicated in-memory store + a fixed policy. *\u002F\n  private readonly delegate: RateLimitMiddleware = new RateLimitMiddleware(new MemoryRateLimitStore(), {\n    limit: 5,\n    window: new TimeSpan(30, \"s\"),\n  });\n\n  \u002F**\n   * Apply the rate-limit gate, delegating to {@link RateLimitMiddleware} (keyed by client IP).\n   *\n   * @param action - The matched route's action.\n   * @param next - The downstream channel.\n   * @returns The downstream response, or a `429` when the per-IP limit is exceeded.\n   *\u002F\n  public handle(action: HttpAction, next: Next): Promise\u003CResponse> {\n    return this.delegate.handle(action, next);\n  }\n}\n","src\u002Fsecurity\u002Fsecurity-rate-limit.middleware.ts",[516,1151,1152,1190,1214,1236,1242,1247,1252,1272,1278,1284,1305,1311,1348,1360,1390,1400,1405,1411,1428,1434,1452,1467,1480,1486,1529,1559,1565],{"__ignoreMap":541},[545,1153,1154,1156,1158,1160,1163,1165,1167,1170,1172,1174,1177,1179,1181,1183,1186,1188],{"class":547,"line":548},[545,1155,1050],{"class":719},[545,1157,756],{"class":551},[545,1159,1065],{"class":719},[545,1161,1162],{"class":712}," HttpAction",[545,1164,785],{"class":551},[545,1166,1065],{"class":719},[545,1168,1169],{"class":712}," Middleware",[545,1171,785],{"class":551},[545,1173,1065],{"class":719},[545,1175,1176],{"class":712}," Next",[545,1178,777],{"class":551},[545,1180,1073],{"class":719},[545,1182,571],{"class":551},[545,1184,1185],{"class":574},"@heximon\u002Fhttp",[545,1187,565],{"class":551},[545,1189,798],{"class":551},[545,1191,1192,1194,1196,1198,1200,1202,1204,1206,1208,1210,1212],{"class":547,"line":555},[545,1193,1050],{"class":719},[545,1195,756],{"class":551},[545,1197,1090],{"class":712},[545,1199,785],{"class":551},[545,1201,1055],{"class":712},[545,1203,777],{"class":551},[545,1205,1073],{"class":719},[545,1207,571],{"class":551},[545,1209,1030],{"class":574},[545,1211,565],{"class":551},[545,1213,798],{"class":551},[545,1215,1216,1218,1220,1223,1225,1227,1229,1232,1234],{"class":547,"line":583},[545,1217,1050],{"class":719},[545,1219,756],{"class":551},[545,1221,1222],{"class":712}," TimeSpan",[545,1224,777],{"class":551},[545,1226,1073],{"class":719},[545,1228,571],{"class":551},[545,1230,1231],{"class":574},"@heximon\u002Fprimitives",[545,1233,565],{"class":551},[545,1235,798],{"class":551},[545,1237,1238],{"class":547,"line":601},[545,1239,1241],{"emptyLinePlaceholder":1240},true,"\n",[545,1243,1244],{"class":547,"line":622},[545,1245,1246],{"class":703},"\u002F**\n",[545,1248,1249],{"class":547,"line":643},[545,1250,1251],{"class":703}," * A per-route rate-limit gate — a discovered `implements Middleware` that delegates to the shipped\n",[545,1253,1254,1257,1260,1264,1267,1269],{"class":547,"line":663},[545,1255,1256],{"class":703}," * ",[545,1258,1259],{"class":719},"{@",[545,1261,1263],{"class":1262},"s6hCs","link",[545,1265,1055],{"class":1266},"sHdIc",[545,1268,793],{"class":719},[545,1270,1271],{"class":703}," over its own in-memory store, throttling to 5 requests \u002F 30 s per client IP\n",[545,1273,1275],{"class":547,"line":1274},8,[545,1276,1277],{"class":703}," * (the shipped default key: `x-forwarded-for`).\n",[545,1279,1281],{"class":547,"line":1280},9,[545,1282,1283],{"class":703}," *\u002F\n",[545,1285,1287,1290,1293,1297,1300,1302],{"class":547,"line":1286},10,[545,1288,1289],{"class":719},"export",[545,1291,1292],{"class":561}," class",[545,1294,1296],{"class":1295},"sBMFI"," SecurityRateLimitMiddleware",[545,1298,1299],{"class":561}," implements",[545,1301,1169],{"class":1295},[545,1303,1304],{"class":551}," {\n",[545,1306,1308],{"class":547,"line":1307},11,[545,1309,1310],{"class":703},"  \u002F** The shipped rate-limit middleware, built over a dedicated in-memory store + a fixed policy. *\u002F\n",[545,1312,1314,1317,1320,1323,1325,1327,1330,1332,1334,1336,1339,1341,1344,1346],{"class":547,"line":1313},12,[545,1315,1316],{"class":561},"  private",[545,1318,1319],{"class":561}," readonly",[545,1321,1322],{"class":734}," delegate",[545,1324,568],{"class":551},[545,1326,1055],{"class":1295},[545,1328,1329],{"class":551}," =",[545,1331,740],{"class":551},[545,1333,1055],{"class":734},[545,1335,727],{"class":712},[545,1337,1338],{"class":551},"new",[545,1340,1090],{"class":734},[545,1342,1343],{"class":712},"()",[545,1345,785],{"class":551},[545,1347,1304],{"class":551},[545,1349,1351,1354,1356,1358],{"class":547,"line":1350},13,[545,1352,1353],{"class":734},"    limit",[545,1355,568],{"class":551},[545,1357,764],{"class":595},[545,1359,580],{"class":551},[545,1361,1363,1366,1368,1370,1372,1374,1377,1379,1381,1384,1386,1388],{"class":547,"line":1362},14,[545,1364,1365],{"class":734},"    window",[545,1367,568],{"class":551},[545,1369,740],{"class":551},[545,1371,1222],{"class":734},[545,1373,727],{"class":712},[545,1375,1376],{"class":595},"30",[545,1378,785],{"class":551},[545,1380,571],{"class":551},[545,1382,1383],{"class":574},"s",[545,1385,565],{"class":551},[545,1387,782],{"class":712},[545,1389,580],{"class":551},[545,1391,1393,1396,1398],{"class":547,"line":1392},15,[545,1394,1395],{"class":551},"  }",[545,1397,782],{"class":712},[545,1399,798],{"class":551},[545,1401,1403],{"class":547,"line":1402},16,[545,1404,1241],{"emptyLinePlaceholder":1240},[545,1406,1408],{"class":547,"line":1407},17,[545,1409,1410],{"class":703},"  \u002F**\n",[545,1412,1414,1417,1419,1421,1423,1425],{"class":547,"line":1413},18,[545,1415,1416],{"class":703},"   * Apply the rate-limit gate, delegating to ",[545,1418,1259],{"class":719},[545,1420,1263],{"class":1262},[545,1422,1055],{"class":1266},[545,1424,793],{"class":719},[545,1426,1427],{"class":703}," (keyed by client IP).\n",[545,1429,1431],{"class":547,"line":1430},19,[545,1432,1433],{"class":703},"   *\n",[545,1435,1437,1440,1443,1446,1449],{"class":547,"line":1436},20,[545,1438,1439],{"class":703},"   * ",[545,1441,1442],{"class":719},"@",[545,1444,1445],{"class":1262},"param",[545,1447,1448],{"class":1266}," action",[545,1450,1451],{"class":703}," - The matched route's action.\n",[545,1453,1455,1457,1459,1461,1464],{"class":547,"line":1454},21,[545,1456,1439],{"class":703},[545,1458,1442],{"class":719},[545,1460,1445],{"class":1262},[545,1462,1463],{"class":1266}," next",[545,1465,1466],{"class":703}," - The downstream channel.\n",[545,1468,1470,1472,1474,1477],{"class":547,"line":1469},22,[545,1471,1439],{"class":703},[545,1473,1442],{"class":719},[545,1475,1476],{"class":1262},"returns",[545,1478,1479],{"class":703}," The downstream response, or a `429` when the per-IP limit is exceeded.\n",[545,1481,1483],{"class":547,"line":1482},23,[545,1484,1485],{"class":703},"   *\u002F\n",[545,1487,1489,1492,1495,1497,1500,1502,1504,1506,1508,1510,1512,1515,1518,1521,1524,1527],{"class":547,"line":1488},24,[545,1490,1491],{"class":561},"  public",[545,1493,1494],{"class":734}," handle",[545,1496,727],{"class":551},[545,1498,1499],{"class":1266},"action",[545,1501,568],{"class":551},[545,1503,1162],{"class":1295},[545,1505,785],{"class":551},[545,1507,1463],{"class":1266},[545,1509,568],{"class":551},[545,1511,1176],{"class":1295},[545,1513,1514],{"class":551},"):",[545,1516,1517],{"class":1295}," Promise",[545,1519,1520],{"class":551},"\u003C",[545,1522,1523],{"class":1295},"Response",[545,1525,1526],{"class":551},">",[545,1528,1304],{"class":551},[545,1530,1532,1535,1538,1541,1544,1547,1549,1551,1553,1555,1557],{"class":547,"line":1531},25,[545,1533,1534],{"class":719},"    return",[545,1536,1537],{"class":551}," this.",[545,1539,1540],{"class":712},"delegate",[545,1542,1543],{"class":551},".",[545,1545,1546],{"class":723},"handle",[545,1548,727],{"class":734},[545,1550,1499],{"class":712},[545,1552,785],{"class":551},[545,1554,1463],{"class":712},[545,1556,782],{"class":734},[545,1558,798],{"class":551},[545,1560,1562],{"class":547,"line":1561},26,[545,1563,1564],{"class":551},"  }\n",[545,1566,1568],{"class":547,"line":1567},27,[545,1569,666],{"class":551},[499,1571,1572,1573,1576,1577,568],{},"Provide the wrapper and name it on the route that needs it — either per-route via the action's\n",[516,1574,1575],{},"middlewares"," type argument, or module-wide under ",[516,1578,1579],{},"http: { middlewares }",[536,1581,1584],{"className":694,"code":1582,"filename":1583,"language":696,"meta":541,"style":541},"import { Module } from \"@heximon\u002Fruntime\";\nimport { SecurityController } from \".\u002Fsecurity.controller\";\nimport { SecurityRateLimitMiddleware } from \".\u002Fsecurity-rate-limit.middleware\";\n\nexport class SecurityModule extends Module({\n  providers: [SecurityRateLimitMiddleware],\n  http: { controllers: [SecurityController] },\n}) {}\n","src\u002Fsecurity\u002Fsecurity.module.ts",[516,1585,1586,1608,1630,1651,1655,1673,1685,1705],{"__ignoreMap":541},[545,1587,1588,1590,1592,1595,1597,1599,1601,1604,1606],{"class":547,"line":548},[545,1589,1050],{"class":719},[545,1591,756],{"class":551},[545,1593,1594],{"class":712}," Module",[545,1596,777],{"class":551},[545,1598,1073],{"class":719},[545,1600,571],{"class":551},[545,1602,1603],{"class":574},"@heximon\u002Fruntime",[545,1605,565],{"class":551},[545,1607,798],{"class":551},[545,1609,1610,1612,1614,1617,1619,1621,1623,1626,1628],{"class":547,"line":555},[545,1611,1050],{"class":719},[545,1613,756],{"class":551},[545,1615,1616],{"class":712}," SecurityController",[545,1618,777],{"class":551},[545,1620,1073],{"class":719},[545,1622,571],{"class":551},[545,1624,1625],{"class":574},".\u002Fsecurity.controller",[545,1627,565],{"class":551},[545,1629,798],{"class":551},[545,1631,1632,1634,1636,1638,1640,1642,1644,1647,1649],{"class":547,"line":583},[545,1633,1050],{"class":719},[545,1635,756],{"class":551},[545,1637,1296],{"class":712},[545,1639,777],{"class":551},[545,1641,1073],{"class":719},[545,1643,571],{"class":551},[545,1645,1646],{"class":574},".\u002Fsecurity-rate-limit.middleware",[545,1648,565],{"class":551},[545,1650,798],{"class":551},[545,1652,1653],{"class":547,"line":601},[545,1654,1241],{"emptyLinePlaceholder":1240},[545,1656,1657,1659,1661,1664,1667,1669,1671],{"class":547,"line":622},[545,1658,1289],{"class":719},[545,1660,1292],{"class":561},[545,1662,1663],{"class":1295}," SecurityModule",[545,1665,1666],{"class":561}," extends",[545,1668,1594],{"class":723},[545,1670,727],{"class":712},[545,1672,552],{"class":551},[545,1674,1675,1678,1680,1683],{"class":547,"line":643},[545,1676,1677],{"class":734},"  providers",[545,1679,568],{"class":551},[545,1681,1682],{"class":712}," [SecurityRateLimitMiddleware]",[545,1684,580],{"class":551},[545,1686,1687,1690,1692,1694,1697,1699,1702],{"class":547,"line":663},[545,1688,1689],{"class":734},"  http",[545,1691,568],{"class":551},[545,1693,756],{"class":551},[545,1695,1696],{"class":734}," controllers",[545,1698,568],{"class":551},[545,1700,1701],{"class":712}," [SecurityController] ",[545,1703,1704],{"class":551},"},\n",[545,1706,1707,1709,1712],{"class":547,"line":1274},[545,1708,793],{"class":551},[545,1710,1711],{"class":712},") ",[545,1713,1714],{"class":551},"{}\n",[536,1716,1719],{"className":694,"code":1717,"filename":1718,"language":696,"meta":541,"style":541},"export class SecurityController implements Controller\u003C\"\u002Frate\"> {\n  public async limited(action: Get\u003C\"\u002Flimited\", { middlewares: [SecurityRateLimitMiddleware] }>) {\n    return { ok: true };\n  }\n}\n","src\u002Fsecurity\u002Fsecurity.controller.ts",[516,1720,1721,1747,1798,1815,1819],{"__ignoreMap":541},[545,1722,1723,1725,1727,1729,1731,1734,1736,1738,1741,1743,1745],{"class":547,"line":548},[545,1724,1289],{"class":719},[545,1726,1292],{"class":561},[545,1728,1616],{"class":1295},[545,1730,1299],{"class":561},[545,1732,1733],{"class":1295}," Controller",[545,1735,1520],{"class":551},[545,1737,565],{"class":551},[545,1739,1740],{"class":574},"\u002Frate",[545,1742,565],{"class":551},[545,1744,1526],{"class":551},[545,1746,1304],{"class":551},[545,1748,1749,1751,1754,1757,1759,1761,1763,1766,1768,1770,1773,1775,1777,1779,1782,1784,1787,1790,1793,1796],{"class":547,"line":555},[545,1750,1491],{"class":561},[545,1752,1753],{"class":561}," async",[545,1755,1756],{"class":734}," limited",[545,1758,727],{"class":551},[545,1760,1499],{"class":1266},[545,1762,568],{"class":551},[545,1764,1765],{"class":1295}," Get",[545,1767,1520],{"class":551},[545,1769,565],{"class":551},[545,1771,1772],{"class":574},"\u002Flimited",[545,1774,565],{"class":551},[545,1776,785],{"class":551},[545,1778,756],{"class":551},[545,1780,1781],{"class":734}," middlewares",[545,1783,568],{"class":551},[545,1785,1786],{"class":712}," [",[545,1788,1789],{"class":1295},"SecurityRateLimitMiddleware",[545,1791,1792],{"class":712},"] ",[545,1794,1795],{"class":551},"}>)",[545,1797,1304],{"class":551},[545,1799,1800,1802,1804,1807,1809,1812],{"class":547,"line":583},[545,1801,1534],{"class":719},[545,1803,756],{"class":551},[545,1805,1806],{"class":734}," ok",[545,1808,568],{"class":551},[545,1810,1811],{"class":983}," true",[545,1813,1814],{"class":551}," };\n",[545,1816,1817],{"class":547,"line":601},[545,1818,1564],{"class":551},[545,1820,1821],{"class":547,"line":622},[545,1822,666],{"class":551},[499,1824,1825,1826,1828,1829,1832,1833,1835],{},"Overriding ",[516,1827,1546],{}," (or adding a subclass method) also gives you full control over key resolution — for\nexample, keying on a user id instead of the client IP by overriding ",[516,1830,1831],{},"resolveKey"," in a subclass of\n",[516,1834,1125],{}," before wrapping it.",[1104,1837,1839,1840],{"id":1838},"alternative-di-resolved-store-via-usefactory","Alternative: DI-resolved store via ",[516,1841,1842],{},"useFactory",[499,1844,1845,1846,1849,1850,1853,1854,1856,1857,1859,1860,1862],{},"If the store itself needs a DI-resolved dependency (a shared ",[516,1847,1848],{},"Storage"," binding, a request-scoped\n",[516,1851,1852],{},"Context","), register ",[516,1855,1125],{}," through a ",[516,1858,1842],{}," provider instead — the factory's\nparameter types are the dependency declaration, and the ",[516,1861,1137],{}," literal is captured in the\nfactory closure:",[536,1864,1867],{"className":694,"code":1865,"filename":1866,"language":696,"meta":541,"style":541},"import { MemoryRateLimitStore } from \"@heximon\u002Fhttp\u002Fsecurity\";\n\nexport class AppRateLimitStore extends MemoryRateLimitStore {}\n","src\u002Fapi\u002Fapp-rate-limit.store.ts",[516,1868,1869,1889,1893],{"__ignoreMap":541},[545,1870,1871,1873,1875,1877,1879,1881,1883,1885,1887],{"class":547,"line":548},[545,1872,1050],{"class":719},[545,1874,756],{"class":551},[545,1876,1090],{"class":712},[545,1878,777],{"class":551},[545,1880,1073],{"class":719},[545,1882,571],{"class":551},[545,1884,1030],{"class":574},[545,1886,565],{"class":551},[545,1888,798],{"class":551},[545,1890,1891],{"class":547,"line":555},[545,1892,1241],{"emptyLinePlaceholder":1240},[545,1894,1895,1897,1899,1902,1904,1906],{"class":547,"line":583},[545,1896,1289],{"class":719},[545,1898,1292],{"class":561},[545,1900,1901],{"class":1295}," AppRateLimitStore",[545,1903,1666],{"class":561},[545,1905,1090],{"class":1295},[545,1907,1908],{"class":551}," {}\n",[536,1910,1913],{"className":694,"code":1911,"filename":1912,"language":696,"meta":541,"style":541},"import { Module } from \"@heximon\u002Fruntime\";\nimport { TimeSpan } from \"@heximon\u002Fprimitives\";\nimport { RateLimitMiddleware } from \"@heximon\u002Fhttp\u002Fsecurity\";\nimport { AppRateLimitStore } from \".\u002Fapp-rate-limit.store\";\nimport { ApiController } from \".\u002Fapi.controller\";\n\nexport class ApiModule extends Module({\n  providers: [\n    AppRateLimitStore,\n    {\n      provide: RateLimitMiddleware,\n      useFactory: (store: AppRateLimitStore): RateLimitMiddleware =>\n        new RateLimitMiddleware(store, { limit: 100, window: new TimeSpan(1, \"m\") }),\n    },\n  ],\n  http: {\n    controllers: [ApiController],\n    middlewares: [RateLimitMiddleware],\n  },\n}) {}\n","src\u002Fapi\u002Fapi.module.ts",[516,1914,1915,1935,1955,1975,1996,2018,2022,2039,2048,2055,2060,2071,2095,2150,2155,2162,2170,2182,2194,2199],{"__ignoreMap":541},[545,1916,1917,1919,1921,1923,1925,1927,1929,1931,1933],{"class":547,"line":548},[545,1918,1050],{"class":719},[545,1920,756],{"class":551},[545,1922,1594],{"class":712},[545,1924,777],{"class":551},[545,1926,1073],{"class":719},[545,1928,571],{"class":551},[545,1930,1603],{"class":574},[545,1932,565],{"class":551},[545,1934,798],{"class":551},[545,1936,1937,1939,1941,1943,1945,1947,1949,1951,1953],{"class":547,"line":555},[545,1938,1050],{"class":719},[545,1940,756],{"class":551},[545,1942,1222],{"class":712},[545,1944,777],{"class":551},[545,1946,1073],{"class":719},[545,1948,571],{"class":551},[545,1950,1231],{"class":574},[545,1952,565],{"class":551},[545,1954,798],{"class":551},[545,1956,1957,1959,1961,1963,1965,1967,1969,1971,1973],{"class":547,"line":583},[545,1958,1050],{"class":719},[545,1960,756],{"class":551},[545,1962,1055],{"class":712},[545,1964,777],{"class":551},[545,1966,1073],{"class":719},[545,1968,571],{"class":551},[545,1970,1030],{"class":574},[545,1972,565],{"class":551},[545,1974,798],{"class":551},[545,1976,1977,1979,1981,1983,1985,1987,1989,1992,1994],{"class":547,"line":601},[545,1978,1050],{"class":719},[545,1980,756],{"class":551},[545,1982,1901],{"class":712},[545,1984,777],{"class":551},[545,1986,1073],{"class":719},[545,1988,571],{"class":551},[545,1990,1991],{"class":574},".\u002Fapp-rate-limit.store",[545,1993,565],{"class":551},[545,1995,798],{"class":551},[545,1997,1998,2000,2002,2005,2007,2009,2011,2014,2016],{"class":547,"line":622},[545,1999,1050],{"class":719},[545,2001,756],{"class":551},[545,2003,2004],{"class":712}," ApiController",[545,2006,777],{"class":551},[545,2008,1073],{"class":719},[545,2010,571],{"class":551},[545,2012,2013],{"class":574},".\u002Fapi.controller",[545,2015,565],{"class":551},[545,2017,798],{"class":551},[545,2019,2020],{"class":547,"line":643},[545,2021,1241],{"emptyLinePlaceholder":1240},[545,2023,2024,2026,2028,2031,2033,2035,2037],{"class":547,"line":663},[545,2025,1289],{"class":719},[545,2027,1292],{"class":561},[545,2029,2030],{"class":1295}," ApiModule",[545,2032,1666],{"class":561},[545,2034,1594],{"class":723},[545,2036,727],{"class":712},[545,2038,552],{"class":551},[545,2040,2041,2043,2045],{"class":547,"line":1274},[545,2042,1677],{"class":734},[545,2044,568],{"class":551},[545,2046,2047],{"class":712}," [\n",[545,2049,2050,2053],{"class":547,"line":1280},[545,2051,2052],{"class":712},"    AppRateLimitStore",[545,2054,580],{"class":551},[545,2056,2057],{"class":547,"line":1286},[545,2058,2059],{"class":551},"    {\n",[545,2061,2062,2065,2067,2069],{"class":547,"line":1307},[545,2063,2064],{"class":734},"      provide",[545,2066,568],{"class":551},[545,2068,1055],{"class":712},[545,2070,580],{"class":551},[545,2072,2073,2076,2078,2081,2084,2086,2088,2090,2092],{"class":547,"line":1313},[545,2074,2075],{"class":723},"      useFactory",[545,2077,568],{"class":551},[545,2079,2080],{"class":551}," (",[545,2082,2083],{"class":1266},"store",[545,2085,568],{"class":551},[545,2087,1901],{"class":1295},[545,2089,1514],{"class":551},[545,2091,1055],{"class":1295},[545,2093,2094],{"class":561}," =>\n",[545,2096,2097,2100,2102,2105,2107,2109,2112,2114,2117,2119,2122,2124,2126,2128,2130,2133,2135,2137,2140,2142,2144,2146,2148],{"class":547,"line":1350},[545,2098,2099],{"class":551},"        new",[545,2101,1055],{"class":723},[545,2103,2104],{"class":712},"(store",[545,2106,785],{"class":551},[545,2108,756],{"class":551},[545,2110,2111],{"class":734}," limit",[545,2113,568],{"class":551},[545,2115,2116],{"class":595}," 100",[545,2118,785],{"class":551},[545,2120,2121],{"class":734}," window",[545,2123,568],{"class":551},[545,2125,740],{"class":551},[545,2127,1222],{"class":723},[545,2129,727],{"class":712},[545,2131,2132],{"class":595},"1",[545,2134,785],{"class":551},[545,2136,571],{"class":551},[545,2138,2139],{"class":574},"m",[545,2141,565],{"class":551},[545,2143,1711],{"class":712},[545,2145,793],{"class":551},[545,2147,782],{"class":712},[545,2149,580],{"class":551},[545,2151,2152],{"class":547,"line":1362},[545,2153,2154],{"class":551},"    },\n",[545,2156,2157,2160],{"class":547,"line":1392},[545,2158,2159],{"class":712},"  ]",[545,2161,580],{"class":551},[545,2163,2164,2166,2168],{"class":547,"line":1402},[545,2165,1689],{"class":734},[545,2167,568],{"class":551},[545,2169,1304],{"class":551},[545,2171,2172,2175,2177,2180],{"class":547,"line":1407},[545,2173,2174],{"class":734},"    controllers",[545,2176,568],{"class":551},[545,2178,2179],{"class":712}," [ApiController]",[545,2181,580],{"class":551},[545,2183,2184,2187,2189,2192],{"class":547,"line":1413},[545,2185,2186],{"class":734},"    middlewares",[545,2188,568],{"class":551},[545,2190,2191],{"class":712}," [RateLimitMiddleware]",[545,2193,580],{"class":551},[545,2195,2196],{"class":547,"line":1430},[545,2197,2198],{"class":551},"  },\n",[545,2200,2201,2203,2205],{"class":547,"line":1436},[545,2202,793],{"class":551},[545,2204,1711],{"class":712},[545,2206,1714],{"class":551},[499,2208,2209,2210,2213,2214,2217],{},"A rate-limited request receives a ",[516,2211,2212],{},"429"," response with a ",[516,2215,2216],{},"Retry-After"," header.",[2219,2220,2222,2227,2228,2231,2232,2235,2236,2238,2239,2242],"callout",{"type":2221},"warning",[511,2223,2224,2226],{},[516,2225,1118],{}," is per-isolate."," State lives in the process's memory, so two Cloudflare Workers\nisolates serving the same route do not share a counter. For distributed-correct rate limiting across\nisolates, use ",[516,2229,2230],{},"RateLimitRoomStore"," from ",[516,2233,2234],{},"@heximon\u002Fdurable\u002Fsecurity"," (see below), or implement\n",[516,2237,1109],{}," over any networked store. The port's ",[516,2240,2241],{},"hit(key, policy)"," method owns the algorithm and\natomicity — swap the impl, not the middleware.",[503,2244,2246,2247,2249],{"id":2245},"distributed-rate-limiting-heximondurablesecurity-distributed-rate-limiting","Distributed rate limiting — ",[516,2248,2234],{}," {#distributed-rate-limiting}",[499,2251,2252,2254],{},[516,2253,1118],{}," doesn't share state across isolates — that's a property of memory, not a bug.",[499,2256,2257,2258,2260,2261,2263,2264,2266,2267,2270],{},"When you need a global counter, ",[516,2259,2234],{}," ships a turnkey ",[516,2262,1109],{}," backed by a Cloudflare\nDurable Object: one single-threaded DO per rate-limit key, so the sliding-window counter is strongly\nconsistent everywhere. The port is the swap seam — ",[516,2265,1125],{},", its policy, and the controller\nstay identical; only the store provider and two ",[516,2268,2269],{},"durable"," module entries change:",[536,2272,2274],{"className":694,"code":2273,"filename":1912,"language":696,"meta":541,"style":541},"import { Module } from \"@heximon\u002Fruntime\";\nimport { TimeSpan } from \"@heximon\u002Fprimitives\";\nimport { RateLimitRoom, RateLimitRoomFactory, RateLimitRoomStore } from \"@heximon\u002Fdurable\u002Fsecurity\";\nimport { RateLimitMiddleware } from \"@heximon\u002Fhttp\u002Fsecurity\";\nimport { SecurityController } from \".\u002Fsecurity.controller\";\n\nexport class ApiModule extends Module({\n  providers: [\n    RateLimitRoomStore,\n    {\n      provide: RateLimitMiddleware,\n      useFactory: (store: RateLimitRoomStore) =>\n        new RateLimitMiddleware(store, { limit: 5, window: new TimeSpan(30, \"s\") }),\n    },\n  ],\n  http: {\n    controllers: [SecurityController],\n    middlewares: [RateLimitMiddleware],\n  },\n  durable: {\n    objects: [RateLimitRoom],\n    factories: [RateLimitRoomFactory],\n  },\n}) {}\n",[516,2275,2276,2296,2316,2347,2367,2387,2391,2407,2415,2422,2426,2436,2454,2502,2506,2512,2520,2531,2541,2545,2554,2566,2578,2582],{"__ignoreMap":541},[545,2277,2278,2280,2282,2284,2286,2288,2290,2292,2294],{"class":547,"line":548},[545,2279,1050],{"class":719},[545,2281,756],{"class":551},[545,2283,1594],{"class":712},[545,2285,777],{"class":551},[545,2287,1073],{"class":719},[545,2289,571],{"class":551},[545,2291,1603],{"class":574},[545,2293,565],{"class":551},[545,2295,798],{"class":551},[545,2297,2298,2300,2302,2304,2306,2308,2310,2312,2314],{"class":547,"line":555},[545,2299,1050],{"class":719},[545,2301,756],{"class":551},[545,2303,1222],{"class":712},[545,2305,777],{"class":551},[545,2307,1073],{"class":719},[545,2309,571],{"class":551},[545,2311,1231],{"class":574},[545,2313,565],{"class":551},[545,2315,798],{"class":551},[545,2317,2318,2320,2322,2325,2327,2330,2332,2335,2337,2339,2341,2343,2345],{"class":547,"line":583},[545,2319,1050],{"class":719},[545,2321,756],{"class":551},[545,2323,2324],{"class":712}," RateLimitRoom",[545,2326,785],{"class":551},[545,2328,2329],{"class":712}," RateLimitRoomFactory",[545,2331,785],{"class":551},[545,2333,2334],{"class":712}," RateLimitRoomStore",[545,2336,777],{"class":551},[545,2338,1073],{"class":719},[545,2340,571],{"class":551},[545,2342,2234],{"class":574},[545,2344,565],{"class":551},[545,2346,798],{"class":551},[545,2348,2349,2351,2353,2355,2357,2359,2361,2363,2365],{"class":547,"line":601},[545,2350,1050],{"class":719},[545,2352,756],{"class":551},[545,2354,1055],{"class":712},[545,2356,777],{"class":551},[545,2358,1073],{"class":719},[545,2360,571],{"class":551},[545,2362,1030],{"class":574},[545,2364,565],{"class":551},[545,2366,798],{"class":551},[545,2368,2369,2371,2373,2375,2377,2379,2381,2383,2385],{"class":547,"line":622},[545,2370,1050],{"class":719},[545,2372,756],{"class":551},[545,2374,1616],{"class":712},[545,2376,777],{"class":551},[545,2378,1073],{"class":719},[545,2380,571],{"class":551},[545,2382,1625],{"class":574},[545,2384,565],{"class":551},[545,2386,798],{"class":551},[545,2388,2389],{"class":547,"line":643},[545,2390,1241],{"emptyLinePlaceholder":1240},[545,2392,2393,2395,2397,2399,2401,2403,2405],{"class":547,"line":663},[545,2394,1289],{"class":719},[545,2396,1292],{"class":561},[545,2398,2030],{"class":1295},[545,2400,1666],{"class":561},[545,2402,1594],{"class":723},[545,2404,727],{"class":712},[545,2406,552],{"class":551},[545,2408,2409,2411,2413],{"class":547,"line":1274},[545,2410,1677],{"class":734},[545,2412,568],{"class":551},[545,2414,2047],{"class":712},[545,2416,2417,2420],{"class":547,"line":1280},[545,2418,2419],{"class":712},"    RateLimitRoomStore",[545,2421,580],{"class":551},[545,2423,2424],{"class":547,"line":1286},[545,2425,2059],{"class":551},[545,2427,2428,2430,2432,2434],{"class":547,"line":1307},[545,2429,2064],{"class":734},[545,2431,568],{"class":551},[545,2433,1055],{"class":712},[545,2435,580],{"class":551},[545,2437,2438,2440,2442,2444,2446,2448,2450,2452],{"class":547,"line":1313},[545,2439,2075],{"class":723},[545,2441,568],{"class":551},[545,2443,2080],{"class":551},[545,2445,2083],{"class":1266},[545,2447,568],{"class":551},[545,2449,2334],{"class":1295},[545,2451,782],{"class":551},[545,2453,2094],{"class":561},[545,2455,2456,2458,2460,2462,2464,2466,2468,2470,2472,2474,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498,2500],{"class":547,"line":1350},[545,2457,2099],{"class":551},[545,2459,1055],{"class":723},[545,2461,2104],{"class":712},[545,2463,785],{"class":551},[545,2465,756],{"class":551},[545,2467,2111],{"class":734},[545,2469,568],{"class":551},[545,2471,764],{"class":595},[545,2473,785],{"class":551},[545,2475,2121],{"class":734},[545,2477,568],{"class":551},[545,2479,740],{"class":551},[545,2481,1222],{"class":723},[545,2483,727],{"class":712},[545,2485,1376],{"class":595},[545,2487,785],{"class":551},[545,2489,571],{"class":551},[545,2491,1383],{"class":574},[545,2493,565],{"class":551},[545,2495,1711],{"class":712},[545,2497,793],{"class":551},[545,2499,782],{"class":712},[545,2501,580],{"class":551},[545,2503,2504],{"class":547,"line":1362},[545,2505,2154],{"class":551},[545,2507,2508,2510],{"class":547,"line":1392},[545,2509,2159],{"class":712},[545,2511,580],{"class":551},[545,2513,2514,2516,2518],{"class":547,"line":1402},[545,2515,1689],{"class":734},[545,2517,568],{"class":551},[545,2519,1304],{"class":551},[545,2521,2522,2524,2526,2529],{"class":547,"line":1407},[545,2523,2174],{"class":734},[545,2525,568],{"class":551},[545,2527,2528],{"class":712}," [SecurityController]",[545,2530,580],{"class":551},[545,2532,2533,2535,2537,2539],{"class":547,"line":1413},[545,2534,2186],{"class":734},[545,2536,568],{"class":551},[545,2538,2191],{"class":712},[545,2540,580],{"class":551},[545,2542,2543],{"class":547,"line":1430},[545,2544,2198],{"class":551},[545,2546,2547,2550,2552],{"class":547,"line":1436},[545,2548,2549],{"class":734},"  durable",[545,2551,568],{"class":551},[545,2553,1304],{"class":551},[545,2555,2556,2559,2561,2564],{"class":547,"line":1454},[545,2557,2558],{"class":734},"    objects",[545,2560,568],{"class":551},[545,2562,2563],{"class":712}," [RateLimitRoom]",[545,2565,580],{"class":551},[545,2567,2568,2571,2573,2576],{"class":547,"line":1469},[545,2569,2570],{"class":734},"    factories",[545,2572,568],{"class":551},[545,2574,2575],{"class":712}," [RateLimitRoomFactory]",[545,2577,580],{"class":551},[545,2579,2580],{"class":547,"line":1482},[545,2581,2198],{"class":551},[545,2583,2584,2586,2588],{"class":547,"line":1488},[545,2585,793],{"class":551},[545,2587,1711],{"class":712},[545,2589,1714],{"class":551},[499,2591,2592,2593,2596,2597,2600,2601,2603,2604,2607,2608,1543],{},"The subpath ships the whole Durable Object tier — ",[516,2594,2595],{},"RateLimitRoom",", its ",[516,2598,2599],{},"RateLimitRoomFactory",", and the\nconcrete ",[516,2602,2230],{}," — so the app ",[511,2605,2606],{},"lists"," them with no local Durable Object shells; the compiler\nrecovers the DO's RPC surface and the factory's bound DO from the package's shipped ",[516,2609,2610],{},".d.ts",[499,2612,2613,2614,2616],{},"One DO per key caps throughput at ~500–1,000 req\u002Fs per key — ",[516,2615,2230],{}," exposes protected sharding hooks to trade\nan exact global limit for ~N× throughput on hot keys.",[499,2618,2619,2620,2622,2623,2626,2627,2630,2631,2634],{},"See ",[524,2621,289],{"href":290}," for how a listed DO is constructed and wired, and\n",[524,2624,2625],{"href":308},"Deploy to Cloudflare"," for registering ",[516,2628,2629],{},"DurablePlugin"," and the generated\n",[516,2632,2633],{},"wrangler.json"," bindings.",[503,2636,2638],{"id":2637},"csrf-posture","CSRF posture",[499,2640,2641,2642,2645,2646,2649],{},"Heximon's built-in auth is bearer-token-only (",[516,2643,2644],{},"Authorization: Bearer \u003Ctoken>","). Classic CSRF attacks work\nby exploiting ambient credentials (cookies, ",[516,2647,2648],{},"\u003Cform>","-submittable headers) that a browser sends automatically\nto a target origin. Bearer tokens are never sent automatically — a cross-origin page cannot read them from\nanother origin's memory, so it cannot forge a request that carries one.",[499,2651,2652,2653,2656],{},"If your app adds cookie-based sessions, wire a CSRF middleware appropriate for that flow. The bearer-only\ndesign means no CSRF middleware is needed for the default ",[516,2654,2655],{},"JWTAuthMiddleware"," setup.",[503,2658,2660],{"id":2659},"see-also","See also",[2662,2663,2664,2677,2683],"ul",{},[2665,2666,2667,2669,2670,2672,2673,2676],"li",{},[524,2668,97],{"href":98}," — the ",[516,2671,2655],{}," and ",[516,2674,2675],{},"GuardMiddleware"," that pair with\nthe security headers.",[2665,2678,2679,2682],{},[524,2680,2681],{"href":58},"Middleware"," — how to attach middleware per controller or module-wide.",[2665,2684,2685,2692,2693,1543],{},[524,2686,2689],{"href":2687,"rel":2688},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fflagship",[528],[511,2690,2691],{},"Security hardening"," — the body guard, response headers, and a rate-limited endpoint exercised with ",[516,2694,2695],{},"curl",[2697,2698,2699],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .s6hCs, html code.shiki .s6hCs{--shiki-light:#9C3EDA;--shiki-light-font-style:italic;--shiki-default:#C792EA;--shiki-default-font-style:italic;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":541,"searchDepth":555,"depth":555,"links":2701},[2702,2703,2704,2713,2715,2716],{"id":505,"depth":555,"text":506},{"id":804,"depth":555,"text":805},{"id":1026,"depth":555,"text":2705,"children":2706},"Rate limiting — @heximon\u002Fhttp\u002Fsecurity",[2707,2709,2711],{"id":1106,"depth":583,"text":2708},"RateLimitStore — the port",{"id":1122,"depth":583,"text":2710},"RateLimitMiddleware — a local delegating wrapper",{"id":1838,"depth":583,"text":2712},"Alternative: DI-resolved store via useFactory",{"id":2245,"depth":555,"text":2714},"Distributed rate limiting — @heximon\u002Fdurable\u002Fsecurity {#distributed-rate-limiting}",{"id":2637,"depth":555,"text":2638},{"id":2659,"depth":555,"text":2660},"Body-size guard (content-length, 413 RFC-9457), SecurityHeaders (nosniff\u002FDENY\u002Fno-referrer\u002FHSTS), RateLimitStore port, MemoryRateLimitStore, RateLimitMiddleware, @heximon\u002Fhttp\u002Fsecurity, bearer-only CSRF posture.","md",null,{},{"icon":192},{"title":189,"description":2717},"9qpjq98g3cf23vtL_V1Vv9L9I2YS_FK3bqIZNqjwJLM",[2725,2727],{"title":185,"path":186,"stem":187,"description":2726,"icon":65,"children":-1},"Idempotency tiers for event, queue, and command dispatch — EventIdempotencyInterceptor, CommandIdempotencyInterceptor, QueueIdempotencyInterceptor, Idempotency-Key header, ContextData.idempotencyKey, Storage port, best-effort dedup.",{"title":194,"path":195,"stem":196,"description":2728,"icon":197,"children":-1},"Compile-time, module-attributed OpenTelemetry tracing with OtelPlugin — heximon.module baked onto every HTTP \u002F CommandBus \u002F QueryBus \u002F EventBus span, OTLP export, samplerRatio, batchOptions.",1783300761903]