[{"data":1,"prerenderedAt":804},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fcore-concepts\u002Fdecorators":176,"\u002Fdocs\u002Fcore-concepts\u002Fdecorators-surround":799},[4,21,86,158],{"title":5,"path":6,"stem":7,"children":8,"status":11,"icon":20},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,16],{"title":10,"path":6,"stem":7,"status":11},"Introduction",null,{"title":13,"path":14,"stem":15,"status":11},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation",{"title":17,"path":18,"stem":19,"status":11},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","1.docs\u002F1.getting-started\u002F3.quick-start",false,{"title":22,"path":23,"stem":24,"children":25,"status":11,"icon":20},"Core Concepts","\u002Fdocs\u002Fcore-concepts","1.docs\u002F2.core-concepts\u002F1.index",[26,28,32,36,46,50,54,58,62,66,70,74,78,82],{"title":27,"path":23,"stem":24,"status":11},"Overview",{"title":29,"path":30,"stem":31,"status":11},"Response","\u002Fdocs\u002Fcore-concepts\u002Fresponse","1.docs\u002F2.core-concepts\u002F10.response",{"title":33,"path":34,"stem":35,"status":11},"Testing","\u002Fdocs\u002Fcore-concepts\u002Ftesting","1.docs\u002F2.core-concepts\u002F12.testing",{"title":37,"path":38,"stem":39,"children":40,"status":11,"icon":20,"defaultOpen":20},"Decorators","\u002Fdocs\u002Fcore-concepts\u002Fdecorators","1.docs\u002F2.core-concepts\u002F13.decorators\u002F1.index",[41,42],{"title":27,"path":38,"stem":39,"status":11},{"title":43,"path":44,"stem":45,"status":11},"Custom","\u002Fdocs\u002Fcore-concepts\u002Fdecorators\u002Fcustom","1.docs\u002F2.core-concepts\u002F13.decorators\u002F2.custom",{"title":47,"path":48,"stem":49,"status":11},"Discovery Service","\u002Fdocs\u002Fcore-concepts\u002Fdiscovery","1.docs\u002F2.core-concepts\u002F14.discovery",{"title":51,"path":52,"stem":53,"status":11},"Application Lifecycle","\u002Fdocs\u002Fcore-concepts\u002Fapp-lifecycle","1.docs\u002F2.core-concepts\u002F15.app-lifecycle",{"title":55,"path":56,"stem":57,"status":11},"Controllers","\u002Fdocs\u002Fcore-concepts\u002Fcontrollers","1.docs\u002F2.core-concepts\u002F2.controllers",{"title":59,"path":60,"stem":61,"status":11},"Routing","\u002Fdocs\u002Fcore-concepts\u002Frouting","1.docs\u002F2.core-concepts\u002F3.routing",{"title":63,"path":64,"stem":65,"status":11},"Providers","\u002Fdocs\u002Fcore-concepts\u002Fproviders","1.docs\u002F2.core-concepts\u002F4.providers",{"title":67,"path":68,"stem":69,"status":11},"Modules","\u002Fdocs\u002Fcore-concepts\u002Fmodules","1.docs\u002F2.core-concepts\u002F5.modules",{"title":71,"path":72,"stem":73,"status":11},"Configuration","\u002Fdocs\u002Fcore-concepts\u002Fconfiguration","1.docs\u002F2.core-concepts\u002F6.configuration",{"title":75,"path":76,"stem":77,"status":11},"Middleware","\u002Fdocs\u002Fcore-concepts\u002Fmiddleware","1.docs\u002F2.core-concepts\u002F7.middleware",{"title":79,"path":80,"stem":81,"status":11},"Guards","\u002Fdocs\u002Fcore-concepts\u002Fguards","1.docs\u002F2.core-concepts\u002F8.guards",{"title":83,"path":84,"stem":85,"status":11},"Exceptions","\u002Fdocs\u002Fcore-concepts\u002Fexceptions","1.docs\u002F2.core-concepts\u002F9.exceptions",{"title":87,"path":88,"stem":89,"children":90,"status":11,"icon":20},"Packages","\u002Fdocs\u002Fpackages","1.docs\u002F3.packages\u002F1.index",[91,92,97,108,112,130,134,138,142,146,150,154],{"title":27,"path":88,"stem":89,"status":11},{"title":93,"path":94,"stem":95,"status":96},"CLI","\u002Fdocs\u002Fpackages\u002Fcli","1.docs\u002F3.packages\u002F10.cli","experimental",{"title":98,"path":99,"stem":100,"children":101,"status":11,"icon":20,"defaultOpen":20},"Events","\u002Fdocs\u002Fpackages\u002Fmessaging","1.docs\u002F3.packages\u002F11.messaging\u002F1.index",[102,104],{"title":27,"path":99,"stem":100,"status":103},"beta",{"title":105,"path":106,"stem":107,"status":96},"Redis","\u002Fdocs\u002Fpackages\u002Fmessaging\u002Fredis","1.docs\u002F3.packages\u002F11.messaging\u002F2.redis",{"title":109,"path":110,"stem":111,"status":103},"Serve Static","\u002Fdocs\u002Fpackages\u002Fserve-static","1.docs\u002F3.packages\u002F12.serve-static",{"title":113,"path":114,"stem":115,"children":116,"status":11,"icon":20,"defaultOpen":20},"Auth","\u002Fdocs\u002Fpackages\u002Fauth","1.docs\u002F3.packages\u002F2.auth\u002F1.index",[117,118,122,126],{"title":27,"path":114,"stem":115,"status":103},{"title":119,"path":120,"stem":121,"status":103},"JWT Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Fjwt","1.docs\u002F3.packages\u002F2.auth\u002F2.jwt",{"title":123,"path":124,"stem":125,"status":103},"Local Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Flocal","1.docs\u002F3.packages\u002F2.auth\u002F3.local",{"title":127,"path":128,"stem":129,"status":96},"OAuth2 Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Foauth2","1.docs\u002F3.packages\u002F2.auth\u002F4.oauth2",{"title":131,"path":132,"stem":133,"status":103},"JWT","\u002Fdocs\u002Fpackages\u002Fjwt","1.docs\u002F3.packages\u002F3.jwt",{"title":135,"path":136,"stem":137,"status":103},"Drizzle","\u002Fdocs\u002Fpackages\u002Fdrizzle","1.docs\u002F3.packages\u002F4.drizzle",{"title":139,"path":140,"stem":141,"status":103},"Papr","\u002Fdocs\u002Fpackages\u002Fpapr","1.docs\u002F3.packages\u002F5.papr",{"title":143,"path":144,"stem":145,"status":103},"Mongoose","\u002Fdocs\u002Fpackages\u002Fmongoose","1.docs\u002F3.packages\u002F6.mongoose",{"title":147,"path":148,"stem":149,"status":103},"Swagger","\u002Fdocs\u002Fpackages\u002Fswagger","1.docs\u002F3.packages\u002F7.swagger",{"title":151,"path":152,"stem":153,"status":103},"Node Server","\u002Fdocs\u002Fpackages\u002Fnode-server","1.docs\u002F3.packages\u002F8.node-server",{"title":155,"path":156,"stem":157,"status":103},"uWS Server","\u002Fdocs\u002Fpackages\u002Fuws-server","1.docs\u002F3.packages\u002F9.uws-server",{"title":159,"path":160,"stem":161,"children":162,"status":11,"icon":20},"Roadmap","\u002Fdocs\u002Froadmap","1.docs\u002F4.roadmap\u002F1.index",[163,164,168,172],{"title":27,"path":160,"stem":161,"status":11},{"title":165,"path":166,"stem":167,"status":11},"Short term (0-3 months)","\u002Fdocs\u002Froadmap\u002Fshort-term","1.docs\u002F4.roadmap\u002F2.short-term",{"title":169,"path":170,"stem":171,"status":11},"Mid term (3-9 months)","\u002Fdocs\u002Froadmap\u002Fmid-term","1.docs\u002F4.roadmap\u002F3.mid-term",{"title":173,"path":174,"stem":175,"status":11},"Long term (9-12+ months)","\u002Fdocs\u002Froadmap\u002Flong-term","1.docs\u002F4.roadmap\u002F4.long-term",{"id":177,"title":27,"body":178,"description":794,"extension":795,"meta":796,"navigation":549,"path":38,"seo":797,"status":11,"stem":39,"__hash__":798},"docs\u002F1.docs\u002F2.core-concepts\u002F13.decorators\u002F1.index.md",{"type":179,"value":180,"toc":787},"minimark",[181,204,224,229,232,255,258,262,269,470,480,484,497,646,649,673,677,688,724,727,738,742,762,773,783],[182,183,184,185,189,190,189,193,189,196,199,200,203],"p",{},"MiiaJS is a decorator-driven framework. ",[186,187,188],"code",{},"@Controller",", ",[186,191,192],{},"@Get",[186,194,195],{},"@UseGuard",[186,197,198],{},"@ValidateBody"," - every declarative knob you reach for is a decorator that attaches metadata to a class or method. The framework reads that metadata later (during ",[186,201,202],{},"app.init()",", in middleware, or in tools like Swagger spec generation) and turns it into runtime behaviour.",[182,205,206,207,211,212,215,216,219,220,223],{},"The decorator system is built on ",[208,209,210],"strong",{},"TC39 native decorators"," - no ",[186,213,214],{},"reflect-metadata",", no experimental compiler flags, no WeakMap-based shadow stores. The ",[186,217,218],{},"Symbol.metadata"," polyfill ships as the first import of ",[186,221,222],{},"@miiajs\u002Fcore",", so it's ready everywhere your code runs.",[225,226,228],"h2",{"id":227},"mental-model","Mental model",[182,230,231],{},"The whole story is two steps:",[233,234,235,246],"ol",{},[236,237,238,241,242,245],"li",{},[208,239,240],{},"Decorators attach metadata at class definition time."," Each decorator runs once, when the class is declared, and writes structured data onto ",[186,243,244],{},"Class[Symbol.metadata]"," keyed by symbols.",[236,247,248,251,252,254],{},[208,249,250],{},"The framework reads that metadata later."," ",[186,253,202],{}," walks every controller, pulls routes, middleware, guards, status codes, and validation schemas off the metadata, and wires them into the router. Per-request middleware can also read metadata to make decisions.",[182,256,257],{},"If you internalise this, every other piece of the framework - and your own custom decorators - falls out for free.",[225,259,261],{"id":260},"built-in-decorators","Built-in decorators",[182,263,264,265,268],{},"Every decorator below is built with the same public factory API that's available to you in ",[266,267,43],"a",{"href":44},".",[270,271,272,291],"table",{},[273,274,275],"thead",{},[276,277,278,282,285,288],"tr",{},[279,280,281],"th",{},"Decorator",[279,283,284],{},"Kind",[279,286,287],{},"What it does",[279,289,290],{},"See",[292,293,294,312,327,343,377,393,414,435,452],"tbody",{},[276,295,296,302,305,308],{},[297,298,299],"td",{},[186,300,301],{},"@Injectable",[297,303,304],{},"class",[297,306,307],{},"Marks a class as DI-resolvable",[297,309,310],{},[266,311,63],{"href":64},[276,313,314,318,320,323],{},[297,315,316],{},[186,317,188],{},[297,319,304],{},[297,321,322],{},"Route prefix + controller marker",[297,324,325],{},[266,326,55],{"href":56},[276,328,329,334,336,339],{},[297,330,331],{},[186,332,333],{},"@Module",[297,335,304],{},[297,337,338],{},"Groups controllers, providers, and imports",[297,340,341],{},[266,342,67],{"href":68},[276,344,345,367,370,373],{},[297,346,347,251,349,251,352,251,355,251,358,251,361,251,364],{},[186,348,192],{},[186,350,351],{},"@Post",[186,353,354],{},"@Put",[186,356,357],{},"@Patch",[186,359,360],{},"@Delete",[186,362,363],{},"@Head",[186,365,366],{},"@Options",[297,368,369],{},"method",[297,371,372],{},"Bind an HTTP route to a handler",[297,374,375],{},[266,376,59],{"href":60},[276,378,379,384,386,389],{},[297,380,381],{},[186,382,383],{},"@Status",[297,385,369],{},[297,387,388],{},"Default status code for the handler's response",[297,390,391],{},[266,392,55],{"href":56},[276,394,395,405,407,410],{},[297,396,397,251,399,251,402],{},[186,398,198],{},[186,400,401],{},"@ValidateQuery",[186,403,404],{},"@ValidateParams",[297,406,369],{},[297,408,409],{},"Zod-like schema validation, transparently replaces the parsed value",[297,411,412],{},[266,413,55],{"href":56},[276,415,416,421,428,431],{},[297,417,418],{},[186,419,420],{},"@Use",[297,422,423,424,427],{},"class ",[208,425,426],{},"or"," method",[297,429,430],{},"Apply Koa-style middleware",[297,432,433],{},[266,434,75],{"href":76},[276,436,437,441,445,448],{},[297,438,439],{},[186,440,195],{},[297,442,423,443,427],{},[208,444,426],{},[297,446,447],{},"Apply one or more guards",[297,449,450],{},[266,451,79],{"href":80},[276,453,454,459,463,466],{},[297,455,456],{},[186,457,458],{},"@SkipGuard",[297,460,423,461,427],{},[208,462,426],{},[297,464,465],{},"Exclude a previously-applied guard from a route",[297,467,468],{},[266,469,79],{"href":80},[182,471,472,473,189,475,189,477,479],{},"The class\u002Fmethod dual decorators (",[186,474,420],{},[186,476,195],{},[186,478,458],{},") inspect their TC39 context and branch - applied to a class they affect every handler in the controller, applied to a method they affect just that handler.",[225,481,483],{"id":482},"storage-model","Storage model",[182,485,486,487,489,490,493,494,496],{},"Metadata lives on the class constructor under ",[186,488,218],{},", keyed by ",[186,491,492],{},"Symbol","s exported from ",[186,495,222],{},":",[498,499,504],"pre",{"className":500,"code":501,"language":502,"meta":503,"style":503},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { ROUTES, getMeta } from '@miiajs\u002Fcore'\n\nclass UserController {\n  @Get('\u002F')\n  list() { \u002F* ... *\u002F }\n}\n\nconst routes = getMeta(UserController, ROUTES)\n\u002F\u002F → [{ method: 'GET', path: '\u002F', handlerName: 'list' }]\n","typescript","",[186,505,506,544,551,564,588,607,613,618,640],{"__ignoreMap":503},[507,508,511,515,519,523,526,529,532,535,538,541],"span",{"class":509,"line":510},"line",1,[507,512,514],{"class":513},"s7zQu","import",[507,516,518],{"class":517},"sMK4o"," {",[507,520,522],{"class":521},"sTEyZ"," ROUTES",[507,524,525],{"class":517},",",[507,527,528],{"class":521}," getMeta",[507,530,531],{"class":517}," }",[507,533,534],{"class":513}," from",[507,536,537],{"class":517}," '",[507,539,222],{"class":540},"sfazB",[507,542,543],{"class":517},"'\n",[507,545,547],{"class":509,"line":546},2,[507,548,550],{"emptyLinePlaceholder":549},true,"\n",[507,552,554,557,561],{"class":509,"line":553},3,[507,555,304],{"class":556},"spNyl",[507,558,560],{"class":559},"sBMFI"," UserController",[507,562,563],{"class":517}," {\n",[507,565,567,570,574,577,580,583,585],{"class":509,"line":566},4,[507,568,569],{"class":517},"  @",[507,571,573],{"class":572},"s2Zo4","Get",[507,575,576],{"class":521},"(",[507,578,579],{"class":517},"'",[507,581,582],{"class":540},"\u002F",[507,584,579],{"class":517},[507,586,587],{"class":521},")\n",[507,589,591,595,598,600,604],{"class":509,"line":590},5,[507,592,594],{"class":593},"swJcz","  list",[507,596,597],{"class":517},"()",[507,599,518],{"class":517},[507,601,603],{"class":602},"sHwdD"," \u002F* ... *\u002F",[507,605,606],{"class":517}," }\n",[507,608,610],{"class":509,"line":609},6,[507,611,612],{"class":517},"}\n",[507,614,616],{"class":509,"line":615},7,[507,617,550],{"emptyLinePlaceholder":549},[507,619,621,624,627,630,632,635,637],{"class":509,"line":620},8,[507,622,623],{"class":556},"const",[507,625,626],{"class":521}," routes ",[507,628,629],{"class":517},"=",[507,631,528],{"class":572},[507,633,634],{"class":521},"(UserController",[507,636,525],{"class":517},[507,638,639],{"class":521}," ROUTES)\n",[507,641,643],{"class":509,"line":642},9,[507,644,645],{"class":602},"\u002F\u002F → [{ method: 'GET', path: '\u002F', handlerName: 'list' }]\n",[182,647,648],{},"A few properties to remember:",[650,651,652,658,667],"ul",{},[236,653,654,657],{},[208,655,656],{},"Class-level scope."," Metadata is attached to the constructor, not to instances. Every instance shares the same metadata.",[236,659,660,663,664,666],{},[208,661,662],{},"Symbol keys."," Always use ",[186,665,492],{},"s, never strings - string keys would collide with user-land properties on the metadata object.",[236,668,669,672],{},[208,670,671],{},"Lifetime = module lifetime."," The metadata exists for as long as the class is reachable. There's no per-request reset.",[225,674,676],{"id":675},"execution-model","Execution model",[182,678,679,680,683,684,687],{},"Decorators run ",[208,681,682],{},"once",", at class definition, in ",[208,685,686],{},"bottom-up order"," when stacked:",[498,689,691],{"className":500,"code":690,"language":502,"meta":503,"style":503},"@A   \u002F\u002F runs second\n@B   \u002F\u002F runs first\nclass Foo {}\n",[186,692,693,704,714],{"__ignoreMap":503},[507,694,695,698,701],{"class":509,"line":510},[507,696,697],{"class":517},"@",[507,699,700],{"class":521},"A   ",[507,702,703],{"class":602},"\u002F\u002F runs second\n",[507,705,706,708,711],{"class":509,"line":546},[507,707,697],{"class":517},[507,709,710],{"class":521},"B   ",[507,712,713],{"class":602},"\u002F\u002F runs first\n",[507,715,716,718,721],{"class":509,"line":553},[507,717,304],{"class":556},[507,719,720],{"class":559}," Foo",[507,722,723],{"class":517}," {}\n",[182,725,726],{},"This matters in exactly one situation: when one decorator reads metadata that another just wrote. In practice most decorators only write, so order is irrelevant - but if you're building decorators that read each other's output, remember the rule.",[182,728,729,730,733,734,737],{},"Decorators are ",[208,731,732],{},"never"," invoked per request. If you need request-time behaviour, write ",[266,735,736],{"href":76},"middleware"," - the decorator's job is to declare intent, the middleware's job is to act on it.",[225,739,741],{"id":740},"extending-the-framework","Extending the framework",[182,743,744,745,747,748,751,752,189,755,189,758,761],{},"Everything in the catalogue above is built with the four factory functions and five metadata helpers that ",[186,746,222],{}," exposes publicly. The same API powers ",[186,749,750],{},"@miiajs\u002Fswagger","'s ",[186,753,754],{},"@ApiTag",[186,756,757],{},"@ApiOperation",[186,759,760],{},"@ApiSecurity",", etc., and it's available to you for any project-specific decorator you need.",[182,763,764,765,768,769,772],{},"For higher-level recipes that always apply together - e.g. ",[186,766,767],{},"@AdminOnly()"," that bundles auth, a role guard, and a status code - compose them with ",[186,770,771],{},"applyDecorators",". No metadata plumbing required; it just stacks existing decorators into one.",[182,774,775,776,779,780,782],{},"See ",[266,777,778],{"href":44},"Custom Decorators"," for the factories, helpers, walkthroughs, and the ",[186,781,771],{}," recipe.",[784,785,786],"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 .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 .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);}",{"title":503,"searchDepth":546,"depth":546,"links":788},[789,790,791,792,793],{"id":227,"depth":546,"text":228},{"id":260,"depth":546,"text":261},{"id":482,"depth":546,"text":483},{"id":675,"depth":546,"text":676},{"id":740,"depth":546,"text":741},"How decorators work in MiiaJS - TC39 native, Symbol.metadata, and the catalogue of built-ins.","md",{},{"title":27,"description":794},"xKn6VG6TfE0Yai3G4AZVdDDBN2ykoPUfloGIIQhcKlQ",[800,802],{"title":33,"path":34,"stem":35,"description":801,"children":-1},"Test your application with the built-in TestApp utility.",{"title":43,"path":44,"stem":45,"description":803,"children":-1},"Build your own decorators with createClassDecorator, createMethodDecorator, createDecorator, createFieldDecorator, and the metadata helpers.",1778575277353]