[{"data":1,"prerenderedAt":2146},["ShallowReactive",2],{"navigation:en":3,"\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frbac:en":311},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Nuxfire Docs","\u002Fdocs","docs\u002F0.index",[9,11,152],{"title":5,"path":6,"stem":7,"icon":10},"i-lucide-layout-grid",{"title":12,"path":13,"stem":14,"children":15,"icon":151},"SaaS Starter Kit","\u002Fdocs\u002Fsaas-starter-kit","docs\u002F1.saas-starter-kit\u002F0.index",[16,19,63,129],{"title":17,"path":13,"stem":14,"icon":18},"What is the SaaS Starter Kit?","i-lucide-info",{"title":20,"icon":21,"hide":22,"path":23,"stem":24,"children":25,"page":62},"Getting Started","i-lucide-play",true,"\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started","docs\u002F1.saas-starter-kit\u002F1.getting-started",[26,30,34,38,42,46,50,54,58],{"title":27,"path":28,"stem":29},"Quick Start","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fquick-start","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F0.quick-start",{"title":31,"path":32,"stem":33},"Installation","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Finstallation","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F1.installation",{"title":35,"path":36,"stem":37},"Cloudflare Access","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fcloudflare-access","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F2.cloudflare-access",{"title":39,"path":40,"stem":41},"Configuration","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fconfiguration","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F3.configuration",{"title":43,"path":44,"stem":45},"Secrets","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fsecrets","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F4.secrets",{"title":47,"path":48,"stem":49},"Environment Variables","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fenvironment-variables","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F5.environment-variables",{"title":51,"path":52,"stem":53},"Deploy","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fdeploy","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F6.deploy",{"title":55,"path":56,"stem":57},"Local Development","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Flocal-development","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F7.local-development",{"title":59,"path":60,"stem":61},"Project Structure","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fproject-structure","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F8.project-structure",false,{"title":64,"icon":65,"hide":22,"path":66,"stem":67,"children":68,"page":62},"Features","i-lucide-box","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures","docs\u002F1.saas-starter-kit\u002F2.features",[69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":70,"path":71,"stem":72},"Authentication","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fauth","docs\u002F1.saas-starter-kit\u002F2.features\u002F1.auth",{"title":74,"path":75,"stem":76},"Rate Limiting","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frate-limiting","docs\u002F1.saas-starter-kit\u002F2.features\u002F10.rate-limiting",{"title":78,"path":79,"stem":80},"WebSockets","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fwebsockets","docs\u002F1.saas-starter-kit\u002F2.features\u002F11.websockets",{"title":82,"path":83,"stem":84},"Blog","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fblog","docs\u002F1.saas-starter-kit\u002F2.features\u002F14.blog",{"title":86,"path":87,"stem":88},"Documentation","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdocumentation","docs\u002F1.saas-starter-kit\u002F2.features\u002F15.documentation",{"title":90,"path":91,"stem":92},"Analytics","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fanalytics","docs\u002F1.saas-starter-kit\u002F2.features\u002F16.analytics",{"title":94,"path":95,"stem":96},"Platform Admin Console","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fplatform-admin","docs\u002F1.saas-starter-kit\u002F2.features\u002F17.platform-admin",{"title":98,"path":99,"stem":100},"Database","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdatabase","docs\u002F1.saas-starter-kit\u002F2.features\u002F2.database",{"title":102,"path":103,"stem":104},"Payments & Billing","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fpayments","docs\u002F1.saas-starter-kit\u002F2.features\u002F3.payments",{"title":106,"path":107,"stem":108},"Emails","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Femails","docs\u002F1.saas-starter-kit\u002F2.features\u002F4.emails",{"title":110,"path":111,"stem":112},"Notifications","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fnotifications","docs\u002F1.saas-starter-kit\u002F2.features\u002F5.notifications",{"title":114,"path":115,"stem":116},"Role-Based Access Control","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frbac","docs\u002F1.saas-starter-kit\u002F2.features\u002F6.rbac",{"title":118,"path":119,"stem":120},"Async Jobs","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fasync-jobs","docs\u002F1.saas-starter-kit\u002F2.features\u002F7.async-jobs",{"title":122,"path":123,"stem":124},"Storage","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fstorage","docs\u002F1.saas-starter-kit\u002F2.features\u002F8.storage",{"title":126,"path":127,"stem":128},"Internationalization","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Finternationalization","docs\u002F1.saas-starter-kit\u002F2.features\u002F9.internationalization",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":62},"Concepts","i-lucide-graduation-cap","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts","docs\u002F1.saas-starter-kit\u002F3.concepts",[135,139,143,147],{"title":136,"path":137,"stem":138},"Technology Stack","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Ftech-stack","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F0.tech-stack",{"title":140,"path":141,"stem":142},"SST.dev","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fsst","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F1.sst",{"title":144,"path":145,"stem":146},"NuxtHub","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fnuxt-hub","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F2.nuxt-hub",{"title":148,"path":149,"stem":150},"Design System & Branding","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fdesign-system","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F3.design-system","i-lucide-zap",{"title":153,"path":154,"stem":155,"children":156,"icon":159},"Fireskills","\u002Fdocs\u002Ffireskills","docs\u002F2.fireskills\u002F0.index",[157,160,219,249,275,293],{"title":158,"path":154,"stem":155,"icon":159},"What is Fireskills?","i-lucide-flame",{"title":20,"icon":21,"hide":22,"path":161,"stem":162,"children":163,"page":62},"\u002Fdocs\u002Ffireskills\u002Fgetting-started","docs\u002F2.fireskills\u002F1.getting-started",[164,167,171,175,179,183,187,191,195,199,203,207,211,215],{"title":27,"path":165,"stem":166},"\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fquick-start","docs\u002F2.fireskills\u002F1.getting-started\u002F00.quick-start",{"title":168,"path":169,"stem":170},"Workflow & Governance","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fworkflow","docs\u002F2.fireskills\u002F1.getting-started\u002F01.workflow",{"title":172,"path":173,"stem":174},"Project Context","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fproject-context","docs\u002F2.fireskills\u002F1.getting-started\u002F02.project-context",{"title":176,"path":177,"stem":178},"Step 0: Setup","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-setup","docs\u002F2.fireskills\u002F1.getting-started\u002F03.step-setup",{"title":180,"path":181,"stem":182},"Step 1: Inbox","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-inbox","docs\u002F2.fireskills\u002F1.getting-started\u002F04.step-inbox",{"title":184,"path":185,"stem":186},"Step 2: Backlog","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-backlog","docs\u002F2.fireskills\u002F1.getting-started\u002F05.step-backlog",{"title":188,"path":189,"stem":190},"Step 3: Specify","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-specify","docs\u002F2.fireskills\u002F1.getting-started\u002F06.step-specify",{"title":192,"path":193,"stem":194},"Step 4: Validate","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-validate","docs\u002F2.fireskills\u002F1.getting-started\u002F07.step-validate",{"title":196,"path":197,"stem":198},"Step 5: Tasks","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tasks","docs\u002F2.fireskills\u002F1.getting-started\u002F08.step-tasks",{"title":200,"path":201,"stem":202},"Step 6: TDD\u002FBDD","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tdd-bdd","docs\u002F2.fireskills\u002F1.getting-started\u002F09.step-tdd-bdd",{"title":204,"path":205,"stem":206},"Step 7: Implement","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-implement","docs\u002F2.fireskills\u002F1.getting-started\u002F10.step-implement",{"title":208,"path":209,"stem":210},"Step 8: Documentator","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-documentator","docs\u002F2.fireskills\u002F1.getting-started\u002F11.step-documentator",{"title":212,"path":213,"stem":214},"Late Changes","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Flate-changes","docs\u002F2.fireskills\u002F1.getting-started\u002F12.late-changes",{"title":216,"path":217,"stem":218},"Other Entry Points","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fother-entry-points","docs\u002F2.fireskills\u002F1.getting-started\u002F13.other-entry-points",{"title":220,"icon":221,"hide":22,"path":222,"stem":223,"children":224,"page":62},"Methodology","i-lucide-git-branch","\u002Fdocs\u002Ffireskills\u002Fmethodology","docs\u002F2.fireskills\u002F2.methodology",[225,229,233,237,241,245],{"title":226,"path":227,"stem":228},"The Three Acts","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-acts","docs\u002F2.fireskills\u002F2.methodology\u002F0.three-acts",{"title":230,"path":231,"stem":232},"The Three Gates","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-gates","docs\u002F2.fireskills\u002F2.methodology\u002F1.three-gates",{"title":234,"path":235,"stem":236},"The Canonical Spec","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fcanonical-spec","docs\u002F2.fireskills\u002F2.methodology\u002F2.canonical-spec",{"title":238,"path":239,"stem":240},"Lifecycle States","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Flifecycle-states","docs\u002F2.fireskills\u002F2.methodology\u002F3.lifecycle-states",{"title":242,"path":243,"stem":244},"Effort Scale","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Feffort-scale","docs\u002F2.fireskills\u002F2.methodology\u002F4.effort-scale",{"title":246,"path":247,"stem":248},"Milestones & Governance","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fgovernance-and-milestones","docs\u002F2.fireskills\u002F2.methodology\u002F5.governance-and-milestones",{"title":250,"icon":251,"hide":22,"path":252,"stem":253,"children":254,"page":62},"Skills","i-lucide-layers","\u002Fdocs\u002Ffireskills\u002Fskills","docs\u002F2.fireskills\u002F3.skills",[255,259,263,267,271],{"title":256,"path":257,"stem":258},"Catalog","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fcatalog","docs\u002F2.fireskills\u002F3.skills\u002F0.catalog",{"title":260,"path":261,"stem":262},"Act I: Define","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-1-define","docs\u002F2.fireskills\u002F3.skills\u002F1.act-1-define",{"title":264,"path":265,"stem":266},"Act II: Design & Prove","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-2-design-prove","docs\u002F2.fireskills\u002F3.skills\u002F2.act-2-design-prove",{"title":268,"path":269,"stem":270},"Act III: Deliver","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-3-deliver","docs\u002F2.fireskills\u002F3.skills\u002F3.act-3-deliver",{"title":272,"path":273,"stem":274},"Governance & Decisions","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fgovernance-and-decisions","docs\u002F2.fireskills\u002F3.skills\u002F4.governance-and-decisions",{"title":276,"icon":277,"hide":22,"path":278,"stem":279,"children":280,"page":62},"Specialists","i-lucide-sparkles","\u002Fdocs\u002Ffireskills\u002Fspecialists","docs\u002F2.fireskills\u002F4.specialists",[281,285,289],{"title":282,"path":283,"stem":284},"Overview","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Foverview","docs\u002F2.fireskills\u002F4.specialists\u002F0.overview",{"title":286,"path":287,"stem":288},"Nuxfire Stack","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fnuxfire-stack","docs\u002F2.fireskills\u002F4.specialists\u002F1.nuxfire-stack",{"title":290,"path":291,"stem":292},"Engineering Specialists","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fengineering-specialists","docs\u002F2.fireskills\u002F4.specialists\u002F2.engineering-specialists",{"title":294,"icon":295,"hide":22,"path":296,"stem":297,"children":298,"page":62},"CLI & Tooling","i-lucide-terminal","\u002Fdocs\u002Ffireskills\u002Fcli","docs\u002F2.fireskills\u002F5.cli",[299,303,307],{"title":300,"path":301,"stem":302},"CLI Overview","\u002Fdocs\u002Ffireskills\u002Fcli\u002Foverview","docs\u002F2.fireskills\u002F5.cli\u002F0.overview",{"title":304,"path":305,"stem":306},"Commands","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fcommands","docs\u002F2.fireskills\u002F5.cli\u002F1.commands",{"title":308,"path":309,"stem":310},"Safety Scripts","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fgovernance-scripts","docs\u002F2.fireskills\u002F5.cli\u002F2.governance-scripts",{"id":312,"title":114,"body":313,"description":2141,"extension":2142,"meta":2143,"navigation":22,"path":115,"seo":2144,"stem":116,"__hash__":2145},"docs\u002Fdocs\u002F1.saas-starter-kit\u002F2.features\u002F6.rbac.md",{"type":314,"value":315,"toc":2134},"minimark",[316,331,336,364,368,1147,1151,1181,1532,1536,1542,1767,1771,1817,2120,2130],[317,318,319,320,330],"p",{},"Nuxfire's RBAC is built on ",[321,322,326],"a",{"href":323,"rel":324},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fnuxt-authorization",[325],"nofollow",[327,328,329],"code",{},"nuxt-authorization"," (a Bouncer-style ability system) with Drizzle and tRPC. There is no Prisma anywhere in this stack — every query, in this feature and every other, goes through Drizzle.",[332,333,335],"h2",{"id":334},"whats-included","What's Included",[337,338,339,343,350,357],"ul",{},[340,341,342],"li",{},"Team-scoped permissions — a role only ever grants access within one team.",[340,344,345,346,349],{},"System roles (",[327,347,348],{},"isSystemRole",") shared across all teams, alongside teams' own custom roles.",[340,351,352,353,356],{},"A default role (",[327,354,355],{},"isDefault",") new members are assigned automatically.",[340,358,359,360,363],{},"Server-side authorization in tRPC, mirrored client-side with a ",[327,361,362],{},"\u003CCan>"," component.",[332,365,367],{"id":366},"schema","Schema",[369,370,376],"pre",{"className":371,"code":372,"filename":373,"language":374,"meta":375,"style":375},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark monokai","export const roles = pgTable(\"Role\", {\n  id: text(\"id\").$default(() => cuid()).primaryKey().notNull(),\n  teamId: text(\"teamId\"), \u002F\u002F null = system role, shared across every team\n  name: text(\"name\").notNull(),\n  description: text(\"description\"),\n  isSystemRole: boolean(\"isSystemRole\").default(false).notNull(),\n  isDefault: boolean(\"isDefault\").default(false).notNull(),\n  \u002F\u002F ...timestamps\n});\n\nexport const permissions = pgTable(\n  \"Permission\",\n  {\n    title: text(\"title\").notNull(),\n    description: text(\"description\"),\n    action: text(\"action\").notNull(),\n    roleId: text(\"roleId\").notNull().references(() => roles.id),\n    \u002F\u002F ...timestamps\n  },\n  (table) => [primaryKey({ columns: [table.action, table.roleId] })],\n);\n\nexport const teamMemberships = pgTable(\n  \"TeamMembership\",\n  {\n    id: text(\"id\").$default(() => cuid()).primaryKey().notNull(),\n    teamId: text(\"teamId\").notNull(),\n    userId: text(\"userId\").notNull(),\n    roleId: text(\"roleId\").notNull().references(() => roles.id),\n    \u002F\u002F ...timestamps\n  },\n  (table) => [unique().on(table.teamId, table.userId)],\n);\n","layers\u002Fteams\u002Fserver\u002Fdatabase\u002Fschema.ts","typescript","",[327,377,378,424,486,513,542,565,607,645,651,662,668,685,698,704,733,755,784,831,837,843,896,903,908,924,936,941,989,1017,1046,1089,1094,1099,1140],{"__ignoreMap":375},[379,380,383,387,391,395,399,403,407,411,415,417,421],"span",{"class":381,"line":382},"line",1,[379,384,386],{"class":385},"sRxSC","export",[379,388,390],{"class":389},"srJo8"," const",[379,392,394],{"class":393},"s91G_"," roles",[379,396,398],{"class":397},"sGXK2"," =",[379,400,402],{"class":401},"sD0ED"," pgTable",[379,404,406],{"class":405},"ss--_","(",[379,408,410],{"class":409},"siCPE","\"",[379,412,414],{"class":413},"sLACW","Role",[379,416,410],{"class":409},[379,418,420],{"class":419},"swvn1",",",[379,422,423],{"class":419}," {\n",[379,425,427,431,434,437,439,441,444,446,449,452,455,457,460,463,466,469,471,474,476,478,481,483],{"class":381,"line":426},2,[379,428,430],{"class":429},"squCx","  id",[379,432,433],{"class":419},":",[379,435,436],{"class":401}," text",[379,438,406],{"class":405},[379,440,410],{"class":409},[379,442,443],{"class":413},"id",[379,445,410],{"class":409},[379,447,448],{"class":405},")",[379,450,451],{"class":419},".",[379,453,454],{"class":401},"$default",[379,456,406],{"class":405},[379,458,459],{"class":419},"()",[379,461,462],{"class":389}," =>",[379,464,465],{"class":401}," cuid",[379,467,468],{"class":405},"())",[379,470,451],{"class":419},[379,472,473],{"class":401},"primaryKey",[379,475,459],{"class":405},[379,477,451],{"class":419},[379,479,480],{"class":401},"notNull",[379,482,459],{"class":405},[379,484,485],{"class":419},",\n",[379,487,489,492,494,496,498,500,503,505,507,509],{"class":381,"line":488},3,[379,490,491],{"class":429},"  teamId",[379,493,433],{"class":419},[379,495,436],{"class":401},[379,497,406],{"class":405},[379,499,410],{"class":409},[379,501,502],{"class":413},"teamId",[379,504,410],{"class":409},[379,506,448],{"class":405},[379,508,420],{"class":419},[379,510,512],{"class":511},"ss7Ak"," \u002F\u002F null = system role, shared across every team\n",[379,514,516,519,521,523,525,527,530,532,534,536,538,540],{"class":381,"line":515},4,[379,517,518],{"class":429},"  name",[379,520,433],{"class":419},[379,522,436],{"class":401},[379,524,406],{"class":405},[379,526,410],{"class":409},[379,528,529],{"class":413},"name",[379,531,410],{"class":409},[379,533,448],{"class":405},[379,535,451],{"class":419},[379,537,480],{"class":401},[379,539,459],{"class":405},[379,541,485],{"class":419},[379,543,545,548,550,552,554,556,559,561,563],{"class":381,"line":544},5,[379,546,547],{"class":429},"  description",[379,549,433],{"class":419},[379,551,436],{"class":401},[379,553,406],{"class":405},[379,555,410],{"class":409},[379,557,558],{"class":413},"description",[379,560,410],{"class":409},[379,562,448],{"class":405},[379,564,485],{"class":419},[379,566,568,571,573,576,578,580,582,584,586,588,591,593,597,599,601,603,605],{"class":381,"line":567},6,[379,569,570],{"class":429},"  isSystemRole",[379,572,433],{"class":419},[379,574,575],{"class":401}," boolean",[379,577,406],{"class":405},[379,579,410],{"class":409},[379,581,348],{"class":413},[379,583,410],{"class":409},[379,585,448],{"class":405},[379,587,451],{"class":419},[379,589,590],{"class":401},"default",[379,592,406],{"class":405},[379,594,596],{"class":595},"s8HiA","false",[379,598,448],{"class":405},[379,600,451],{"class":419},[379,602,480],{"class":401},[379,604,459],{"class":405},[379,606,485],{"class":419},[379,608,610,613,615,617,619,621,623,625,627,629,631,633,635,637,639,641,643],{"class":381,"line":609},7,[379,611,612],{"class":429},"  isDefault",[379,614,433],{"class":419},[379,616,575],{"class":401},[379,618,406],{"class":405},[379,620,410],{"class":409},[379,622,355],{"class":413},[379,624,410],{"class":409},[379,626,448],{"class":405},[379,628,451],{"class":419},[379,630,590],{"class":401},[379,632,406],{"class":405},[379,634,596],{"class":595},[379,636,448],{"class":405},[379,638,451],{"class":419},[379,640,480],{"class":401},[379,642,459],{"class":405},[379,644,485],{"class":419},[379,646,648],{"class":381,"line":647},8,[379,649,650],{"class":511},"  \u002F\u002F ...timestamps\n",[379,652,654,657,659],{"class":381,"line":653},9,[379,655,656],{"class":419},"}",[379,658,448],{"class":405},[379,660,661],{"class":419},";\n",[379,663,665],{"class":381,"line":664},10,[379,666,667],{"emptyLinePlaceholder":22},"\n",[379,669,671,673,675,678,680,682],{"class":381,"line":670},11,[379,672,386],{"class":385},[379,674,390],{"class":389},[379,676,677],{"class":393}," permissions",[379,679,398],{"class":397},[379,681,402],{"class":401},[379,683,684],{"class":405},"(\n",[379,686,688,691,694,696],{"class":381,"line":687},12,[379,689,690],{"class":409},"  \"",[379,692,693],{"class":413},"Permission",[379,695,410],{"class":409},[379,697,485],{"class":419},[379,699,701],{"class":381,"line":700},13,[379,702,703],{"class":419},"  {\n",[379,705,707,710,712,714,716,718,721,723,725,727,729,731],{"class":381,"line":706},14,[379,708,709],{"class":429},"    title",[379,711,433],{"class":419},[379,713,436],{"class":401},[379,715,406],{"class":405},[379,717,410],{"class":409},[379,719,720],{"class":413},"title",[379,722,410],{"class":409},[379,724,448],{"class":405},[379,726,451],{"class":419},[379,728,480],{"class":401},[379,730,459],{"class":405},[379,732,485],{"class":419},[379,734,736,739,741,743,745,747,749,751,753],{"class":381,"line":735},15,[379,737,738],{"class":429},"    description",[379,740,433],{"class":419},[379,742,436],{"class":401},[379,744,406],{"class":405},[379,746,410],{"class":409},[379,748,558],{"class":413},[379,750,410],{"class":409},[379,752,448],{"class":405},[379,754,485],{"class":419},[379,756,758,761,763,765,767,769,772,774,776,778,780,782],{"class":381,"line":757},16,[379,759,760],{"class":429},"    action",[379,762,433],{"class":419},[379,764,436],{"class":401},[379,766,406],{"class":405},[379,768,410],{"class":409},[379,770,771],{"class":413},"action",[379,773,410],{"class":409},[379,775,448],{"class":405},[379,777,451],{"class":419},[379,779,480],{"class":401},[379,781,459],{"class":405},[379,783,485],{"class":419},[379,785,787,790,792,794,796,798,801,803,805,807,809,811,813,816,818,820,822,824,826,829],{"class":381,"line":786},17,[379,788,789],{"class":429},"    roleId",[379,791,433],{"class":419},[379,793,436],{"class":401},[379,795,406],{"class":405},[379,797,410],{"class":409},[379,799,800],{"class":413},"roleId",[379,802,410],{"class":409},[379,804,448],{"class":405},[379,806,451],{"class":419},[379,808,480],{"class":401},[379,810,459],{"class":405},[379,812,451],{"class":419},[379,814,815],{"class":401},"references",[379,817,406],{"class":405},[379,819,459],{"class":419},[379,821,462],{"class":389},[379,823,394],{"class":405},[379,825,451],{"class":419},[379,827,828],{"class":405},"id)",[379,830,485],{"class":419},[379,832,834],{"class":381,"line":833},18,[379,835,836],{"class":511},"    \u002F\u002F ...timestamps\n",[379,838,840],{"class":381,"line":839},19,[379,841,842],{"class":419},"  },\n",[379,844,846,849,853,855,857,860,862,864,867,870,872,875,877,879,881,884,886,889,891,894],{"class":381,"line":845},20,[379,847,848],{"class":419},"  (",[379,850,852],{"class":851},"sQgqH","table",[379,854,448],{"class":419},[379,856,462],{"class":389},[379,858,859],{"class":405}," [",[379,861,473],{"class":401},[379,863,406],{"class":405},[379,865,866],{"class":419},"{",[379,868,869],{"class":429}," columns",[379,871,433],{"class":419},[379,873,874],{"class":405}," [table",[379,876,451],{"class":419},[379,878,771],{"class":405},[379,880,420],{"class":419},[379,882,883],{"class":405}," table",[379,885,451],{"class":419},[379,887,888],{"class":405},"roleId] ",[379,890,656],{"class":419},[379,892,893],{"class":405},")]",[379,895,485],{"class":419},[379,897,899,901],{"class":381,"line":898},21,[379,900,448],{"class":405},[379,902,661],{"class":419},[379,904,906],{"class":381,"line":905},22,[379,907,667],{"emptyLinePlaceholder":22},[379,909,911,913,915,918,920,922],{"class":381,"line":910},23,[379,912,386],{"class":385},[379,914,390],{"class":389},[379,916,917],{"class":393}," teamMemberships",[379,919,398],{"class":397},[379,921,402],{"class":401},[379,923,684],{"class":405},[379,925,927,929,932,934],{"class":381,"line":926},24,[379,928,690],{"class":409},[379,930,931],{"class":413},"TeamMembership",[379,933,410],{"class":409},[379,935,485],{"class":419},[379,937,939],{"class":381,"line":938},25,[379,940,703],{"class":419},[379,942,944,947,949,951,953,955,957,959,961,963,965,967,969,971,973,975,977,979,981,983,985,987],{"class":381,"line":943},26,[379,945,946],{"class":429},"    id",[379,948,433],{"class":419},[379,950,436],{"class":401},[379,952,406],{"class":405},[379,954,410],{"class":409},[379,956,443],{"class":413},[379,958,410],{"class":409},[379,960,448],{"class":405},[379,962,451],{"class":419},[379,964,454],{"class":401},[379,966,406],{"class":405},[379,968,459],{"class":419},[379,970,462],{"class":389},[379,972,465],{"class":401},[379,974,468],{"class":405},[379,976,451],{"class":419},[379,978,473],{"class":401},[379,980,459],{"class":405},[379,982,451],{"class":419},[379,984,480],{"class":401},[379,986,459],{"class":405},[379,988,485],{"class":419},[379,990,992,995,997,999,1001,1003,1005,1007,1009,1011,1013,1015],{"class":381,"line":991},27,[379,993,994],{"class":429},"    teamId",[379,996,433],{"class":419},[379,998,436],{"class":401},[379,1000,406],{"class":405},[379,1002,410],{"class":409},[379,1004,502],{"class":413},[379,1006,410],{"class":409},[379,1008,448],{"class":405},[379,1010,451],{"class":419},[379,1012,480],{"class":401},[379,1014,459],{"class":405},[379,1016,485],{"class":419},[379,1018,1020,1023,1025,1027,1029,1031,1034,1036,1038,1040,1042,1044],{"class":381,"line":1019},28,[379,1021,1022],{"class":429},"    userId",[379,1024,433],{"class":419},[379,1026,436],{"class":401},[379,1028,406],{"class":405},[379,1030,410],{"class":409},[379,1032,1033],{"class":413},"userId",[379,1035,410],{"class":409},[379,1037,448],{"class":405},[379,1039,451],{"class":419},[379,1041,480],{"class":401},[379,1043,459],{"class":405},[379,1045,485],{"class":419},[379,1047,1049,1051,1053,1055,1057,1059,1061,1063,1065,1067,1069,1071,1073,1075,1077,1079,1081,1083,1085,1087],{"class":381,"line":1048},29,[379,1050,789],{"class":429},[379,1052,433],{"class":419},[379,1054,436],{"class":401},[379,1056,406],{"class":405},[379,1058,410],{"class":409},[379,1060,800],{"class":413},[379,1062,410],{"class":409},[379,1064,448],{"class":405},[379,1066,451],{"class":419},[379,1068,480],{"class":401},[379,1070,459],{"class":405},[379,1072,451],{"class":419},[379,1074,815],{"class":401},[379,1076,406],{"class":405},[379,1078,459],{"class":419},[379,1080,462],{"class":389},[379,1082,394],{"class":405},[379,1084,451],{"class":419},[379,1086,828],{"class":405},[379,1088,485],{"class":419},[379,1090,1092],{"class":381,"line":1091},30,[379,1093,836],{"class":511},[379,1095,1097],{"class":381,"line":1096},31,[379,1098,842],{"class":419},[379,1100,1102,1104,1106,1108,1110,1112,1115,1117,1119,1122,1125,1127,1129,1131,1133,1135,1138],{"class":381,"line":1101},32,[379,1103,848],{"class":419},[379,1105,852],{"class":851},[379,1107,448],{"class":419},[379,1109,462],{"class":389},[379,1111,859],{"class":405},[379,1113,1114],{"class":401},"unique",[379,1116,459],{"class":405},[379,1118,451],{"class":419},[379,1120,1121],{"class":401},"on",[379,1123,1124],{"class":405},"(table",[379,1126,451],{"class":419},[379,1128,502],{"class":405},[379,1130,420],{"class":419},[379,1132,883],{"class":405},[379,1134,451],{"class":419},[379,1136,1137],{"class":405},"userId)]",[379,1139,485],{"class":419},[379,1141,1143,1145],{"class":381,"line":1142},33,[379,1144,448],{"class":405},[379,1146,661],{"class":419},[332,1148,1150],{"id":1149},"defining-abilities","Defining Abilities",[317,1152,1153,1154,1157,1158,1161,1162,1164,1165,1168,1169,1172,1173,1176,1177,1180],{},"Abilities live in ",[327,1155,1156],{},"layers\u002Fteams\u002Fshared\u002Futils\u002Fabilities.ts"," — shared between client and server since it's under ",[327,1159,1160],{},"shared\u002F",", and defined with ",[327,1163,329],{},"'s ",[327,1166,1167],{},"defineAbility",". Every name is prefixed with the layer that owns it (",[327,1170,1171],{},"teams*",", ",[327,1174,1175],{},"kanban*","): Nuxt auto-imports every layer's ",[327,1178,1179],{},"shared\u002Futils\u002F"," into one flat namespace keyed by export name, so two layers exporting the same bare name would collide silently.",[369,1182,1184],{"className":371,"code":1183,"filename":1156,"language":374,"meta":375,"style":375},"import { PERMISSIONS } from \".\u002Fpermissions\";\n\nconst hasTeamPermission = (user: User | null, teamId: string, permission: string) =>\n  !!user?.teams?.includes(teamId) &&\n  (user?.permissions?.[teamId] || []).includes(permission);\n\nexport const teamsUpdateTeamDetails = defineAbility(\n  (user: User | null, teamId: string) =>\n    hasTeamPermission(user, teamId, PERMISSIONS.TEAMS.UPDATE),\n);\n\nexport const teamsRemoveMember = defineAbility(\n  (user: User | null, teamId: string, memberId?: string) =>\n    hasTeamPermission(user, teamId, PERMISSIONS.TEAMS.MEMBERS.REMOVE) &&\n    (!memberId || memberId !== user?.id), \u002F\u002F can't remove yourself\n);\n",[327,1185,1186,1213,1217,1271,1295,1325,1329,1345,1371,1401,1407,1411,1426,1462,1495,1526],{"__ignoreMap":375},[379,1187,1188,1191,1194,1197,1200,1203,1206,1209,1211],{"class":381,"line":382},[379,1189,1190],{"class":385},"import",[379,1192,1193],{"class":419}," {",[379,1195,1196],{"class":405}," PERMISSIONS",[379,1198,1199],{"class":419}," }",[379,1201,1202],{"class":385}," from",[379,1204,1205],{"class":409}," \"",[379,1207,1208],{"class":413},".\u002Fpermissions",[379,1210,410],{"class":409},[379,1212,661],{"class":419},[379,1214,1215],{"class":381,"line":426},[379,1216,667],{"emptyLinePlaceholder":22},[379,1218,1219,1222,1226,1228,1231,1234,1236,1240,1243,1247,1249,1252,1254,1257,1259,1262,1264,1266,1268],{"class":381,"line":488},[379,1220,1221],{"class":389},"const",[379,1223,1225],{"class":1224},"sh7YU"," hasTeamPermission",[379,1227,398],{"class":397},[379,1229,1230],{"class":419}," (",[379,1232,1233],{"class":851},"user",[379,1235,433],{"class":397},[379,1237,1239],{"class":1238},"sKvfc"," User",[379,1241,1242],{"class":397}," |",[379,1244,1246],{"class":1245},"s_MOj"," null",[379,1248,420],{"class":419},[379,1250,1251],{"class":851}," teamId",[379,1253,433],{"class":397},[379,1255,1256],{"class":1245}," string",[379,1258,420],{"class":419},[379,1260,1261],{"class":851}," permission",[379,1263,433],{"class":397},[379,1265,1256],{"class":1245},[379,1267,448],{"class":419},[379,1269,1270],{"class":389}," =>\n",[379,1272,1273,1276,1278,1281,1284,1286,1289,1292],{"class":381,"line":515},[379,1274,1275],{"class":397},"  !!",[379,1277,1233],{"class":405},[379,1279,1280],{"class":419},"?.",[379,1282,1283],{"class":405},"teams",[379,1285,1280],{"class":419},[379,1287,1288],{"class":401},"includes",[379,1290,1291],{"class":405},"(teamId) ",[379,1293,1294],{"class":397},"&&\n",[379,1296,1297,1300,1302,1305,1307,1310,1313,1316,1318,1320,1323],{"class":381,"line":544},[379,1298,1299],{"class":405},"  (user",[379,1301,1280],{"class":419},[379,1303,1304],{"class":405},"permissions",[379,1306,1280],{"class":419},[379,1308,1309],{"class":405},"[teamId] ",[379,1311,1312],{"class":397},"||",[379,1314,1315],{"class":405}," [])",[379,1317,451],{"class":419},[379,1319,1288],{"class":401},[379,1321,1322],{"class":405},"(permission)",[379,1324,661],{"class":419},[379,1326,1327],{"class":381,"line":567},[379,1328,667],{"emptyLinePlaceholder":22},[379,1330,1331,1333,1335,1338,1340,1343],{"class":381,"line":609},[379,1332,386],{"class":385},[379,1334,390],{"class":389},[379,1336,1337],{"class":393}," teamsUpdateTeamDetails",[379,1339,398],{"class":397},[379,1341,1342],{"class":401}," defineAbility",[379,1344,684],{"class":405},[379,1346,1347,1349,1351,1353,1355,1357,1359,1361,1363,1365,1367,1369],{"class":381,"line":647},[379,1348,848],{"class":419},[379,1350,1233],{"class":851},[379,1352,433],{"class":397},[379,1354,1239],{"class":1238},[379,1356,1242],{"class":397},[379,1358,1246],{"class":1245},[379,1360,420],{"class":419},[379,1362,1251],{"class":851},[379,1364,433],{"class":397},[379,1366,1256],{"class":1245},[379,1368,448],{"class":419},[379,1370,1270],{"class":389},[379,1372,1373,1376,1379,1381,1383,1385,1387,1389,1392,1394,1397,1399],{"class":381,"line":653},[379,1374,1375],{"class":401},"    hasTeamPermission",[379,1377,1378],{"class":405},"(user",[379,1380,420],{"class":419},[379,1382,1251],{"class":405},[379,1384,420],{"class":419},[379,1386,1196],{"class":393},[379,1388,451],{"class":419},[379,1390,1391],{"class":393},"TEAMS",[379,1393,451],{"class":419},[379,1395,1396],{"class":393},"UPDATE",[379,1398,448],{"class":405},[379,1400,485],{"class":419},[379,1402,1403,1405],{"class":381,"line":664},[379,1404,448],{"class":405},[379,1406,661],{"class":419},[379,1408,1409],{"class":381,"line":670},[379,1410,667],{"emptyLinePlaceholder":22},[379,1412,1413,1415,1417,1420,1422,1424],{"class":381,"line":687},[379,1414,386],{"class":385},[379,1416,390],{"class":389},[379,1418,1419],{"class":393}," teamsRemoveMember",[379,1421,398],{"class":397},[379,1423,1342],{"class":401},[379,1425,684],{"class":405},[379,1427,1428,1430,1432,1434,1436,1438,1440,1442,1444,1446,1448,1450,1453,1456,1458,1460],{"class":381,"line":700},[379,1429,848],{"class":419},[379,1431,1233],{"class":851},[379,1433,433],{"class":397},[379,1435,1239],{"class":1238},[379,1437,1242],{"class":397},[379,1439,1246],{"class":1245},[379,1441,420],{"class":419},[379,1443,1251],{"class":851},[379,1445,433],{"class":397},[379,1447,1256],{"class":1245},[379,1449,420],{"class":419},[379,1451,1452],{"class":851}," memberId",[379,1454,1455],{"class":397},"?:",[379,1457,1256],{"class":1245},[379,1459,448],{"class":419},[379,1461,1270],{"class":389},[379,1463,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1485,1487,1490,1493],{"class":381,"line":706},[379,1465,1375],{"class":401},[379,1467,1378],{"class":405},[379,1469,420],{"class":419},[379,1471,1251],{"class":405},[379,1473,420],{"class":419},[379,1475,1196],{"class":393},[379,1477,451],{"class":419},[379,1479,1391],{"class":393},[379,1481,451],{"class":419},[379,1483,1484],{"class":393},"MEMBERS",[379,1486,451],{"class":419},[379,1488,1489],{"class":393},"REMOVE",[379,1491,1492],{"class":405},") ",[379,1494,1294],{"class":397},[379,1496,1497,1500,1503,1506,1508,1511,1514,1517,1519,1521,1523],{"class":381,"line":735},[379,1498,1499],{"class":405},"    (",[379,1501,1502],{"class":397},"!",[379,1504,1505],{"class":405},"memberId ",[379,1507,1312],{"class":397},[379,1509,1510],{"class":405}," memberId ",[379,1512,1513],{"class":397},"!==",[379,1515,1516],{"class":405}," user",[379,1518,1280],{"class":419},[379,1520,828],{"class":405},[379,1522,420],{"class":419},[379,1524,1525],{"class":511}," \u002F\u002F can't remove yourself\n",[379,1527,1528,1530],{"class":381,"line":757},[379,1529,448],{"class":405},[379,1531,661],{"class":419},[332,1533,1535],{"id":1534},"using-in-components","Using in Components",[317,1537,1538,1539,1541],{},"The ",[327,1540,362],{}," component gates rendering the same way the ability gates the request:",[369,1543,1547],{"className":1544,"code":1545,"language":1546,"meta":375,"style":375},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark monokai","\u003Ctemplate>\n  \u003CCan :ability=\"sendInviteAbility\" :args=\"[team?.id || '']\">\n    \u003CUForm :schema=\"inviteSchema\" :state=\"inviteForm\" @submit=\"sendInvite\">\n      \u003C!-- invite form -->\n    \u003C\u002FUForm>\n  \u003C\u002FCan>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nimport { teamsSendInvite as sendInviteAbility } from \"@nuxfire\u002Flayer-teams\u002Fshared\u002Futils\u002Fabilities\";\n\u003C\u002Fscript>\n","vue",[327,1548,1549,1561,1619,1671,1676,1685,1694,1703,1707,1731,1759],{"__ignoreMap":375},[379,1550,1551,1554,1558],{"class":381,"line":382},[379,1552,1553],{"class":419},"\u003C",[379,1555,1557],{"class":1556},"sHsBP","template",[379,1559,1560],{"class":419},">\n",[379,1562,1563,1566,1569,1572,1576,1579,1582,1585,1587,1589,1592,1594,1596,1599,1602,1604,1606,1609,1612,1615,1617],{"class":381,"line":426},[379,1564,1565],{"class":419},"  \u003C",[379,1567,1568],{"class":1556},"Can",[379,1570,1571],{"class":419}," :",[379,1573,1575],{"class":1574},"s_lYk","ability",[379,1577,1578],{"class":419},"=",[379,1580,410],{"class":1581},"s00De",[379,1583,1584],{"class":405},"sendInviteAbility",[379,1586,410],{"class":1581},[379,1588,1571],{"class":419},[379,1590,1591],{"class":1574},"args",[379,1593,1578],{"class":419},[379,1595,410],{"class":1581},[379,1597,1598],{"class":419},"[",[379,1600,1601],{"class":405},"team",[379,1603,1280],{"class":419},[379,1605,443],{"class":405},[379,1607,1608],{"class":397}," ||",[379,1610,1611],{"class":409}," ''",[379,1613,1614],{"class":419},"]",[379,1616,410],{"class":1581},[379,1618,1560],{"class":419},[379,1620,1621,1624,1627,1629,1631,1633,1635,1638,1640,1642,1645,1647,1649,1652,1654,1657,1660,1662,1664,1667,1669],{"class":381,"line":488},[379,1622,1623],{"class":419},"    \u003C",[379,1625,1626],{"class":1556},"UForm",[379,1628,1571],{"class":419},[379,1630,366],{"class":1574},[379,1632,1578],{"class":419},[379,1634,410],{"class":1581},[379,1636,1637],{"class":405},"inviteSchema",[379,1639,410],{"class":1581},[379,1641,1571],{"class":419},[379,1643,1644],{"class":1574},"state",[379,1646,1578],{"class":419},[379,1648,410],{"class":1581},[379,1650,1651],{"class":405},"inviteForm",[379,1653,410],{"class":1581},[379,1655,1656],{"class":419}," @",[379,1658,1659],{"class":1574},"submit",[379,1661,1578],{"class":419},[379,1663,410],{"class":1581},[379,1665,1666],{"class":405},"sendInvite",[379,1668,410],{"class":1581},[379,1670,1560],{"class":419},[379,1672,1673],{"class":381,"line":515},[379,1674,1675],{"class":511},"      \u003C!-- invite form -->\n",[379,1677,1678,1681,1683],{"class":381,"line":544},[379,1679,1680],{"class":419},"    \u003C\u002F",[379,1682,1626],{"class":1556},[379,1684,1560],{"class":419},[379,1686,1687,1690,1692],{"class":381,"line":567},[379,1688,1689],{"class":419},"  \u003C\u002F",[379,1691,1568],{"class":1556},[379,1693,1560],{"class":419},[379,1695,1696,1699,1701],{"class":381,"line":609},[379,1697,1698],{"class":419},"\u003C\u002F",[379,1700,1557],{"class":1556},[379,1702,1560],{"class":419},[379,1704,1705],{"class":381,"line":647},[379,1706,667],{"emptyLinePlaceholder":22},[379,1708,1709,1711,1714,1717,1720,1722,1724,1727,1729],{"class":381,"line":653},[379,1710,1553],{"class":419},[379,1712,1713],{"class":1556},"script",[379,1715,1716],{"class":1574}," setup",[379,1718,1719],{"class":1574}," lang",[379,1721,1578],{"class":419},[379,1723,410],{"class":409},[379,1725,1726],{"class":413},"ts",[379,1728,410],{"class":409},[379,1730,1560],{"class":419},[379,1732,1733,1735,1737,1740,1743,1746,1748,1750,1752,1755,1757],{"class":381,"line":664},[379,1734,1190],{"class":385},[379,1736,1193],{"class":419},[379,1738,1739],{"class":405}," teamsSendInvite",[379,1741,1742],{"class":385}," as",[379,1744,1745],{"class":405}," sendInviteAbility",[379,1747,1199],{"class":419},[379,1749,1202],{"class":385},[379,1751,1205],{"class":409},[379,1753,1754],{"class":413},"@nuxfire\u002Flayer-teams\u002Fshared\u002Futils\u002Fabilities",[379,1756,410],{"class":409},[379,1758,661],{"class":419},[379,1760,1761,1763,1765],{"class":381,"line":670},[379,1762,1698],{"class":419},[379,1764,1713],{"class":1556},[379,1766,1560],{"class":419},[332,1768,1770],{"id":1769},"api-authorization","API Authorization",[317,1772,1773,1776,1777,1780,1781,1784,1785,1788,1789,1788,1792,1795,1796,1798,1799,1788,1801,1788,1803,1805,1806,1808,1809,1812,1813,1816],{},[327,1774,1775],{},"abilityProcedure"," (built on ",[327,1778,1779],{},"protectedProcedure"," in ",[327,1782,1783],{},"apps\u002Fapp\u002Fserver\u002Ftrpc\u002Ftrpc.ts",") adds ",[327,1786,1787],{},"authorize","\u002F",[327,1790,1791],{},"allows",[327,1793,1794],{},"denies"," to the tRPC context, backed by ",[327,1797,329],{},"'s own ",[327,1800,1787],{},[327,1802,1791],{},[327,1804,1794],{},". ",[327,1807,1787],{}," throws — a denial becomes a ",[327,1810,1811],{},"FORBIDDEN"," TRPCError and is logged (",[327,1814,1815],{},"console.warn(\"authz denied\", ...)",", visible in Cloudflare Workers Logs) before the error reaches the client:",[369,1818,1821],{"className":371,"code":1819,"filename":1820,"language":374,"meta":375,"style":375},"export default router({\n  list: abilityProcedure.query(async ({ ctx: { authorize, user } }) => {\n    await authorize(teamsListTeams);\n\n    const teams = await useDB().query.teams.findMany({\n      with: { memberships: { where: eq(teamMemberships.userId, user.id) } },\n      columns: { id: true, name: true, slug: true, description: true, logo: true },\n    });\n\n    return teams.filter((team) => team.memberships.length > 0);\n  }),\n});\n","layers\u002Fteams\u002Fserver\u002Ftrpc\u002Fteams.ts",[327,1822,1823,1838,1886,1902,1906,1941,1989,2044,2053,2057,2103,2112],{"__ignoreMap":375},[379,1824,1825,1827,1830,1833,1835],{"class":381,"line":382},[379,1826,386],{"class":385},[379,1828,1829],{"class":385}," default",[379,1831,1832],{"class":401}," router",[379,1834,406],{"class":405},[379,1836,1837],{"class":419},"{\n",[379,1839,1840,1843,1845,1848,1850,1853,1855,1859,1862,1866,1868,1870,1873,1875,1877,1879,1882,1884],{"class":381,"line":426},[379,1841,1842],{"class":429},"  list",[379,1844,433],{"class":419},[379,1846,1847],{"class":405}," abilityProcedure",[379,1849,451],{"class":419},[379,1851,1852],{"class":401},"query",[379,1854,406],{"class":405},[379,1856,1858],{"class":1857},"sTNss","async",[379,1860,1861],{"class":419}," ({",[379,1863,1865],{"class":1864},"sIDdj"," ctx",[379,1867,433],{"class":419},[379,1869,1193],{"class":419},[379,1871,1872],{"class":851}," authorize",[379,1874,420],{"class":419},[379,1876,1516],{"class":851},[379,1878,1199],{"class":419},[379,1880,1881],{"class":419}," })",[379,1883,462],{"class":389},[379,1885,423],{"class":419},[379,1887,1888,1891,1893,1895,1898,1900],{"class":381,"line":488},[379,1889,1890],{"class":385},"    await",[379,1892,1872],{"class":401},[379,1894,406],{"class":429},[379,1896,1897],{"class":405},"teamsListTeams",[379,1899,448],{"class":429},[379,1901,661],{"class":419},[379,1903,1904],{"class":381,"line":515},[379,1905,667],{"emptyLinePlaceholder":22},[379,1907,1908,1911,1914,1916,1919,1922,1924,1926,1928,1930,1932,1934,1937,1939],{"class":381,"line":544},[379,1909,1910],{"class":389},"    const",[379,1912,1913],{"class":393}," teams",[379,1915,398],{"class":397},[379,1917,1918],{"class":385}," await",[379,1920,1921],{"class":401}," useDB",[379,1923,459],{"class":429},[379,1925,451],{"class":419},[379,1927,1852],{"class":405},[379,1929,451],{"class":419},[379,1931,1283],{"class":405},[379,1933,451],{"class":419},[379,1935,1936],{"class":401},"findMany",[379,1938,406],{"class":429},[379,1940,1837],{"class":419},[379,1942,1943,1946,1948,1950,1953,1955,1957,1960,1962,1965,1967,1970,1972,1974,1976,1978,1980,1982,1984,1986],{"class":381,"line":567},[379,1944,1945],{"class":429},"      with",[379,1947,433],{"class":419},[379,1949,1193],{"class":419},[379,1951,1952],{"class":429}," memberships",[379,1954,433],{"class":419},[379,1956,1193],{"class":419},[379,1958,1959],{"class":429}," where",[379,1961,433],{"class":419},[379,1963,1964],{"class":401}," eq",[379,1966,406],{"class":429},[379,1968,1969],{"class":405},"teamMemberships",[379,1971,451],{"class":419},[379,1973,1033],{"class":405},[379,1975,420],{"class":419},[379,1977,1516],{"class":405},[379,1979,451],{"class":419},[379,1981,443],{"class":405},[379,1983,1492],{"class":429},[379,1985,656],{"class":419},[379,1987,1988],{"class":419}," },\n",[379,1990,1991,1994,1996,1998,2001,2003,2006,2008,2011,2013,2015,2017,2020,2022,2024,2026,2029,2031,2033,2035,2038,2040,2042],{"class":381,"line":609},[379,1992,1993],{"class":429},"      columns",[379,1995,433],{"class":419},[379,1997,1193],{"class":419},[379,1999,2000],{"class":429}," id",[379,2002,433],{"class":419},[379,2004,2005],{"class":595}," true",[379,2007,420],{"class":419},[379,2009,2010],{"class":429}," name",[379,2012,433],{"class":419},[379,2014,2005],{"class":595},[379,2016,420],{"class":419},[379,2018,2019],{"class":429}," slug",[379,2021,433],{"class":419},[379,2023,2005],{"class":595},[379,2025,420],{"class":419},[379,2027,2028],{"class":429}," description",[379,2030,433],{"class":419},[379,2032,2005],{"class":595},[379,2034,420],{"class":419},[379,2036,2037],{"class":429}," logo",[379,2039,433],{"class":419},[379,2041,2005],{"class":595},[379,2043,1988],{"class":419},[379,2045,2046,2049,2051],{"class":381,"line":647},[379,2047,2048],{"class":419},"    }",[379,2050,448],{"class":429},[379,2052,661],{"class":419},[379,2054,2055],{"class":381,"line":653},[379,2056,667],{"emptyLinePlaceholder":22},[379,2058,2059,2062,2064,2066,2069,2071,2073,2075,2077,2079,2082,2084,2087,2089,2092,2095,2099,2101],{"class":381,"line":664},[379,2060,2061],{"class":385},"    return",[379,2063,1913],{"class":405},[379,2065,451],{"class":419},[379,2067,2068],{"class":401},"filter",[379,2070,406],{"class":429},[379,2072,406],{"class":419},[379,2074,1601],{"class":851},[379,2076,448],{"class":419},[379,2078,462],{"class":389},[379,2080,2081],{"class":405}," team",[379,2083,451],{"class":419},[379,2085,2086],{"class":405},"memberships",[379,2088,451],{"class":419},[379,2090,2091],{"class":393},"length",[379,2093,2094],{"class":397}," >",[379,2096,2098],{"class":2097},"sYThS"," 0",[379,2100,448],{"class":429},[379,2102,661],{"class":419},[379,2104,2105,2108,2110],{"class":381,"line":670},[379,2106,2107],{"class":419},"  }",[379,2109,448],{"class":405},[379,2111,485],{"class":419},[379,2113,2114,2116,2118],{"class":381,"line":687},[379,2115,656],{"class":419},[379,2117,448],{"class":405},[379,2119,661],{"class":419},[317,2121,2122,2123,2126,2127,2129],{},"This is deliberately a separate procedure from ",[327,2124,2125],{},"platformAdminProcedure"," — see ",[321,2128,94],{"href":95},". Platform-owner authority is never routed through the tenant ability layer, so a tenant-scoped permission can never grant platform-scoped access.",[2131,2132,2133],"style",{},"html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .s91G_, html code.shiki .s91G_{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#F8F8F2}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .squCx, html code.shiki .squCx{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .s8HiA, html code.shiki .s8HiA{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sQgqH, html code.shiki .sQgqH{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-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);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sh7YU, html code.shiki .sh7YU{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sKvfc, html code.shiki .sKvfc{--shiki-light:#E2931D;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .s_MOj, html code.shiki .s_MOj{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sTNss, html code.shiki .sTNss{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sIDdj, html code.shiki .sIDdj{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sHsBP, html code.shiki .sHsBP{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D;--shiki-sepia:#F92672}html pre.shiki code .s_lYk, html code.shiki .s_lYk{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .s00De, html code.shiki .s00De{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#F8F8F2}",{"title":375,"searchDepth":426,"depth":426,"links":2135},[2136,2137,2138,2139,2140],{"id":334,"depth":426,"text":335},{"id":366,"depth":426,"text":367},{"id":1149,"depth":426,"text":1150},{"id":1534,"depth":426,"text":1535},{"id":1769,"depth":426,"text":1770},"Team-scoped RBAC using nuxt-authorization, Drizzle and tRPC — type-safe from the database to the UI.","md",{},{"title":114,"description":2141},"Zik5I6K9d_DKjWqmugbHJblbJhOYYmvY_esudGlTBRU",1790707485288]