permdock 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/README.md +106 -47
  2. package/dist/a2a/index.d.ts +7 -16
  3. package/dist/a2a/index.js +59 -98
  4. package/dist/adapter-context-mlWsVGGg.js +23 -0
  5. package/dist/ai-sdk/index.d.ts +37 -16
  6. package/dist/ai-sdk/index.js +30 -13
  7. package/dist/approvals/index.d.ts +3 -3
  8. package/dist/approvals/index.js +5 -4
  9. package/dist/{approvals-DaxY-Bdg.js → approvals-DbYAuNkG.js} +17 -11
  10. package/dist/approvers-DT4AVyIg.js +52 -0
  11. package/dist/{arazzo-CTeVuXr5.js → arazzo-BAgw9ap6.js} +2 -2
  12. package/dist/{arazzo-aoTkqYsJ.js → arazzo-CKwwqFWz.js} +2 -2
  13. package/dist/authzen/index.d.ts +4 -13
  14. package/dist/authzen/index.js +16 -50
  15. package/dist/better-auth/index.d.ts +20 -3
  16. package/dist/better-auth/index.js +27 -7
  17. package/dist/better-supabase/index.d.ts +223 -0
  18. package/dist/better-supabase/index.js +648 -0
  19. package/dist/bind-C_ob3LKa.d.ts +25 -0
  20. package/dist/bind-CuzGytRf.js +97 -0
  21. package/dist/boundary-BM8a_P6E.js +13 -0
  22. package/dist/boundary-BmHxVH1J.d.ts +15 -0
  23. package/dist/canonical-json-DemiK4Vp.js +26 -0
  24. package/dist/{capability-BDG_nkxt.d.ts → capability-2kYTMWDv.d.ts} +2 -2
  25. package/dist/{capability-B68OFnZx.js → capability-4qPdO9gk.js} +7 -5
  26. package/dist/catalog/index.d.ts +1 -1
  27. package/dist/catalog/index.js +1 -1
  28. package/dist/catalog-CRW5Mx_B.js +2 -0
  29. package/dist/{catalog-H-vFGwWK.js → catalog-DWF5cYqB.js} +4 -4
  30. package/dist/{catalog-B0E6bggc.js → catalog-dFZdWCGN.js} +2 -2
  31. package/dist/{catalog-doc-BSo_Q_-6.js → catalog-doc-DdGm82XT.js} +20 -32
  32. package/dist/claude-agent/index.d.ts +5 -14
  33. package/dist/claude-agent/index.js +4 -10
  34. package/dist/clerk/index.d.ts +12 -3
  35. package/dist/clerk/index.js +26 -5
  36. package/dist/cli/bin.js +1 -1
  37. package/dist/cli/index.d.ts +3 -3
  38. package/dist/cli/index.js +2 -2
  39. package/dist/clients-C7zLFuWT.d.ts +12 -0
  40. package/dist/clients-DjU5ABMy.js +23 -0
  41. package/dist/cloud/index.d.ts +4 -5
  42. package/dist/cloud/index.js +20 -6
  43. package/dist/{cloud-BNQTrmrr.js → cloud-CB_ELYuX.js} +2 -2
  44. package/dist/{cloud-Cuxr6Czw.js → cloud-DWLXO2af.js} +7 -6
  45. package/dist/collect-DClJsheJ.js +83 -0
  46. package/dist/{collect-O-tOtbnk.js → collect-DSTE3ml9.js} +194 -42
  47. package/dist/collect-DSWOk19R.js +2 -0
  48. package/dist/{commands-BMh_Etm2.js → commands-DSxCqG9A.js} +16 -12
  49. package/dist/compile/index.d.ts +3 -0
  50. package/dist/compile/index.js +2 -0
  51. package/dist/{compile-D22iwvuV.js → compile-Ba4blROR.js} +85 -30
  52. package/dist/compile-BkRyBDBw.d.ts +94 -0
  53. package/dist/config-BJiM-xAm.js +157 -0
  54. package/dist/config-Dnszbv-6.js +36 -0
  55. package/dist/config-report-DMvWKUxL.js +44 -0
  56. package/dist/{connection-JvqwHODC.js → connection-CU8MQxRi.js} +1 -1
  57. package/dist/{context-CKEAabd7.js → context-Bcy85rGi.js} +36 -27
  58. package/dist/convex/index.d.ts +9 -4
  59. package/dist/convex/index.js +14 -4
  60. package/dist/create-B1d519XK.d.ts +245 -0
  61. package/dist/create-CMwIl-w2.js +253 -0
  62. package/dist/{credential-B_rkUNlY.js → credential-8P81ff4u.js} +26 -46
  63. package/dist/delegation-D8pUEuce.js +103 -0
  64. package/dist/{describe-Bt1YD5uS.js → describe-B_gVZEVi.js} +10 -15
  65. package/dist/{describe-DernyItf.d.ts → describe-DMYiCjJV.d.ts} +9 -10
  66. package/dist/{diff-x5Il8LVa.js → diff-2VaeChzX.js} +44 -11
  67. package/dist/{diff-BUzf5Poi.js → diff-DBIhz_f2.js} +2 -2
  68. package/dist/{doctor-Bqo6FwUa.js → doctor-BwCAMLx_.js} +2 -2
  69. package/dist/doctor-collect-CHk6XWOA.js +665 -0
  70. package/dist/doctor-igIiM_Hl.js +1194 -0
  71. package/dist/drizzle/index.d.ts +4 -3
  72. package/dist/drizzle/index.js +3 -3
  73. package/dist/elysia/index.d.ts +6 -28
  74. package/dist/elysia/index.js +16 -60
  75. package/dist/{errors-DSMnAVNa.js → errors-CWfoNg9N.js} +8 -4
  76. package/dist/{errors-Iy71s7Oj.js → errors-Cz5zn0mW.js} +17 -71
  77. package/dist/{errors-DbZ1YOnb.d.ts → errors-DPdqI50v.d.ts} +8 -21
  78. package/dist/{errors-m3u9TmDu.js → errors-DRnGZHzF.js} +4 -1
  79. package/dist/evaluation-items-CfCCejQd.js +40 -0
  80. package/dist/{evaluations-DsAU9ppl.js → evaluations-tz6D9A2G.js} +28 -46
  81. package/dist/eve/index.d.ts +6 -15
  82. package/dist/eve/index.js +7 -12
  83. package/dist/expiry-BoBJ8Tvc.js +7 -0
  84. package/dist/express/index.d.ts +6 -29
  85. package/dist/express/index.js +28 -58
  86. package/dist/fastify/index.d.ts +6 -29
  87. package/dist/fastify/index.js +16 -65
  88. package/dist/fields-BMl1RxoX.js +26 -0
  89. package/dist/{files-B_wAGYmt.js → files-DWUN9PzI.js} +5 -1
  90. package/dist/{fixtures-Cvaw0gDG.js → fixtures-ht28Cplr.js} +5 -2
  91. package/dist/{freeze-y1_jQL4v.js → freeze-CrU8nQeX.js} +31 -2
  92. package/dist/{from-snapshot-BMGnhmgv.js → from-snapshot-CTLijvdm.js} +66 -48
  93. package/dist/{grantee-Bv04_Vzf.js → grantee-Cv5Sogfv.js} +88 -7
  94. package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
  95. package/dist/{headers-B5RRv3Xm.js → headers-BZSDieNT.js} +1 -1
  96. package/dist/{headers-C8SHQccD.d.ts → headers-Cf-zWvsO.d.ts} +1 -1
  97. package/dist/helpers-H_KARDVC.js +421 -0
  98. package/dist/hono/index.d.ts +6 -28
  99. package/dist/hono/index.js +11 -43
  100. package/dist/{hosted-BwKQ1BTA.js → hosted-DJQw46hn.js} +6 -5
  101. package/dist/{http-GgVApX1k.js → http-BIhmLfCc.js} +4 -20
  102. package/dist/http-SO7qGttf.js +44 -0
  103. package/dist/ids-DC4V4CFu.js +18 -0
  104. package/dist/index-0nNqHspG.d.ts +6 -0
  105. package/dist/{index-xIxJLwOQ.d.ts → index-BNc7Wer_.d.ts} +75 -7
  106. package/dist/{index-CltcQ4Bf.d.ts → index-C7Tw7MaW.d.ts} +68 -5
  107. package/dist/{index-LF_hS-yn.d.ts → index-C8z4RjQV.d.ts} +1 -1
  108. package/dist/index.d.ts +14 -9
  109. package/dist/index.js +22 -17
  110. package/dist/instance-options-Dhhcnm3y.js +22 -0
  111. package/dist/instance-options-jARdwfPN.d.ts +11 -0
  112. package/dist/{parse-DPfIvFMU.js → json-schema-BsAflUGW.js} +28 -57
  113. package/dist/jwt/index.d.ts +10 -6
  114. package/dist/jwt/index.js +32 -13
  115. package/dist/kernel-_RRHmnMY.js +208 -0
  116. package/dist/kysely/index.d.ts +4 -3
  117. package/dist/kysely/index.js +3 -3
  118. package/dist/live-options-H2eG8dfJ.js +60 -0
  119. package/dist/{load-BZ24CpZP.js → load-DhWEB9P1.js} +16 -10
  120. package/dist/load-DwJUafYN.js +2 -0
  121. package/dist/manifest-iaoBXHKc.js +783 -0
  122. package/dist/manifest-uDS9y5de.d.ts +206 -0
  123. package/dist/{map-DowSO96j.js → map-AcxK9o_D.js} +4 -15
  124. package/dist/{map-claims-B_6I1Rn-.js → map-claims-Z4QZOiFF.js} +13 -4
  125. package/dist/map-error-pgUWNNtG.js +23 -0
  126. package/dist/may-use-DndQ5tQ-.js +77 -0
  127. package/dist/mcp/index.d.ts +54 -22
  128. package/dist/mcp/index.js +218 -178
  129. package/dist/nest/index.d.ts +26 -31
  130. package/dist/nest/index.js +75 -84
  131. package/dist/next/client.d.ts +7 -8
  132. package/dist/next/client.js +11 -9
  133. package/dist/next/index.d.ts +30 -47
  134. package/dist/next/index.js +45 -60
  135. package/dist/next/plugin.d.ts +1 -1
  136. package/dist/next/plugin.js +32 -1
  137. package/dist/node/index.d.ts +9 -28
  138. package/dist/node/index.js +11 -43
  139. package/dist/openai/index.d.ts +6 -15
  140. package/dist/openai/index.js +7 -20
  141. package/dist/openapi/index.d.ts +87 -4
  142. package/dist/openapi/index.js +3 -3
  143. package/dist/{openapi-DcqM8nU7.js → openapi-BqRBvAng.js} +237 -5
  144. package/dist/{openapi-DWD0Uc_4.js → openapi-CqqEbHsL.js} +5 -5
  145. package/dist/{openapi-import-BWRUNNeW.js → openapi-import-cmwetbzw.js} +1 -1
  146. package/dist/{openapi-CwePaF7C.js → openapi-l0xYHkcv.js} +3 -3
  147. package/dist/{openapi-schema-D8j_T9tO.js → openapi-schema--ARjyfQr.js} +2 -2
  148. package/dist/orpc/index.d.ts +15 -28
  149. package/dist/orpc/index.js +74 -117
  150. package/dist/otel/index.d.ts +2 -2
  151. package/dist/parse-BuyjxhZV.js +53 -0
  152. package/dist/parse-local-manifest-BrMozJCo.js +36 -0
  153. package/dist/parse-local-manifest-JLnaBH0S.d.ts +10 -0
  154. package/dist/pdp/index.d.ts +2 -2
  155. package/dist/pdp/index.js +14 -127
  156. package/dist/{permdock-yoZ7EjxX.js → permdock-CbgvLnuo.js} +672 -149
  157. package/dist/{permissions-B8vCg_bI.d.ts → permissions-CDgvKG5L.d.ts} +2 -2
  158. package/dist/{permissions-DC7GROPA.js → permissions-DVoF6dMt.js} +77 -15
  159. package/dist/{permissions-B4apnahQ.d.ts → permissions-DttnqqxC.d.ts} +34 -5
  160. package/dist/{permissions-CofRqesP.js → permissions-RJrovw98.js} +3 -3
  161. package/dist/{pins-CqE1jZuF.js → pins-8ILTftC9.js} +2 -2
  162. package/dist/{policy-Cq2fB8Q5.d.ts → policy-D2W7uv19.d.ts} +2 -2
  163. package/dist/{policy-CInmNGkM.d.ts → policy-IB6yxpC3.d.ts} +351 -42
  164. package/dist/{policy-ANp36PnI.js → policy-xyWg7QdR.js} +173 -22
  165. package/dist/powersync-BylawD_U.js +540 -0
  166. package/dist/powersync-DliZK_-y.js +62 -0
  167. package/dist/powersync-e_AZrKbg.js +2 -0
  168. package/dist/prisma/index.d.ts +3 -2
  169. package/dist/prisma/index.js +45 -20
  170. package/dist/{problem-Cgp9-KZA.js → problem-B43ztKIm.js} +74 -109
  171. package/dist/problem-details-DX075l9V.d.ts +7 -0
  172. package/dist/problem-details-_AMOYz-w.js +144 -0
  173. package/dist/{protected-BuPAycJT.d.ts → protected-BdnIEFkY.d.ts} +5 -4
  174. package/dist/protected-utU-SLuy.js +100 -0
  175. package/dist/protected-xAr24FEC.d.ts +40 -0
  176. package/dist/provider-CSQd7m92.js +52 -0
  177. package/dist/{provider-wTAUda2v.d.ts → provider-DZY281jO.d.ts} +1 -1
  178. package/dist/provider-store-Cfbvo4DE.js +43 -0
  179. package/dist/react/index.d.ts +7 -5
  180. package/dist/react/index.js +5 -4
  181. package/dist/react/provider-client.d.ts +1 -1
  182. package/dist/react/provider-client.js +1 -1
  183. package/dist/react-native/index.d.ts +166 -10
  184. package/dist/react-native/index.js +607 -85
  185. package/dist/{refs-ChLSxbST.js → refs-KYb4ntaz.js} +4 -3
  186. package/dist/{relations-r4soIFZB.js → relations-cjOL01hZ.js} +110 -31
  187. package/dist/replay-BsOyTrdV.js +28 -0
  188. package/dist/replay-CYyiLiwO.d.ts +5 -0
  189. package/dist/resource-ref-CaS9yVPi.js +20 -0
  190. package/dist/revocations-Bhr0aMIC.js +27 -0
  191. package/dist/{rls-BOFU3chG.js → rls-B4ur8nKQ.js} +8 -3
  192. package/dist/rls-DQtdgTHB.js +2521 -0
  193. package/dist/rls-fields-74oZPXWL.js +3582 -0
  194. package/dist/{rls-graph-DxQ39PJj.js → rls-graph-CHwx0V8q.js} +100 -36
  195. package/dist/{rls-import-CXV6LBlS.js → rls-import-BTFVk3jH.js} +7 -6
  196. package/dist/{rls-migrate-DrFPbf8p.js → rls-migrate-CN4TlJTO.js} +6 -5
  197. package/dist/rls-ownership-RuFqaqGz.js +843 -0
  198. package/dist/rls-shared-Cewd_-zI.js +495 -0
  199. package/dist/rls-verify-CVQTHTh5.js +746 -0
  200. package/dist/{row-check-BajTgQZ-.d.ts → row-check-Dt35czLy.d.ts} +12 -15
  201. package/dist/row-conditions-h2HythXQ.js +27 -0
  202. package/dist/rpc-DL9Sqvb1.js +89 -0
  203. package/dist/{run-CJ6UvS3a.js → run-DKDbM4Du.js} +31 -12
  204. package/dist/runtime-CB8gQFvS.js +11 -0
  205. package/dist/{saas-BRrZzJkM.js → saas-DhpJjnBA.js} +17 -7
  206. package/dist/{schema-P8yoma__.js → schema-D3MnDMxa.js} +8 -4
  207. package/dist/scim/index.d.ts +1 -1
  208. package/dist/scim/index.js +1 -1
  209. package/dist/{scim-9NFa0XVZ.js → scim-BFGBBAqR.js} +1 -1
  210. package/dist/{scopes-cKVp_WTw.js → scopes-CVdPrWN-.js} +35 -8
  211. package/dist/server/index.d.ts +22 -11
  212. package/dist/server/index.js +11 -8
  213. package/dist/{credentials-BgRX3WEg.js → server-DlZ28Oz5.js} +1 -1
  214. package/dist/shared-DRu8VFVM.js +123 -0
  215. package/dist/{sink-Cfr9-7YC.d.ts → sink-B1fZzIMf.d.ts} +1 -1
  216. package/dist/skills-Biq5uup3.js +192 -0
  217. package/dist/{skills-C_lpV4Jx.js → skills-Bx-U0irG.js} +10 -4
  218. package/dist/{snapshot-DE8dE_hz.js → snapshot-Enxd0n-s.js} +138 -214
  219. package/dist/snapshot-cache-B-LxUahj.d.ts +45 -0
  220. package/dist/snapshot-cache-D6jLelln.js +44 -0
  221. package/dist/solid/index.d.ts +39 -9
  222. package/dist/solid/index.js +76 -85
  223. package/dist/sources-4p0-4xQm.js +545 -0
  224. package/dist/sources-BdOYLw9j.d.ts +192 -0
  225. package/dist/{sql-Bll1d7y0.js → sql-xdg5f4Fi.js} +6 -1
  226. package/dist/{src-CTNT-PBW.js → src-BDwEZWrZ.js} +149 -11
  227. package/dist/ssf/index.d.ts +3 -2
  228. package/dist/ssf/index.js +3 -29
  229. package/dist/store-DMAWwAJV.js +371 -0
  230. package/dist/{store-Bq90395i.d.ts → store-jOBYpiXC.d.ts} +13 -4
  231. package/dist/store-options-ByhZq1jV.js +716 -0
  232. package/dist/{stores-CkG2HrSg.js → stores-BT2pSCub.js} +10 -63
  233. package/dist/{stores-CvOnu_2T.d.ts → stores-C0IMQrGI.d.ts} +20 -9
  234. package/dist/{stream-BhMfZOwr.d.ts → stream-D1RXubw2.d.ts} +2 -2
  235. package/dist/{stream-Q_xlB6Ko.js → stream-DDpvynSB.js} +16 -2
  236. package/dist/subject-settings-BwBmCdTR.js +128 -0
  237. package/dist/supabase/index.d.ts +133 -6
  238. package/dist/supabase/index.js +4 -3
  239. package/dist/supabase/middleware.d.ts +32 -27
  240. package/dist/supabase/middleware.js +56 -22
  241. package/dist/{supabase-D8UlBA7Z.js → supabase-Boqb9a_Y.js} +3 -3
  242. package/dist/{supabase-DTxGtYdi.js → supabase-C0qESOa-.js} +347 -367
  243. package/dist/supabase-config-BpPXt3x1.js +472 -0
  244. package/dist/supabase-hook-6sYLXg_u.js +2 -0
  245. package/dist/{supabase-hook-D_OqGb_V.js → supabase-hook-CSLQ4zJ3.js} +1037 -705
  246. package/dist/supautils-Cn4R4cJ4.js +91 -0
  247. package/dist/svelte/PermissionBoundary.svelte +37 -0
  248. package/dist/svelte/Protected.svelte +8 -2
  249. package/dist/svelte/index.d.ts +9 -6
  250. package/dist/svelte/index.js +61 -7
  251. package/dist/svelte/runtime.d.ts +4 -3
  252. package/dist/svelte/runtime.js +4 -3
  253. package/dist/svelte/source.d.ts +9 -6
  254. package/dist/svelte/source.js +7 -4
  255. package/dist/terminal/index.d.ts +6 -14
  256. package/dist/terminal/index.js +44 -32
  257. package/dist/testing/index.d.ts +105 -16
  258. package/dist/testing/index.js +504 -40
  259. package/dist/testing/saas/index.d.ts +4 -4
  260. package/dist/testing/saas/index.js +2 -2
  261. package/dist/testing/saas/permissions.d.ts +1 -1
  262. package/dist/testing/saas/permissions.js +1 -1
  263. package/dist/token-CIWxJOCh.js +50 -0
  264. package/dist/trpc/index.d.ts +7 -26
  265. package/dist/trpc/index.js +17 -100
  266. package/dist/types-BnIEz1sU.d.ts +48 -0
  267. package/dist/{types-CxquUByI.d.ts → types-Bvc4oWT6.d.ts} +1 -1
  268. package/dist/{sources-DOpW5Ila.d.ts → types-C97IskBw.d.ts} +86 -127
  269. package/dist/types-CKNSyIf_.d.ts +52 -0
  270. package/dist/types-Cq_H8N_X.d.ts +197 -0
  271. package/dist/{types-D6Z6-rKJ.d.ts → types-DbjRN55U.d.ts} +273 -22
  272. package/dist/{types-BBK-exvJ.d.ts → types-Dnemwd77.d.ts} +7 -1
  273. package/dist/{types-BvBk1wgn.d.ts → types-DxiCGmmd.d.ts} +5 -3
  274. package/dist/{types-B9dmiiab.d.ts → types-QCuYJh4q.d.ts} +1 -1
  275. package/dist/{types-B8w5PFtS.d.ts → types-aqOHTHcp.d.ts} +17 -1
  276. package/dist/unplugin/index.d.ts +1 -1
  277. package/dist/unplugin/index.js +10 -9
  278. package/dist/usage-DorAJiU_.js +2 -0
  279. package/dist/{usage-1ozMubLY.js → usage-GTixvDDU.js} +2 -2
  280. package/dist/{usage-CUnK6Ou9.js → usage-ItS7nLcl.js} +225 -62
  281. package/dist/validation-error-Ba264OaJ.d.ts +26 -0
  282. package/dist/validation-error-CnjZ4t92.js +33 -0
  283. package/dist/{validity-D0uRmJKJ.js → validity-uOp8UpYn.js} +57 -36
  284. package/dist/{verifier-B90agnhl.js → verifier-BxBo6I44.js} +10 -5
  285. package/dist/version-BvacVTZR.js +17 -0
  286. package/dist/views-Soe7bGSC.js +95 -0
  287. package/dist/{vocabulary-Dk0fs-Jk.d.ts → vocabulary-DA8a8zif.d.ts} +1 -1
  288. package/dist/vue/index.d.ts +35 -13
  289. package/dist/vue/index.js +86 -93
  290. package/dist/watch-BwxLTYMZ.js +2 -0
  291. package/dist/watch-DVBJ9cBq.js +128 -0
  292. package/dist/webmcp/index.d.ts +2 -2
  293. package/dist/webmcp/index.js +7 -13
  294. package/package.json +62 -36
  295. package/schemas/approval-request-v1.json +175 -0
  296. package/schemas/catalog-v1.json +29 -1
  297. package/schemas/supabase-claims-v1.json +6 -1
  298. package/schemas/supabase-manifest-v1.json +150 -6
  299. package/skills/permdock/SKILL.md +7 -7
  300. package/skills/permdock-agents/SKILL.md +5 -5
  301. package/skills/permdock-agents/references/runtimes.md +12 -10
  302. package/skills/permdock-approvals/SKILL.md +4 -4
  303. package/skills/permdock-approvals/references/stores-and-resume.md +15 -4
  304. package/skills/permdock-audit/SKILL.md +3 -3
  305. package/skills/permdock-credentials/SKILL.md +4 -4
  306. package/skills/permdock-credentials/references/tokens-keys-links.md +7 -2
  307. package/skills/permdock-data/SKILL.md +4 -4
  308. package/skills/permdock-data/references/queries-and-rls.md +14 -6
  309. package/skills/permdock-data/references/relationships.md +5 -3
  310. package/skills/permdock-tenancy/SKILL.md +9 -6
  311. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +14 -8
  312. package/skills/permdock-wire/SKILL.md +4 -4
  313. package/skills/permdock-wire/references/adapters.md +42 -30
  314. package/skills/permdock-wire/references/policy-options.md +5 -3
  315. package/dist/approvers-aH0PJkmf.js +0 -20
  316. package/dist/catalog-idsHc0vo.js +0 -2
  317. package/dist/collect-B7_TIfmg.js +0 -49
  318. package/dist/collect-fRPAQIWb.js +0 -2
  319. package/dist/compile-CQbvyIBr.d.ts +0 -30
  320. package/dist/config-BPYmjTOp.js +0 -26
  321. package/dist/context-gtAwAILx.js +0 -6
  322. package/dist/create-BKF3dgFk.d.ts +0 -162
  323. package/dist/create-CSkhDU9T.js +0 -222
  324. package/dist/doctor-BGle8Gqi.js +0 -1314
  325. package/dist/helpers-DnSOrhB9.js +0 -682
  326. package/dist/index-fG6NSXlc.d.ts +0 -9
  327. package/dist/kernel-YOGCWNLf.js +0 -211
  328. package/dist/load-QOOm1z70.js +0 -2
  329. package/dist/manifest-DDQbC6K0.d.ts +0 -118
  330. package/dist/map-error-RJ3ZsUyA.js +0 -16
  331. package/dist/may-use-CnFEjVEp.js +0 -37
  332. package/dist/pg-4GJWDUxG.js +0 -953
  333. package/dist/plugin-4gr7IxFJ.js +0 -65
  334. package/dist/protected-B4K3BKoX.js +0 -138
  335. package/dist/protected-wY7nXhY9.d.ts +0 -23
  336. package/dist/provider-_wx46HpB.js +0 -48
  337. package/dist/rls-CJVja9Ww.js +0 -2119
  338. package/dist/rls-helpers-BxRuif0l.js +0 -1346
  339. package/dist/runtime-DP9ttFh1.js +0 -27
  340. package/dist/skills-Dx3QLnMY.js +0 -110
  341. package/dist/source-DoBBYJi2.js +0 -6
  342. package/dist/sources-DVHM3Mwq.js +0 -284
  343. package/dist/store-C6hFW6ta.js +0 -508
  344. package/dist/subject-settings-xt7V845g.js +0 -82
  345. package/dist/supabase-hook-DW-xP4hU.js +0 -2
  346. package/dist/types-DbWdEfcm.d.ts +0 -87
  347. package/dist/types-bva3i4Gf.d.ts +0 -98
  348. package/dist/types-i4BAOvdb.d.ts +0 -97
  349. package/dist/usage-PyEor6GA.js +0 -2
  350. package/dist/version-CnSh33Fj.js +0 -16
