[{"data":1,"prerenderedAt":1798},["ShallowReactive",2],{"navigation":3,"\u002Fnest\u002Fguards":173,"\u002Fnest\u002Fguards-surround":1793},[4,9,14,19,46,96,109,127,148],{"title":5,"path":6,"stem":7,"icon":8},"Introduction","\u002Fintroduction","01.introduction","i-lucide-info",{"title":10,"path":11,"stem":12,"icon":13},"Installation","\u002Finstallation","02.installation","i-lucide-circle-arrow-down",{"title":15,"path":16,"stem":17,"icon":18},"First App","\u002Ffirst-app","03.first-app","i-lucide-play",{"title":20,"icon":21,"path":22,"stem":23,"children":24,"page":45},"Core","i-lucide-container","\u002Fcore","10.core",[25,30,35,40],{"title":26,"path":27,"stem":28,"icon":29},"Architecture","\u002Fcore\u002Farchitecture","10.core\u002F1.architecture","i-lucide-folder-tree",{"title":31,"path":32,"stem":33,"icon":34},"Concepts","\u002Fcore\u002Fconcepts","10.core\u002F2.concepts","i-lucide-lightbulb",{"title":36,"path":37,"stem":38,"icon":39},"Runtime","\u002Fcore\u002Fruntime","10.core\u002F3.runtime","i-lucide-cpu",{"title":41,"path":42,"stem":43,"icon":44},"Modules","\u002Fcore\u002Fmodules","10.core\u002F4.modules","i-lucide-puzzle",false,{"title":47,"icon":48,"path":49,"stem":50,"children":51,"page":45},"Server","i-simple-icons-nestjs","\u002Fnest","11.nest",[52,55,72,77,82,87,92],{"title":5,"path":53,"stem":54,"icon":8},"\u002Fnest\u002Fintroduction","11.nest\u002F1.introduction",{"title":56,"path":57,"stem":58,"children":59,"icon":71},"Database","\u002Fnest\u002Fdatabase","11.nest\u002F2.database\u002F1.index",[60,61,66],{"title":56,"path":57,"stem":58,"icon":8},{"title":62,"path":63,"stem":64,"icon":65},"Models","\u002Fnest\u002Fdatabase\u002Fmodels","11.nest\u002F2.database\u002F2.models","i-lucide-database-zap",{"title":67,"path":68,"stem":69,"icon":70},"Plugins","\u002Fnest\u002Fdatabase\u002Fplugins","11.nest\u002F2.database\u002F3.plugins","i-lucide-plug","i-lucide-database",{"title":73,"path":74,"stem":75,"icon":76},"Controllers","\u002Fnest\u002Fcontrollers","11.nest\u002F3.controllers","i-lucide-route",{"title":78,"path":79,"stem":80,"icon":81},"Guards","\u002Fnest\u002Fguards","11.nest\u002F4.guards","i-lucide-shield-check",{"title":83,"path":84,"stem":85,"icon":86},"Services","\u002Fnest\u002Fservices","11.nest\u002F5.services","i-lucide-layers",{"title":88,"path":89,"stem":90,"icon":91},"Locales","\u002Fnest\u002Flocales","11.nest\u002F6.locales","i-lucide-languages",{"title":93,"path":94,"stem":95},"Env","\u002Fnest\u002Fenv","11.nest\u002F7.env",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":45},"Client","i-simple-icons-nuxt","\u002Fnuxt","12.nuxt",[102,105],{"title":5,"path":103,"stem":104},"\u002Fnuxt\u002Fintroduction","12.nuxt\u002F1.introduction",{"title":106,"path":107,"stem":108},"Coming Soon","\u002Fnuxt\u002Fcoming-soon","12.nuxt\u002F2.coming-soon",{"title":110,"icon":111,"path":112,"stem":113,"children":114,"page":45},"Configuration","i-lucide-settings","\u002Fconfiguration","13.configuration",[115,119,123],{"title":116,"path":117,"stem":118},"Opensya Config","\u002Fconfiguration\u002Fopensya-config","13.configuration\u002F1.opensya-config",{"title":120,"path":121,"stem":122},"Runtime Config","\u002Fconfiguration\u002Fruntime-config","13.configuration\u002F2.runtime-config",{"title":124,"path":125,"stem":126},"Server Config","\u002Fconfiguration\u002Fserver-config","13.configuration\u002F3.server-config",{"title":128,"icon":129,"path":130,"stem":131,"children":132,"page":45},"Deployment","i-lucide-cloud","\u002Fdeployment","14.deployment",[133,136,140,144],{"title":5,"path":134,"stem":135},"\u002Fdeployment\u002Fintroduction","14.deployment\u002F1.introduction",{"title":137,"path":138,"stem":139},"Docker","\u002Fdeployment\u002Fdocker","14.deployment\u002F2.docker",{"title":141,"path":142,"stem":143},"Production","\u002Fdeployment\u002Fproduction","14.deployment\u002F3.production",{"title":145,"path":146,"stem":147},"Self Hosting","\u002Fdeployment\u002Fself-hosting","14.deployment\u002F4.self-hosting",{"title":149,"icon":150,"path":151,"stem":152,"children":153,"page":45},"Advanced","i-lucide-plus","\u002Fadvanced","15.advanced",[154,158,162,165,169],{"title":155,"path":156,"stem":157},"Internals","\u002Fadvanced\u002Finternals","15.advanced\u002F1.internals",{"title":159,"path":160,"stem":161},"Compiler","\u002Fadvanced\u002Fcompiler","15.advanced\u002F2.compiler",{"title":41,"path":163,"stem":164},"\u002Fadvanced\u002Fmodules","15.advanced\u002F3.modules",{"title":166,"path":167,"stem":168},"Globals","\u002Fadvanced\u002Fglobals","15.advanced\u002F4.globals",{"title":170,"path":171,"stem":172},"Lifecycle","\u002Fadvanced\u002Flifecycle","15.advanced\u002F5.lifecycle",{"id":174,"title":78,"body":175,"description":1786,"extension":1787,"links":1788,"meta":1789,"navigation":1790,"path":79,"seo":1791,"stem":80,"__hash__":1792},"docs\u002F11.nest\u002F4.guards.md",{"type":176,"value":177,"toc":1774},"minimark",[178,182,186,189,197,204,209,216,423,429,433,436,439,461,464,500,506,550,554,557,560,618,624,716,723,727,730,943,946,1036,1045,1049,1052,1123,1126,1188,1198,1202,1205,1474,1477,1581,1585,1588,1638,1642,1645,1663,1713,1717,1720,1723,1729,1732,1735,1752,1757,1761,1764,1767,1770],[179,180,78],"h1",{"id":181},"guards",[183,184,185],"p",{},"Guards define access control rules in the OpenSya backend runtime.",[183,187,188],{},"They are used to protect controllers, validate permissions and stop unauthorized requests before the controller handler is executed.",[183,190,191,192,196],{},"OpenSya guards are discovered automatically from the ",[193,194,195],"code",{},"server\u002Fguards"," directory and executed by the generated backend runtime.",[198,199,201],"callout",{"color":200,"icon":81},"primary",[183,202,203],{},"Guards allow OpenSya applications to keep access control modular, reusable and runtime-aware.",[205,206,208],"h2",{"id":207},"creating-a-guard","Creating a Guard",[183,210,211,212,215],{},"A guard is created using the global ",[193,213,214],{},"defineGuard"," helper.",[217,218,224],"pre",{"className":219,"code":220,"filename":221,"language":222,"meta":223,"style":223},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineGuard(({ controllerOptions, request }) => {\n  if (!controllerOptions.roles) return;\n\n  if (!controllerOptions.roles.includes(request._user?.role)) {\n    return {\n      pass: false,\n      errorMessage: $t('session.errors.not_authorized'),\n    };\n  }\n});\n","server\u002Fguards\u002Froles.ts","ts","",[193,225,226,270,301,308,350,358,374,401,407,413],{"__ignoreMap":223},[227,228,231,235,238,242,246,250,254,257,260,263,267],"span",{"class":229,"line":230},"line",1,[227,232,234],{"class":233},"s7zQu","export",[227,236,237],{"class":233}," default",[227,239,241],{"class":240},"s2Zo4"," defineGuard",[227,243,245],{"class":244},"sTEyZ","(",[227,247,249],{"class":248},"sMK4o","({",[227,251,253],{"class":252},"sHdIc"," controllerOptions",[227,255,256],{"class":248},",",[227,258,259],{"class":252}," request",[227,261,262],{"class":248}," })",[227,264,266],{"class":265},"spNyl"," =>",[227,268,269],{"class":248}," {\n",[227,271,273,276,280,283,286,289,292,295,298],{"class":229,"line":272},2,[227,274,275],{"class":233},"  if",[227,277,279],{"class":278},"swJcz"," (",[227,281,282],{"class":248},"!",[227,284,285],{"class":244},"controllerOptions",[227,287,288],{"class":248},".",[227,290,291],{"class":244},"roles",[227,293,294],{"class":278},") ",[227,296,297],{"class":233},"return",[227,299,300],{"class":248},";\n",[227,302,304],{"class":229,"line":303},3,[227,305,307],{"emptyLinePlaceholder":306},true,"\n",[227,309,311,313,315,317,319,321,323,325,328,330,333,335,338,341,344,347],{"class":229,"line":310},4,[227,312,275],{"class":233},[227,314,279],{"class":278},[227,316,282],{"class":248},[227,318,285],{"class":244},[227,320,288],{"class":248},[227,322,291],{"class":244},[227,324,288],{"class":248},[227,326,327],{"class":240},"includes",[227,329,245],{"class":278},[227,331,332],{"class":244},"request",[227,334,288],{"class":248},[227,336,337],{"class":244},"_user",[227,339,340],{"class":248},"?.",[227,342,343],{"class":244},"role",[227,345,346],{"class":278},")) ",[227,348,349],{"class":248},"{\n",[227,351,353,356],{"class":229,"line":352},5,[227,354,355],{"class":233},"    return",[227,357,269],{"class":248},[227,359,361,364,367,371],{"class":229,"line":360},6,[227,362,363],{"class":278},"      pass",[227,365,366],{"class":248},":",[227,368,370],{"class":369},"sfNiH"," false",[227,372,373],{"class":248},",\n",[227,375,377,380,382,385,387,390,394,396,399],{"class":229,"line":376},7,[227,378,379],{"class":278},"      errorMessage",[227,381,366],{"class":248},[227,383,384],{"class":240}," $t",[227,386,245],{"class":278},[227,388,389],{"class":248},"'",[227,391,393],{"class":392},"sfazB","session.errors.not_authorized",[227,395,389],{"class":248},[227,397,398],{"class":278},")",[227,400,373],{"class":248},[227,402,404],{"class":229,"line":403},8,[227,405,406],{"class":248},"    };\n",[227,408,410],{"class":229,"line":409},9,[227,411,412],{"class":248},"  }\n",[227,414,416,419,421],{"class":229,"line":415},10,[227,417,418],{"class":248},"}",[227,420,398],{"class":244},[227,422,300],{"class":248},[183,424,425,426,428],{},"This guard checks the ",[193,427,291],{}," option declared on a controller and blocks the request if the current user does not have the required role.",[205,430,432],{"id":431},"how-guards-work","How Guards Work",[183,434,435],{},"A guard receives runtime information about the current request and the controller being executed.",[183,437,438],{},"It can:",[440,441,442,446,449,452,455,458],"ul",{},[443,444,445],"li",{},"Read controller options",[443,447,448],{},"Read the current request",[443,450,451],{},"Check the authenticated user",[443,453,454],{},"Validate roles or permissions",[443,456,457],{},"Stop the request",[443,459,460],{},"Return an error message",[183,462,463],{},"If the guard does not return anything, the request continues.",[217,465,467],{"className":219,"code":466,"language":222,"meta":223,"style":223},"export default defineGuard(() => {\n  \u002F\u002F No return means the request is allowed to continue.\n});\n",[193,468,469,486,492],{"__ignoreMap":223},[227,470,471,473,475,477,479,482,484],{"class":229,"line":230},[227,472,234],{"class":233},[227,474,237],{"class":233},[227,476,241],{"class":240},[227,478,245],{"class":244},[227,480,481],{"class":248},"()",[227,483,266],{"class":265},[227,485,269],{"class":248},[227,487,488],{"class":229,"line":272},[227,489,491],{"class":490},"sHwdD","  \u002F\u002F No return means the request is allowed to continue.\n",[227,493,494,496,498],{"class":229,"line":303},[227,495,418],{"class":248},[227,497,398],{"class":244},[227,499,300],{"class":248},[183,501,502,503,288],{},"To block the request, return an object with ",[193,504,505],{},"pass: false",[217,507,509],{"className":219,"code":508,"language":222,"meta":223,"style":223},"return {\n  pass: false,\n  errorMessage: 'Not authorized',\n};\n",[193,510,511,517,528,545],{"__ignoreMap":223},[227,512,513,515],{"class":229,"line":230},[227,514,297],{"class":233},[227,516,269],{"class":248},[227,518,519,522,524,526],{"class":229,"line":272},[227,520,521],{"class":278},"  pass",[227,523,366],{"class":248},[227,525,370],{"class":369},[227,527,373],{"class":248},[227,529,530,533,535,538,541,543],{"class":229,"line":303},[227,531,532],{"class":278},"  errorMessage",[227,534,366],{"class":248},[227,536,537],{"class":248}," '",[227,539,540],{"class":392},"Not authorized",[227,542,389],{"class":248},[227,544,373],{"class":248},[227,546,547],{"class":229,"line":310},[227,548,549],{"class":248},"};\n",[205,551,553],{"id":552},"extending-controller-options","Extending Controller Options",[183,555,556],{},"Guards can extend controller options using TypeScript module augmentation.",[183,558,559],{},"This allows a guard to introduce custom options that controllers can use.",[217,561,563],{"className":219,"code":562,"filename":221,"language":222,"meta":223,"style":223},"declare module '#core\u002Fnest\u002Ftypes\u002Fcontrollers' {\n  interface ControllerOptions {\n    roles?: string[];\n  }\n}\n",[193,564,565,582,593,609,613],{"__ignoreMap":223},[227,566,567,570,573,575,578,580],{"class":229,"line":230},[227,568,569],{"class":265},"declare",[227,571,572],{"class":265}," module",[227,574,537],{"class":248},[227,576,577],{"class":392},"#core\u002Fnest\u002Ftypes\u002Fcontrollers",[227,579,389],{"class":248},[227,581,269],{"class":248},[227,583,584,587,591],{"class":229,"line":272},[227,585,586],{"class":265},"  interface",[227,588,590],{"class":589},"sBMFI"," ControllerOptions",[227,592,269],{"class":248},[227,594,595,598,601,604,607],{"class":229,"line":303},[227,596,597],{"class":278},"    roles",[227,599,600],{"class":248},"?:",[227,602,603],{"class":589}," string",[227,605,606],{"class":278},"[]",[227,608,300],{"class":248},[227,610,611],{"class":229,"line":310},[227,612,412],{"class":248},[227,614,615],{"class":229,"line":352},[227,616,617],{"class":248},"}\n",[183,619,620,621,623],{},"After declaring this augmentation, controllers can use the ",[193,622,291],{}," option.",[217,625,628],{"className":219,"code":626,"filename":627,"language":222,"meta":223,"style":223},"export default defineController(\n  async () => {\n    return useService('user.list')();\n  },\n  {\n    roles: ['admin'],\n  },\n);\n","server\u002Fcontrollers\u002Fadmin\u002Fusers\u002Findex.get.ts",[193,629,630,642,654,675,680,685,706,710],{"__ignoreMap":223},[227,631,632,634,636,639],{"class":229,"line":230},[227,633,234],{"class":233},[227,635,237],{"class":233},[227,637,638],{"class":240}," defineController",[227,640,641],{"class":244},"(\n",[227,643,644,647,650,652],{"class":229,"line":272},[227,645,646],{"class":265},"  async",[227,648,649],{"class":248}," ()",[227,651,266],{"class":265},[227,653,269],{"class":248},[227,655,656,658,661,663,665,668,670,673],{"class":229,"line":303},[227,657,355],{"class":233},[227,659,660],{"class":240}," useService",[227,662,245],{"class":278},[227,664,389],{"class":248},[227,666,667],{"class":392},"user.list",[227,669,389],{"class":248},[227,671,672],{"class":278},")()",[227,674,300],{"class":248},[227,676,677],{"class":229,"line":310},[227,678,679],{"class":248},"  },\n",[227,681,682],{"class":229,"line":352},[227,683,684],{"class":248},"  {\n",[227,686,687,689,691,694,696,699,701,704],{"class":229,"line":360},[227,688,597],{"class":278},[227,690,366],{"class":248},[227,692,693],{"class":244}," [",[227,695,389],{"class":248},[227,697,698],{"class":392},"admin",[227,700,389],{"class":248},[227,702,703],{"class":244},"]",[227,705,373],{"class":248},[227,707,708],{"class":229,"line":376},[227,709,679],{"class":248},[227,711,712,714],{"class":229,"line":403},[227,713,398],{"class":244},[227,715,300],{"class":248},[198,717,720],{"color":718,"icon":719},"info","i-lucide-code-xml",[183,721,722],{},"Controller options can be extended by guards to create application-specific access rules.",[205,724,726],{"id":725},"role-based-access-control","Role-based Access Control",[183,728,729],{},"A common use case is role-based access control.",[217,731,733],{"className":219,"code":732,"filename":221,"language":222,"meta":223,"style":223},"declare module '#core\u002Fnest\u002Ftypes\u002Fcontrollers' {\n  interface ControllerOptions {\n    roles?: string[];\n  }\n}\n\nexport default defineGuard(({ controllerOptions, request }) => {\n  if (!controllerOptions.roles) return;\n\n  const userRole = request._user?.role;\n\n  if (!controllerOptions.roles.includes(userRole)) {\n    return {\n      pass: false,\n      errorMessage: $t('session.errors.not_authorized'),\n    };\n  }\n});\n",[193,734,735,749,757,769,773,777,781,805,825,829,852,857,885,892,903,924,929,934],{"__ignoreMap":223},[227,736,737,739,741,743,745,747],{"class":229,"line":230},[227,738,569],{"class":265},[227,740,572],{"class":265},[227,742,537],{"class":248},[227,744,577],{"class":392},[227,746,389],{"class":248},[227,748,269],{"class":248},[227,750,751,753,755],{"class":229,"line":272},[227,752,586],{"class":265},[227,754,590],{"class":589},[227,756,269],{"class":248},[227,758,759,761,763,765,767],{"class":229,"line":303},[227,760,597],{"class":278},[227,762,600],{"class":248},[227,764,603],{"class":589},[227,766,606],{"class":278},[227,768,300],{"class":248},[227,770,771],{"class":229,"line":310},[227,772,412],{"class":248},[227,774,775],{"class":229,"line":352},[227,776,617],{"class":248},[227,778,779],{"class":229,"line":360},[227,780,307],{"emptyLinePlaceholder":306},[227,782,783,785,787,789,791,793,795,797,799,801,803],{"class":229,"line":376},[227,784,234],{"class":233},[227,786,237],{"class":233},[227,788,241],{"class":240},[227,790,245],{"class":244},[227,792,249],{"class":248},[227,794,253],{"class":252},[227,796,256],{"class":248},[227,798,259],{"class":252},[227,800,262],{"class":248},[227,802,266],{"class":265},[227,804,269],{"class":248},[227,806,807,809,811,813,815,817,819,821,823],{"class":229,"line":403},[227,808,275],{"class":233},[227,810,279],{"class":278},[227,812,282],{"class":248},[227,814,285],{"class":244},[227,816,288],{"class":248},[227,818,291],{"class":244},[227,820,294],{"class":278},[227,822,297],{"class":233},[227,824,300],{"class":248},[227,826,827],{"class":229,"line":409},[227,828,307],{"emptyLinePlaceholder":306},[227,830,831,834,837,840,842,844,846,848,850],{"class":229,"line":415},[227,832,833],{"class":265},"  const",[227,835,836],{"class":244}," userRole",[227,838,839],{"class":248}," =",[227,841,259],{"class":244},[227,843,288],{"class":248},[227,845,337],{"class":244},[227,847,340],{"class":248},[227,849,343],{"class":244},[227,851,300],{"class":248},[227,853,855],{"class":229,"line":854},11,[227,856,307],{"emptyLinePlaceholder":306},[227,858,860,862,864,866,868,870,872,874,876,878,881,883],{"class":229,"line":859},12,[227,861,275],{"class":233},[227,863,279],{"class":278},[227,865,282],{"class":248},[227,867,285],{"class":244},[227,869,288],{"class":248},[227,871,291],{"class":244},[227,873,288],{"class":248},[227,875,327],{"class":240},[227,877,245],{"class":278},[227,879,880],{"class":244},"userRole",[227,882,346],{"class":278},[227,884,349],{"class":248},[227,886,888,890],{"class":229,"line":887},13,[227,889,355],{"class":233},[227,891,269],{"class":248},[227,893,895,897,899,901],{"class":229,"line":894},14,[227,896,363],{"class":278},[227,898,366],{"class":248},[227,900,370],{"class":369},[227,902,373],{"class":248},[227,904,906,908,910,912,914,916,918,920,922],{"class":229,"line":905},15,[227,907,379],{"class":278},[227,909,366],{"class":248},[227,911,384],{"class":240},[227,913,245],{"class":278},[227,915,389],{"class":248},[227,917,393],{"class":392},[227,919,389],{"class":248},[227,921,398],{"class":278},[227,923,373],{"class":248},[227,925,927],{"class":229,"line":926},16,[227,928,406],{"class":248},[227,930,932],{"class":229,"line":931},17,[227,933,412],{"class":248},[227,935,937,939,941],{"class":229,"line":936},18,[227,938,418],{"class":248},[227,940,398],{"class":244},[227,942,300],{"class":248},[183,944,945],{},"Usage inside a controller:",[217,947,950],{"className":219,"code":948,"filename":949,"language":222,"meta":223,"style":223},"export default defineController(\n  async () => {\n    return useService('report.list')();\n  },\n  {\n    roles: ['admin', 'manager'],\n  },\n);\n","server\u002Fcontrollers\u002Fadmin\u002Freports\u002Findex.get.ts",[193,951,952,962,972,991,995,999,1026,1030],{"__ignoreMap":223},[227,953,954,956,958,960],{"class":229,"line":230},[227,955,234],{"class":233},[227,957,237],{"class":233},[227,959,638],{"class":240},[227,961,641],{"class":244},[227,963,964,966,968,970],{"class":229,"line":272},[227,965,646],{"class":265},[227,967,649],{"class":248},[227,969,266],{"class":265},[227,971,269],{"class":248},[227,973,974,976,978,980,982,985,987,989],{"class":229,"line":303},[227,975,355],{"class":233},[227,977,660],{"class":240},[227,979,245],{"class":278},[227,981,389],{"class":248},[227,983,984],{"class":392},"report.list",[227,986,389],{"class":248},[227,988,672],{"class":278},[227,990,300],{"class":248},[227,992,993],{"class":229,"line":310},[227,994,679],{"class":248},[227,996,997],{"class":229,"line":352},[227,998,684],{"class":248},[227,1000,1001,1003,1005,1007,1009,1011,1013,1015,1017,1020,1022,1024],{"class":229,"line":360},[227,1002,597],{"class":278},[227,1004,366],{"class":248},[227,1006,693],{"class":244},[227,1008,389],{"class":248},[227,1010,698],{"class":392},[227,1012,389],{"class":248},[227,1014,256],{"class":248},[227,1016,537],{"class":248},[227,1018,1019],{"class":392},"manager",[227,1021,389],{"class":248},[227,1023,703],{"class":244},[227,1025,373],{"class":248},[227,1027,1028],{"class":229,"line":376},[227,1029,679],{"class":248},[227,1031,1032,1034],{"class":229,"line":403},[227,1033,398],{"class":244},[227,1035,300],{"class":248},[183,1037,1038,1039,1041,1042,1044],{},"Only users with the ",[193,1040,698],{}," or ",[193,1043,1019],{}," role can access this endpoint.",[205,1046,1048],{"id":1047},"public-controllers","Public Controllers",[183,1050,1051],{},"Public controllers are intentionally exposed without authentication or access checks.",[217,1053,1056],{"className":219,"code":1054,"filename":1055,"language":222,"meta":223,"style":223},"export default defineController(\n  async () => {\n    return useService('config.get')();\n  },\n  { public: true },\n);\n","server\u002Fcontrollers\u002Fconfig\u002Findex.get.ts",[193,1057,1058,1068,1078,1097,1101,1117],{"__ignoreMap":223},[227,1059,1060,1062,1064,1066],{"class":229,"line":230},[227,1061,234],{"class":233},[227,1063,237],{"class":233},[227,1065,638],{"class":240},[227,1067,641],{"class":244},[227,1069,1070,1072,1074,1076],{"class":229,"line":272},[227,1071,646],{"class":265},[227,1073,649],{"class":248},[227,1075,266],{"class":265},[227,1077,269],{"class":248},[227,1079,1080,1082,1084,1086,1088,1091,1093,1095],{"class":229,"line":303},[227,1081,355],{"class":233},[227,1083,660],{"class":240},[227,1085,245],{"class":278},[227,1087,389],{"class":248},[227,1089,1090],{"class":392},"config.get",[227,1092,389],{"class":248},[227,1094,672],{"class":278},[227,1096,300],{"class":248},[227,1098,1099],{"class":229,"line":310},[227,1100,679],{"class":248},[227,1102,1103,1106,1109,1111,1114],{"class":229,"line":352},[227,1104,1105],{"class":248},"  {",[227,1107,1108],{"class":278}," public",[227,1110,366],{"class":248},[227,1112,1113],{"class":369}," true",[227,1115,1116],{"class":248}," },\n",[227,1118,1119,1121],{"class":229,"line":360},[227,1120,398],{"class":244},[227,1122,300],{"class":248},[183,1124,1125],{},"Guards should generally ignore public controllers unless they are designed to run globally for all requests.",[217,1127,1130],{"className":219,"code":1128,"filename":1129,"language":222,"meta":223,"style":223},"export default defineGuard(({ controllerOptions }) => {\n  if (controllerOptions.public) return;\n\n  \u002F\u002F Protected-only logic here.\n});\n","server\u002Fguards\u002Fcustom.ts",[193,1131,1132,1152,1171,1175,1180],{"__ignoreMap":223},[227,1133,1134,1136,1138,1140,1142,1144,1146,1148,1150],{"class":229,"line":230},[227,1135,234],{"class":233},[227,1137,237],{"class":233},[227,1139,241],{"class":240},[227,1141,245],{"class":244},[227,1143,249],{"class":248},[227,1145,253],{"class":252},[227,1147,262],{"class":248},[227,1149,266],{"class":265},[227,1151,269],{"class":248},[227,1153,1154,1156,1158,1160,1162,1165,1167,1169],{"class":229,"line":272},[227,1155,275],{"class":233},[227,1157,279],{"class":278},[227,1159,285],{"class":244},[227,1161,288],{"class":248},[227,1163,1164],{"class":244},"public",[227,1166,294],{"class":278},[227,1168,297],{"class":233},[227,1170,300],{"class":248},[227,1172,1173],{"class":229,"line":303},[227,1174,307],{"emptyLinePlaceholder":306},[227,1176,1177],{"class":229,"line":310},[227,1178,1179],{"class":490},"  \u002F\u002F Protected-only logic here.\n",[227,1181,1182,1184,1186],{"class":229,"line":352},[227,1183,418],{"class":248},[227,1185,398],{"class":244},[227,1187,300],{"class":248},[198,1189,1192,1195],{"color":1190,"icon":1191},"warning","i-lucide-shield-alert",[183,1193,1194],{},"Be careful when creating global guards.",[183,1196,1197],{},"A guard can affect every protected controller in the backend runtime.",[205,1199,1201],{"id":1200},"permission-guard-example","Permission Guard Example",[183,1203,1204],{},"You can create custom access rules beyond simple roles.",[217,1206,1209],{"className":219,"code":1207,"filename":1208,"language":222,"meta":223,"style":223},"declare module '#core\u002Fnest\u002Ftypes\u002Fcontrollers' {\n  interface ControllerOptions {\n    permissions?: string[];\n  }\n}\n\nexport default defineGuard(({ controllerOptions, request }) => {\n  if (!controllerOptions.permissions?.length) return;\n\n  const userPermissions = request._user?.permissions ?? [];\n\n  const hasPermission = controllerOptions.permissions.every((permission) =>\n    userPermissions.includes(permission),\n  );\n\n  if (!hasPermission) {\n    return {\n      pass: false,\n      errorMessage: $t('session.errors.not_authorized'),\n    };\n  }\n});\n","server\u002Fguards\u002Fpermissions.ts",[193,1210,1211,1225,1233,1246,1250,1254,1258,1282,1308,1312,1339,1343,1375,1392,1399,1403,1418,1424,1434,1455,1460,1465],{"__ignoreMap":223},[227,1212,1213,1215,1217,1219,1221,1223],{"class":229,"line":230},[227,1214,569],{"class":265},[227,1216,572],{"class":265},[227,1218,537],{"class":248},[227,1220,577],{"class":392},[227,1222,389],{"class":248},[227,1224,269],{"class":248},[227,1226,1227,1229,1231],{"class":229,"line":272},[227,1228,586],{"class":265},[227,1230,590],{"class":589},[227,1232,269],{"class":248},[227,1234,1235,1238,1240,1242,1244],{"class":229,"line":303},[227,1236,1237],{"class":278},"    permissions",[227,1239,600],{"class":248},[227,1241,603],{"class":589},[227,1243,606],{"class":278},[227,1245,300],{"class":248},[227,1247,1248],{"class":229,"line":310},[227,1249,412],{"class":248},[227,1251,1252],{"class":229,"line":352},[227,1253,617],{"class":248},[227,1255,1256],{"class":229,"line":360},[227,1257,307],{"emptyLinePlaceholder":306},[227,1259,1260,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280],{"class":229,"line":376},[227,1261,234],{"class":233},[227,1263,237],{"class":233},[227,1265,241],{"class":240},[227,1267,245],{"class":244},[227,1269,249],{"class":248},[227,1271,253],{"class":252},[227,1273,256],{"class":248},[227,1275,259],{"class":252},[227,1277,262],{"class":248},[227,1279,266],{"class":265},[227,1281,269],{"class":248},[227,1283,1284,1286,1288,1290,1292,1294,1297,1299,1302,1304,1306],{"class":229,"line":403},[227,1285,275],{"class":233},[227,1287,279],{"class":278},[227,1289,282],{"class":248},[227,1291,285],{"class":244},[227,1293,288],{"class":248},[227,1295,1296],{"class":244},"permissions",[227,1298,340],{"class":248},[227,1300,1301],{"class":244},"length",[227,1303,294],{"class":278},[227,1305,297],{"class":233},[227,1307,300],{"class":248},[227,1309,1310],{"class":229,"line":409},[227,1311,307],{"emptyLinePlaceholder":306},[227,1313,1314,1316,1319,1321,1323,1325,1327,1329,1331,1334,1337],{"class":229,"line":415},[227,1315,833],{"class":265},[227,1317,1318],{"class":244}," userPermissions",[227,1320,839],{"class":248},[227,1322,259],{"class":244},[227,1324,288],{"class":248},[227,1326,337],{"class":244},[227,1328,340],{"class":248},[227,1330,1296],{"class":244},[227,1332,1333],{"class":248}," ??",[227,1335,1336],{"class":278}," []",[227,1338,300],{"class":248},[227,1340,1341],{"class":229,"line":854},[227,1342,307],{"emptyLinePlaceholder":306},[227,1344,1345,1347,1350,1352,1354,1356,1358,1360,1363,1365,1367,1370,1372],{"class":229,"line":859},[227,1346,833],{"class":265},[227,1348,1349],{"class":244}," hasPermission",[227,1351,839],{"class":248},[227,1353,253],{"class":244},[227,1355,288],{"class":248},[227,1357,1296],{"class":244},[227,1359,288],{"class":248},[227,1361,1362],{"class":240},"every",[227,1364,245],{"class":278},[227,1366,245],{"class":248},[227,1368,1369],{"class":252},"permission",[227,1371,398],{"class":248},[227,1373,1374],{"class":265}," =>\n",[227,1376,1377,1380,1382,1384,1386,1388,1390],{"class":229,"line":887},[227,1378,1379],{"class":244},"    userPermissions",[227,1381,288],{"class":248},[227,1383,327],{"class":240},[227,1385,245],{"class":278},[227,1387,1369],{"class":244},[227,1389,398],{"class":278},[227,1391,373],{"class":248},[227,1393,1394,1397],{"class":229,"line":894},[227,1395,1396],{"class":278},"  )",[227,1398,300],{"class":248},[227,1400,1401],{"class":229,"line":905},[227,1402,307],{"emptyLinePlaceholder":306},[227,1404,1405,1407,1409,1411,1414,1416],{"class":229,"line":926},[227,1406,275],{"class":233},[227,1408,279],{"class":278},[227,1410,282],{"class":248},[227,1412,1413],{"class":244},"hasPermission",[227,1415,294],{"class":278},[227,1417,349],{"class":248},[227,1419,1420,1422],{"class":229,"line":931},[227,1421,355],{"class":233},[227,1423,269],{"class":248},[227,1425,1426,1428,1430,1432],{"class":229,"line":936},[227,1427,363],{"class":278},[227,1429,366],{"class":248},[227,1431,370],{"class":369},[227,1433,373],{"class":248},[227,1435,1437,1439,1441,1443,1445,1447,1449,1451,1453],{"class":229,"line":1436},19,[227,1438,379],{"class":278},[227,1440,366],{"class":248},[227,1442,384],{"class":240},[227,1444,245],{"class":278},[227,1446,389],{"class":248},[227,1448,393],{"class":392},[227,1450,389],{"class":248},[227,1452,398],{"class":278},[227,1454,373],{"class":248},[227,1456,1458],{"class":229,"line":1457},20,[227,1459,406],{"class":248},[227,1461,1463],{"class":229,"line":1462},21,[227,1464,412],{"class":248},[227,1466,1468,1470,1472],{"class":229,"line":1467},22,[227,1469,418],{"class":248},[227,1471,398],{"class":244},[227,1473,300],{"class":248},[183,1475,1476],{},"Usage:",[217,1478,1481],{"className":219,"code":1479,"filename":1480,"language":222,"meta":223,"style":223},"export default defineController(\n  async ({ req }) => {\n    return useService('candidate.deleteMany')(req.body.ids);\n  },\n  {\n    permissions: ['candidate.delete'],\n  },\n);\n","server\u002Fcontrollers\u002Fcandidates\u002Findex.delete.ts",[193,1482,1483,1493,1509,1544,1548,1552,1571,1575],{"__ignoreMap":223},[227,1484,1485,1487,1489,1491],{"class":229,"line":230},[227,1486,234],{"class":233},[227,1488,237],{"class":233},[227,1490,638],{"class":240},[227,1492,641],{"class":244},[227,1494,1495,1497,1500,1503,1505,1507],{"class":229,"line":272},[227,1496,646],{"class":265},[227,1498,1499],{"class":248}," ({",[227,1501,1502],{"class":252}," req",[227,1504,262],{"class":248},[227,1506,266],{"class":265},[227,1508,269],{"class":248},[227,1510,1511,1513,1515,1517,1519,1522,1524,1527,1530,1532,1535,1537,1540,1542],{"class":229,"line":303},[227,1512,355],{"class":233},[227,1514,660],{"class":240},[227,1516,245],{"class":278},[227,1518,389],{"class":248},[227,1520,1521],{"class":392},"candidate.deleteMany",[227,1523,389],{"class":248},[227,1525,1526],{"class":278},")(",[227,1528,1529],{"class":244},"req",[227,1531,288],{"class":248},[227,1533,1534],{"class":244},"body",[227,1536,288],{"class":248},[227,1538,1539],{"class":244},"ids",[227,1541,398],{"class":278},[227,1543,300],{"class":248},[227,1545,1546],{"class":229,"line":310},[227,1547,679],{"class":248},[227,1549,1550],{"class":229,"line":352},[227,1551,684],{"class":248},[227,1553,1554,1556,1558,1560,1562,1565,1567,1569],{"class":229,"line":360},[227,1555,1237],{"class":278},[227,1557,366],{"class":248},[227,1559,693],{"class":244},[227,1561,389],{"class":248},[227,1563,1564],{"class":392},"candidate.delete",[227,1566,389],{"class":248},[227,1568,703],{"class":244},[227,1570,373],{"class":248},[227,1572,1573],{"class":229,"line":376},[227,1574,679],{"class":248},[227,1576,1577,1579],{"class":229,"line":403},[227,1578,398],{"class":244},[227,1580,300],{"class":248},[205,1582,1584],{"id":1583},"guard-return-value","Guard Return Value",[183,1586,1587],{},"A guard can either allow the request to continue or block it.",[1589,1590,1591,1605],"table",{},[1592,1593,1594],"thead",{},[1595,1596,1597,1602],"tr",{},[1598,1599,1601],"th",{"align":1600},"left","Return Value",[1598,1603,1604],{"align":1600},"Behavior",[1606,1607,1608,1619,1628],"tbody",{},[1595,1609,1610,1616],{},[1611,1612,1613],"td",{},[193,1614,1615],{},"undefined",[1611,1617,1618],{},"The request continues.",[1595,1620,1621,1626],{},[1611,1622,1623],{},[193,1624,1625],{},"{ pass: true }",[1611,1627,1618],{},[1595,1629,1630,1635],{},[1611,1631,1632],{},[193,1633,1634],{},"{ pass: false, errorMessage: string }",[1611,1636,1637],{},"The request is blocked with an error message.",[205,1639,1641],{"id":1640},"runtime-discovery","Runtime Discovery",[183,1643,1644],{},"During startup, OpenSya automatically:",[1646,1647,1648,1651,1654,1657,1660],"ol",{},[443,1649,1650],{},"Discovers guard files",[443,1652,1653],{},"Registers guards in the generated backend runtime",[443,1655,1656],{},"Resolves controller options",[443,1658,1659],{},"Executes guards before controller handlers",[443,1661,1662],{},"Blocks or allows requests based on guard results",[217,1664,1669],{"className":1665,"code":1666,"filename":1667,"language":1668,"meta":223,"style":223},"language-txt shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Filesystem Discovery\n        ↓\nGuard Registration\n        ↓\nController Option Resolution\n        ↓\nGuard Execution\n        ↓\nController Execution\n","Runtime Lifecycle","txt",[193,1670,1671,1676,1681,1686,1690,1695,1699,1704,1708],{"__ignoreMap":223},[227,1672,1673],{"class":229,"line":230},[227,1674,1675],{},"Filesystem Discovery\n",[227,1677,1678],{"class":229,"line":272},[227,1679,1680],{},"        ↓\n",[227,1682,1683],{"class":229,"line":303},[227,1684,1685],{},"Guard Registration\n",[227,1687,1688],{"class":229,"line":310},[227,1689,1680],{},[227,1691,1692],{"class":229,"line":352},[227,1693,1694],{},"Controller Option Resolution\n",[227,1696,1697],{"class":229,"line":360},[227,1698,1680],{},[227,1700,1701],{"class":229,"line":376},[227,1702,1703],{},"Guard Execution\n",[227,1705,1706],{"class":229,"line":403},[227,1707,1680],{},[227,1709,1710],{"class":229,"line":409},[227,1711,1712],{},"Controller Execution\n",[205,1714,1716],{"id":1715},"best-practices","Best Practices",[183,1718,1719],{},"Keep guards focused on access control.",[183,1721,1722],{},"A guard should usually answer one question:",[1724,1725,1726],"blockquote",{},[183,1727,1728],{},"Is this request allowed to continue?",[183,1730,1731],{},"Avoid putting business workflows inside guards. Business logic should usually live in services.",[183,1733,1734],{},"Good guard responsibilities include:",[440,1736,1737,1740,1743,1746,1749],{},[443,1738,1739],{},"Authentication checks",[443,1741,1742],{},"Role validation",[443,1744,1745],{},"Permission validation",[443,1747,1748],{},"Ownership checks",[443,1750,1751],{},"Request-level access rules",[198,1753,1754],{"color":718,"icon":86},[183,1755,1756],{},"Use guards for access decisions and services for business logic.",[205,1758,1760],{"id":1759},"philosophy","Philosophy",[183,1762,1763],{},"Guards are part of the OpenSya runtime orchestration system.",[183,1765,1766],{},"They allow recruitment and business platforms to define reusable access rules without scattering authorization logic across controllers.",[183,1768,1769],{},"This keeps controllers thin, access control consistent and backend infrastructures easier to maintain at scale.",[1771,1772,1773],"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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":223,"searchDepth":230,"depth":272,"links":1775},[1776,1777,1778,1779,1780,1781,1782,1783,1784,1785],{"id":207,"depth":272,"text":208},{"id":431,"depth":272,"text":432},{"id":552,"depth":272,"text":553},{"id":725,"depth":272,"text":726},{"id":1047,"depth":272,"text":1048},{"id":1200,"depth":272,"text":1201},{"id":1583,"depth":272,"text":1584},{"id":1640,"depth":272,"text":1641},{"id":1715,"depth":272,"text":1716},{"id":1759,"depth":272,"text":1760},"Learn how to create runtime guards and access control rules in the OpenSya Nest runtime.","md",null,{},{"icon":81},{"title":78,"description":1786},"E5DmeRV-SE4QmK3UMt6GeE3BTfLZLrOlkYWK6Y2-gRU",[1794,1796],{"title":73,"path":74,"stem":75,"description":1795,"icon":76,"children":-1},"Learn how to define HTTP controllers with the OpenSya Nest runtime.",{"title":83,"path":84,"stem":85,"description":1797,"icon":86,"children":-1},"Learn how to define reusable business logic with the OpenSya Nest runtime.",1779143767266]