[{"data":1,"prerenderedAt":3092},["ShallowReactive",2],{"navigation":3,"/docs/auth-security/standard-role-template":186,"/docs/auth-security/standard-role-template-surround":3087},[4],{"title":5,"path":6,"stem":7,"children":8,"page":39},"Docs","/docs","docs",[9,40,60,78,100,114,158],{"title":10,"path":11,"stem":12,"children":13,"page":39},"Guide","/docs/guide","docs/1.guide",[14,19,24,29,34],{"title":15,"path":16,"stem":17,"icon":18},"Getting Started","/docs/guide/get-started","docs/1.guide/1.get-started","i-lucide-rocket",{"title":20,"path":21,"stem":22,"icon":23},"Basics","/docs/guide/basics","docs/1.guide/2.basics","i-lucide-book-open",{"title":25,"path":26,"stem":27,"icon":28},"Authentication","/docs/guide/auth","docs/1.guide/3.auth","i-lucide-shield-check",{"title":30,"path":31,"stem":32,"icon":33},"Permissions","/docs/guide/permissions","docs/1.guide/4.permissions","i-lucide-shield",{"title":35,"path":36,"stem":37,"icon":38},"Core Concepts","/docs/guide/concepts","docs/1.guide/5.concepts","i-lucide-lightbulb",false,{"title":41,"path":42,"stem":43,"children":44,"page":39},"Data Fetching","/docs/data-fetching","docs/2.data-fetching",[45,50,55],{"title":46,"path":47,"stem":48,"icon":49},"Fetching Data","/docs/data-fetching/queries","docs/2.data-fetching/1.queries","i-lucide-database",{"title":51,"path":52,"stem":53,"icon":54},"Pagination","/docs/data-fetching/pagination","docs/2.data-fetching/2.pagination","i-lucide-list",{"title":56,"path":57,"stem":58,"icon":59},"Caching & Data Reuse","/docs/data-fetching/caching-reuse","docs/2.data-fetching/3.caching-reuse","i-lucide-database-zap",{"title":61,"path":62,"stem":63,"children":64,"page":39},"Mutations","/docs/mutations","docs/3.mutations",[65,69,74],{"title":61,"path":66,"stem":67,"icon":68},"/docs/mutations/mutations","docs/3.mutations/1.mutations","i-lucide-pen-tool",{"title":70,"path":71,"stem":72,"icon":73},"Actions","/docs/mutations/actions","docs/3.mutations/2.actions","i-lucide-zap",{"title":75,"path":76,"stem":77,"icon":73},"Optimistic Updates","/docs/mutations/optimistic-updates","docs/3.mutations/3.optimistic-updates",{"title":79,"path":80,"stem":81,"children":82,"page":39},"Auth Security","/docs/auth-security","docs/4.auth-security",[83,87,91,95],{"title":84,"path":85,"stem":86,"icon":28},"Permissions Setup","/docs/auth-security/permissions-setup","docs/4.auth-security/0.permissions-setup",{"title":25,"path":88,"stem":89,"icon":90},"/docs/auth-security/authentication","docs/4.auth-security/1.authentication","i-lucide-lock",{"title":92,"path":93,"stem":94,"icon":33},"Permissions Reference","/docs/auth-security/permissions","docs/4.auth-security/2.permissions",{"title":96,"path":97,"stem":98,"icon":99},"Standard Role Template","/docs/auth-security/standard-role-template","docs/4.auth-security/3.standard-role-template","i-lucide-file-check",{"title":101,"path":102,"stem":103,"children":104,"page":39},"Server Side","/docs/server-side","docs/5.server-side",[105,110],{"title":106,"path":107,"stem":108,"icon":109},"Server Routes","/docs/server-side/server-routes","docs/5.server-side/1.server-routes","i-lucide-server",{"title":111,"path":112,"stem":113,"icon":109},"SSR & Hydration","/docs/server-side/ssr-hydration","docs/5.server-side/2.ssr-hydration",{"title":115,"path":116,"stem":117,"children":118,"page":39},"Advanced","/docs/advanced","docs/6.advanced",[119,124,129,134,139,144,149,154],{"title":120,"path":121,"stem":122,"icon":123},"Connection State","/docs/advanced/connection-state","docs/6.advanced/1.connection-state","i-lucide-wifi",{"title":125,"path":126,"stem":127,"icon":128},"Client Access","/docs/advanced/client-access","docs/6.advanced/2.client-access","i-lucide-box",{"title":130,"path":131,"stem":132,"icon":133},"Performance","/docs/advanced/performance","docs/6.advanced/3.performance","i-lucide-gauge",{"title":135,"path":136,"stem":137,"icon":138},"Error Handling","/docs/advanced/error-handling","docs/6.advanced/4.error-handling","i-lucide-alert-circle",{"title":140,"path":141,"stem":142,"icon":143},"File Storage","/docs/advanced/file-storage","docs/6.advanced/5.file-storage","i-lucide-upload",{"title":145,"path":146,"stem":147,"icon":148},"Logging","/docs/advanced/logging","docs/6.advanced/6.logging","i-lucide-scroll-text",{"title":150,"path":151,"stem":152,"icon":153},"Module Configuration","/docs/advanced/module-config","docs/6.advanced/7.module-config","i-lucide-settings",{"title":155,"path":156,"stem":157,"icon":54},"API Surface","/docs/advanced/api-surface","docs/6.advanced/8.api-surface",{"title":159,"path":160,"stem":161,"children":162,"page":39},"Recipes","/docs/recipes","docs/7.recipes",[163,168,173,178,182],{"title":164,"path":165,"stem":166,"icon":167},"Protected Dashboard","/docs/recipes/protected-dashboard","docs/7.recipes/1.protected-dashboard","i-lucide-layout-dashboard",{"title":169,"path":170,"stem":171,"icon":172},"Real-Time Feed","/docs/recipes/realtime-feed","docs/7.recipes/2.realtime-feed","i-lucide-messages-square",{"title":174,"path":175,"stem":176,"icon":177},"User Augmentation","/docs/recipes/user-augmentation","docs/7.recipes/3.user-augmentation","i-lucide-user-round-cog",{"title":179,"path":180,"stem":181,"icon":28},"Auth Guards and Permissions","/docs/recipes/auth-guards-and-permissions","docs/7.recipes/4.auth-guards-and-permissions",{"title":183,"path":184,"stem":185,"icon":73},"Instant List → Detail Navigation","/docs/recipes/instant-list-detail-cache-reuse","docs/7.recipes/5.instant-list-detail-cache-reuse",{"id":187,"title":96,"body":188,"description":3079,"extension":3080,"links":3081,"meta":3082,"navigation":3083,"path":97,"seo":3084,"sitemap":3085,"stem":98,"__hash__":3086},"docs/docs/4.auth-security/3.standard-role-template.md",{"type":189,"value":190,"toc":3070},"minimark",[191,199,209,212,217,220,265,267,271,373,375,379,1666,1668,1672,2365,2367,2371,2682,2684,2688,2883,2886,3031,3033,3037,3066],[192,193,195],"callout",{"icon":194},"i-lucide-info",[196,197,198],"p",{},"Opinionated starter for fast adoption. Customize roles, resources, and checks to match your product.",[192,200,202],{"icon":201,"to":85},"i-lucide-book",[196,203,204,205,208],{},"Need the full walkthrough? See ",[206,207,84],"a",{"href":85},".",[210,211],"hr",{},[213,214,216],"h2",{"id":215},"what-you-get","What You Get",[196,218,219],{},"This scaffold gives you a canonical org-based model:",[221,222,223,241,248,255],"ul",{},[224,225,226,227,231,232,231,235,231,238],"li",{},"Roles: ",[228,229,230],"code",{},"owner",", ",[228,233,234],{},"admin",[228,236,237],{},"member",[228,239,240],{},"viewer",[224,242,243,244,247],{},"Shared ",[228,245,246],{},"checkPermission()"," logic for frontend + backend",[224,249,250,251,254],{},"Backend ",[228,252,253],{},"authorize()"," guard for mutations/actions",[224,256,257,258,261,262],{},"Frontend ",[228,259,260],{},"usePermissions()"," composable via ",[228,263,264],{},"createPermissions",[210,266],{},[213,268,270],{"id":269},"_1-enable-permission-helpers","1) Enable Permission Helpers",[272,273,279],"pre",{"className":274,"code":275,"filename":276,"language":277,"meta":278,"style":278},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  modules: ['better-convex-nuxt'],\n  convex: {\n    permissions: true,\n  },\n})\n","nuxt.config.ts","ts","",[228,280,281,305,333,344,358,364],{"__ignoreMap":278},[282,283,286,290,293,297,301],"span",{"class":284,"line":285},"line",1,[282,287,289],{"class":288},"s7zQu","export",[282,291,292],{"class":288}," default",[282,294,296],{"class":295},"s2Zo4"," defineNuxtConfig",[282,298,300],{"class":299},"sTEyZ","(",[282,302,304],{"class":303},"sMK4o","{\n",[282,306,308,312,315,318,321,325,327,330],{"class":284,"line":307},2,[282,309,311],{"class":310},"swJcz","  modules",[282,313,314],{"class":303},":",[282,316,317],{"class":299}," [",[282,319,320],{"class":303},"'",[282,322,324],{"class":323},"sfazB","better-convex-nuxt",[282,326,320],{"class":303},[282,328,329],{"class":299},"]",[282,331,332],{"class":303},",\n",[282,334,336,339,341],{"class":284,"line":335},3,[282,337,338],{"class":310},"  convex",[282,340,314],{"class":303},[282,342,343],{"class":303}," {\n",[282,345,347,350,352,356],{"class":284,"line":346},4,[282,348,349],{"class":310},"    permissions",[282,351,314],{"class":303},[282,353,355],{"class":354},"sfNiH"," true",[282,357,332],{"class":303},[282,359,361],{"class":284,"line":360},5,[282,362,363],{"class":303},"  },\n",[282,365,367,370],{"class":284,"line":366},6,[282,368,369],{"class":303},"}",[282,371,372],{"class":299},")\n",[210,374],{},[213,376,378],{"id":377},"_2-shared-permission-config","2) Shared Permission Config",[272,380,383],{"className":274,"code":381,"filename":382,"language":277,"meta":278,"style":278},"export const ROLES = ['owner', 'admin', 'member', 'viewer'] as const\nexport type Role = (typeof ROLES)[number]\n\nexport const permissions = {\n  global: {\n    'org.settings': { roles: ['owner'] },\n    'org.invite': { roles: ['owner', 'admin'] },\n    'org.members': { roles: ['owner', 'admin'] },\n  },\n  post: {\n    create: { roles: ['owner', 'admin', 'member'] },\n    read: { roles: ['owner', 'admin', 'member', 'viewer'] },\n    update: { own: ['member'], any: ['owner', 'admin'] },\n    delete: { own: ['member'], any: ['owner', 'admin'] },\n    publish: { roles: ['owner', 'admin'] },\n  },\n} as const\n\ntype GlobalPermission = keyof (typeof permissions)['global']\ntype PostPermission = `post.${keyof (typeof permissions)['post']}`\nexport type Permission = GlobalPermission | PostPermission\n\nexport interface PermissionContext {\n  role: Role\n  userId: string\n  organizationId: string | null\n}\n\nexport interface Resource {\n  ownerId?: string\n  organizationId?: string\n}\n\ntype PermissionRule = { roles: readonly Role[] } | { own: readonly Role[]; any: readonly Role[] }\n\nexport function checkPermission(\n  ctx: PermissionContext | null,\n  permission: Permission,\n  resource?: Resource,\n): boolean {\n  if (!ctx) return false\n\n  if (permission in permissions.global) {\n    const rule = permissions.global[permission as GlobalPermission]\n    return rule.roles.includes(ctx.role)\n  }\n\n  const [resourceType, action] = permission.split('.') as [string, string]\n  const resourcePerms = permissions[resourceType as keyof typeof permissions]\n  if (!resourcePerms || resourceType === 'global') return false\n\n  const rule = (resourcePerms as Record\u003Cstring, PermissionRule>)[action]\n  if (!rule) return false\n\n  if ('roles' in rule) {\n    return rule.roles.includes(ctx.role)\n  }\n\n  if (rule.any.includes(ctx.role)) return true\n\n  if (!resource?.ownerId) return false\n  return rule.own.includes(ctx.role) && resource.ownerId === ctx.userId\n}\n","convex/permissions.config.ts",[228,384,385,442,471,477,490,499,532,570,608,613,623,665,715,767,817,851,856,866,871,901,941,961,966,979,990,1001,1017,1023,1028,1040,1051,1060,1065,1070,1126,1131,1145,1163,1175,1187,1198,1221,1226,1250,1278,1307,1313,1318,1369,1396,1429,1434,1472,1490,1495,1516,1541,1546,1551,1585,1590,1614,1661],{"__ignoreMap":278},[282,386,387,389,393,396,399,401,403,405,407,410,413,415,417,419,421,423,425,427,429,431,433,436,439],{"class":284,"line":285},[282,388,289],{"class":288},[282,390,392],{"class":391},"spNyl"," const",[282,394,395],{"class":299}," ROLES ",[282,397,398],{"class":303},"=",[282,400,317],{"class":299},[282,402,320],{"class":303},[282,404,230],{"class":323},[282,406,320],{"class":303},[282,408,409],{"class":303},",",[282,411,412],{"class":303}," '",[282,414,234],{"class":323},[282,416,320],{"class":303},[282,418,409],{"class":303},[282,420,412],{"class":303},[282,422,237],{"class":323},[282,424,320],{"class":303},[282,426,409],{"class":303},[282,428,412],{"class":303},[282,430,240],{"class":323},[282,432,320],{"class":303},[282,434,435],{"class":299},"] ",[282,437,438],{"class":288},"as",[282,440,441],{"class":391}," const\n",[282,443,444,446,449,453,456,459,462,465,468],{"class":284,"line":307},[282,445,289],{"class":288},[282,447,448],{"class":391}," type",[282,450,452],{"class":451},"sBMFI"," Role",[282,454,455],{"class":303}," =",[282,457,458],{"class":299}," (",[282,460,461],{"class":303},"typeof",[282,463,464],{"class":299}," ROLES)[",[282,466,467],{"class":451},"number",[282,469,470],{"class":299},"]\n",[282,472,473],{"class":284,"line":335},[282,474,476],{"emptyLinePlaceholder":475},true,"\n",[282,478,479,481,483,486,488],{"class":284,"line":346},[282,480,289],{"class":288},[282,482,392],{"class":391},[282,484,485],{"class":299}," permissions ",[282,487,398],{"class":303},[282,489,343],{"class":303},[282,491,492,495,497],{"class":284,"line":360},[282,493,494],{"class":310},"  global",[282,496,314],{"class":303},[282,498,343],{"class":303},[282,500,501,504,507,509,511,514,517,519,521,523,525,527,529],{"class":284,"line":366},[282,502,503],{"class":303},"    '",[282,505,506],{"class":310},"org.settings",[282,508,320],{"class":303},[282,510,314],{"class":303},[282,512,513],{"class":303}," {",[282,515,516],{"class":310}," roles",[282,518,314],{"class":303},[282,520,317],{"class":299},[282,522,320],{"class":303},[282,524,230],{"class":323},[282,526,320],{"class":303},[282,528,435],{"class":299},[282,530,531],{"class":303},"},\n",[282,533,535,537,540,542,544,546,548,550,552,554,556,558,560,562,564,566,568],{"class":284,"line":534},7,[282,536,503],{"class":303},[282,538,539],{"class":310},"org.invite",[282,541,320],{"class":303},[282,543,314],{"class":303},[282,545,513],{"class":303},[282,547,516],{"class":310},[282,549,314],{"class":303},[282,551,317],{"class":299},[282,553,320],{"class":303},[282,555,230],{"class":323},[282,557,320],{"class":303},[282,559,409],{"class":303},[282,561,412],{"class":303},[282,563,234],{"class":323},[282,565,320],{"class":303},[282,567,435],{"class":299},[282,569,531],{"class":303},[282,571,573,575,578,580,582,584,586,588,590,592,594,596,598,600,602,604,606],{"class":284,"line":572},8,[282,574,503],{"class":303},[282,576,577],{"class":310},"org.members",[282,579,320],{"class":303},[282,581,314],{"class":303},[282,583,513],{"class":303},[282,585,516],{"class":310},[282,587,314],{"class":303},[282,589,317],{"class":299},[282,591,320],{"class":303},[282,593,230],{"class":323},[282,595,320],{"class":303},[282,597,409],{"class":303},[282,599,412],{"class":303},[282,601,234],{"class":323},[282,603,320],{"class":303},[282,605,435],{"class":299},[282,607,531],{"class":303},[282,609,611],{"class":284,"line":610},9,[282,612,363],{"class":303},[282,614,616,619,621],{"class":284,"line":615},10,[282,617,618],{"class":310},"  post",[282,620,314],{"class":303},[282,622,343],{"class":303},[282,624,626,629,631,633,635,637,639,641,643,645,647,649,651,653,655,657,659,661,663],{"class":284,"line":625},11,[282,627,628],{"class":310},"    create",[282,630,314],{"class":303},[282,632,513],{"class":303},[282,634,516],{"class":310},[282,636,314],{"class":303},[282,638,317],{"class":299},[282,640,320],{"class":303},[282,642,230],{"class":323},[282,644,320],{"class":303},[282,646,409],{"class":303},[282,648,412],{"class":303},[282,650,234],{"class":323},[282,652,320],{"class":303},[282,654,409],{"class":303},[282,656,412],{"class":303},[282,658,237],{"class":323},[282,660,320],{"class":303},[282,662,435],{"class":299},[282,664,531],{"class":303},[282,666,668,671,673,675,677,679,681,683,685,687,689,691,693,695,697,699,701,703,705,707,709,711,713],{"class":284,"line":667},12,[282,669,670],{"class":310},"    read",[282,672,314],{"class":303},[282,674,513],{"class":303},[282,676,516],{"class":310},[282,678,314],{"class":303},[282,680,317],{"class":299},[282,682,320],{"class":303},[282,684,230],{"class":323},[282,686,320],{"class":303},[282,688,409],{"class":303},[282,690,412],{"class":303},[282,692,234],{"class":323},[282,694,320],{"class":303},[282,696,409],{"class":303},[282,698,412],{"class":303},[282,700,237],{"class":323},[282,702,320],{"class":303},[282,704,409],{"class":303},[282,706,412],{"class":303},[282,708,240],{"class":323},[282,710,320],{"class":303},[282,712,435],{"class":299},[282,714,531],{"class":303},[282,716,718,721,723,725,728,730,732,734,736,738,740,742,745,747,749,751,753,755,757,759,761,763,765],{"class":284,"line":717},13,[282,719,720],{"class":310},"    update",[282,722,314],{"class":303},[282,724,513],{"class":303},[282,726,727],{"class":310}," own",[282,729,314],{"class":303},[282,731,317],{"class":299},[282,733,320],{"class":303},[282,735,237],{"class":323},[282,737,320],{"class":303},[282,739,329],{"class":299},[282,741,409],{"class":303},[282,743,744],{"class":310}," any",[282,746,314],{"class":303},[282,748,317],{"class":299},[282,750,320],{"class":303},[282,752,230],{"class":323},[282,754,320],{"class":303},[282,756,409],{"class":303},[282,758,412],{"class":303},[282,760,234],{"class":323},[282,762,320],{"class":303},[282,764,435],{"class":299},[282,766,531],{"class":303},[282,768,770,773,775,777,779,781,783,785,787,789,791,793,795,797,799,801,803,805,807,809,811,813,815],{"class":284,"line":769},14,[282,771,772],{"class":310},"    delete",[282,774,314],{"class":303},[282,776,513],{"class":303},[282,778,727],{"class":310},[282,780,314],{"class":303},[282,782,317],{"class":299},[282,784,320],{"class":303},[282,786,237],{"class":323},[282,788,320],{"class":303},[282,790,329],{"class":299},[282,792,409],{"class":303},[282,794,744],{"class":310},[282,796,314],{"class":303},[282,798,317],{"class":299},[282,800,320],{"class":303},[282,802,230],{"class":323},[282,804,320],{"class":303},[282,806,409],{"class":303},[282,808,412],{"class":303},[282,810,234],{"class":323},[282,812,320],{"class":303},[282,814,435],{"class":299},[282,816,531],{"class":303},[282,818,820,823,825,827,829,831,833,835,837,839,841,843,845,847,849],{"class":284,"line":819},15,[282,821,822],{"class":310},"    publish",[282,824,314],{"class":303},[282,826,513],{"class":303},[282,828,516],{"class":310},[282,830,314],{"class":303},[282,832,317],{"class":299},[282,834,320],{"class":303},[282,836,230],{"class":323},[282,838,320],{"class":303},[282,840,409],{"class":303},[282,842,412],{"class":303},[282,844,234],{"class":323},[282,846,320],{"class":303},[282,848,435],{"class":299},[282,850,531],{"class":303},[282,852,854],{"class":284,"line":853},16,[282,855,363],{"class":303},[282,857,859,861,864],{"class":284,"line":858},17,[282,860,369],{"class":303},[282,862,863],{"class":288}," as",[282,865,441],{"class":391},[282,867,869],{"class":284,"line":868},18,[282,870,476],{"emptyLinePlaceholder":475},[282,872,874,877,880,882,885,887,889,892,894,897,899],{"class":284,"line":873},19,[282,875,876],{"class":391},"type",[282,878,879],{"class":451}," GlobalPermission",[282,881,455],{"class":303},[282,883,884],{"class":303}," keyof",[282,886,458],{"class":299},[282,888,461],{"class":303},[282,890,891],{"class":299}," permissions)[",[282,893,320],{"class":303},[282,895,896],{"class":323},"global",[282,898,320],{"class":303},[282,900,470],{"class":299},[282,902,904,906,909,911,914,917,920,923,925,927,929,931,934,936,938],{"class":284,"line":903},20,[282,905,876],{"class":391},[282,907,908],{"class":451}," PostPermission",[282,910,455],{"class":303},[282,912,913],{"class":303}," `",[282,915,916],{"class":323},"post.",[282,918,919],{"class":303},"${",[282,921,922],{"class":303},"keyof",[282,924,458],{"class":299},[282,926,461],{"class":303},[282,928,891],{"class":299},[282,930,320],{"class":303},[282,932,933],{"class":323},"post",[282,935,320],{"class":303},[282,937,329],{"class":299},[282,939,940],{"class":303},"}`\n",[282,942,944,946,948,951,953,955,958],{"class":284,"line":943},21,[282,945,289],{"class":288},[282,947,448],{"class":391},[282,949,950],{"class":451}," Permission",[282,952,455],{"class":303},[282,954,879],{"class":451},[282,956,957],{"class":303}," |",[282,959,960],{"class":451}," PostPermission\n",[282,962,964],{"class":284,"line":963},22,[282,965,476],{"emptyLinePlaceholder":475},[282,967,969,971,974,977],{"class":284,"line":968},23,[282,970,289],{"class":288},[282,972,973],{"class":391}," interface",[282,975,976],{"class":451}," PermissionContext",[282,978,343],{"class":303},[282,980,982,985,987],{"class":284,"line":981},24,[282,983,984],{"class":310},"  role",[282,986,314],{"class":303},[282,988,989],{"class":451}," Role\n",[282,991,993,996,998],{"class":284,"line":992},25,[282,994,995],{"class":310},"  userId",[282,997,314],{"class":303},[282,999,1000],{"class":451}," string\n",[282,1002,1004,1007,1009,1012,1014],{"class":284,"line":1003},26,[282,1005,1006],{"class":310},"  organizationId",[282,1008,314],{"class":303},[282,1010,1011],{"class":451}," string",[282,1013,957],{"class":303},[282,1015,1016],{"class":451}," null\n",[282,1018,1020],{"class":284,"line":1019},27,[282,1021,1022],{"class":303},"}\n",[282,1024,1026],{"class":284,"line":1025},28,[282,1027,476],{"emptyLinePlaceholder":475},[282,1029,1031,1033,1035,1038],{"class":284,"line":1030},29,[282,1032,289],{"class":288},[282,1034,973],{"class":391},[282,1036,1037],{"class":451}," Resource",[282,1039,343],{"class":303},[282,1041,1043,1046,1049],{"class":284,"line":1042},30,[282,1044,1045],{"class":310},"  ownerId",[282,1047,1048],{"class":303},"?:",[282,1050,1000],{"class":451},[282,1052,1054,1056,1058],{"class":284,"line":1053},31,[282,1055,1006],{"class":310},[282,1057,1048],{"class":303},[282,1059,1000],{"class":451},[282,1061,1063],{"class":284,"line":1062},32,[282,1064,1022],{"class":303},[282,1066,1068],{"class":284,"line":1067},33,[282,1069,476],{"emptyLinePlaceholder":475},[282,1071,1073,1075,1078,1080,1082,1084,1086,1089,1091,1094,1096,1098,1100,1102,1104,1106,1108,1111,1114,1116,1118,1120,1122,1124],{"class":284,"line":1072},34,[282,1074,876],{"class":391},[282,1076,1077],{"class":451}," PermissionRule",[282,1079,455],{"class":303},[282,1081,513],{"class":303},[282,1083,516],{"class":310},[282,1085,314],{"class":303},[282,1087,1088],{"class":391}," readonly",[282,1090,452],{"class":451},[282,1092,1093],{"class":299},"[] ",[282,1095,369],{"class":303},[282,1097,957],{"class":303},[282,1099,513],{"class":303},[282,1101,727],{"class":310},[282,1103,314],{"class":303},[282,1105,1088],{"class":391},[282,1107,452],{"class":451},[282,1109,1110],{"class":299},"[]",[282,1112,1113],{"class":303},";",[282,1115,744],{"class":310},[282,1117,314],{"class":303},[282,1119,1088],{"class":391},[282,1121,452],{"class":451},[282,1123,1093],{"class":299},[282,1125,1022],{"class":303},[282,1127,1129],{"class":284,"line":1128},35,[282,1130,476],{"emptyLinePlaceholder":475},[282,1132,1134,1136,1139,1142],{"class":284,"line":1133},36,[282,1135,289],{"class":288},[282,1137,1138],{"class":391}," function",[282,1140,1141],{"class":295}," checkPermission",[282,1143,1144],{"class":303},"(\n",[282,1146,1148,1152,1154,1156,1158,1161],{"class":284,"line":1147},37,[282,1149,1151],{"class":1150},"sHdIc","  ctx",[282,1153,314],{"class":303},[282,1155,976],{"class":451},[282,1157,957],{"class":303},[282,1159,1160],{"class":451}," null",[282,1162,332],{"class":303},[282,1164,1166,1169,1171,1173],{"class":284,"line":1165},38,[282,1167,1168],{"class":1150},"  permission",[282,1170,314],{"class":303},[282,1172,950],{"class":451},[282,1174,332],{"class":303},[282,1176,1178,1181,1183,1185],{"class":284,"line":1177},39,[282,1179,1180],{"class":1150},"  resource",[282,1182,1048],{"class":303},[282,1184,1037],{"class":451},[282,1186,332],{"class":303},[282,1188,1190,1193,1196],{"class":284,"line":1189},40,[282,1191,1192],{"class":303},"):",[282,1194,1195],{"class":451}," boolean",[282,1197,343],{"class":303},[282,1199,1201,1204,1206,1209,1212,1215,1218],{"class":284,"line":1200},41,[282,1202,1203],{"class":288},"  if",[282,1205,458],{"class":310},[282,1207,1208],{"class":303},"!",[282,1210,1211],{"class":299},"ctx",[282,1213,1214],{"class":310},") ",[282,1216,1217],{"class":288},"return",[282,1219,1220],{"class":354}," false\n",[282,1222,1224],{"class":284,"line":1223},42,[282,1225,476],{"emptyLinePlaceholder":475},[282,1227,1229,1231,1233,1236,1239,1242,1244,1246,1248],{"class":284,"line":1228},43,[282,1230,1203],{"class":288},[282,1232,458],{"class":310},[282,1234,1235],{"class":299},"permission",[282,1237,1238],{"class":303}," in",[282,1240,1241],{"class":299}," permissions",[282,1243,208],{"class":303},[282,1245,896],{"class":299},[282,1247,1214],{"class":310},[282,1249,304],{"class":303},[282,1251,1253,1256,1259,1261,1263,1265,1267,1270,1272,1274,1276],{"class":284,"line":1252},44,[282,1254,1255],{"class":391},"    const",[282,1257,1258],{"class":299}," rule",[282,1260,455],{"class":303},[282,1262,1241],{"class":299},[282,1264,208],{"class":303},[282,1266,896],{"class":299},[282,1268,1269],{"class":310},"[",[282,1271,1235],{"class":299},[282,1273,863],{"class":288},[282,1275,879],{"class":451},[282,1277,470],{"class":310},[282,1279,1281,1284,1286,1288,1291,1293,1296,1298,1300,1302,1305],{"class":284,"line":1280},45,[282,1282,1283],{"class":288},"    return",[282,1285,1258],{"class":299},[282,1287,208],{"class":303},[282,1289,1290],{"class":299},"roles",[282,1292,208],{"class":303},[282,1294,1295],{"class":295},"includes",[282,1297,300],{"class":310},[282,1299,1211],{"class":299},[282,1301,208],{"class":303},[282,1303,1304],{"class":299},"role",[282,1306,372],{"class":310},[282,1308,1310],{"class":284,"line":1309},46,[282,1311,1312],{"class":303},"  }\n",[282,1314,1316],{"class":284,"line":1315},47,[282,1317,476],{"emptyLinePlaceholder":475},[282,1319,1321,1324,1326,1329,1331,1334,1336,1338,1341,1343,1346,1348,1350,1352,1354,1356,1358,1360,1363,1365,1367],{"class":284,"line":1320},48,[282,1322,1323],{"class":391},"  const",[282,1325,317],{"class":303},[282,1327,1328],{"class":299},"resourceType",[282,1330,409],{"class":303},[282,1332,1333],{"class":299}," action",[282,1335,329],{"class":303},[282,1337,455],{"class":303},[282,1339,1340],{"class":299}," permission",[282,1342,208],{"class":303},[282,1344,1345],{"class":295},"split",[282,1347,300],{"class":310},[282,1349,320],{"class":303},[282,1351,208],{"class":323},[282,1353,320],{"class":303},[282,1355,1214],{"class":310},[282,1357,438],{"class":288},[282,1359,317],{"class":310},[282,1361,1362],{"class":451},"string",[282,1364,409],{"class":303},[282,1366,1011],{"class":451},[282,1368,470],{"class":310},[282,1370,1372,1374,1377,1379,1381,1383,1385,1387,1389,1392,1394],{"class":284,"line":1371},49,[282,1373,1323],{"class":391},[282,1375,1376],{"class":299}," resourcePerms",[282,1378,455],{"class":303},[282,1380,1241],{"class":299},[282,1382,1269],{"class":310},[282,1384,1328],{"class":299},[282,1386,863],{"class":288},[282,1388,884],{"class":303},[282,1390,1391],{"class":303}," typeof",[282,1393,1241],{"class":299},[282,1395,470],{"class":310},[282,1397,1399,1401,1403,1405,1408,1411,1414,1417,1419,1421,1423,1425,1427],{"class":284,"line":1398},50,[282,1400,1203],{"class":288},[282,1402,458],{"class":310},[282,1404,1208],{"class":303},[282,1406,1407],{"class":299},"resourcePerms",[282,1409,1410],{"class":303}," ||",[282,1412,1413],{"class":299}," resourceType",[282,1415,1416],{"class":303}," ===",[282,1418,412],{"class":303},[282,1420,896],{"class":323},[282,1422,320],{"class":303},[282,1424,1214],{"class":310},[282,1426,1217],{"class":288},[282,1428,1220],{"class":354},[282,1430,1432],{"class":284,"line":1431},51,[282,1433,476],{"emptyLinePlaceholder":475},[282,1435,1437,1439,1441,1443,1445,1447,1449,1452,1455,1457,1459,1461,1464,1467,1470],{"class":284,"line":1436},52,[282,1438,1323],{"class":391},[282,1440,1258],{"class":299},[282,1442,455],{"class":303},[282,1444,458],{"class":310},[282,1446,1407],{"class":299},[282,1448,863],{"class":288},[282,1450,1451],{"class":451}," Record",[282,1453,1454],{"class":303},"\u003C",[282,1456,1362],{"class":451},[282,1458,409],{"class":303},[282,1460,1077],{"class":451},[282,1462,1463],{"class":303},">",[282,1465,1466],{"class":310},")[",[282,1468,1469],{"class":299},"action",[282,1471,470],{"class":310},[282,1473,1475,1477,1479,1481,1484,1486,1488],{"class":284,"line":1474},53,[282,1476,1203],{"class":288},[282,1478,458],{"class":310},[282,1480,1208],{"class":303},[282,1482,1483],{"class":299},"rule",[282,1485,1214],{"class":310},[282,1487,1217],{"class":288},[282,1489,1220],{"class":354},[282,1491,1493],{"class":284,"line":1492},54,[282,1494,476],{"emptyLinePlaceholder":475},[282,1496,1498,1500,1502,1504,1506,1508,1510,1512,1514],{"class":284,"line":1497},55,[282,1499,1203],{"class":288},[282,1501,458],{"class":310},[282,1503,320],{"class":303},[282,1505,1290],{"class":323},[282,1507,320],{"class":303},[282,1509,1238],{"class":303},[282,1511,1258],{"class":299},[282,1513,1214],{"class":310},[282,1515,304],{"class":303},[282,1517,1519,1521,1523,1525,1527,1529,1531,1533,1535,1537,1539],{"class":284,"line":1518},56,[282,1520,1283],{"class":288},[282,1522,1258],{"class":299},[282,1524,208],{"class":303},[282,1526,1290],{"class":299},[282,1528,208],{"class":303},[282,1530,1295],{"class":295},[282,1532,300],{"class":310},[282,1534,1211],{"class":299},[282,1536,208],{"class":303},[282,1538,1304],{"class":299},[282,1540,372],{"class":310},[282,1542,1544],{"class":284,"line":1543},57,[282,1545,1312],{"class":303},[282,1547,1549],{"class":284,"line":1548},58,[282,1550,476],{"emptyLinePlaceholder":475},[282,1552,1554,1556,1558,1560,1562,1565,1567,1569,1571,1573,1575,1577,1580,1582],{"class":284,"line":1553},59,[282,1555,1203],{"class":288},[282,1557,458],{"class":310},[282,1559,1483],{"class":299},[282,1561,208],{"class":303},[282,1563,1564],{"class":299},"any",[282,1566,208],{"class":303},[282,1568,1295],{"class":295},[282,1570,300],{"class":310},[282,1572,1211],{"class":299},[282,1574,208],{"class":303},[282,1576,1304],{"class":299},[282,1578,1579],{"class":310},")) ",[282,1581,1217],{"class":288},[282,1583,1584],{"class":354}," true\n",[282,1586,1588],{"class":284,"line":1587},60,[282,1589,476],{"emptyLinePlaceholder":475},[282,1591,1593,1595,1597,1599,1602,1605,1608,1610,1612],{"class":284,"line":1592},61,[282,1594,1203],{"class":288},[282,1596,458],{"class":310},[282,1598,1208],{"class":303},[282,1600,1601],{"class":299},"resource",[282,1603,1604],{"class":303},"?.",[282,1606,1607],{"class":299},"ownerId",[282,1609,1214],{"class":310},[282,1611,1217],{"class":288},[282,1613,1220],{"class":354},[282,1615,1617,1620,1622,1624,1627,1629,1631,1633,1635,1637,1639,1641,1644,1647,1649,1651,1653,1656,1658],{"class":284,"line":1616},62,[282,1618,1619],{"class":288},"  return",[282,1621,1258],{"class":299},[282,1623,208],{"class":303},[282,1625,1626],{"class":299},"own",[282,1628,208],{"class":303},[282,1630,1295],{"class":295},[282,1632,300],{"class":310},[282,1634,1211],{"class":299},[282,1636,208],{"class":303},[282,1638,1304],{"class":299},[282,1640,1214],{"class":310},[282,1642,1643],{"class":303},"&&",[282,1645,1646],{"class":299}," resource",[282,1648,208],{"class":303},[282,1650,1607],{"class":299},[282,1652,1416],{"class":303},[282,1654,1655],{"class":299}," ctx",[282,1657,208],{"class":303},[282,1659,1660],{"class":299},"userId\n",[282,1662,1664],{"class":284,"line":1663},63,[282,1665,1022],{"class":303},[210,1667],{},[213,1669,1671],{"id":1670},"_3-backend-authorization-helper","3) Backend Authorization Helper",[272,1673,1676],{"className":274,"code":1674,"filename":1675,"language":277,"meta":278,"style":278},"import { ConvexError } from 'convex/values'\nimport type { MutationCtx, QueryCtx, ActionCtx } from '../_generated/server'\nimport {\n  checkPermission,\n  type Permission,\n  type Resource,\n  type PermissionContext,\n} from '../permissions.config'\n\ntype Ctx = MutationCtx | QueryCtx | ActionCtx\n\nasync function getPermissionContext(ctx: Ctx): Promise\u003CPermissionContext | null> {\n  const identity = await ctx.auth.getUserIdentity()\n  if (!identity) return null\n\n  const user = await ctx.db\n    .query('users')\n    .withIndex('by_auth_id', (q) => q.eq('authId', identity.subject))\n    .first()\n\n  if (!user) return null\n\n  return {\n    role: user.role,\n    userId: identity.subject,\n    organizationId: user.organizationId ?? null,\n  }\n}\n\nexport async function authorize(\n  ctx: Ctx,\n  permission: Permission,\n  resource?: Resource,\n): Promise\u003CPermissionContext> {\n  const context = await getPermissionContext(ctx)\n\n  if (!context) {\n    throw new ConvexError('Unauthorized')\n  }\n\n  if (\n    resource?.organizationId &&\n    context.organizationId &&\n    resource.organizationId !== context.organizationId\n  ) {\n    throw new ConvexError('Forbidden')\n  }\n\n  if (!checkPermission(context, permission, resource)) {\n    throw new ConvexError('Forbidden')\n  }\n\n  return context\n}\n","convex/lib/permissions.ts",[228,1677,1678,1702,1734,1740,1747,1756,1764,1772,1785,1789,1809,1813,1849,1876,1893,1897,1915,1934,1992,2001,2005,2022,2026,2032,2047,2062,2082,2086,2090,2094,2108,2118,2128,2138,2152,2171,2175,2190,2211,2215,2219,2226,2238,2249,2267,2274,2293,2297,2301,2328,2346,2350,2354,2361],{"__ignoreMap":278},[282,1679,1680,1683,1685,1688,1691,1694,1696,1699],{"class":284,"line":285},[282,1681,1682],{"class":288},"import",[282,1684,513],{"class":303},[282,1686,1687],{"class":299}," ConvexError",[282,1689,1690],{"class":303}," }",[282,1692,1693],{"class":288}," from",[282,1695,412],{"class":303},[282,1697,1698],{"class":323},"convex/values",[282,1700,1701],{"class":303},"'\n",[282,1703,1704,1706,1708,1710,1713,1715,1718,1720,1723,1725,1727,1729,1732],{"class":284,"line":307},[282,1705,1682],{"class":288},[282,1707,448],{"class":288},[282,1709,513],{"class":303},[282,1711,1712],{"class":299}," MutationCtx",[282,1714,409],{"class":303},[282,1716,1717],{"class":299}," QueryCtx",[282,1719,409],{"class":303},[282,1721,1722],{"class":299}," ActionCtx",[282,1724,1690],{"class":303},[282,1726,1693],{"class":288},[282,1728,412],{"class":303},[282,1730,1731],{"class":323},"../_generated/server",[282,1733,1701],{"class":303},[282,1735,1736,1738],{"class":284,"line":335},[282,1737,1682],{"class":288},[282,1739,343],{"class":303},[282,1741,1742,1745],{"class":284,"line":346},[282,1743,1744],{"class":299},"  checkPermission",[282,1746,332],{"class":303},[282,1748,1749,1752,1754],{"class":284,"line":360},[282,1750,1751],{"class":288},"  type",[282,1753,950],{"class":299},[282,1755,332],{"class":303},[282,1757,1758,1760,1762],{"class":284,"line":366},[282,1759,1751],{"class":288},[282,1761,1037],{"class":299},[282,1763,332],{"class":303},[282,1765,1766,1768,1770],{"class":284,"line":534},[282,1767,1751],{"class":288},[282,1769,976],{"class":299},[282,1771,332],{"class":303},[282,1773,1774,1776,1778,1780,1783],{"class":284,"line":572},[282,1775,369],{"class":303},[282,1777,1693],{"class":288},[282,1779,412],{"class":303},[282,1781,1782],{"class":323},"../permissions.config",[282,1784,1701],{"class":303},[282,1786,1787],{"class":284,"line":610},[282,1788,476],{"emptyLinePlaceholder":475},[282,1790,1791,1793,1796,1798,1800,1802,1804,1806],{"class":284,"line":615},[282,1792,876],{"class":391},[282,1794,1795],{"class":451}," Ctx",[282,1797,455],{"class":303},[282,1799,1712],{"class":451},[282,1801,957],{"class":303},[282,1803,1717],{"class":451},[282,1805,957],{"class":303},[282,1807,1808],{"class":451}," ActionCtx\n",[282,1810,1811],{"class":284,"line":625},[282,1812,476],{"emptyLinePlaceholder":475},[282,1814,1815,1818,1820,1823,1825,1827,1829,1831,1833,1836,1838,1841,1843,1845,1847],{"class":284,"line":667},[282,1816,1817],{"class":391},"async",[282,1819,1138],{"class":391},[282,1821,1822],{"class":295}," getPermissionContext",[282,1824,300],{"class":303},[282,1826,1211],{"class":1150},[282,1828,314],{"class":303},[282,1830,1795],{"class":451},[282,1832,1192],{"class":303},[282,1834,1835],{"class":451}," Promise",[282,1837,1454],{"class":303},[282,1839,1840],{"class":451},"PermissionContext",[282,1842,957],{"class":303},[282,1844,1160],{"class":451},[282,1846,1463],{"class":303},[282,1848,343],{"class":303},[282,1850,1851,1853,1856,1858,1861,1863,1865,1868,1870,1873],{"class":284,"line":717},[282,1852,1323],{"class":391},[282,1854,1855],{"class":299}," identity",[282,1857,455],{"class":303},[282,1859,1860],{"class":288}," await",[282,1862,1655],{"class":299},[282,1864,208],{"class":303},[282,1866,1867],{"class":299},"auth",[282,1869,208],{"class":303},[282,1871,1872],{"class":295},"getUserIdentity",[282,1874,1875],{"class":310},"()\n",[282,1877,1878,1880,1882,1884,1887,1889,1891],{"class":284,"line":769},[282,1879,1203],{"class":288},[282,1881,458],{"class":310},[282,1883,1208],{"class":303},[282,1885,1886],{"class":299},"identity",[282,1888,1214],{"class":310},[282,1890,1217],{"class":288},[282,1892,1016],{"class":303},[282,1894,1895],{"class":284,"line":819},[282,1896,476],{"emptyLinePlaceholder":475},[282,1898,1899,1901,1904,1906,1908,1910,1912],{"class":284,"line":853},[282,1900,1323],{"class":391},[282,1902,1903],{"class":299}," user",[282,1905,455],{"class":303},[282,1907,1860],{"class":288},[282,1909,1655],{"class":299},[282,1911,208],{"class":303},[282,1913,1914],{"class":299},"db\n",[282,1916,1917,1920,1923,1925,1927,1930,1932],{"class":284,"line":858},[282,1918,1919],{"class":303},"    .",[282,1921,1922],{"class":295},"query",[282,1924,300],{"class":310},[282,1926,320],{"class":303},[282,1928,1929],{"class":323},"users",[282,1931,320],{"class":303},[282,1933,372],{"class":310},[282,1935,1936,1938,1941,1943,1945,1948,1950,1952,1954,1957,1960,1963,1966,1968,1971,1973,1975,1978,1980,1982,1984,1986,1989],{"class":284,"line":868},[282,1937,1919],{"class":303},[282,1939,1940],{"class":295},"withIndex",[282,1942,300],{"class":310},[282,1944,320],{"class":303},[282,1946,1947],{"class":323},"by_auth_id",[282,1949,320],{"class":303},[282,1951,409],{"class":303},[282,1953,458],{"class":303},[282,1955,1956],{"class":1150},"q",[282,1958,1959],{"class":303},")",[282,1961,1962],{"class":391}," =>",[282,1964,1965],{"class":299}," q",[282,1967,208],{"class":303},[282,1969,1970],{"class":295},"eq",[282,1972,300],{"class":310},[282,1974,320],{"class":303},[282,1976,1977],{"class":323},"authId",[282,1979,320],{"class":303},[282,1981,409],{"class":303},[282,1983,1855],{"class":299},[282,1985,208],{"class":303},[282,1987,1988],{"class":299},"subject",[282,1990,1991],{"class":310},"))\n",[282,1993,1994,1996,1999],{"class":284,"line":873},[282,1995,1919],{"class":303},[282,1997,1998],{"class":295},"first",[282,2000,1875],{"class":310},[282,2002,2003],{"class":284,"line":903},[282,2004,476],{"emptyLinePlaceholder":475},[282,2006,2007,2009,2011,2013,2016,2018,2020],{"class":284,"line":943},[282,2008,1203],{"class":288},[282,2010,458],{"class":310},[282,2012,1208],{"class":303},[282,2014,2015],{"class":299},"user",[282,2017,1214],{"class":310},[282,2019,1217],{"class":288},[282,2021,1016],{"class":303},[282,2023,2024],{"class":284,"line":963},[282,2025,476],{"emptyLinePlaceholder":475},[282,2027,2028,2030],{"class":284,"line":968},[282,2029,1619],{"class":288},[282,2031,343],{"class":303},[282,2033,2034,2037,2039,2041,2043,2045],{"class":284,"line":981},[282,2035,2036],{"class":310},"    role",[282,2038,314],{"class":303},[282,2040,1903],{"class":299},[282,2042,208],{"class":303},[282,2044,1304],{"class":299},[282,2046,332],{"class":303},[282,2048,2049,2052,2054,2056,2058,2060],{"class":284,"line":992},[282,2050,2051],{"class":310},"    userId",[282,2053,314],{"class":303},[282,2055,1855],{"class":299},[282,2057,208],{"class":303},[282,2059,1988],{"class":299},[282,2061,332],{"class":303},[282,2063,2064,2067,2069,2071,2073,2076,2079],{"class":284,"line":1003},[282,2065,2066],{"class":310},"    organizationId",[282,2068,314],{"class":303},[282,2070,1903],{"class":299},[282,2072,208],{"class":303},[282,2074,2075],{"class":299},"organizationId",[282,2077,2078],{"class":303}," ??",[282,2080,2081],{"class":303}," null,\n",[282,2083,2084],{"class":284,"line":1019},[282,2085,1312],{"class":303},[282,2087,2088],{"class":284,"line":1025},[282,2089,1022],{"class":303},[282,2091,2092],{"class":284,"line":1030},[282,2093,476],{"emptyLinePlaceholder":475},[282,2095,2096,2098,2101,2103,2106],{"class":284,"line":1042},[282,2097,289],{"class":288},[282,2099,2100],{"class":391}," async",[282,2102,1138],{"class":391},[282,2104,2105],{"class":295}," authorize",[282,2107,1144],{"class":303},[282,2109,2110,2112,2114,2116],{"class":284,"line":1053},[282,2111,1151],{"class":1150},[282,2113,314],{"class":303},[282,2115,1795],{"class":451},[282,2117,332],{"class":303},[282,2119,2120,2122,2124,2126],{"class":284,"line":1062},[282,2121,1168],{"class":1150},[282,2123,314],{"class":303},[282,2125,950],{"class":451},[282,2127,332],{"class":303},[282,2129,2130,2132,2134,2136],{"class":284,"line":1067},[282,2131,1180],{"class":1150},[282,2133,1048],{"class":303},[282,2135,1037],{"class":451},[282,2137,332],{"class":303},[282,2139,2140,2142,2144,2146,2148,2150],{"class":284,"line":1072},[282,2141,1192],{"class":303},[282,2143,1835],{"class":451},[282,2145,1454],{"class":303},[282,2147,1840],{"class":451},[282,2149,1463],{"class":303},[282,2151,343],{"class":303},[282,2153,2154,2156,2159,2161,2163,2165,2167,2169],{"class":284,"line":1128},[282,2155,1323],{"class":391},[282,2157,2158],{"class":299}," context",[282,2160,455],{"class":303},[282,2162,1860],{"class":288},[282,2164,1822],{"class":295},[282,2166,300],{"class":310},[282,2168,1211],{"class":299},[282,2170,372],{"class":310},[282,2172,2173],{"class":284,"line":1133},[282,2174,476],{"emptyLinePlaceholder":475},[282,2176,2177,2179,2181,2183,2186,2188],{"class":284,"line":1147},[282,2178,1203],{"class":288},[282,2180,458],{"class":310},[282,2182,1208],{"class":303},[282,2184,2185],{"class":299},"context",[282,2187,1214],{"class":310},[282,2189,304],{"class":303},[282,2191,2192,2195,2198,2200,2202,2204,2207,2209],{"class":284,"line":1165},[282,2193,2194],{"class":288},"    throw",[282,2196,2197],{"class":303}," new",[282,2199,1687],{"class":295},[282,2201,300],{"class":310},[282,2203,320],{"class":303},[282,2205,2206],{"class":323},"Unauthorized",[282,2208,320],{"class":303},[282,2210,372],{"class":310},[282,2212,2213],{"class":284,"line":1177},[282,2214,1312],{"class":303},[282,2216,2217],{"class":284,"line":1189},[282,2218,476],{"emptyLinePlaceholder":475},[282,2220,2221,2223],{"class":284,"line":1200},[282,2222,1203],{"class":288},[282,2224,2225],{"class":310}," (\n",[282,2227,2228,2231,2233,2235],{"class":284,"line":1223},[282,2229,2230],{"class":299},"    resource",[282,2232,1604],{"class":303},[282,2234,2075],{"class":299},[282,2236,2237],{"class":303}," &&\n",[282,2239,2240,2243,2245,2247],{"class":284,"line":1228},[282,2241,2242],{"class":299},"    context",[282,2244,208],{"class":303},[282,2246,2075],{"class":299},[282,2248,2237],{"class":303},[282,2250,2251,2253,2255,2257,2260,2262,2264],{"class":284,"line":1252},[282,2252,2230],{"class":299},[282,2254,208],{"class":303},[282,2256,2075],{"class":299},[282,2258,2259],{"class":303}," !==",[282,2261,2158],{"class":299},[282,2263,208],{"class":303},[282,2265,2266],{"class":299},"organizationId\n",[282,2268,2269,2272],{"class":284,"line":1280},[282,2270,2271],{"class":310},"  ) ",[282,2273,304],{"class":303},[282,2275,2276,2278,2280,2282,2284,2286,2289,2291],{"class":284,"line":1309},[282,2277,2194],{"class":288},[282,2279,2197],{"class":303},[282,2281,1687],{"class":295},[282,2283,300],{"class":310},[282,2285,320],{"class":303},[282,2287,2288],{"class":323},"Forbidden",[282,2290,320],{"class":303},[282,2292,372],{"class":310},[282,2294,2295],{"class":284,"line":1315},[282,2296,1312],{"class":303},[282,2298,2299],{"class":284,"line":1320},[282,2300,476],{"emptyLinePlaceholder":475},[282,2302,2303,2305,2307,2309,2312,2314,2316,2318,2320,2322,2324,2326],{"class":284,"line":1371},[282,2304,1203],{"class":288},[282,2306,458],{"class":310},[282,2308,1208],{"class":303},[282,2310,2311],{"class":295},"checkPermission",[282,2313,300],{"class":310},[282,2315,2185],{"class":299},[282,2317,409],{"class":303},[282,2319,1340],{"class":299},[282,2321,409],{"class":303},[282,2323,1646],{"class":299},[282,2325,1579],{"class":310},[282,2327,304],{"class":303},[282,2329,2330,2332,2334,2336,2338,2340,2342,2344],{"class":284,"line":1398},[282,2331,2194],{"class":288},[282,2333,2197],{"class":303},[282,2335,1687],{"class":295},[282,2337,300],{"class":310},[282,2339,320],{"class":303},[282,2341,2288],{"class":323},[282,2343,320],{"class":303},[282,2345,372],{"class":310},[282,2347,2348],{"class":284,"line":1431},[282,2349,1312],{"class":303},[282,2351,2352],{"class":284,"line":1436},[282,2353,476],{"emptyLinePlaceholder":475},[282,2355,2356,2358],{"class":284,"line":1474},[282,2357,1619],{"class":288},[282,2359,2360],{"class":299}," context\n",[282,2362,2363],{"class":284,"line":1492},[282,2364,1022],{"class":303},[210,2366],{},[213,2368,2370],{"id":2369},"_4-permission-context-query","4) Permission Context Query",[272,2372,2375],{"className":274,"code":2373,"filename":2374,"language":277,"meta":278,"style":278},"import { query } from './_generated/server'\n\nexport const getPermissionContext = query({\n  args: {},\n  handler: async (ctx) => {\n    const identity = await ctx.auth.getUserIdentity()\n    if (!identity) return null\n\n    const user = await ctx.db\n      .query('users')\n      .withIndex('by_auth_id', (q) => q.eq('authId', identity.subject))\n      .first()\n\n    if (!user) return null\n\n    return {\n      userId: identity.subject,\n      role: user.role,\n      organizationId: user.organizationId ?? null,\n      isAuthenticated: true,\n    }\n  },\n})\n","convex/auth.ts",[228,2376,2377,2397,2401,2418,2428,2447,2469,2486,2490,2506,2523,2571,2579,2583,2599,2603,2609,2624,2639,2656,2667,2672,2676],{"__ignoreMap":278},[282,2378,2379,2381,2383,2386,2388,2390,2392,2395],{"class":284,"line":285},[282,2380,1682],{"class":288},[282,2382,513],{"class":303},[282,2384,2385],{"class":299}," query",[282,2387,1690],{"class":303},[282,2389,1693],{"class":288},[282,2391,412],{"class":303},[282,2393,2394],{"class":323},"./_generated/server",[282,2396,1701],{"class":303},[282,2398,2399],{"class":284,"line":307},[282,2400,476],{"emptyLinePlaceholder":475},[282,2402,2403,2405,2407,2410,2412,2414,2416],{"class":284,"line":335},[282,2404,289],{"class":288},[282,2406,392],{"class":391},[282,2408,2409],{"class":299}," getPermissionContext ",[282,2411,398],{"class":303},[282,2413,2385],{"class":295},[282,2415,300],{"class":299},[282,2417,304],{"class":303},[282,2419,2420,2423,2425],{"class":284,"line":346},[282,2421,2422],{"class":310},"  args",[282,2424,314],{"class":303},[282,2426,2427],{"class":303}," {},\n",[282,2429,2430,2433,2435,2437,2439,2441,2443,2445],{"class":284,"line":360},[282,2431,2432],{"class":295},"  handler",[282,2434,314],{"class":303},[282,2436,2100],{"class":391},[282,2438,458],{"class":303},[282,2440,1211],{"class":1150},[282,2442,1959],{"class":303},[282,2444,1962],{"class":391},[282,2446,343],{"class":303},[282,2448,2449,2451,2453,2455,2457,2459,2461,2463,2465,2467],{"class":284,"line":366},[282,2450,1255],{"class":391},[282,2452,1855],{"class":299},[282,2454,455],{"class":303},[282,2456,1860],{"class":288},[282,2458,1655],{"class":299},[282,2460,208],{"class":303},[282,2462,1867],{"class":299},[282,2464,208],{"class":303},[282,2466,1872],{"class":295},[282,2468,1875],{"class":310},[282,2470,2471,2474,2476,2478,2480,2482,2484],{"class":284,"line":534},[282,2472,2473],{"class":288},"    if",[282,2475,458],{"class":310},[282,2477,1208],{"class":303},[282,2479,1886],{"class":299},[282,2481,1214],{"class":310},[282,2483,1217],{"class":288},[282,2485,1016],{"class":303},[282,2487,2488],{"class":284,"line":572},[282,2489,476],{"emptyLinePlaceholder":475},[282,2491,2492,2494,2496,2498,2500,2502,2504],{"class":284,"line":610},[282,2493,1255],{"class":391},[282,2495,1903],{"class":299},[282,2497,455],{"class":303},[282,2499,1860],{"class":288},[282,2501,1655],{"class":299},[282,2503,208],{"class":303},[282,2505,1914],{"class":299},[282,2507,2508,2511,2513,2515,2517,2519,2521],{"class":284,"line":615},[282,2509,2510],{"class":303},"      .",[282,2512,1922],{"class":295},[282,2514,300],{"class":310},[282,2516,320],{"class":303},[282,2518,1929],{"class":323},[282,2520,320],{"class":303},[282,2522,372],{"class":310},[282,2524,2525,2527,2529,2531,2533,2535,2537,2539,2541,2543,2545,2547,2549,2551,2553,2555,2557,2559,2561,2563,2565,2567,2569],{"class":284,"line":625},[282,2526,2510],{"class":303},[282,2528,1940],{"class":295},[282,2530,300],{"class":310},[282,2532,320],{"class":303},[282,2534,1947],{"class":323},[282,2536,320],{"class":303},[282,2538,409],{"class":303},[282,2540,458],{"class":303},[282,2542,1956],{"class":1150},[282,2544,1959],{"class":303},[282,2546,1962],{"class":391},[282,2548,1965],{"class":299},[282,2550,208],{"class":303},[282,2552,1970],{"class":295},[282,2554,300],{"class":310},[282,2556,320],{"class":303},[282,2558,1977],{"class":323},[282,2560,320],{"class":303},[282,2562,409],{"class":303},[282,2564,1855],{"class":299},[282,2566,208],{"class":303},[282,2568,1988],{"class":299},[282,2570,1991],{"class":310},[282,2572,2573,2575,2577],{"class":284,"line":667},[282,2574,2510],{"class":303},[282,2576,1998],{"class":295},[282,2578,1875],{"class":310},[282,2580,2581],{"class":284,"line":717},[282,2582,476],{"emptyLinePlaceholder":475},[282,2584,2585,2587,2589,2591,2593,2595,2597],{"class":284,"line":769},[282,2586,2473],{"class":288},[282,2588,458],{"class":310},[282,2590,1208],{"class":303},[282,2592,2015],{"class":299},[282,2594,1214],{"class":310},[282,2596,1217],{"class":288},[282,2598,1016],{"class":303},[282,2600,2601],{"class":284,"line":819},[282,2602,476],{"emptyLinePlaceholder":475},[282,2604,2605,2607],{"class":284,"line":853},[282,2606,1283],{"class":288},[282,2608,343],{"class":303},[282,2610,2611,2614,2616,2618,2620,2622],{"class":284,"line":858},[282,2612,2613],{"class":310},"      userId",[282,2615,314],{"class":303},[282,2617,1855],{"class":299},[282,2619,208],{"class":303},[282,2621,1988],{"class":299},[282,2623,332],{"class":303},[282,2625,2626,2629,2631,2633,2635,2637],{"class":284,"line":868},[282,2627,2628],{"class":310},"      role",[282,2630,314],{"class":303},[282,2632,1903],{"class":299},[282,2634,208],{"class":303},[282,2636,1304],{"class":299},[282,2638,332],{"class":303},[282,2640,2641,2644,2646,2648,2650,2652,2654],{"class":284,"line":873},[282,2642,2643],{"class":310},"      organizationId",[282,2645,314],{"class":303},[282,2647,1903],{"class":299},[282,2649,208],{"class":303},[282,2651,2075],{"class":299},[282,2653,2078],{"class":303},[282,2655,2081],{"class":303},[282,2657,2658,2661,2663,2665],{"class":284,"line":903},[282,2659,2660],{"class":310},"      isAuthenticated",[282,2662,314],{"class":303},[282,2664,355],{"class":354},[282,2666,332],{"class":303},[282,2668,2669],{"class":284,"line":943},[282,2670,2671],{"class":303},"    }\n",[282,2673,2674],{"class":284,"line":963},[282,2675,363],{"class":303},[282,2677,2678,2680],{"class":284,"line":968},[282,2679,369],{"class":303},[282,2681,372],{"class":299},[210,2683],{},[213,2685,2687],{"id":2686},"_5-frontend-composable","5) Frontend Composable",[272,2689,2692],{"className":274,"code":2690,"filename":2691,"language":277,"meta":278,"style":278},"import { api } from '~~/convex/_generated/api'\nimport { checkPermission, type Permission, type Resource } from '~~/convex/permissions.config'\n\nexport const usePermissions = createPermissions\u003C\n  { role: 'owner' | 'admin' | 'member' | 'viewer'; userId: string; organizationId: string | null },\n  Permission,\n  Resource\n>({\n  query: api.auth.getPermissionContext,\n  checkPermission,\n})\n","composables/usePermissions.ts",[228,2693,2694,2714,2745,2749,2766,2831,2838,2843,2851,2871,2877],{"__ignoreMap":278},[282,2695,2696,2698,2700,2703,2705,2707,2709,2712],{"class":284,"line":285},[282,2697,1682],{"class":288},[282,2699,513],{"class":303},[282,2701,2702],{"class":299}," api",[282,2704,1690],{"class":303},[282,2706,1693],{"class":288},[282,2708,412],{"class":303},[282,2710,2711],{"class":323},"~~/convex/_generated/api",[282,2713,1701],{"class":303},[282,2715,2716,2718,2720,2722,2724,2726,2728,2730,2732,2734,2736,2738,2740,2743],{"class":284,"line":307},[282,2717,1682],{"class":288},[282,2719,513],{"class":303},[282,2721,1141],{"class":299},[282,2723,409],{"class":303},[282,2725,448],{"class":288},[282,2727,950],{"class":299},[282,2729,409],{"class":303},[282,2731,448],{"class":288},[282,2733,1037],{"class":299},[282,2735,1690],{"class":303},[282,2737,1693],{"class":288},[282,2739,412],{"class":303},[282,2741,2742],{"class":323},"~~/convex/permissions.config",[282,2744,1701],{"class":303},[282,2746,2747],{"class":284,"line":335},[282,2748,476],{"emptyLinePlaceholder":475},[282,2750,2751,2753,2755,2758,2760,2763],{"class":284,"line":346},[282,2752,289],{"class":288},[282,2754,392],{"class":391},[282,2756,2757],{"class":299}," usePermissions ",[282,2759,398],{"class":303},[282,2761,2762],{"class":299}," createPermissions",[282,2764,2765],{"class":303},"\u003C\n",[282,2767,2768,2771,2774,2776,2778,2780,2782,2784,2786,2788,2790,2792,2794,2796,2798,2800,2802,2804,2806,2808,2811,2813,2815,2817,2820,2822,2824,2826,2828],{"class":284,"line":360},[282,2769,2770],{"class":303},"  {",[282,2772,2773],{"class":451}," role",[282,2775,314],{"class":303},[282,2777,412],{"class":303},[282,2779,230],{"class":323},[282,2781,320],{"class":303},[282,2783,957],{"class":303},[282,2785,412],{"class":303},[282,2787,234],{"class":323},[282,2789,320],{"class":303},[282,2791,957],{"class":303},[282,2793,412],{"class":303},[282,2795,237],{"class":323},[282,2797,320],{"class":303},[282,2799,957],{"class":303},[282,2801,412],{"class":303},[282,2803,240],{"class":323},[282,2805,320],{"class":303},[282,2807,1113],{"class":303},[282,2809,2810],{"class":451}," userId",[282,2812,314],{"class":303},[282,2814,1011],{"class":299},[282,2816,1113],{"class":303},[282,2818,2819],{"class":451}," organizationId",[282,2821,314],{"class":303},[282,2823,1011],{"class":299},[282,2825,957],{"class":303},[282,2827,1160],{"class":303},[282,2829,2830],{"class":303}," },\n",[282,2832,2833,2836],{"class":284,"line":366},[282,2834,2835],{"class":299},"  Permission",[282,2837,332],{"class":303},[282,2839,2840],{"class":284,"line":534},[282,2841,2842],{"class":299},"  Resource\n",[282,2844,2845,2847,2849],{"class":284,"line":572},[282,2846,1463],{"class":303},[282,2848,300],{"class":299},[282,2850,304],{"class":303},[282,2852,2853,2856,2858,2860,2862,2864,2866,2869],{"class":284,"line":610},[282,2854,2855],{"class":310},"  query",[282,2857,314],{"class":303},[282,2859,2702],{"class":299},[282,2861,208],{"class":303},[282,2863,1867],{"class":299},[282,2865,208],{"class":303},[282,2867,2868],{"class":299},"getPermissionContext",[282,2870,332],{"class":303},[282,2872,2873,2875],{"class":284,"line":615},[282,2874,1744],{"class":299},[282,2876,332],{"class":303},[282,2878,2879,2881],{"class":284,"line":625},[282,2880,369],{"class":303},[282,2882,372],{"class":299},[196,2884,2885],{},"Use in components:",[272,2887,2891],{"className":2888,"code":2889,"language":2890,"meta":278,"style":278},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nconst { can, role } = usePermissions()\n\u003C/script>\n\n\u003Ctemplate>\n  \u003Cbutton v-if=\"can('post.create')\">New Post\u003C/button>\n  \u003Cbutton v-if=\"can('org.invite')\">Invite Member\u003C/button>\n\u003C/template>\n","vue",[228,2892,2893,2918,2942,2951,2955,2964,2995,3023],{"__ignoreMap":278},[282,2894,2895,2897,2900,2903,2906,2908,2911,2913,2915],{"class":284,"line":285},[282,2896,1454],{"class":303},[282,2898,2899],{"class":310},"script",[282,2901,2902],{"class":391}," setup",[282,2904,2905],{"class":391}," lang",[282,2907,398],{"class":303},[282,2909,2910],{"class":303},"\"",[282,2912,277],{"class":323},[282,2914,2910],{"class":303},[282,2916,2917],{"class":303},">\n",[282,2919,2920,2923,2925,2928,2930,2933,2935,2937,2940],{"class":284,"line":307},[282,2921,2922],{"class":391},"const",[282,2924,513],{"class":303},[282,2926,2927],{"class":299}," can",[282,2929,409],{"class":303},[282,2931,2932],{"class":299}," role ",[282,2934,369],{"class":303},[282,2936,455],{"class":303},[282,2938,2939],{"class":295}," usePermissions",[282,2941,1875],{"class":299},[282,2943,2944,2947,2949],{"class":284,"line":335},[282,2945,2946],{"class":303},"\u003C/",[282,2948,2899],{"class":310},[282,2950,2917],{"class":303},[282,2952,2953],{"class":284,"line":346},[282,2954,476],{"emptyLinePlaceholder":475},[282,2956,2957,2959,2962],{"class":284,"line":360},[282,2958,1454],{"class":303},[282,2960,2961],{"class":310},"template",[282,2963,2917],{"class":303},[282,2965,2966,2969,2972,2975,2977,2979,2982,2984,2986,2989,2991,2993],{"class":284,"line":366},[282,2967,2968],{"class":303},"  \u003C",[282,2970,2971],{"class":310},"button",[282,2973,2974],{"class":391}," v-if",[282,2976,398],{"class":303},[282,2978,2910],{"class":303},[282,2980,2981],{"class":323},"can('post.create')",[282,2983,2910],{"class":303},[282,2985,1463],{"class":303},[282,2987,2988],{"class":299},"New Post",[282,2990,2946],{"class":303},[282,2992,2971],{"class":310},[282,2994,2917],{"class":303},[282,2996,2997,2999,3001,3003,3005,3007,3010,3012,3014,3017,3019,3021],{"class":284,"line":534},[282,2998,2968],{"class":303},[282,3000,2971],{"class":310},[282,3002,2974],{"class":391},[282,3004,398],{"class":303},[282,3006,2910],{"class":303},[282,3008,3009],{"class":323},"can('org.invite')",[282,3011,2910],{"class":303},[282,3013,1463],{"class":303},[282,3015,3016],{"class":299},"Invite Member",[282,3018,2946],{"class":303},[282,3020,2971],{"class":310},[282,3022,2917],{"class":303},[282,3024,3025,3027,3029],{"class":284,"line":572},[282,3026,2946],{"class":303},[282,3028,2961],{"class":310},[282,3030,2917],{"class":303},[210,3032],{},[213,3034,3036],{"id":3035},"next-customizations","Next Customizations",[221,3038,3039,3054,3060],{},[224,3040,3041,3042,3044,3045,231,3048,231,3051,1959],{},"Add resource groups beyond ",[228,3043,933],{}," (for example ",[228,3046,3047],{},"comment",[228,3049,3050],{},"invoice",[228,3052,3053],{},"project",[224,3055,3056,3057,3059],{},"Tighten org checks in ",[228,3058,253],{}," for all org-scoped resources",[224,3061,3062,3063,3065],{},"Replace broad ",[228,3064,2288],{}," errors with domain-specific errors when needed",[3067,3068,3069],"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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":278,"searchDepth":285,"depth":307,"links":3071},[3072,3073,3074,3075,3076,3077,3078],{"id":215,"depth":307,"text":216},{"id":269,"depth":307,"text":270},{"id":377,"depth":307,"text":378},{"id":1670,"depth":307,"text":1671},{"id":2369,"depth":307,"text":2370},{"id":2686,"depth":307,"text":2687},{"id":3035,"depth":307,"text":3036},"Opinionated starter scaffold for role-based permissions with Better Auth + Convex + Nuxt.","md",null,{},{"icon":99},{"title":96,"description":3079},{"loc":97},"sd1xy1suJHnAwBC2wtNbuWZPMoqgKJLTD9NmjtzZTw8",[3088,3090],{"title":92,"path":93,"stem":94,"description":3089,"icon":33,"children":-1},"API reference for role-based access control with ownership rules.",{"title":106,"path":107,"stem":108,"description":3091,"icon":109,"children":-1},"Execute Convex operations from Nuxt server routes, middleware, and webhooks.",1772891786493]