@@ -1,12 +1,13 @@
1
1
  import { t as compact } from "./compact-y6vfu2_f.js";
2
- import { n as freezeDeep } from "./freeze-y1_jQL4v.js";
3
- import { t as ignoreRejection } from "./thenable-okc2xDsj.js";
4
- import { t as anonymousSubject } from "./subject-C6dLxqHU.js";
5
- import { o as parseCapability } from "./capability-B68OFnZx.js";
2
+ import { t as canonicalJson } from "./canonical-json-DemiK4Vp.js";
3
+ import { o as parseCapability } from "./capability-4qPdO9gk.js";
4
+ import { t as ApprovalError } from "./errors-DRnGZHzF.js";
5
+ import { a as decodeApprovalCursor, i as approvalPageSize, o as encodeApprovalCursor, t as applyApprovalVerdict } from "./store-DMAWwAJV.js";
6
6
  import { t as loadJose } from "./load-jose-BL6LH4bL.js";
7
7
  import "./budget-NbEtbJC_.js";
8
- import { a as quoteSqlTable, i as quoteSqlLiteral, r as quoteSqlIdent } from "./sql-Bll1d7y0.js";
9
- import "./sources-DVHM3Mwq.js";
8
+ import { a as quoteSqlTable, i as quoteSqlLiteral, r as quoteSqlIdent } from "./sql-xdg5f4Fi.js";
9
+ import { c as hookApiNames, d as keptKeys, l as roleColumn } from "./sources-4p0-4xQm.js";
10
+ import { i as readMemberships } from "./manifest-iaoBXHKc.js";
10
11
  //#region src/supabase/capability.ts
