[{"data":1,"prerenderedAt":2272},["ShallowReactive",2],{"navigation_docs":3,"-docs-essentials-permissions":493,"-docs-essentials-permissions-surround":2267},[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":102,"body":495,"description":2260,"extension":2261,"links":2262,"meta":2263,"navigation":2264,"path":103,"seo":2265,"stem":104,"__hash__":2266},"docs\u002Fdocs\u002F02.essentials\u002F11.permissions.md",{"type":496,"value":497,"toc":2253},"minimark",[498,527,550,555,570,999,1006,1010,1040,1233,1236,1534,1543,1566,1570,1586,2033,2044,2048,2067,2157,2181,2185,2249],[499,500,501,504,505,509,510,513,514,518,519,522,523,526],"p",{},[502,503,97],"a",{"href":98}," tells you ",[506,507,508],"em",{},"who"," is calling; permissions decide ",[506,511,512],{},"what they can do",".\nHeximon's answer is scope-based: a signed token carries the caller's granted scopes inline, each route declares\nthe scopes it requires, and a guard compares the two before your handler runs. Scopes are plain strings — there\nis no permission registry to install — so a common convention is ",[515,516,517],"code",{},"domain:resource:action",", like ",[515,520,521],{},"task:create","\nor ",[515,524,525],{},"admin:stats:read",".",[499,528,529,530,533,534,537,538,541,542,545,546,549],{},"You enforce them one of two ways: automatically with ",[515,531,532],{},"GuardMiddleware"," for routes declared on a\n",[502,535,536],{"href":68},"contract",", or manually with ",[515,539,540],{},"AuthContext.isAllowed(...)"," for inline routes. Both read the\nsame principal the auth middleware stored, and both produce the same ",[515,543,544],{},"401"," (no principal) \u002F ",[515,547,548],{},"403","\n(under-scoped) distinction.",[551,552,554],"h2",{"id":553},"declare-scopes-on-a-contract-route","Declare scopes on a contract route",[499,556,557,560,561,565,566,569],{},[515,558,559],{},"Route.scopes(...)"," records the required scopes directly on the route descriptor, alongside its body and\nresponse schemas. A route with ",[562,563,564],"strong",{},"no"," ",[515,567,568],{},"scopes()"," is open; a route with scopes requires a principal that grants\nevery one of them.",[571,572,578],"pre",{"className":573,"code":574,"filename":575,"language":576,"meta":577,"style":577},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Contract, Route } from \"@heximon\u002Fcontract\";\nimport { SchemaArray } from \"@heximon\u002Fschema\";\nimport { CreateTaskBody, TaskIdParams, TaskResponse } from \".\u002Ftask.dto\";\n\nclass TaskListResponse extends SchemaArray(TaskResponse) {}\n\nexport class TaskApi extends Contract({\n  prefix: \"\u002Fapi\u002Ftasks\",\n  routes: {\n    list: Route.get(\"\u002F\").scopes(\"task:read\").responses({ 200: TaskListResponse }),\n    create: Route.post(\"\u002F\").scopes(\"task:create\").body(CreateTaskBody).responses({ 201: TaskResponse }),\n    complete: Route.post(\"\u002F:id\u002Fcomplete\")\n      .scopes(\"task:complete\")\n      .pathParams(TaskIdParams)\n      .responses({ 200: TaskResponse }),\n  },\n}) {}\n","task.api.ts","ts","",[515,579,580,622,645,678,685,708,713,735,755,766,835,904,930,949,960,983,989],{"__ignoreMap":577},[581,582,585,589,593,597,600,603,606,609,612,616,619],"span",{"class":583,"line":584},"line",1,[581,586,588],{"class":587},"s7zQu","import",[581,590,592],{"class":591},"sMK4o"," {",[581,594,596],{"class":595},"sTEyZ"," Contract",[581,598,599],{"class":591},",",[581,601,602],{"class":595}," Route",[581,604,605],{"class":591}," }",[581,607,608],{"class":587}," from",[581,610,611],{"class":591}," \"",[581,613,615],{"class":614},"sfazB","@heximon\u002Fcontract",[581,617,618],{"class":591},"\"",[581,620,621],{"class":591},";\n",[581,623,625,627,629,632,634,636,638,641,643],{"class":583,"line":624},2,[581,626,588],{"class":587},[581,628,592],{"class":591},[581,630,631],{"class":595}," SchemaArray",[581,633,605],{"class":591},[581,635,608],{"class":587},[581,637,611],{"class":591},[581,639,640],{"class":614},"@heximon\u002Fschema",[581,642,618],{"class":591},[581,644,621],{"class":591},[581,646,648,650,652,655,657,660,662,665,667,669,671,674,676],{"class":583,"line":647},3,[581,649,588],{"class":587},[581,651,592],{"class":591},[581,653,654],{"class":595}," CreateTaskBody",[581,656,599],{"class":591},[581,658,659],{"class":595}," TaskIdParams",[581,661,599],{"class":591},[581,663,664],{"class":595}," TaskResponse",[581,666,605],{"class":591},[581,668,608],{"class":587},[581,670,611],{"class":591},[581,672,673],{"class":614},".\u002Ftask.dto",[581,675,618],{"class":591},[581,677,621],{"class":591},[581,679,681],{"class":583,"line":680},4,[581,682,684],{"emptyLinePlaceholder":683},true,"\n",[581,686,688,692,696,699,702,705],{"class":583,"line":687},5,[581,689,691],{"class":690},"spNyl","class",[581,693,695],{"class":694},"sBMFI"," TaskListResponse",[581,697,698],{"class":690}," extends",[581,700,631],{"class":701},"s2Zo4",[581,703,704],{"class":595},"(TaskResponse) ",[581,706,707],{"class":591},"{}\n",[581,709,711],{"class":583,"line":710},6,[581,712,684],{"emptyLinePlaceholder":683},[581,714,716,719,722,725,727,729,732],{"class":583,"line":715},7,[581,717,718],{"class":587},"export",[581,720,721],{"class":690}," class",[581,723,724],{"class":694}," TaskApi",[581,726,698],{"class":690},[581,728,596],{"class":701},[581,730,731],{"class":595},"(",[581,733,734],{"class":591},"{\n",[581,736,738,742,745,747,750,752],{"class":583,"line":737},8,[581,739,741],{"class":740},"swJcz","  prefix",[581,743,744],{"class":591},":",[581,746,611],{"class":591},[581,748,749],{"class":614},"\u002Fapi\u002Ftasks",[581,751,618],{"class":591},[581,753,754],{"class":591},",\n",[581,756,758,761,763],{"class":583,"line":757},9,[581,759,760],{"class":740},"  routes",[581,762,744],{"class":591},[581,764,765],{"class":591}," {\n",[581,767,769,772,774,776,778,781,783,785,788,790,793,795,798,800,802,805,807,809,811,814,816,819,823,825,828,831,833],{"class":583,"line":768},10,[581,770,771],{"class":740},"    list",[581,773,744],{"class":591},[581,775,602],{"class":595},[581,777,526],{"class":591},[581,779,780],{"class":701},"get",[581,782,731],{"class":595},[581,784,618],{"class":591},[581,786,787],{"class":614},"\u002F",[581,789,618],{"class":591},[581,791,792],{"class":595},")",[581,794,526],{"class":591},[581,796,797],{"class":701},"scopes",[581,799,731],{"class":595},[581,801,618],{"class":591},[581,803,804],{"class":614},"task:read",[581,806,618],{"class":591},[581,808,792],{"class":595},[581,810,526],{"class":591},[581,812,813],{"class":701},"responses",[581,815,731],{"class":595},[581,817,818],{"class":591},"{",[581,820,822],{"class":821},"sbssI"," 200",[581,824,744],{"class":591},[581,826,827],{"class":595}," TaskListResponse ",[581,829,830],{"class":591},"}",[581,832,792],{"class":595},[581,834,754],{"class":591},[581,836,838,841,843,845,847,850,852,854,856,858,860,862,864,866,868,870,872,874,876,879,882,884,886,888,890,893,895,898,900,902],{"class":583,"line":837},11,[581,839,840],{"class":740},"    create",[581,842,744],{"class":591},[581,844,602],{"class":595},[581,846,526],{"class":591},[581,848,849],{"class":701},"post",[581,851,731],{"class":595},[581,853,618],{"class":591},[581,855,787],{"class":614},[581,857,618],{"class":591},[581,859,792],{"class":595},[581,861,526],{"class":591},[581,863,797],{"class":701},[581,865,731],{"class":595},[581,867,618],{"class":591},[581,869,521],{"class":614},[581,871,618],{"class":591},[581,873,792],{"class":595},[581,875,526],{"class":591},[581,877,878],{"class":701},"body",[581,880,881],{"class":595},"(CreateTaskBody)",[581,883,526],{"class":591},[581,885,813],{"class":701},[581,887,731],{"class":595},[581,889,818],{"class":591},[581,891,892],{"class":821}," 201",[581,894,744],{"class":591},[581,896,897],{"class":595}," TaskResponse ",[581,899,830],{"class":591},[581,901,792],{"class":595},[581,903,754],{"class":591},[581,905,907,910,912,914,916,918,920,922,925,927],{"class":583,"line":906},12,[581,908,909],{"class":740},"    complete",[581,911,744],{"class":591},[581,913,602],{"class":595},[581,915,526],{"class":591},[581,917,849],{"class":701},[581,919,731],{"class":595},[581,921,618],{"class":591},[581,923,924],{"class":614},"\u002F:id\u002Fcomplete",[581,926,618],{"class":591},[581,928,929],{"class":595},")\n",[581,931,933,936,938,940,942,945,947],{"class":583,"line":932},13,[581,934,935],{"class":591},"      .",[581,937,797],{"class":701},[581,939,731],{"class":595},[581,941,618],{"class":591},[581,943,944],{"class":614},"task:complete",[581,946,618],{"class":591},[581,948,929],{"class":595},[581,950,952,954,957],{"class":583,"line":951},14,[581,953,935],{"class":591},[581,955,956],{"class":701},"pathParams",[581,958,959],{"class":595},"(TaskIdParams)\n",[581,961,963,965,967,969,971,973,975,977,979,981],{"class":583,"line":962},15,[581,964,935],{"class":591},[581,966,813],{"class":701},[581,968,731],{"class":595},[581,970,818],{"class":591},[581,972,822],{"class":821},[581,974,744],{"class":591},[581,976,897],{"class":595},[581,978,830],{"class":591},[581,980,792],{"class":595},[581,982,754],{"class":591},[581,984,986],{"class":583,"line":985},16,[581,987,988],{"class":591},"  },\n",[581,990,992,994,997],{"class":583,"line":991},17,[581,993,830],{"class":591},[581,995,996],{"class":595},") ",[581,998,707],{"class":591},[499,1000,1001,1002,1005],{},"Keeping the scope on the contract means the requirement travels with the route everywhere the contract goes —\nthe server enforces it, OpenAPI documents it, and a client reads it from the same value. The dispatcher seeds\nthat descriptor into the request ",[515,1003,1004],{},"Context"," at match time, which is exactly where the guard looks for it next.",[551,1007,1009],{"id":1008},"enforce-with-guardmiddleware","Enforce with GuardMiddleware",[499,1011,1012,1014,1015,1017,1018,1021,1022,1024,1025,1028,1029,1031,1032,1035,1036,1039],{},[515,1013,532],{}," reads the matched route's scopes from the request ",[515,1016,1004],{}," and compares them against the\nstored principal. Like ",[515,1019,1020],{},"JWTAuthMiddleware"," (see ",[502,1023,97],{"href":98},"), it is a\n",[562,1026,1027],{},"bare provider"," — its constructor is only DI tokens (",[515,1030,1004],{}," + ",[515,1033,1034],{},"AuthContext","), so the compiler recovers it\nfrom the package's shipped types and constructs it directly. There's no wrapper to write; list both shipped\nclasses in ",[515,1037,1038],{},"http.middlewares",", auth first, guard second:",[571,1041,1044],{"className":573,"code":1042,"filename":1043,"language":576,"meta":577,"style":577},"import { GuardMiddleware, JWTAuthMiddleware } from \"@heximon\u002Fauth\";\nimport { Module } from \"@heximon\u002Fruntime\";\nimport { TasksController } from \".\u002Ftasks.controller\";\n\nexport class AuthModule extends Module({\n  providers: [\n    \u002F\u002F ...AuthContext \u002F JWTFactory \u002F IdentityKeyPair providers — see Authentication\n  ],\n  http: {\n    controllers: [TasksController],\n    middlewares: [JWTAuthMiddleware, GuardMiddleware],\n  },\n  exports: [JWTAuthMiddleware, GuardMiddleware \u002F* ...and the rest *\u002F],\n}) {}\n","auth.module.ts",[515,1045,1046,1073,1095,1117,1121,1138,1148,1154,1161,1170,1182,1199,1203,1225],{"__ignoreMap":577},[581,1047,1048,1050,1052,1055,1057,1060,1062,1064,1066,1069,1071],{"class":583,"line":584},[581,1049,588],{"class":587},[581,1051,592],{"class":591},[581,1053,1054],{"class":595}," GuardMiddleware",[581,1056,599],{"class":591},[581,1058,1059],{"class":595}," JWTAuthMiddleware",[581,1061,605],{"class":591},[581,1063,608],{"class":587},[581,1065,611],{"class":591},[581,1067,1068],{"class":614},"@heximon\u002Fauth",[581,1070,618],{"class":591},[581,1072,621],{"class":591},[581,1074,1075,1077,1079,1082,1084,1086,1088,1091,1093],{"class":583,"line":624},[581,1076,588],{"class":587},[581,1078,592],{"class":591},[581,1080,1081],{"class":595}," Module",[581,1083,605],{"class":591},[581,1085,608],{"class":587},[581,1087,611],{"class":591},[581,1089,1090],{"class":614},"@heximon\u002Fruntime",[581,1092,618],{"class":591},[581,1094,621],{"class":591},[581,1096,1097,1099,1101,1104,1106,1108,1110,1113,1115],{"class":583,"line":647},[581,1098,588],{"class":587},[581,1100,592],{"class":591},[581,1102,1103],{"class":595}," TasksController",[581,1105,605],{"class":591},[581,1107,608],{"class":587},[581,1109,611],{"class":591},[581,1111,1112],{"class":614},".\u002Ftasks.controller",[581,1114,618],{"class":591},[581,1116,621],{"class":591},[581,1118,1119],{"class":583,"line":680},[581,1120,684],{"emptyLinePlaceholder":683},[581,1122,1123,1125,1127,1130,1132,1134,1136],{"class":583,"line":687},[581,1124,718],{"class":587},[581,1126,721],{"class":690},[581,1128,1129],{"class":694}," AuthModule",[581,1131,698],{"class":690},[581,1133,1081],{"class":701},[581,1135,731],{"class":595},[581,1137,734],{"class":591},[581,1139,1140,1143,1145],{"class":583,"line":710},[581,1141,1142],{"class":740},"  providers",[581,1144,744],{"class":591},[581,1146,1147],{"class":595}," [\n",[581,1149,1150],{"class":583,"line":715},[581,1151,1153],{"class":1152},"sHwdD","    \u002F\u002F ...AuthContext \u002F JWTFactory \u002F IdentityKeyPair providers — see Authentication\n",[581,1155,1156,1159],{"class":583,"line":737},[581,1157,1158],{"class":595},"  ]",[581,1160,754],{"class":591},[581,1162,1163,1166,1168],{"class":583,"line":757},[581,1164,1165],{"class":740},"  http",[581,1167,744],{"class":591},[581,1169,765],{"class":591},[581,1171,1172,1175,1177,1180],{"class":583,"line":768},[581,1173,1174],{"class":740},"    controllers",[581,1176,744],{"class":591},[581,1178,1179],{"class":595}," [TasksController]",[581,1181,754],{"class":591},[581,1183,1184,1187,1189,1192,1194,1197],{"class":583,"line":837},[581,1185,1186],{"class":740},"    middlewares",[581,1188,744],{"class":591},[581,1190,1191],{"class":595}," [JWTAuthMiddleware",[581,1193,599],{"class":591},[581,1195,1196],{"class":595}," GuardMiddleware]",[581,1198,754],{"class":591},[581,1200,1201],{"class":583,"line":906},[581,1202,988],{"class":591},[581,1204,1205,1208,1210,1212,1214,1217,1220,1223],{"class":583,"line":932},[581,1206,1207],{"class":740},"  exports",[581,1209,744],{"class":591},[581,1211,1191],{"class":595},[581,1213,599],{"class":591},[581,1215,1216],{"class":595}," GuardMiddleware ",[581,1218,1219],{"class":1152},"\u002F* ...and the rest *\u002F",[581,1221,1222],{"class":595},"]",[581,1224,754],{"class":591},[581,1226,1227,1229,1231],{"class":583,"line":951},[581,1228,830],{"class":591},[581,1230,996],{"class":595},[581,1232,707],{"class":591},[499,1234,1235],{},"Then list the same chain on the contract-bound controller — auth first, guard second:",[571,1237,1240],{"className":573,"code":1238,"filename":1239,"language":576,"meta":577,"style":577},"import { GuardMiddleware, JWTAuthMiddleware } from \"@heximon\u002Fauth\";\nimport { type Action, type Controller } from \"@heximon\u002Fhttp\";\nimport { TaskApi } from \".\u002Ftask.api\";\n\nexport class TasksController\n  implements Controller\u003C{ contract: TaskApi; middlewares: [JWTAuthMiddleware, GuardMiddleware] }>\n{\n  \u002F\u002F Runs only for a principal holding `task:read` — enforced before the handler.\n  public async list(action: Action\u003CTaskApi, \"list\">) {\n    \u002F\u002F ...\n  }\n\n  public async create(action: Action\u003CTaskApi, \"create\">) {\n    \u002F\u002F ... — requires `task:create`\n  }\n\n  public async complete(action: Action\u003CTaskApi, \"complete\">) {\n    \u002F\u002F ... — requires `task:complete`\n  }\n}\n","tasks.controller.ts",[515,1241,1242,1266,1298,1319,1323,1332,1372,1376,1381,1422,1427,1432,1436,1470,1475,1479,1483,1517,1523,1528],{"__ignoreMap":577},[581,1243,1244,1246,1248,1250,1252,1254,1256,1258,1260,1262,1264],{"class":583,"line":584},[581,1245,588],{"class":587},[581,1247,592],{"class":591},[581,1249,1054],{"class":595},[581,1251,599],{"class":591},[581,1253,1059],{"class":595},[581,1255,605],{"class":591},[581,1257,608],{"class":587},[581,1259,611],{"class":591},[581,1261,1068],{"class":614},[581,1263,618],{"class":591},[581,1265,621],{"class":591},[581,1267,1268,1270,1272,1275,1278,1280,1282,1285,1287,1289,1291,1294,1296],{"class":583,"line":624},[581,1269,588],{"class":587},[581,1271,592],{"class":591},[581,1273,1274],{"class":587}," type",[581,1276,1277],{"class":595}," Action",[581,1279,599],{"class":591},[581,1281,1274],{"class":587},[581,1283,1284],{"class":595}," Controller",[581,1286,605],{"class":591},[581,1288,608],{"class":587},[581,1290,611],{"class":591},[581,1292,1293],{"class":614},"@heximon\u002Fhttp",[581,1295,618],{"class":591},[581,1297,621],{"class":591},[581,1299,1300,1302,1304,1306,1308,1310,1312,1315,1317],{"class":583,"line":647},[581,1301,588],{"class":587},[581,1303,592],{"class":591},[581,1305,724],{"class":595},[581,1307,605],{"class":591},[581,1309,608],{"class":587},[581,1311,611],{"class":591},[581,1313,1314],{"class":614},".\u002Ftask.api",[581,1316,618],{"class":591},[581,1318,621],{"class":591},[581,1320,1321],{"class":583,"line":680},[581,1322,684],{"emptyLinePlaceholder":683},[581,1324,1325,1327,1329],{"class":583,"line":687},[581,1326,718],{"class":587},[581,1328,721],{"class":690},[581,1330,1331],{"class":694}," TasksController\n",[581,1333,1334,1337,1339,1342,1345,1347,1349,1352,1355,1357,1360,1362,1364,1366,1369],{"class":583,"line":710},[581,1335,1336],{"class":690},"  implements",[581,1338,1284],{"class":694},[581,1340,1341],{"class":591},"\u003C{",[581,1343,1344],{"class":740}," contract",[581,1346,744],{"class":591},[581,1348,724],{"class":694},[581,1350,1351],{"class":591},";",[581,1353,1354],{"class":740}," middlewares",[581,1356,744],{"class":591},[581,1358,1359],{"class":595}," [",[581,1361,1020],{"class":694},[581,1363,599],{"class":591},[581,1365,1054],{"class":694},[581,1367,1368],{"class":595},"] ",[581,1370,1371],{"class":591},"}>\n",[581,1373,1374],{"class":583,"line":715},[581,1375,734],{"class":591},[581,1377,1378],{"class":583,"line":737},[581,1379,1380],{"class":1152},"  \u002F\u002F Runs only for a principal holding `task:read` — enforced before the handler.\n",[581,1382,1383,1386,1389,1392,1394,1398,1400,1402,1405,1408,1410,1412,1415,1417,1420],{"class":583,"line":757},[581,1384,1385],{"class":690},"  public",[581,1387,1388],{"class":690}," async",[581,1390,1391],{"class":740}," list",[581,1393,731],{"class":591},[581,1395,1397],{"class":1396},"sHdIc","action",[581,1399,744],{"class":591},[581,1401,1277],{"class":694},[581,1403,1404],{"class":591},"\u003C",[581,1406,1407],{"class":694},"TaskApi",[581,1409,599],{"class":591},[581,1411,611],{"class":591},[581,1413,1414],{"class":614},"list",[581,1416,618],{"class":591},[581,1418,1419],{"class":591},">)",[581,1421,765],{"class":591},[581,1423,1424],{"class":583,"line":768},[581,1425,1426],{"class":1152},"    \u002F\u002F ...\n",[581,1428,1429],{"class":583,"line":837},[581,1430,1431],{"class":591},"  }\n",[581,1433,1434],{"class":583,"line":906},[581,1435,684],{"emptyLinePlaceholder":683},[581,1437,1438,1440,1442,1445,1447,1449,1451,1453,1455,1457,1459,1461,1464,1466,1468],{"class":583,"line":932},[581,1439,1385],{"class":690},[581,1441,1388],{"class":690},[581,1443,1444],{"class":740}," create",[581,1446,731],{"class":591},[581,1448,1397],{"class":1396},[581,1450,744],{"class":591},[581,1452,1277],{"class":694},[581,1454,1404],{"class":591},[581,1456,1407],{"class":694},[581,1458,599],{"class":591},[581,1460,611],{"class":591},[581,1462,1463],{"class":614},"create",[581,1465,618],{"class":591},[581,1467,1419],{"class":591},[581,1469,765],{"class":591},[581,1471,1472],{"class":583,"line":951},[581,1473,1474],{"class":1152},"    \u002F\u002F ... — requires `task:create`\n",[581,1476,1477],{"class":583,"line":962},[581,1478,1431],{"class":591},[581,1480,1481],{"class":583,"line":985},[581,1482,684],{"emptyLinePlaceholder":683},[581,1484,1485,1487,1489,1492,1494,1496,1498,1500,1502,1504,1506,1508,1511,1513,1515],{"class":583,"line":991},[581,1486,1385],{"class":690},[581,1488,1388],{"class":690},[581,1490,1491],{"class":740}," complete",[581,1493,731],{"class":591},[581,1495,1397],{"class":1396},[581,1497,744],{"class":591},[581,1499,1277],{"class":694},[581,1501,1404],{"class":591},[581,1503,1407],{"class":694},[581,1505,599],{"class":591},[581,1507,611],{"class":591},[581,1509,1510],{"class":614},"complete",[581,1512,618],{"class":591},[581,1514,1419],{"class":591},[581,1516,765],{"class":591},[581,1518,1520],{"class":583,"line":1519},18,[581,1521,1522],{"class":1152},"    \u002F\u002F ... — requires `task:complete`\n",[581,1524,1526],{"class":583,"line":1525},19,[581,1527,1431],{"class":591},[581,1529,1531],{"class":583,"line":1530},20,[581,1532,1533],{"class":591},"}\n",[499,1535,1536,1537,1539,1540,1542],{},"For each request the guard resolves to one of four outcomes: open route → continue; scopes declared but no\nprincipal → ",[515,1538,544],{},"; principal lacking a scope → ",[515,1541,548],{},"; all scopes granted → continue. Your handler never sees an\nunder-scoped caller.",[1544,1545,1547,565,1552,1554,1555,1557,1558,1561,1562,1565],"callout",{"type":1546},"warning",[562,1548,1549,1550,526],{},"Order the chain auth-then-guard, or every guarded route returns ",[515,1551,544],{},[515,1553,532],{}," reads the principal\nthat ",[515,1556,1020],{}," stored earlier in the same chain — it does no token verification of its own. If the\nguard runs first, the principal isn't there yet, so a route with declared scopes resolves to \"scopes declared\nbut no principal\" and returns ",[515,1559,1560],{},"401 application\u002Fproblem+json"," even for a perfectly valid token. The fix is the\nlist order: ",[515,1563,1564],{},"middlewares: [JWTAuthMiddleware, GuardMiddleware]",", auth before guard.",[551,1567,1569],{"id":1568},"check-scopes-manually-on-inline-routes","Check scopes manually on inline routes",[499,1571,1572,1573,1576,1577,1580,1581,1583,1584,526],{},"Inline routes — declared by the handler's ",[515,1574,1575],{},"Get\u003C...>"," \u002F ",[515,1578,1579],{},"Post\u003C...>"," parameter type rather than a contract — carry\nno ",[515,1582,797],{},", so the guard has nothing to read. That's deliberate: inline routes trade the contract's shared\nmetadata for terseness, and authorization is one of the things you give up. Authenticate with the auth\nmiddleware, then enforce the scope yourself through ",[515,1585,1034],{},[571,1587,1590],{"className":573,"code":1588,"filename":1589,"language":576,"meta":577,"style":577},"import { AuthContext, JWTAuthMiddleware } from \"@heximon\u002Fauth\";\nimport type { Controller, Get } from \"@heximon\u002Fhttp\";\n\nexport class AdminController implements Controller\u003C{\n  prefix: \"\u002Fadmin\";\n  middlewares: [JWTAuthMiddleware];\n}> {\n  private static readonly requiredScope: string = \"admin:stats:read\";\n\n  public constructor(private readonly authContext: AuthContext) {}\n\n  public async stats(action: Get\u003C\"\u002Fstats\">): Promise\u003CResponse> {\n    if (this.authContext.principal() === null) {\n      return action.respond(401, { error: \"Authentication is required.\" });\n    }\n\n    if (!this.authContext.isAllowed(AdminController.requiredScope)) {\n      return action.respond(403, { error: `Requires the '${AdminController.requiredScope}' scope.` });\n    }\n\n    return action.respond(200, { totalRequests: 42, activeSessions: 7 });\n  }\n}\n","admin.controller.ts",[515,1591,1592,1617,1644,1648,1665,1680,1695,1702,1732,1736,1762,1766,1808,1840,1879,1884,1888,1919,1970,1974,1978,2023,2028],{"__ignoreMap":577},[581,1593,1594,1596,1598,1601,1603,1605,1607,1609,1611,1613,1615],{"class":583,"line":584},[581,1595,588],{"class":587},[581,1597,592],{"class":591},[581,1599,1600],{"class":595}," AuthContext",[581,1602,599],{"class":591},[581,1604,1059],{"class":595},[581,1606,605],{"class":591},[581,1608,608],{"class":587},[581,1610,611],{"class":591},[581,1612,1068],{"class":614},[581,1614,618],{"class":591},[581,1616,621],{"class":591},[581,1618,1619,1621,1623,1625,1627,1629,1632,1634,1636,1638,1640,1642],{"class":583,"line":624},[581,1620,588],{"class":587},[581,1622,1274],{"class":587},[581,1624,592],{"class":591},[581,1626,1284],{"class":595},[581,1628,599],{"class":591},[581,1630,1631],{"class":595}," Get",[581,1633,605],{"class":591},[581,1635,608],{"class":587},[581,1637,611],{"class":591},[581,1639,1293],{"class":614},[581,1641,618],{"class":591},[581,1643,621],{"class":591},[581,1645,1646],{"class":583,"line":647},[581,1647,684],{"emptyLinePlaceholder":683},[581,1649,1650,1652,1654,1657,1660,1662],{"class":583,"line":680},[581,1651,718],{"class":587},[581,1653,721],{"class":690},[581,1655,1656],{"class":694}," AdminController",[581,1658,1659],{"class":690}," implements",[581,1661,1284],{"class":701},[581,1663,1664],{"class":591},"\u003C{\n",[581,1666,1667,1669,1671,1673,1676,1678],{"class":583,"line":687},[581,1668,741],{"class":740},[581,1670,744],{"class":591},[581,1672,611],{"class":591},[581,1674,1675],{"class":614},"\u002Fadmin",[581,1677,618],{"class":591},[581,1679,621],{"class":591},[581,1681,1682,1685,1687,1689,1691,1693],{"class":583,"line":710},[581,1683,1684],{"class":740},"  middlewares",[581,1686,744],{"class":591},[581,1688,1359],{"class":595},[581,1690,1020],{"class":694},[581,1692,1222],{"class":595},[581,1694,621],{"class":591},[581,1696,1697,1700],{"class":583,"line":715},[581,1698,1699],{"class":591},"}>",[581,1701,765],{"class":591},[581,1703,1704,1707,1710,1713,1716,1718,1721,1724,1726,1728,1730],{"class":583,"line":737},[581,1705,1706],{"class":690},"  private",[581,1708,1709],{"class":690}," static",[581,1711,1712],{"class":690}," readonly",[581,1714,1715],{"class":740}," requiredScope",[581,1717,744],{"class":591},[581,1719,1720],{"class":694}," string",[581,1722,1723],{"class":591}," =",[581,1725,611],{"class":591},[581,1727,525],{"class":614},[581,1729,618],{"class":591},[581,1731,621],{"class":591},[581,1733,1734],{"class":583,"line":757},[581,1735,684],{"emptyLinePlaceholder":683},[581,1737,1738,1740,1743,1745,1748,1750,1753,1755,1757,1759],{"class":583,"line":768},[581,1739,1385],{"class":690},[581,1741,1742],{"class":690}," constructor",[581,1744,731],{"class":591},[581,1746,1747],{"class":690},"private",[581,1749,1712],{"class":690},[581,1751,1752],{"class":1396}," authContext",[581,1754,744],{"class":591},[581,1756,1600],{"class":694},[581,1758,792],{"class":591},[581,1760,1761],{"class":591}," {}\n",[581,1763,1764],{"class":583,"line":837},[581,1765,684],{"emptyLinePlaceholder":683},[581,1767,1768,1770,1772,1775,1777,1779,1781,1783,1785,1787,1790,1792,1795,1798,1800,1803,1806],{"class":583,"line":906},[581,1769,1385],{"class":690},[581,1771,1388],{"class":690},[581,1773,1774],{"class":740}," stats",[581,1776,731],{"class":591},[581,1778,1397],{"class":1396},[581,1780,744],{"class":591},[581,1782,1631],{"class":694},[581,1784,1404],{"class":591},[581,1786,618],{"class":591},[581,1788,1789],{"class":614},"\u002Fstats",[581,1791,618],{"class":591},[581,1793,1794],{"class":591},">):",[581,1796,1797],{"class":694}," Promise",[581,1799,1404],{"class":591},[581,1801,1802],{"class":694},"Response",[581,1804,1805],{"class":591},">",[581,1807,765],{"class":591},[581,1809,1810,1813,1816,1819,1822,1824,1827,1830,1833,1836,1838],{"class":583,"line":932},[581,1811,1812],{"class":587},"    if",[581,1814,1815],{"class":740}," (",[581,1817,1818],{"class":591},"this.",[581,1820,1821],{"class":595},"authContext",[581,1823,526],{"class":591},[581,1825,1826],{"class":701},"principal",[581,1828,1829],{"class":740},"() ",[581,1831,1832],{"class":591},"===",[581,1834,1835],{"class":591}," null",[581,1837,996],{"class":740},[581,1839,734],{"class":591},[581,1841,1842,1845,1848,1850,1853,1855,1857,1859,1861,1864,1866,1868,1871,1873,1875,1877],{"class":583,"line":951},[581,1843,1844],{"class":587},"      return",[581,1846,1847],{"class":595}," action",[581,1849,526],{"class":591},[581,1851,1852],{"class":701},"respond",[581,1854,731],{"class":740},[581,1856,544],{"class":821},[581,1858,599],{"class":591},[581,1860,592],{"class":591},[581,1862,1863],{"class":740}," error",[581,1865,744],{"class":591},[581,1867,611],{"class":591},[581,1869,1870],{"class":614},"Authentication is required.",[581,1872,618],{"class":591},[581,1874,605],{"class":591},[581,1876,792],{"class":740},[581,1878,621],{"class":591},[581,1880,1881],{"class":583,"line":962},[581,1882,1883],{"class":591},"    }\n",[581,1885,1886],{"class":583,"line":985},[581,1887,684],{"emptyLinePlaceholder":683},[581,1889,1890,1892,1894,1897,1899,1901,1904,1906,1909,1911,1914,1917],{"class":583,"line":991},[581,1891,1812],{"class":587},[581,1893,1815],{"class":740},[581,1895,1896],{"class":591},"!this.",[581,1898,1821],{"class":595},[581,1900,526],{"class":591},[581,1902,1903],{"class":701},"isAllowed",[581,1905,731],{"class":740},[581,1907,1908],{"class":595},"AdminController",[581,1910,526],{"class":591},[581,1912,1913],{"class":595},"requiredScope",[581,1915,1916],{"class":740},")) ",[581,1918,734],{"class":591},[581,1920,1921,1923,1925,1927,1929,1931,1933,1935,1937,1939,1941,1944,1947,1950,1952,1954,1956,1958,1961,1964,1966,1968],{"class":583,"line":1519},[581,1922,1844],{"class":587},[581,1924,1847],{"class":595},[581,1926,526],{"class":591},[581,1928,1852],{"class":701},[581,1930,731],{"class":740},[581,1932,548],{"class":821},[581,1934,599],{"class":591},[581,1936,592],{"class":591},[581,1938,1863],{"class":740},[581,1940,744],{"class":591},[581,1942,1943],{"class":591}," `",[581,1945,1946],{"class":614},"Requires the '",[581,1948,1949],{"class":591},"${",[581,1951,1908],{"class":595},[581,1953,526],{"class":591},[581,1955,1913],{"class":595},[581,1957,830],{"class":591},[581,1959,1960],{"class":614},"' scope.",[581,1962,1963],{"class":591},"`",[581,1965,605],{"class":591},[581,1967,792],{"class":740},[581,1969,621],{"class":591},[581,1971,1972],{"class":583,"line":1525},[581,1973,1883],{"class":591},[581,1975,1976],{"class":583,"line":1530},[581,1977,684],{"emptyLinePlaceholder":683},[581,1979,1981,1984,1986,1988,1990,1992,1995,1997,1999,2002,2004,2007,2009,2012,2014,2017,2019,2021],{"class":583,"line":1980},21,[581,1982,1983],{"class":587},"    return",[581,1985,1847],{"class":595},[581,1987,526],{"class":591},[581,1989,1852],{"class":701},[581,1991,731],{"class":740},[581,1993,1994],{"class":821},"200",[581,1996,599],{"class":591},[581,1998,592],{"class":591},[581,2000,2001],{"class":740}," totalRequests",[581,2003,744],{"class":591},[581,2005,2006],{"class":821}," 42",[581,2008,599],{"class":591},[581,2010,2011],{"class":740}," activeSessions",[581,2013,744],{"class":591},[581,2015,2016],{"class":821}," 7",[581,2018,605],{"class":591},[581,2020,792],{"class":740},[581,2022,621],{"class":591},[581,2024,2026],{"class":583,"line":2025},22,[581,2027,1431],{"class":591},[581,2029,2031],{"class":583,"line":2030},23,[581,2032,1533],{"class":591},[499,2034,2035,2036,1576,2038,2040,2041,2043],{},"This produces exactly the ",[515,2037,544],{},[515,2039,548],{}," outcomes a guarded contract route would, because ",[515,2042,1903],{}," reads the\nsame stored principal the guard would — the only difference is that you write the two checks by hand instead of\ndeclaring them on a route.",[551,2045,2047],{"id":2046},"type-your-scope-codes","Type your scope codes",[499,2049,2050,2051,2054,2055,2058,2059,2062,2063,2066],{},"By default a scope is any ",[515,2052,2053],{},"string",". Narrow it to your app's exact permission codes by declaration-merging the\nglobal ",[515,2056,2057],{},"RequestDefaults"," seam, so a typo in a ",[515,2060,2061],{},"scopes(...)"," call or an ",[515,2064,2065],{},"isAllowed(...)"," argument is a compile\nerror instead of a silently never-granted permission.",[571,2068,2071],{"className":573,"code":2069,"filename":2070,"language":576,"meta":577,"style":577},"declare global {\n  interface RequestDefaults {\n    scopes: (\"task:read\" | \"task:create\" | \"task:complete\" | \"admin:stats:read\")[];\n  }\n}\n\nexport {};\n","scopes.d.ts",[515,2072,2073,2083,2093,2138,2142,2146,2150],{"__ignoreMap":577},[581,2074,2075,2078,2081],{"class":583,"line":584},[581,2076,2077],{"class":690},"declare",[581,2079,2080],{"class":595}," global ",[581,2082,734],{"class":591},[581,2084,2085,2088,2091],{"class":583,"line":624},[581,2086,2087],{"class":690},"  interface",[581,2089,2090],{"class":694}," RequestDefaults",[581,2092,765],{"class":591},[581,2094,2095,2098,2100,2102,2104,2106,2108,2111,2113,2115,2117,2119,2121,2123,2125,2127,2129,2131,2133,2136],{"class":583,"line":647},[581,2096,2097],{"class":740},"    scopes",[581,2099,744],{"class":591},[581,2101,1815],{"class":740},[581,2103,618],{"class":591},[581,2105,804],{"class":614},[581,2107,618],{"class":591},[581,2109,2110],{"class":591}," |",[581,2112,611],{"class":591},[581,2114,521],{"class":614},[581,2116,618],{"class":591},[581,2118,2110],{"class":591},[581,2120,611],{"class":591},[581,2122,944],{"class":614},[581,2124,618],{"class":591},[581,2126,2110],{"class":591},[581,2128,611],{"class":591},[581,2130,525],{"class":614},[581,2132,618],{"class":591},[581,2134,2135],{"class":740},")[]",[581,2137,621],{"class":591},[581,2139,2140],{"class":583,"line":680},[581,2141,1431],{"class":591},[581,2143,2144],{"class":583,"line":687},[581,2145,1533],{"class":591},[581,2147,2148],{"class":583,"line":710},[581,2149,684],{"emptyLinePlaceholder":683},[581,2151,2152,2154],{"class":583,"line":715},[581,2153,718],{"class":587},[581,2155,2156],{"class":591}," {};\n",[499,2158,2159,2161,2162,2165,2166,2169,2170,2173,2174,2177,2178,2180],{},[515,2160,797],{}," must be typed as the ",[562,2163,2164],{},"array"," of your scope codes — ",[515,2167,2168],{},"(\"a\" | \"b\")[]",", not a bare union — because\n",[515,2171,2172],{},"RequestScope"," is derived as ",[515,2175,2176],{},"RequestScopes[number]",", which extracts the element type. Without this seam, scopes\nfall back to ",[515,2179,2053],{}," — fine for prototyping, but the typed array is worth the one file once your permission set\nsettles, because it turns \"this guard never passes\" debugging into a red squiggle.",[551,2182,2184],{"id":2183},"see-also","See also",[2186,2187,2188,2201,2215,2224],"ul",{},[2189,2190,2191,2193,2194,2197,2198,2200],"li",{},[502,2192,97],{"href":98}," — issue tokens carrying the right ",[515,2195,2196],{},"permissions"," claim and wire\n",[515,2199,1034],{},", the principal these scopes are checked against.",[2189,2202,2203,2205,2206,2208,2209,2211,2212,2214],{},[502,2204,67],{"href":68}," — where ",[515,2207,559],{}," lives alongside the ",[515,2210,878],{}," and ",[515,2213,813],{},"\nschemas on a shared route table.",[2189,2216,2217,2219,2220,2223],{},[502,2218,57],{"href":58}," — the two controller modes and how a ",[515,2221,2222],{},"middlewares: [...]"," chain runs\nbefore a handler.",[2189,2225,2226,2234,2235,2237,2238,2241,2242,1576,2244,1576,2246,2248],{},[502,2227,2231],{"href":2228,"rel":2229},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL07-auth",[2230],"nofollow",[562,2232,2233],{},"Example L07 — auth","\n— register, login, a request-scoped ",[515,2236,1034],{},", and an ",[515,2239,2240],{},"\u002Fadmin\u002Fstats"," route that proves the manual\n",[515,2243,544],{},[515,2245,548],{},[515,2247,1994],{}," scope ladder.",[2250,2251,2252],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .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 .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 .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}",{"title":577,"searchDepth":624,"depth":624,"links":2254},[2255,2256,2257,2258,2259],{"id":553,"depth":624,"text":554},{"id":1008,"depth":624,"text":1009},{"id":1568,"depth":624,"text":1569},{"id":2046,"depth":624,"text":2047},{"id":2183,"depth":624,"text":2184},"Declare per-route scopes with Route.scopes, enforce them with GuardMiddleware, and run manual checks through AuthContext.isAllowed on inline routes.","md",null,{},{"icon":65},{"title":102,"description":2260},"uSzgWHsEqHCAqXFaUNWVtlx-y2lh18yq_0932mgZ5qE",[2268,2270],{"title":97,"path":98,"stem":99,"description":2269,"icon":100,"children":-1},"Verify callers with JWT, hash passwords through the PasswordHashingAlgorithm port, read the request-scoped AuthContext, and list JWTAuthMiddleware directly in your app.",{"title":106,"path":107,"stem":108,"description":2271,"icon":109,"children":-1},"Throw an error and get a clean response — the HeximonError family, ErrorFilter mapping, and the RFC 9457 problem+json envelope.",1783300761903]