[{"data":1,"prerenderedAt":1220},["ShallowReactive",2],{"navigation_docs":3,"-core-concepts":36,"-core-concepts-surround":1215},[4,8,12,16,20,24,28,32],{"title":5,"path":6,"stem":7},"Getting started","\u002Fgetting-started","1.getting-started",{"title":9,"path":10,"stem":11},"Core concepts","\u002Fcore-concepts","2.core-concepts",{"title":13,"path":14,"stem":15},"Cross-cutting concerns","\u002Fcross-cutting","3.cross-cutting",{"title":17,"path":18,"stem":19},"Tenancy & RLS","\u002Ftenancy-and-rls","4.tenancy-and-rls",{"title":21,"path":22,"stem":23},"How the codegen works","\u002Fhow-the-codegen-works","5.how-the-codegen-works",{"title":25,"path":26,"stem":27},"vs. NestJS","\u002Fvs-nestjs","6.vs-nestjs",{"title":29,"path":30,"stem":31},"Before \u002F after","\u002Fbefore-after","7.before-after",{"title":33,"path":34,"stem":35},"Modules","\u002Fmodules","8.modules",{"id":37,"title":9,"body":38,"description":1209,"extension":1210,"links":1211,"meta":1212,"navigation":363,"path":10,"seo":1213,"stem":11,"__hash__":1214},"docs\u002F2.core-concepts.md",{"type":39,"value":40,"toc":1201},"minimark",[41,46,78,146,169,173,191,237,248,267,271,281,447,450,593,618,637,683,687,717,873,897,1036,1061,1065,1071,1102,1113,1117,1197],[42,43,45],"h2",{"id":44},"decorators-are-build-time-annotations","Decorators are build-time annotations",[47,48,49,50,54,55,54,58,54,61,64,65,69,70,73,74,77],"p",{},"The decorators (",[51,52,53],"code",{},"@Controller",", ",[51,56,57],{},"@Injectable",[51,59,60],{},"@Get",[51,62,63],{},"@UseGuards",", …) are ",[66,67,68],"strong",{},"no-ops at runtime",".\nThey exist so the class is valid TypeScript and so the codegen's AST has something to read. There\nis no ",[51,71,72],{},"reflect-metadata",", no ",[51,75,76],{},"design:paramtypes",", nothing inspected at runtime.",[79,80,85],"pre",{"className":81,"code":82,"language":83,"meta":84,"style":84},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export const Controller =\n  (_path?: string): ClassDecorator =>\n  () => {}\n","ts","",[51,86,87,108,134],{"__ignoreMap":84},[88,89,92,96,100,104],"span",{"class":90,"line":91},"line",1,[88,93,95],{"class":94},"s7zQu","export",[88,97,99],{"class":98},"spNyl"," const",[88,101,103],{"class":102},"sTEyZ"," Controller ",[88,105,107],{"class":106},"sMK4o","=\n",[88,109,111,114,118,121,125,128,131],{"class":90,"line":110},2,[88,112,113],{"class":106},"  (",[88,115,117],{"class":116},"sHdIc","_path",[88,119,120],{"class":106},"?:",[88,122,124],{"class":123},"sBMFI"," string",[88,126,127],{"class":106},"):",[88,129,130],{"class":123}," ClassDecorator",[88,132,133],{"class":98}," =>\n",[88,135,137,140,143],{"class":90,"line":136},3,[88,138,139],{"class":106},"  ()",[88,141,142],{"class":98}," =>",[88,144,145],{"class":106}," {}\n",[47,147,148,149,152,153,156,157,156,160,163,164,168],{},"All the meaning is extracted at build time by reading the syntax tree. The decorators and roost\ntypes are ",[66,150,151],{},"auto-imported"," into server code, so you write ",[51,154,155],{},"@Controller()"," \u002F ",[51,158,159],{},"@Get()",[51,161,162],{},"Ctx","\nwithout an import line — see ",[165,166,5],"a",{"href":167},"\u002Fgetting-started#auto-imports",".",[42,170,172],{"id":171},"dependency-injection-awilix","Dependency injection (awilix)",[47,174,175,176,182,183,186,187,190],{},"roost uses ",[165,177,181],{"href":178,"rel":179},"https:\u002F\u002Fgithub.com\u002Fjeffijoe\u002Fawilix",[180],"nofollow","awilix"," with ",[66,184,185],{},"request scopes"," and\n",[51,188,189],{},"strict: true"," (which throws on lifetime leakage — a SINGLETON depending on a SCOPED provider —\nat boot, not in production).",[192,193,194,205,225],"ul",{},[195,196,197,200,201,204],"li",{},[66,198,199],{},"SINGLETON"," providers (plain ",[51,202,203],{},"@Injectable()",") live for the process — the shared store, the DB\npool.",[195,206,207,210,211,214,215,218,219,221,222,168],{},[66,208,209],{},"SCOPED"," providers (",[51,212,213],{},"@Scoped()",", or ",[51,216,217],{},"@Injectable({ scope: 'scoped' })","; ",[51,220,53],{}," and\nguards\u002Ffilters\u002Finterceptors by default) are built fresh per request and can inject the per-request\n",[51,223,224],{},"RequestContext",[195,226,227,210,230,214,233,236],{},[66,228,229],{},"TRANSIENT",[51,231,232],{},"@Transient()",[51,234,235],{},"@Injectable({ scope: 'transient' })",") get a new\ninstance on every resolution.",[47,238,239,156,241,243,244,247],{},[51,240,213],{},[51,242,232],{}," are roost shorthands — less boilerplate than the ",[51,245,246],{},"@Injectable({ scope })","\nlong form, which stays for Nest familiarity. Both work.",[47,249,250,251,254,255,258,259,262,263,266],{},"The dependency graph comes from ",[66,252,253],{},"constructor parameter types"," — ",[51,256,257],{},"constructor(private repo: ProjectsRepo)"," means \"inject ",[51,260,261],{},"projectsRepo","\". roost emits explicit ",[51,264,265],{},"asFunction"," factories from these,\nso it never relies on awilix's minification-fragile param-name parsing.",[42,268,270],{"id":269},"request-input-validation-injection","Request input: validation & injection",[47,272,273,274,277,278,280],{},"Validation always comes from a ",[66,275,276],{},"zod schema"," (there's no ",[51,279,72],{},", so a type can't be a\nvalidator — a runtime schema is the minimal requirement). There are two ways to take the validated\nbody; they're equivalent in guarantee, differing only in how the handler reads it:",[79,282,284],{"className":81,"code":283,"language":83,"meta":84,"style":84},"\u002F\u002F Injection (Nest-faithful): the validated body is bound as the argument.\n@Post()\ncreate(@Body(createProjectSchema) dto: CreateProjectDto) {\n  return this.projects.create(dto.name)\n}\n\n\u002F\u002F Context style: validate ctx.body in place, read it off ctx.\n@Post()\n@ValidateBody(createProjectSchema)\ncreate(ctx: Ctx\u003CCreateProjectDto>) {\n  return this.projects.create(ctx.body.name)\n}\n",[51,285,286,292,304,321,352,358,365,371,380,391,413,442],{"__ignoreMap":84},[88,287,288],{"class":90,"line":91},[88,289,291],{"class":290},"sHwdD","\u002F\u002F Injection (Nest-faithful): the validated body is bound as the argument.\n",[88,293,294,297,301],{"class":90,"line":110},[88,295,296],{"class":106},"@",[88,298,300],{"class":299},"s2Zo4","Post",[88,302,303],{"class":102},"()\n",[88,305,306,309,312,315,318],{"class":90,"line":136},[88,307,308],{"class":299},"create",[88,310,311],{"class":102},"(@",[88,313,314],{"class":299},"Body",[88,316,317],{"class":102},"(createProjectSchema) dto: CreateProjectDto) ",[88,319,320],{"class":106},"{\n",[88,322,324,327,330,333,335,337,341,344,346,349],{"class":90,"line":323},4,[88,325,326],{"class":94},"  return",[88,328,329],{"class":106}," this.",[88,331,332],{"class":102},"projects",[88,334,168],{"class":106},[88,336,308],{"class":299},[88,338,340],{"class":339},"swJcz","(",[88,342,343],{"class":102},"dto",[88,345,168],{"class":106},[88,347,348],{"class":102},"name",[88,350,351],{"class":339},")\n",[88,353,355],{"class":90,"line":354},5,[88,356,357],{"class":106},"}\n",[88,359,361],{"class":90,"line":360},6,[88,362,364],{"emptyLinePlaceholder":363},true,"\n",[88,366,368],{"class":90,"line":367},7,[88,369,370],{"class":290},"\u002F\u002F Context style: validate ctx.body in place, read it off ctx.\n",[88,372,374,376,378],{"class":90,"line":373},8,[88,375,296],{"class":106},[88,377,300],{"class":299},[88,379,303],{"class":102},[88,381,383,385,388],{"class":90,"line":382},9,[88,384,296],{"class":106},[88,386,387],{"class":299},"ValidateBody",[88,389,390],{"class":102},"(createProjectSchema)\n",[88,392,394,396,399,402,405,408,411],{"class":90,"line":393},10,[88,395,308],{"class":299},[88,397,398],{"class":102},"(ctx: Ctx",[88,400,401],{"class":106},"\u003C",[88,403,404],{"class":102},"CreateProjectDto",[88,406,407],{"class":106},">",[88,409,410],{"class":102},") ",[88,412,320],{"class":106},[88,414,416,418,420,422,424,426,428,431,433,436,438,440],{"class":90,"line":415},11,[88,417,326],{"class":94},[88,419,329],{"class":106},[88,421,332],{"class":102},[88,423,168],{"class":106},[88,425,308],{"class":299},[88,427,340],{"class":339},[88,429,430],{"class":102},"ctx",[88,432,168],{"class":106},[88,434,435],{"class":102},"body",[88,437,168],{"class":106},[88,439,348],{"class":102},[88,441,351],{"class":339},[88,443,445],{"class":90,"line":444},12,[88,446,357],{"class":106},[47,448,449],{},"The injection decorators bind handler arguments from the request, in declaration order:",[451,452,453,466],"table",{},[454,455,456],"thead",{},[457,458,459,463],"tr",{},[460,461,462],"th",{},"Decorator",[460,464,465],{},"Injects",[467,468,469,484,497,515,538,560,576],"tbody",{},[457,470,471,477],{},[472,473,474],"td",{},[51,475,476],{},"@Body(schema)",[472,478,479,480,483],{},"the ",[66,481,482],{},"validated"," body (bad input → 400 before the handler)",[457,485,486,491],{},[472,487,488],{},[51,489,490],{},"@Body(null)",[472,492,479,493,496],{},[66,494,495],{},"raw"," body, no validation — explicit opt-out",[457,498,499,505],{},[472,500,501,504],{},[51,502,503],{},"@Body()"," (bare)",[472,506,507,508,511,512,514],{},"a ",[66,509,510],{},"build error"," — pass a schema, or ",[51,513,490],{}," to skip",[457,516,517,528],{},[472,518,519,156,522,156,525],{},[51,520,521],{},"@Param('id')",[51,523,524],{},"@Param()",[51,526,527],{},"@Param('id', pipe)",[472,529,530,531,533,534,537],{},"a route param; bare ",[51,532,524],{}," ",[66,535,536],{},"infers the key from the parameter name","; an optional pipe transforms\u002Fvalidates it",[457,539,540,545],{},[472,541,542],{},[51,543,544],{},"@Query(schema)",[472,546,547,548,551,552,555,556,559],{},"the validated ",[66,549,550],{},"whole"," query (",[51,553,554],{},"@Query(null)"," raw, bare ",[51,557,558],{},"@Query()"," errors)",[457,561,562,570],{},[472,563,564,156,567],{},[51,565,566],{},"@Query('page')",[51,568,569],{},"@Query('page', pipe)",[472,571,507,572,575],{},[66,573,574],{},"single"," query param (raw, or run through a pipe)",[457,577,578,583],{},[472,579,580],{},[51,581,582],{},"@Ctx()",[472,584,585,586,588,589,592],{},"the full ",[51,587,162],{}," (an undecorated ",[51,590,591],{},"ctx: Ctx"," param does too)",[47,594,595,598,599,602,603,606,607,609,610,614,615,617],{},[51,596,597],{},"@Body"," is ",[66,600,601],{},"only"," the param injector; the method-level validation marker is named ",[51,604,605],{},"@ValidateBody","\nso the name never implies the Nest-style injection that form doesn't do. A bare ",[51,608,503],{}," is\nrejected at build time on purpose — injection never ",[611,612,613],"em",{},"silently"," skips validation, the way a\nreflect-metadata framework's ",[51,616,503],{}," might appear to validate when nothing is wired.",[47,619,620,621,624,625,628,629,632,633,636],{},"Validation runs through zod's ",[51,622,623],{},"parseAsync",", so ",[66,626,627],{},"async refinements work"," — a schema with an\n",[51,630,631],{},"async .refine"," (e.g. a DB-backed uniqueness check) validates before the handler, and a rejection\nstill maps to a ",[51,634,635],{},"400"," like any other validation failure.",[47,638,639,533,644,647,648,651,652,655,656,658,659,662,663,666,667,670,671,674,675,678,679,682],{},[66,640,641,643],{},[51,642,524],{}," infers its key from the parameter name.",[51,645,646],{},"get(@Param() id: string)"," binds\n",[51,649,650],{},"ctx.params.id"," — roost reads the parameter name from the AST at build time (before any minifier\nrenames it), so repeating ",[51,653,654],{},"'id'"," is unnecessary. Nest needs ",[51,657,521],{}," because it reads names at\n",[611,660,661],{},"runtime",", where minification has erased them; roost's build-time pass doesn't have that limitation.\nPass an explicit key only when the names differ (",[51,664,665],{},"@Param('id') userId","). Either way, the key is\n",[66,668,669],{},"checked against the route path"," at build time — a ",[51,672,673],{},"@Param"," with no matching ",[51,676,677],{},":key"," is a hard\nerror, so a typo surfaces at codegen, not as a silent ",[51,680,681],{},"undefined"," in production.",[42,684,686],{"id":685},"pipes","Pipes",[47,688,689,690,692,693,695,696,695,699,701,702,705,706,54,709,712,713,716],{},"A \"pipe\" in roost is just a ",[66,691,276],{}," — the thing ",[51,694,597],{},"\u002F",[51,697,698],{},"@Query",[51,700,673],{}," already accept. A\nzod schema does both NestJS pipe jobs at once: it ",[66,703,704],{},"transforms"," (coerce, ",[51,707,708],{},".transform()",[51,710,711],{},".default()",")\nand ",[66,714,715],{},"validates"," (throwing → 400 on bad input). So instead of Nest's menu of single-purpose pipe\nclasses, you pass one schema:",[79,718,720],{"className":81,"code":719,"language":83,"meta":84,"style":84},"@Get(':id')\nfindOne(@Param('id', ParseInt) id: number) {   \u002F\u002F \"0x1f\"\u002F\"1.5\"\u002F\"abc\" → 400; \"42\" → 42\n  return this.cats.findOne(id)\n}\n\n@Get()\nfindAll(@Query('page', ParseInt.default(1)) page: number) {   \u002F\u002F ?page=2 → 2, absent → 1\n  return this.cats.page(page)\n}\n",[51,721,722,742,773,792,796,800,808,851,869],{"__ignoreMap":84},[88,723,724,726,729,731,734,738,740],{"class":90,"line":91},[88,725,296],{"class":106},[88,727,728],{"class":299},"Get",[88,730,340],{"class":102},[88,732,733],{"class":106},"'",[88,735,737],{"class":736},"sfazB",":id",[88,739,733],{"class":106},[88,741,351],{"class":102},[88,743,744,747,749,752,754,756,759,761,764,767,770],{"class":90,"line":110},[88,745,746],{"class":299},"findOne",[88,748,311],{"class":102},[88,750,751],{"class":299},"Param",[88,753,340],{"class":102},[88,755,733],{"class":106},[88,757,758],{"class":736},"id",[88,760,733],{"class":106},[88,762,763],{"class":106},",",[88,765,766],{"class":102}," ParseInt) id: number) ",[88,768,769],{"class":106},"{",[88,771,772],{"class":290},"   \u002F\u002F \"0x1f\"\u002F\"1.5\"\u002F\"abc\" → 400; \"42\" → 42\n",[88,774,775,777,779,782,784,786,788,790],{"class":90,"line":136},[88,776,326],{"class":94},[88,778,329],{"class":106},[88,780,781],{"class":102},"cats",[88,783,168],{"class":106},[88,785,746],{"class":299},[88,787,340],{"class":339},[88,789,758],{"class":102},[88,791,351],{"class":339},[88,793,794],{"class":90,"line":323},[88,795,357],{"class":106},[88,797,798],{"class":90,"line":354},[88,799,364],{"emptyLinePlaceholder":363},[88,801,802,804,806],{"class":90,"line":360},[88,803,296],{"class":106},[88,805,728],{"class":299},[88,807,303],{"class":102},[88,809,810,813,815,818,820,822,825,827,829,832,834,837,839,843,846,848],{"class":90,"line":367},[88,811,812],{"class":299},"findAll",[88,814,311],{"class":102},[88,816,817],{"class":299},"Query",[88,819,340],{"class":102},[88,821,733],{"class":106},[88,823,824],{"class":736},"page",[88,826,733],{"class":106},[88,828,763],{"class":106},[88,830,831],{"class":102}," ParseInt",[88,833,168],{"class":106},[88,835,836],{"class":299},"default",[88,838,340],{"class":102},[88,840,842],{"class":841},"sbssI","1",[88,844,845],{"class":102},")) page: number) ",[88,847,769],{"class":106},[88,849,850],{"class":290},"   \u002F\u002F ?page=2 → 2, absent → 1\n",[88,852,853,855,857,859,861,863,865,867],{"class":90,"line":373},[88,854,326],{"class":94},[88,856,329],{"class":106},[88,858,781],{"class":102},[88,860,168],{"class":106},[88,862,824],{"class":299},[88,864,340],{"class":339},[88,866,824],{"class":102},[88,868,351],{"class":339},[88,870,871],{"class":90,"line":382},[88,872,357],{"class":106},[47,874,875,695,878,695,881,695,884,695,887,695,890,695,893,896],{},[51,876,877],{},"ParseInt",[51,879,880],{},"ParseFloat",[51,882,883],{},"ParseBool",[51,885,886],{},"ParseUUID",[51,888,889],{},"ParseEnum",[51,891,892],{},"ParseArray",[51,894,895],{},"DefaultValue"," are\nauto-imported helpers mirroring Nest's built-in pipes — but they're plain schemas, so they map to\nzod idioms and chain with any zod method:",[451,898,899,909],{},[454,900,901],{},[457,902,903,906],{},[460,904,905],{},"NestJS pipe",[460,907,908],{},"roost",[467,910,911,927,938,952,966,981,994,1010,1020],{},[457,912,913,918],{},[472,914,915],{},[51,916,917],{},"ParseIntPipe",[472,919,920,922,923,926],{},[51,921,877],{}," (",[51,924,925],{},"z.string().regex(int).transform(Number)",")",[457,928,929,934],{},[472,930,931],{},[51,932,933],{},"ParseFloatPipe",[472,935,936],{},[51,937,880],{},[457,939,940,945],{},[472,941,942],{},[51,943,944],{},"ParseBoolPipe",[472,946,947,922,949,926],{},[51,948,883],{},[51,950,951],{},"z.stringbool()",[457,953,954,959],{},[472,955,956],{},[51,957,958],{},"ParseUUIDPipe",[472,960,961,922,963,926],{},[51,962,886],{},[51,964,965],{},"z.uuid()",[457,967,968,973],{},[472,969,970],{},[51,971,972],{},"ParseEnumPipe",[472,974,975,922,978,926],{},[51,976,977],{},"ParseEnum(['a','b'])",[51,979,980],{},"z.enum",[457,982,983,988],{},[472,984,985],{},[51,986,987],{},"ParseArrayPipe",[472,989,990,993],{},[51,991,992],{},"ParseArray(ParseInt)"," (split + per-item)",[457,995,996,1001],{},[472,997,998],{},[51,999,1000],{},"DefaultValuePipe",[472,1002,1003,1006,1007],{},[51,1004,1005],{},"DefaultValue(1, ParseInt)"," or just ",[51,1008,1009],{},".default(1)",[457,1011,1012,1017],{},[472,1013,1014],{},[51,1015,1016],{},"ValidationPipe",[472,1018,1019],{},"the schema itself",[457,1021,1022,1028],{},[472,1023,1024,1025],{},"a custom ",[51,1026,1027],{},"PipeTransform",[472,1029,1030,156,1033],{},[51,1031,1032],{},".transform(fn)",[51,1034,1035],{},".refine(fn)",[47,1037,1038,1039,922,1042,1045,1046,1049,1050,1053,1054,1056,1057,1060],{},"There's ",[66,1040,1041],{},"no multi-pipe chain syntax",[51,1043,1044],{},"@Query('x', PipeA, PipeB)",") — a zod schema already composes,\nso the chain is one expression: ",[51,1047,1048],{},"@Query('activeOnly', ParseBool.default(false))"," is Nest's\n",[51,1051,1052],{},"new DefaultValuePipe(false), ParseBoolPipe",". Every pipe throws on a bad value (→ 400); only\n",[51,1055,895],{}," substitutes — and only for an ",[611,1058,1059],{},"absent"," value, never an invalid one.",[42,1062,1064],{"id":1063},"two-generated-artifacts","Two generated artifacts",[47,1066,1067,1068,127],{},"From your decorated classes, roost emits (into a gitignored ",[51,1069,1070],{},".roost\u002F",[1072,1073,1074,1089],"ol",{},[195,1075,1076,922,1079,1082,1083,695,1085,1088],{},[66,1077,1078],{},"Route delegates",[51,1080,1081],{},".roost\u002Fapi\u002F**",") — one tiny Nitro file per ",[51,1084,60],{},[51,1086,1087],{},"@Post","\u002F…, scanned by\nNitro's normal file-based router.",[195,1090,1091,922,1094,1097,1098,1101],{},[66,1092,1093],{},"The DI manifest",[51,1095,1096],{},".roost\u002Fdi.generated.ts",") — the awilix ",[51,1099,1100],{},"container.register({...})",",\nplus a plugin that wires it at startup.",[47,1103,1104,1105,1108,1109,1112],{},"Both are real files. The ",[66,1106,1107],{},"dependency direction is inverted",": generated files import ",[611,1110,1111],{},"from"," the\nruntime, and nothing in the runtime imports generated code — which is what keeps the heavy\nbuild-time dependency (ts-morph) out of your edge bundle.",[42,1114,1116],{"id":1115},"the-magic-spectrum","The magic spectrum",[451,1118,1119,1132],{},[454,1120,1121],{},[457,1122,1123,1126,1129],{},[460,1124,1125],{},"Level",[460,1127,1128],{},"Codegen reads",[460,1130,1131],{},"Emits",[467,1133,1134,1145,1165,1182],{},[457,1135,1136,1139,1142],{},[472,1137,1138],{},"0",[472,1140,1141],{},"nothing",[472,1143,1144],{},"you hand-write the route files (plain Nitro)",[457,1146,1147,1152,1162],{},[472,1148,1149],{},[66,1150,1151],{},"1 (today)",[472,1153,1154,1157,1158,1161],{},[51,1155,1156],{},"@Controller\u002F@Get\u002F@UseGuards\u002F@UseFilters\u002F@UseInterceptors"," + ",[51,1159,1160],{},"@Body\u002F@Param\u002F@Query\u002F@Ctx"," + ctor types",[472,1163,1164],{},"route files + DI wiring + cross-cutting + param injection",[457,1166,1167,1170,1179],{},[472,1168,1169],{},"2",[472,1171,1172,1173,54,1176],{},"+ ",[51,1174,1175],{},"@Module",[51,1177,1178],{},"@Catch(Type)",[472,1180,1181],{},"per-module scopes, typed exception matching",[457,1183,1184,1187,1190],{},[472,1185,1186],{},"3",[472,1188,1189],{},"+ zod DTOs",[472,1191,1192,1193,1196],{},"OpenAPI, a typed ",[51,1194,1195],{},"$fetch"," client, RLS policy stubs",[1198,1199,1200],"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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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}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 .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 .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}",{"title":84,"searchDepth":110,"depth":110,"links":1202},[1203,1204,1205,1206,1207,1208],{"id":44,"depth":110,"text":45},{"id":171,"depth":110,"text":172},{"id":269,"depth":110,"text":270},{"id":685,"depth":110,"text":686},{"id":1063,"depth":110,"text":1064},{"id":1115,"depth":110,"text":1116},"Decorators as build-time annotations, awilix DI, and the two generated artifacts.","md",null,{},{"title":9,"description":1209},"ticiVOM5hdKL6BZ3CeSkbU9vzP6c3UfXCG3KltTEK9Q",[1216,1218],{"title":5,"path":6,"stem":7,"description":1217,"children":-1},"Install nuxt-roost and write your first decorated controller.",{"title":13,"path":14,"stem":15,"description":1219,"children":-1},"Guards, interceptors, and filters — all DI'd providers, differing only in when they run.",1780506501961]