11
12
  const DEFAULT_TTL = 300;
12
13
  const MAX_TTL = 3600;
@@ -62,7 +63,7 @@ const KNOWN = /* @__PURE__ */ new Set([
62
63
  "act",
63
64
  "app_metadata"
64
65
  ]);
65
- function isRecord$1(value) {
66
+ function isRecord$2(value) {
66
67
  return value !== null && typeof value === "object" && !Array.isArray(value);
67
68
  }
68
69
  function own(record, key) {
@@ -83,7 +84,7 @@ function optional(record, key, path, issues, check, expected) {
83
84
  }
84
85
  const isString = (value) => typeof value === "string";
85
86
  function checkMembership(item, path, issues) {
86
- if (!isRecord$1(item)) {
87
+ if (!isRecord$2(item)) {
87
88
  issue(issues, path, "Expected a membership object");
88
89
  return;
89
90
  }
@@ -98,13 +99,14 @@ function checkMembership(item, path, issues) {
98
99
  "grantedBy",
99
100
  "reason"
100
101
  ]) optional(item, key, path, issues, isString, "a string");
101
- optional(item, "within", path, issues, (value) => isRecord$1(value) && Object.values(value).every((id) => typeof id === "string"), "an object of string ids");
102
- optional(item, "on", path, issues, (value) => isRecord$1(value) && typeof own(value, "resource") === "string" && typeof own(value, "id") === "string", "an object with string resource and id");
102
+ optional(item, "within", path, issues, (value) => isRecord$2(value) && Object.values(value).every((id) => typeof id === "string"), "an object of string ids");
103
+ optional(item, "on", path, issues, (value) => isRecord$2(value) && typeof own(value, "resource") === "string" && typeof own(value, "id") === "string", "an object with string resource and id");
103
104
  optional(item, "expiresAt", path, issues, (value) => typeof value === "number" && Number.isFinite(value), "a number of seconds since the epoch");
104
- optional(item, "member", path, issues, (value) => isRecord$1(value) && typeof own(value, "group") === "string" && own(value, "group") !== "", "an object with a non-empty string group");
105
+ optional(item, "member", path, issues, (value) => isRecord$2(value) && typeof own(value, "group") === "string" && own(value, "group") !== "", "an object with a non-empty string group");
105
106
  optional(item, "managedBy", path, issues, (value) => value === "idp", "'idp'");
106
107
  optional(item, "entitlements", path, issues, isStrings, "an array of strings");
107
- optional(item, "grants", path, issues, isRecord$1, "an object");
108
+ optional(item, "keep", path, issues, isStrings, "an array of strings");
109
+ optional(item, "grants", path, issues, isRecord$2, "an object");
108
110
  if (!(own(item, "scope") !== void 0 && own(item, "id") !== void 0 || own(item, "tenant") !== void 0 || own(item, "team") !== void 0 || own(item, "on") !== void 0)) issue(issues, path, "Expected scope and id, tenant, team or on");
109
111
  }
110
112
  function checkPermDockClaims(record, tenantClaim, path, issues) {
@@ -121,7 +123,7 @@ function checkPermDockClaims(record, tenantClaim, path, issues) {
121
123
  }
122
124
  optional(record, "memberships_truncated", path, issues, (value) => typeof value === "boolean", "a boolean");
123
125
  optional(record, tenantClaim, path, issues, isString, "a string");
124
- optional(record, "attrs", path, issues, isRecord$1, "an object");
126
+ optional(record, "attrs", path, issues, isRecord$2, "an object");
125
127
  optional(record, "authz_ver", path, issues, (value) => Number.isInteger(value), "an integer");
126
128
  }
127
129
  /** The outer level's `kind`: none, `support` with a `session_id`, or `impersonation`. */
@@ -142,7 +144,7 @@ function checkAct(value, issues) {
142
144
  let current = value;
143
145
  const path = ["act"];
144
146
  while (current !== void 0) {
145
- if (!isRecord$1(current)) {
147
+ if (!isRecord$2(current)) {
146
148
  issue(issues, path, "Expected an object");
147
149
  return;
148
150
  }
@@ -155,7 +157,7 @@ function checkAct(value, issues) {
155
157
  }
156
158
  function checkClaims(value, tenantClaim) {
157
159
  const issues = [];
158
- if (!isRecord$1(value)) {
160
+ if (!isRecord$2(value)) {
159
161
  issue(issues, [], "Expected a claims object");
160
162
  return issues;
161
163
  }
@@ -166,7 +168,7 @@ function checkClaims(value, tenantClaim) {
166
168
  if (act !== void 0) checkAct(act, issues);
167
169
  const meta = own(value, "app_metadata");
168
170
  if (meta !== void 0) {
169
- if (isRecord$1(meta)) checkPermDockClaims(meta, tenantClaim, ["app_metadata"], issues);
171
+ if (isRecord$2(meta)) checkPermDockClaims(meta, tenantClaim, ["app_metadata"], issues);
170
172
  else issue(issues, ["app_metadata"], "Expected an object");
171
173
  }
172
174
  return issues;
@@ -176,8 +178,8 @@ function merge(base, app) {
176
178
  if (issues.length > 0) return { issues };
177
179
  const baseValue = base.value;
178
180
  const appValue = app.value;
179
- if (!isRecord$1(appValue)) return { issues: [{ message: "Expected the extension to output an object" }] };
180
- return { value: isRecord$1(baseValue) ? {
181
+ if (!isRecord$2(appValue)) return { issues: [{ message: "Expected the extension to output an object" }] };
182
+ return { value: isRecord$2(baseValue) ? {
181
183
  ...baseValue,
182
184
  ...appValue
183
185
  } : appValue };
@@ -190,9 +192,9 @@ function schemaOf(validate) {
190
192
  validate
191
193
  }),
192
194
  extend(app) {
193
- if (!isRecord$1(app) && typeof app !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
195
+ if (!isRecord$2(app) && typeof app !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
194
196
  const props = Reflect.get(app, "~standard");
195
- if (!isRecord$1(props) || typeof props["validate"] !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
197
+ if (!isRecord$2(props) || typeof props["validate"] !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
196
198
  const run = app["~standard"].validate.bind(app["~standard"]);
197
199
  return schemaOf((value) => {
198
200
  const base = validate(value);
@@ -223,6 +225,289 @@ function supabaseClaims(options = {}) {
223
225
  });
224
226
  }
225
227
  //#endregion
228
+ //#region src/supabase/postgrest.ts
229
+ function callRpc(client, schema, fn, args) {
230
+ return client.schema(schema).rpc(fn, args);
231
+ }
232
+ function isRecord$1(value) {
233
+ return value !== null && typeof value === "object" && !Array.isArray(value);
234
+ }
235
+ function strings(value) {
236
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
237
+ }
238
+ function grantOf(value) {
239
+ if (!isRecord$1(value) || typeof value["permission"] !== "string") return;
240
+ return compact({
241
+ permission: value["permission"],
242
+ effect: value["effect"] === "deny" ? "deny" : "allow",
243
+ level: typeof value["level"] === "string" ? value["level"] : void 0
244
+ });
245
+ }
246
+ function customRoleOf(value) {
247
+ if (!isRecord$1(value) || typeof value["name"] !== "string") return;
248
+ const grants = Array.isArray(value["grants"]) ? value["grants"].flatMap((item) => {
249
+ const grant = grantOf(item);
250
+ return grant === void 0 ? [] : [grant];
251
+ }) : [];
252
+ const includes = strings(value["includes"]);
253
+ const body = {
254
+ name: value["name"],
255
+ grants,
256
+ ...includes.length === 0 ? {} : { includes }
257
+ };
258
+ if (value["scope"] === "global") return value["tenant"] === void 0 ? {
259
+ ...body,
260
+ scope: "global"
261
+ } : void 0;
262
+ if (typeof value["tenant"] !== "string") return;
263
+ return compact({
264
+ ...body,
265
+ tenant: value["tenant"],
266
+ scope: typeof value["scope"] === "string" ? value["scope"] : void 0,
267
+ id: typeof value["id"] === "string" ? value["id"] : void 0
268
+ });
269
+ }
270
+ function readMemberEntries(value) {
271
+ if (!Array.isArray(value)) return [];
272
+ return value.flatMap((item) => {
273
+ if (!isRecord$1(item) || !isRecord$1(item["principal"])) return [];
274
+ const id = item["principal"]["id"];
275
+ const [membership] = readMemberships([item["membership"]]).memberships;
276
+ return typeof id === "string" && id !== "" && membership !== void 0 ? [{
277
+ principal: { id },
278
+ membership
279
+ }] : [];
280
+ });
281
+ }
282
+ function versionOf(value) {
283
+ const version = typeof value === "string" ? Number(value) : value;
284
+ return typeof version === "number" && Number.isFinite(version) ? version : void 0;
285
+ }
286
+ /** Reads `subject_for`'s JSON; anything it cannot read is left out, and a malformed record is no record. */
287
+ function readSubjectRecord(value) {
288
+ if (!isRecord$1(value) || typeof value["id"] !== "string") return;
289
+ if (value["active"] !== true) return {
290
+ id: value["id"],
291
+ active: false,
292
+ roles: [],
293
+ memberships: [],
294
+ customRoles: []
295
+ };
296
+ const version = value["authzVersion"];
297
+ return compact({
298
+ id: value["id"],
299
+ active: true,
300
+ roles: strings(value["roles"]),
301
+ memberships: readMemberships(value["memberships"]).memberships,
302
+ customRoles: Array.isArray(value["customRoles"]) ? value["customRoles"].flatMap((item) => {
303
+ const role = customRoleOf(item);
304
+ return role === void 0 ? [] : [role];
305
+ }) : [],
306
+ authzVersion: typeof version === "number" && Number.isFinite(version) ? version : void 0
307
+ });
308
+ }
309
+ /**
310
+ * Membership, custom-role and subject sources over the `subject_for(p_user)`,
311
+ * `authz_version_for(p_user)` and `members_of(p_scope, p_id)` functions
312
+ * `permdock supabase hook generate` writes, for a backend that reaches
313
+ * Postgres only through PostgREST. `memberships.version` reads only the
314
+ * version, so `claimsFirst` with `onStale: 'reread'` reads the full subject
315
+ * only for a stale token; when the version function is missing it falls back
316
+ * to `subject_for`. With `policy`, a token that claims a custom role has its
317
+ * subject read in one `subject_for` call instead, and custom roles are read
318
+ * only for a subject that holds one. Each user and each instance is read once per
319
+ * `postgrestSources` call, so create it per request or per job.
320
+ */
321
+ function postgrestSources(client, options = {}) {
322
+ const api = options.api;
323
+ const names = api === void 0 ? void 0 : hookApiNames(api.prefix);
324
+ const schema = options.schema ?? (api === void 0 ? "permdock" : api.schema ?? "public");
325
+ const fn = options.fn ?? names?.subjectFor ?? "subject_for";
326
+ const membersFn = options.membersFn ?? names?.membersOf ?? "members_of";
327
+ const versionFn = options.versionFn ?? names?.authzVersionFor ?? "authz_version_for";
328
+ const declared = options.policy === void 0 ? void 0 : options.policy.index.declaredRoles;
329
+ const onlyDeclared = (held) => declared !== void 0 && held?.every((name) => declared.has(name)) === true;
330
+ const loaded = /* @__PURE__ */ new Map();
331
+ const versions = /* @__PURE__ */ new Map();
332
+ const listed = /* @__PURE__ */ new Map();
333
+ const list = (query) => {
334
+ const key = JSON.stringify([query.scope, query.id]);
335
+ const cached = listed.get(key);
336
+ if (cached !== void 0) return cached.then((entries) => [...entries]);
337
+ const pending = Promise.resolve(callRpc(client, schema, membersFn, {
338
+ p_scope: query.scope,
339
+ p_id: query.id
340
+ })).then((result) => {
341
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${membersFn} failed: ${result.error.message}`);
342
+ return readMemberEntries(result.data);
343
+ });
344
+ listed.set(key, pending);
345
+ return pending.then((entries) => [...entries]);
346
+ };
347
+ const record = (userId) => {
348
+ const cached = loaded.get(userId);
349
+ if (cached !== void 0) return cached;
350
+ const pending = Promise.resolve(callRpc(client, schema, fn, { p_user: userId })).then((result) => {
351
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
352
+ return readSubjectRecord(result.data);
353
+ });
354
+ loaded.set(userId, pending);
355
+ return pending;
356
+ };
357
+ const version = (userId) => {
358
+ const read = loaded.get(userId);
359
+ if (read !== void 0) return read.then((found) => found?.authzVersion);
360
+ const cached = versions.get(userId);
361
+ if (cached !== void 0) return cached;
362
+ const pending = Promise.resolve(callRpc(client, schema, versionFn, { p_user: userId })).then((result) => result.error === null ? versionOf(result.data) : record(userId).then((found) => found?.authzVersion));
363
+ versions.set(userId, pending);
364
+ return pending;
365
+ };
366
+ const live = async (userId) => {
367
+ const found = await record(userId);
368
+ return found?.active === true ? found : void 0;
369
+ };
370
+ return {
371
+ memberships: {
372
+ async membershipsFor(principal) {
373
+ return [...(await live(principal.id))?.memberships ?? []];
374
+ },
375
+ version(principal) {
376
+ return declared !== void 0 && !onlyDeclared([...principal.roles ?? [], ...(principal.memberships ?? []).flatMap((membership) => membership.roles)]) ? record(principal.id).then((found) => found?.authzVersion) : version(principal.id);
377
+ },
378
+ list
379
+ },
380
+ customRoles(principal) {
381
+ return {
382
+ async rolesFor(tenant, context) {
383
+ if (onlyDeclared(context?.held)) return [];
384
+ return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.tenant === tenant);
385
+ },
386
+ async globalRoles(context) {
387
+ if (onlyDeclared(context?.held)) return [];
388
+ return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.scope === "global");
389
+ }
390
+ };
391
+ },
392
+ async subject(userId) {
393
+ const found = await live(userId);
394
+ if (found === void 0) return {
395
+ principal: null,
396
+ context: {}
397
+ };
398
+ return {
399
+ principal: compact({
400
+ id: found.id,
401
+ roles: found.roles,
402
+ memberships: found.memberships,
403
+ authzVersion: found.authzVersion
404
+ }),
405
+ context: {}
406
+ };
407
+ },
408
+ record
409
+ };
410
+ }
411
+ //#endregion
412
+ //#region src/supabase/approval-store.ts
413
+ function isRecord(value) {
414
+ return value !== null && typeof value === "object" && !Array.isArray(value);
415
+ }
416
+ /** A stored body as the request it is; the store wrote it from an `ApprovalRequest`. */
417
+ function requestOf(value) {
418
+ if (!isRecord(value) || value["v"] !== 1 || typeof value["token"] !== "string") return null;
419
+ return value;
420
+ }
421
+ function filterOf(filter) {
422
+ return compact({
423
+ status: filter.status,
424
+ tenant: filter.tenant,
425
+ principalId: filter.principalId,
426
+ actorId: filter.actorId,
427
+ session: filter.session
428
+ });
429
+ }
430
+ /**
431
+ * An `ApprovalStore` over the table and functions `rls.approvals` generates,
432
+ * called through supabase-js (`client.schema(schema).rpc(...)`) with a
433
+ * client that may execute them, such as a `service_role` client. Each method
434
+ * is one atomic statement in the database: a repeated ask keeps the open
435
+ * request, two racing approvers both count towards a quorum, and two racing
436
+ * resumes never both consume an approval.
437
+ */
438
+ function supabaseApprovalStore(client, options = {}) {
439
+ const schema = options.schema ?? "permdock";
440
+ const call = async (fn, args) => {
441
+ const result = await callRpc(client, schema, fn, args);
442
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
443
+ return result.data;
444
+ };
445
+ const get = async (token) => requestOf(await call("permdock_approval_get", { p_token: token }));
446
+ return {
447
+ ...options.ttl === void 0 ? {} : { ttl: options.ttl },
448
+ async create(request) {
449
+ await call("permdock_approval_open", { p_request: request });
450
+ if (options.onOpen !== void 0) {
451
+ const stored = await get(request.token);
452
+ if (stored !== null && canonicalJson(stored) === canonicalJson(request)) await options.onOpen(stored);
453
+ }
454
+ },
455
+ get,
456
+ async resolve(token, verdict) {
457
+ const current = await get(token);
458
+ if (current === null) throw new ApprovalError("approval-not-found", "approval was not found");
459
+ const next = applyApprovalVerdict(current, verdict);
460
+ const written = requestOf(await call("permdock_approval_resolve", {
461
+ p_token: token,
462
+ p_next: next,
463
+ p_seen: current.approvals?.length ?? 0
464
+ }));
465
+ if (written === null) throw new ApprovalError("approval-not-pending", "approval is not pending");
466
+ return written;
467
+ },
468
+ async consume(token, now = /* @__PURE__ */ new Date()) {
469
+ return requestOf(await call("permdock_approval_consume", {
470
+ p_token: token,
471
+ p_now: now.toISOString()
472
+ }));
473
+ },
474
+ async list(query) {
475
+ const after = query.cursor === void 0 ? void 0 : decodeApprovalCursor(query.cursor);
476
+ if (after === null) return { items: [] };
477
+ const size = approvalPageSize(query.limit);
478
+ const data = await call("permdock_approval_list", {
479
+ p_filter: filterOf(query),
480
+ p_after_created: after?.[0] ?? null,
481
+ p_after_token: after?.[1] ?? null,
482
+ p_limit: size + 1
483
+ });
484
+ const rows = Array.isArray(data) ? data.flatMap((row) => {
485
+ const request = requestOf(row);
486
+ return request === null ? [] : [request];
487
+ }) : [];
488
+ const items = rows.slice(0, size);
489
+ const last = items.at(-1);
490
+ return rows.length > size && last !== void 0 ? {
491
+ items,
492
+ next: encodeApprovalCursor(last)
493
+ } : { items };
494
+ },
495
+ async expire(now = /* @__PURE__ */ new Date()) {
496
+ const count = await call("permdock_approval_expire", { p_now: now.toISOString() });
497
+ return typeof count === "number" ? count : 0;
498
+ },
499
+ async cancel(filter, meta) {
500
+ const count = await call("permdock_approval_cancel", {
501
+ p_filter: filterOf(filter),
502
+ p_by: meta.by,
503
+ p_note: meta.note ?? null,
504
+ p_now: (/* @__PURE__ */ new Date()).toISOString()
505
+ });
506
+ return typeof count === "number" ? count : 0;
507
+ }
508
+ };
509
+ }
510
+ //#endregion
226
511
  //#region src/supabase/rls.ts
227
512
  function isTable(value) {
228
513
  return value !== null && typeof value === "object" && "table" in value && typeof value.table === "string";
@@ -236,7 +521,9 @@ function supabaseRls(options = {}) {
236
521
  tenantClaim: options.tenantClaim ?? "tenant_id",
237
522
  tenantType: options.tenantType,
238
523
  memberships,
239
- suspension: options.suspension
524
+ suspension: options.suspension,
525
+ realtime: options.realtime,
526
+ storage: options.storage
240
527
  });
241
528
  }
242
529
  const ident = (name) => quoteSqlIdent(name);
@@ -245,6 +532,13 @@ const literal = quoteSqlLiteral;
245
532
  function qualifiedTable(name) {
246
533
  return table(name.includes(".") ? name : `public.${name}`);
247
534
  }
535
+ /** The memberships table's role key over alias `m`, joined to its roles table when it holds a reference. */
536
+ function tenantRole(memberships) {
537
+ return roleColumn(memberships.role, memberships.table.includes(".") ? memberships.table : `public.${memberships.table}`, "m", {
538
+ label: "authorizeSql tenant.role",
539
+ indent: " "
540
+ });
541
+ }
248
542
  function textArray(values) {
249
543
  return values.length === 0 ? `'{}'::text[]` : `array[${values.map(literal).join(", ")}]::text[]`;
250
544
  }
@@ -258,7 +552,10 @@ function activeRow(row, id, text = false) {
258
552
  if (row.disabledAt === void 0 && row.status === void 0) throw new TypeError("PermDock: a suspension table needs disabledAt or status");
259
553
  return `exists (select 1 from ${qualifiedTable(row.table)} s where ${parts.join(" and ")})`;
260
554
  }
261
- /** Early `return false` for a suspended user, or a tenant request for a suspended instance. */
555
+ /**
556
+ * Early `return false` for a suspended user, or a tenant request for a
557
+ * suspended instance unless its scope keeps the requested permission.
558
+ */
262
559
  function suspendedGuards(suspension, scope, uid) {
263
560
  const lines = [];
264
561
  const users = suspension?.users;
@@ -266,9 +563,13 @@ function suspendedGuards(suspension, scope, uid) {
266
563
  return false; -- suspended user
267
564
  end if;`);
268
565
  const tenant = suspension?.scopes?.[scope];
269
- if (tenant !== void 0) lines.push(` if requested_tenant is not null and not ${activeRow(tenant, "requested_tenant", true)} then
566
+ if (tenant !== void 0) {
567
+ const keep = keptKeys(tenant);
568
+ const kept = keep.length === 0 ? "" : ` and not (requested_permission::text = any(${textArray(keep)}))`;
569
+ lines.push(` if requested_tenant is not null and not ${activeRow(tenant, "requested_tenant", true)}${kept} then
270
570
  return false; -- suspended ${scope}
271
571
  end if;`);
572
+ }
272
573
  return lines.map((line) => `\n${line}`).join("");
273
574
  }
274
575
  function claimEntries(where, value) {
@@ -289,16 +590,26 @@ function customHolds(q, scope, allows, denies, includes) {
289
590
  ))
290
591
  )`;
291
592
  }
292
- function customDatabaseBranch(q, scope, memberships, declared) {
293
- const match = `c.tenant_id::text = requested_tenant and c.scope = ${literal(scope)} and c.scope_id is null and c.role = m.${ident(memberships.role)}::text`;
593
+ function disabledLine(memberships, suspension) {
594
+ if (memberships.disabledAt === void 0) return "";
595
+ const column = `m.${ident(memberships.disabledAt)}`;
596
+ const keep = keptKeys(suspension?.memberships);
597
+ return keep.length === 0 ? `\n and ${column} is null` : `\n and (${column} is null or requested_permission::text = any(${textArray(keep)}))`;
598
+ }
599
+ function claimKept(suspension) {
600
+ return keptKeys(suspension?.memberships).length === 0 ? "" : `\n and case coalesce(jsonb_typeof(m -> 'keep'), 'null') when 'null' then true when 'array' then m -> 'keep' @> jsonb_build_array(requested_permission::text) else false end`;
601
+ }
602
+ function customDatabaseBranch(q, scope, memberships, declared, levels, suspension) {
603
+ const role = tenantRole(memberships);
604
+ const match = `c.tenant_id::text = requested_tenant and c.scope = ${literal(scope)} and c.scope_id is null and c.role = ${role.sql}`;
294
605
  const rows = (source, value, extra) => `array(select c.${value} from ${q(source)} c where ${match}${extra})`;
295
606
  return ` or exists (
296
607
  select 1
297
- from ${qualifiedTable(memberships.table)} m
608
+ from ${qualifiedTable(memberships.table)} m${role.join}
298
609
  where m.${ident(memberships.user)} = v_member_user
299
610
  and m.${ident(memberships.tenant)} = v_member_tenant
300
- and not (m.${ident(memberships.role)}::text = any(${textArray(declared)}))${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}
301
- and ${customHolds(q, scope, rows("custom_role_permissions", "permission", " and c.effect = 'allow'"), rows("custom_role_permissions", "permission", " and c.effect = 'deny'"), rows("custom_role_includes", "include_role", ""))}
611
+ and not (${role.sql} = any(${textArray(declared)}))${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}${disabledLine(memberships, suspension)}
612
+ and ${customHolds(q, scope, rows("custom_role_permissions", levels ? "permission || coalesce('@' || c.level, '')" : "permission", " and c.effect = 'allow'"), rows("custom_role_permissions", "permission", " and c.effect = 'deny'"), rows("custom_role_includes", "include_role", ""))}
302
613
  )`;
303
614
  }
304
615
  /**
@@ -324,13 +635,14 @@ function databaseBody(q, scope, memberships, custom, suspension) {
324
635
  return false; -- no memberships table configured
325
636
  end if;`;
326
637
  if (memberships !== void 0 && tenantColumn !== void 0) {
638
+ const role = tenantRole(memberships);
327
639
  const held = (effect) => `exists (
328
640
  select 1
329
- from ${qualifiedTable(memberships.table)} m
330
- join ${q("role_permissions")} rp on rp.role = m.${ident(memberships.role)}::text
641
+ from ${qualifiedTable(memberships.table)} m${role.join}
642
+ join ${q("role_permissions")} rp on rp.role = ${role.sql}
331
643
  where m.${ident(memberships.user)} = v_member_user
332
644
  and m.${ident(tenantColumn)} = v_member_tenant
333
- and ${effectMatch(literal(scope), effect)}${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}
645
+ and ${effectMatch(literal(scope), effect)}${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}${disabledLine(memberships, suspension)}
334
646
  )`;
335
647
  tenantBranch = ` if requested_tenant is not null then
336
648
  begin
@@ -342,7 +654,7 @@ function databaseBody(q, scope, memberships, custom, suspension) {
342
654
  return (${held("allow")}${custom === void 0 ? "" : customDatabaseBranch(q, scope, {
343
655
  ...memberships,
344
656
  tenant: tenantColumn
345
- }, custom.declared)})
657
+ }, custom.declared, custom.levels === true, suspension)})
346
658
  and not ${held("deny")}
347
659
  and not ${global("deny")};
348
660
  end if;`;
@@ -381,7 +693,7 @@ function jwtBody(q, scope, custom, suspension) {
381
693
  cross join lateral (select m -> 'grants' -> r.role as g) cg
382
694
  where m ->> 'scope' = ${literal(scope)}
383
695
  and m ->> 'id' = requested_tenant
384
- and ${CLAIM_UNEXPIRED}
696
+ and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
385
697
  and jsonb_typeof(cg.g) = 'array'
386
698
  and not (r.role = any(${textArray(custom.declared)}))
387
699
  and ${customHolds(q, scope, claimEntries("left(e, 1) not in ('-', '@')", "e"), claimEntries("left(e, 1) = '-'", "substr(e, 2)"), claimEntries("left(e, 1) = '@'", "substr(e, 2)"))}
@@ -392,7 +704,7 @@ function jwtBody(q, scope, custom, suspension) {
392
704
  join ${q("role_permissions")} rp on rp.role = r.role
393
705
  where m ->> 'scope' = ${literal(scope)}
394
706
  and m ->> 'id' = requested_tenant
395
- and ${CLAIM_UNEXPIRED}
707
+ and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
396
708
  and ${effectMatch(literal(scope), effect)}
397
709
  )`;
398
710
  const global = (effect) => `exists (
@@ -461,336 +773,4 @@ grant execute on function ${signature} to authenticated;
461
773
  `;
462
774
  }
463
775
  //#endregion
464
- //#region src/supabase/subject.ts
465
- const REGISTERED = /* @__PURE__ */ new Set([
466
- "sub",
467
- "role",
468
- "iss",
469
- "aud",
470
- "exp",
471
- "iat",
472
- "nbf",
473
- "aal",
474
- "amr",
475
- "acr",
476
- "session_id",
477
- "email",
478
- "phone",
479
- "is_anonymous",
480
- "app_metadata",
481
- "user_metadata",
482
- "act",
483
- "client_id",
484
- "scope"
485
- ]);
486
- function isRecord(value) {
487
- return value !== null && typeof value === "object" && !Array.isArray(value);
488
- }
489
- /** Top-level first, then `app_metadata`. `null` counts as absent: the RBAC hook writes `null` for a user with no role row. */
490
- function readClaim(claims, name) {
491
- const top = Object.hasOwn(claims, name) ? claims[name] : void 0;
492
- if (top !== void 0 && top !== null) return top;
493
- const meta = claims["app_metadata"];
494
- if (isRecord(meta) && Object.hasOwn(meta, name)) return meta[name] ?? void 0;
495
- }
496
- function asRoles(value, declared) {
497
- const raw = typeof value === "string" ? value === "" ? [] : [value] : Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
498
- if (declared === void 0) return raw;
499
- const allowed = new Set(declared);
500
- return raw.filter((role) => allowed.has(role));
501
- }
502
- /** Reads the `memberships` claim; an entry it cannot read is dropped and its index reported. */
503
- function readMemberships(value) {
504
- if (!Array.isArray(value)) return {
505
- memberships: [],
506
- dropped: []
507
- };
508
- const out = [];
509
- const dropped = [];
510
- for (const [index, item] of value.entries()) {
511
- const membership = asMembership(item);
512
- if (membership === void 0) dropped.push(index);
513
- else out.push(membership);
514
- }
515
- return {
516
- memberships: out,
517
- dropped
518
- };
519
- }
520
- function asMembership(item) {
521
- if (!isRecord(item) || !Array.isArray(item["roles"])) return;
522
- const roles = item["roles"].filter((role) => typeof role === "string");
523
- if (roles.length === 0) return;
524
- const scope = typeof item["scope"] === "string" ? item["scope"] : void 0;
525
- const id = typeof item["id"] === "string" ? item["id"] : void 0;
526
- const within = isRecord(item["within"]) ? Object.fromEntries(Object.entries(item["within"]).filter((entry) => typeof entry[1] === "string")) : void 0;
527
- const tenant = typeof item["tenant"] === "string" ? item["tenant"] : void 0;
528
- const team = typeof item["team"] === "string" ? item["team"] : void 0;
529
- const onRecord = isRecord(item["on"]) ? item["on"] : void 0;
530
- const on = onRecord !== void 0 && typeof onRecord["resource"] === "string" && typeof onRecord["id"] === "string" ? {
531
- resource: onRecord["resource"],
532
- id: onRecord["id"]
533
- } : void 0;
534
- if ((scope === void 0 || id === void 0) && tenant === void 0 && team === void 0 && on === void 0) return;
535
- return compact({
536
- roles,
537
- scope,
538
- id,
539
- within,
540
- tenant,
541
- team,
542
- on,
543
- via: typeof item["via"] === "string" ? item["via"] : void 0,
544
- expiresAt: typeof item["expiresAt"] === "number" ? item["expiresAt"] : void 0,
545
- grantedBy: typeof item["grantedBy"] === "string" ? item["grantedBy"] : void 0,
546
- reason: typeof item["reason"] === "string" ? item["reason"] : void 0,
547
- member: memberOf(item["member"]),
548
- managedBy: item["managedBy"] === "idp" ? "idp" : void 0,
549
- entitlements: Array.isArray(item["entitlements"]) ? item["entitlements"].filter((seat) => typeof seat === "string") : void 0
550
- });
551
- }
552
- function memberOf(value) {
553
- if (value === null || typeof value !== "object" || !Object.hasOwn(value, "group")) return;
554
- const group = value.group;
555
- return typeof group === "string" && group !== "" ? { group } : void 0;
556
- }
557
- function asStrings(value) {
558
- return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
559
- }
560
- /** `claims[plans][tenant]`: only the active tenant's entry, never another tenant's. */
561
- function plansFor(claims, name, tenant) {
562
- if (name === void 0 || tenant === void 0) return [];
563
- const byTenant = readClaim(claims, name);
564
- if (!isRecord(byTenant) || !Object.hasOwn(byTenant, tenant)) return [];
565
- return asStrings(byTenant[tenant]);
566
- }
567
- const INVALID_CHAIN = Object.freeze({
568
- ok: false,
569
- reason: "invalid-chain"
570
- });
571
- const NO_ACTOR = Object.freeze({ ok: true });
572
- /** Own entries of one `act` level, with the nested `act` copied the same way. */
573
- function copyAct(level) {
574
- const entries = Object.entries(level).map(([key, value]) => [key, key === "act" && isRecord(value) ? copyAct(value) : value]);
575
- return Object.fromEntries(entries);
576
- }
577
- /**
578
- * The outer `act` level by its `kind`, the marker better-supabase writes: none is an OAuth client
579
- * or agent chain, `support` a support session (with `session_id`), `impersonation` an admin acting
580
- * as the user. Any other `kind`, or a support level without `session_id`, is invalid.
581
- */
582
- function actingParty(outer, id) {
583
- const marked = Object.hasOwn(outer, "kind") ? outer["kind"] : void 0;
584
- const kind = marked === void 0 && Object.hasOwn(outer, "session_id") ? "support" : marked;
585
- const chain = copyAct(outer);
586
- const reason = typeof outer["reason"] === "string" ? outer["reason"] : void 0;
587
- switch (kind) {
588
- case void 0: return freezeDeep({
589
- ok: true,
590
- actor: {
591
- id,
592
- kind: "oauth-client",
593
- chain
594
- }
595
- });
596
- case "support": {
597
- const session = outer["session_id"];
598
- const readOnly = Object.hasOwn(outer, "read_only") ? outer["read_only"] : false;
599
- if (typeof session !== "string" || session === "" || typeof readOnly !== "boolean") return INVALID_CHAIN;
600
- return freezeDeep({
601
- ok: true,
602
- actor: compact({
603
- id,
604
- kind: "support",
605
- sessionId: session,
606
- readOnly,
607
- reason,
608
- chain
609
- })
610
- });
611
- }
612
- case "impersonation": return freezeDeep({
613
- ok: true,
614
- actor: compact({
615
- id,
616
- kind: "impersonation",
617
- reason,
618
- chain
619
- })
620
- });
621
- default: return INVALID_CHAIN;
622
- }
623
- }
624
- function readActor(claims) {
625
- if (Object.hasOwn(claims, "act") && claims["act"] !== void 0) {
626
- let current = claims["act"];
627
- while (current !== void 0) {
628
- const level = isRecord(current) ? current["sub"] : void 0;
629
- if (!isRecord(current) || typeof level !== "string" || level === "") return INVALID_CHAIN;
630
- current = Object.hasOwn(current, "act") ? current["act"] : void 0;
631
- }
632
- const outer = claims["act"];
633
- const sub = isRecord(outer) ? outer["sub"] : void 0;
634
- if (!isRecord(outer) || typeof sub !== "string") return INVALID_CHAIN;
635
- return actingParty(outer, sub);
636
- }
637
- const client = Object.hasOwn(claims, "client_id") ? claims["client_id"] : void 0;
638
- if (typeof client === "string" && client !== "") return freezeDeep({
639
- ok: true,
640
- actor: {
641
- id: client,
642
- kind: "oauth-client"
643
- }
644
- });
645
- return NO_ACTOR;
646
- }
647
- /**
648
- * Who acts for the user: the outermost `sub` of an RFC 8693 `act` chain (the current
649
- * actor; nested levels are prior actors, kept on `chain` for audit), else the
650
- * OAuth `client_id` of a third-party app. The outer level's `kind` names the actor:
651
- * none is `oauth-client`, `support` a support session, `impersonation` an admin acting as the
652
- * user. Reads only `act` and `client_id`; the caller applies the role rule first (`anon` and
653
- * `service_role` are anonymous and carry no actor). An `act` that is not a chain of objects each
654
- * with a non-empty `sub`, that names another `kind`, or a support level without `session_id`,
655
- * is `{ ok: false }` and must deny.
656
- */
657
- function actorOf(claims) {
658
- try {
659
- return isRecord(claims) ? readActor(claims) : NO_ACTOR;
660
- } catch {
661
- return INVALID_CHAIN;
662
- }
663
- }
664
- /** The OAuth `scope` claim (a space-separated string or a list) as `scopes`; `undefined` when empty. */
665
- function delegationOf(claims) {
666
- try {
667
- if (!isRecord(claims) || !Object.hasOwn(claims, "scope")) return;
668
- const scope = claims["scope"];
669
- const scopes = typeof scope === "string" ? scope.split(/\s+/u).filter(Boolean) : asStrings(scope);
670
- return scopes.length > 0 ? freezeDeep({ scopes }) : void 0;
671
- } catch {
672
- return;
673
- }
674
- }
675
- function subjectDelegation(claims, chain) {
676
- const delegation = compact({
677
- scopes: delegationOf(claims)?.scopes,
678
- chain
679
- });
680
- return Object.keys(delegation).length === 0 ? void 0 : delegation;
681
- }
682
- function emit(options, reason, cause) {
683
- try {
684
- options.onAuth?.({
685
- reason,
686
- cause,
687
- source: "supabase"
688
- });
689
- } catch {}
690
- }
691
- function validateClaims(extra, schema) {
692
- const result = schema["~standard"].validate(extra);
693
- if (result instanceof Promise) {
694
- ignoreRejection(result);
695
- return;
696
- }
697
- if ("issues" in result && result.issues !== void 0) return;
698
- const value = result.value;
699
- return isRecord(value) ? value : void 0;
700
- }
701
- function extraClaims(claims) {
702
- const extra = {};
703
- const meta = claims["app_metadata"];
704
- if (isRecord(meta)) for (const [key, value] of Object.entries(meta)) extra[key] = value;
705
- for (const [key, value] of Object.entries(claims)) {
706
- if (REGISTERED.has(key) || key === "user_metadata") continue;
707
- extra[key] = value;
708
- }
709
- return extra;
710
- }
711
- function mapClaims(claims, options) {
712
- const role = claims["role"];
713
- if (role === "anon" || role === "service_role") return anonymousSubject();
714
- const id = claims["sub"];
715
- if (typeof id !== "string" || id === "") return anonymousSubject();
716
- const act = readActor(claims);
717
- if (!act.ok) {
718
- emit(options, "invalid-token", act.reason);
719
- return anonymousSubject();
720
- }
721
- if (options.anonymousSignIns === "deny" && claims["is_anonymous"] === true) return anonymousSubject();
722
- const actor = act.actor === void 0 ? void 0 : act.actor.kind === "support" ? {
723
- id: act.actor.id,
724
- kind: act.actor.kind,
725
- sessionId: act.actor.sessionId,
726
- readOnly: act.actor.readOnly
727
- } : {
728
- id: act.actor.id,
729
- kind: act.actor.kind
730
- };
731
- const roleClaim = options.roles ?? "user_role";
732
- const tenantClaim = options.tenant ?? "tenant_id";
733
- const membershipsClaim = options.memberships ?? "memberships";
734
- let extra = extraClaims(claims);
735
- if (options.schema !== void 0) extra = validateClaims(extra, options.schema) ?? {};
736
- const include = new Set(options.include ?? []);
737
- const tenantValue = readClaim(claims, tenantClaim);
738
- const version = readClaim(claims, "authz_ver");
739
- const tenant = typeof tenantValue === "string" ? tenantValue : void 0;
740
- const { memberships, dropped } = readMemberships(readClaim(claims, membershipsClaim));
741
- if (dropped.length > 0) emit(options, "schema", "membership-dropped");
742
- const plans = plansFor(claims, options.plans, tenant);
743
- const principal = compact({
744
- id,
745
- kind: "user",
746
- roles: asRoles(readClaim(claims, roleClaim), options.declared),
747
- tenant,
748
- plans: plans.length > 0 ? plans : void 0,
749
- memberships,
750
- membershipsTruncated: readClaim(claims, "memberships_truncated") === true ? true : void 0,
751
- authzVersion: typeof version === "number" && Number.isInteger(version) ? version : void 0,
752
- issuer: typeof claims["iss"] === "string" ? claims["iss"] : void 0,
753
- assurance: typeof claims["aal"] === "string" ? { acr: claims["aal"] } : void 0,
754
- claims: Object.keys(extra).length === 0 ? void 0 : extra,
755
- email: include.has("email") && typeof claims["email"] === "string" ? claims["email"] : void 0,
756
- phone: include.has("phone") && typeof claims["phone"] === "string" ? claims["phone"] : void 0,
757
- is_anonymous: include.has("is_anonymous") && typeof claims["is_anonymous"] === "boolean" ? claims["is_anonymous"] : void 0
758
- });
759
- const session = typeof claims["session_id"] === "string" ? claims["session_id"] : void 0;
760
- const expiresAt = typeof claims["exp"] === "number" ? claims["exp"] : void 0;
761
- return freezeDeep(compact({
762
- principal,
763
- actor,
764
- delegation: act.actor?.kind === "oauth-client" ? subjectDelegation(claims, act.actor.chain) : void 0,
765
- context: {},
766
- session,
767
- expiresAt
768
- }));
769
- }
770
- function subjectFromSupabase(claims, options = {}) {
771
- try {
772
- if (!isRecord(claims)) return anonymousSubject();
773
- const rest = {};
774
- for (const [key, value] of Object.entries(claims)) {
775
- if (key === "user_metadata") continue;
776
- rest[key] = value;
777
- }
778
- return mapClaims(rest, options);
779
- } catch {
780
- return anonymousSubject();
781
- }
782
- }
783
- /**
784
- * A verified session object (for example better-supabase's `AuthSession`) in, `Subject` out.
785
- * Only `kind: 'user'` sessions map; `anon`, `service`, `invalid` and anything else are anonymous.
786
- */
787
- function subjectFromSupabaseSession(session, options = {}) {
788
- try {
789
- if (session === null || session === void 0 || session.kind !== "user") return anonymousSubject();
790
- return subjectFromSupabase(session.claims, options);
791
- } catch {
792
- return anonymousSubject();
793
- }
794
- }
795
- //#endregion
796
- export { subjectFromSupabaseSession as a, supabaseClaims as c, subjectFromSupabase as i, exchangeCapability as l, delegationOf as n, authorizeSql as o, readMemberships as r, supabaseRls as s, actorOf as t };
776
+ export { readSubjectRecord as a, postgrestSources as i, supabaseRls as n, supabaseClaims as o, supabaseApprovalStore as r, exchangeCapability as s, authorizeSql as t };