permdock 0.1.0 → 0.2.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 (349) 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-cmvX2jDe.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 +206 -0
  18. package/dist/better-supabase/index.js +620 -0
  19. package/dist/bind-CVy3Espv.d.ts +25 -0
  20. package/dist/bind-VnYn2HKq.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-B68OFnZx.js → capability-4qPdO9gk.js} +7 -5
  25. package/dist/{capability-BDG_nkxt.d.ts → capability-Dq43tT1u.d.ts} +2 -2
  26. package/dist/catalog/index.d.ts +1 -1
  27. package/dist/catalog/index.js +1 -1
  28. package/dist/catalog-BjZSovXQ.js +2 -0
  29. package/dist/{catalog-doc-BSo_Q_-6.js → catalog-doc-Dsc9y7sd.js} +23 -12
  30. package/dist/{catalog-B0E6bggc.js → catalog-h2tlKFkq.js} +2 -2
  31. package/dist/{catalog-H-vFGwWK.js → catalog-z8q6bi_r.js} +4 -4
  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-BGhHS-lY.js} +2 -2
  44. package/dist/{cloud-Cuxr6Czw.js → cloud-Bo3e9Ak3.js} +7 -6
  45. package/dist/{collect-O-tOtbnk.js → collect-DDDv_ESs.js} +194 -42
  46. package/dist/collect-DLlujdHC.js +83 -0
  47. package/dist/collect-rG2IQ3t0.js +2 -0
  48. package/dist/{commands-BMh_Etm2.js → commands-DWOrSQic.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-CNnl6uIt.d.ts +94 -0
  53. package/dist/config-BJiM-xAm.js +157 -0
  54. package/dist/config-Bn00Z3ks.js +36 -0
  55. package/dist/config-report-Dw_JcUqT.js +44 -0
  56. package/dist/{connection-JvqwHODC.js → connection-CU8MQxRi.js} +1 -1
  57. package/dist/{context-CKEAabd7.js → context-Ttp0ekMT.js} +36 -27
  58. package/dist/convex/index.d.ts +9 -4
  59. package/dist/convex/index.js +14 -4
  60. package/dist/create-BWyx3jua.d.ts +245 -0
  61. package/dist/create-CPhDL6qx.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-PdoqESvg.d.ts} +9 -10
  66. package/dist/{diff-x5Il8LVa.js → diff-B8Tunc3o.js} +44 -11
  67. package/dist/{diff-BUzf5Poi.js → diff-CzqLxZ77.js} +2 -2
  68. package/dist/doctor-WpvG6p4k.js +1194 -0
  69. package/dist/doctor-collect-ByfYlNv1.js +664 -0
  70. package/dist/{doctor-Bqo6FwUa.js → doctor-rOr-4ZfS.js} +2 -2
  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-DAqevpNk.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-C3sHpZNS.js} +65 -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-LF_hS-yn.d.ts → index-A0YNL8jZ.d.ts} +1 -1
  105. package/dist/index-CtE07CBF.d.ts +6 -0
  106. package/dist/{index-xIxJLwOQ.d.ts → index-D3vbkoSI.d.ts} +75 -7
  107. package/dist/{index-CltcQ4Bf.d.ts → index-D6_cSa1z.d.ts} +68 -5
  108. package/dist/index.d.ts +14 -9
  109. package/dist/index.js +22 -17
  110. package/dist/instance-options-BK_rNOSC.d.ts +11 -0
  111. package/dist/instance-options-Dhhcnm3y.js +22 -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-GSQnMz3O.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-CwePaF7C.js → openapi-Bbg4wGVL.js} +3 -3
  144. package/dist/{openapi-DcqM8nU7.js → openapi-BqRBvAng.js} +237 -5
  145. package/dist/{openapi-DWD0Uc_4.js → openapi-CqqEbHsL.js} +5 -5
  146. package/dist/{openapi-import-BWRUNNeW.js → openapi-import-cmwetbzw.js} +1 -1
  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-BkGQNzAh.d.ts +10 -0
  153. package/dist/parse-local-manifest-BrMozJCo.js +36 -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-CzqXjCpU.js} +641 -126
  157. package/dist/{permissions-B8vCg_bI.d.ts → permissions-CDgvKG5L.d.ts} +2 -2
  158. package/dist/{permissions-CofRqesP.js → permissions-CpZrivYv.js} +3 -3
  159. package/dist/{permissions-DC7GROPA.js → permissions-DVoF6dMt.js} +77 -15
  160. package/dist/{permissions-B4apnahQ.d.ts → permissions-DttnqqxC.d.ts} +34 -5
  161. package/dist/{pins-CqE1jZuF.js → pins-8ILTftC9.js} +2 -2
  162. package/dist/{policy-CInmNGkM.d.ts → policy-CFZAr_Al.d.ts} +330 -37
  163. package/dist/{policy-Cq2fB8Q5.d.ts → policy-D8UFyERw.d.ts} +2 -2
  164. package/dist/{policy-ANp36PnI.js → policy-xyWg7QdR.js} +173 -22
  165. package/dist/powersync-A8x_Yyvh.js +2 -0
  166. package/dist/powersync-C7kLglqX.js +540 -0
  167. package/dist/powersync-yW1UUFzp.js +62 -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-CkL50EEf.d.ts +7 -0
  172. package/dist/problem-details-_AMOYz-w.js +144 -0
  173. package/dist/{protected-BuPAycJT.d.ts → protected-CNsMzrVd.d.ts} +5 -4
  174. package/dist/protected-Cs6kTaHo.js +100 -0
  175. package/dist/protected-bZs6rbT1.d.ts +40 -0
  176. package/dist/{provider-wTAUda2v.d.ts → provider-Cjr62YMV.d.ts} +1 -1
  177. package/dist/provider-DLzpb2Xz.js +52 -0
  178. package/dist/provider-store-DNyC1y48.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-sqBGMnNs.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-BMNydpHk.js +2521 -0
  192. package/dist/{rls-BOFU3chG.js → rls-CEvs64Kj.js} +8 -3
  193. package/dist/rls-fields-BMasREhR.js +3502 -0
  194. package/dist/{rls-graph-DxQ39PJj.js → rls-graph-pc9fuXYm.js} +100 -36
  195. package/dist/{rls-import-CXV6LBlS.js → rls-import-D8F7j35Q.js} +7 -6
  196. package/dist/{rls-migrate-DrFPbf8p.js → rls-migrate-7wikfrVI.js} +6 -5
  197. package/dist/rls-ownership-B5Lkq62W.js +843 -0
  198. package/dist/rls-shared-aOQ4hGTO.js +493 -0
  199. package/dist/rls-verify-D8B7dOTh.js +745 -0
  200. package/dist/{row-check-BajTgQZ-.d.ts → row-check-Dt35czLy.d.ts} +12 -15
  201. package/dist/rpc-DOK54_CS.js +89 -0
  202. package/dist/{run-CJ6UvS3a.js → run-YXCJDNYk.js} +31 -12
  203. package/dist/runtime-CB8gQFvS.js +11 -0
  204. package/dist/{saas-BRrZzJkM.js → saas-Bj_FFkjN.js} +17 -7
  205. package/dist/{schema-P8yoma__.js → schema-D3MnDMxa.js} +8 -4
  206. package/dist/scim/index.d.ts +1 -1
  207. package/dist/scim/index.js +1 -1
  208. package/dist/{scim-9NFa0XVZ.js → scim-BFGBBAqR.js} +1 -1
  209. package/dist/{scopes-cKVp_WTw.js → scopes-CVdPrWN-.js} +35 -8
  210. package/dist/server/index.d.ts +22 -11
  211. package/dist/server/index.js +11 -8
  212. package/dist/{credentials-BgRX3WEg.js → server-DlZ28Oz5.js} +1 -1
  213. package/dist/shared-DRu8VFVM.js +123 -0
  214. package/dist/{sink-Cfr9-7YC.d.ts → sink-Gs6TTVa-.d.ts} +1 -1
  215. package/dist/skills-Biq5uup3.js +192 -0
  216. package/dist/{skills-C_lpV4Jx.js → skills-JaymNCdK.js} +10 -4
  217. package/dist/{snapshot-DE8dE_hz.js → snapshot-Enxd0n-s.js} +138 -214
  218. package/dist/snapshot-cache-D6jLelln.js +44 -0
  219. package/dist/snapshot-cache-DwQH8ufx.d.ts +45 -0
  220. package/dist/solid/index.d.ts +39 -9
  221. package/dist/solid/index.js +76 -85
  222. package/dist/sources-B0UvrJ21.js +534 -0
  223. package/dist/sources-BcJgw0lt.d.ts +192 -0
  224. package/dist/{sql-Bll1d7y0.js → sql-xdg5f4Fi.js} +6 -1
  225. package/dist/{src-CTNT-PBW.js → src-CSbUiozF.js} +149 -11
  226. package/dist/ssf/index.d.ts +3 -2
  227. package/dist/ssf/index.js +3 -29
  228. package/dist/store-DMAWwAJV.js +371 -0
  229. package/dist/{store-Bq90395i.d.ts → store-D_pjn91-.d.ts} +13 -4
  230. package/dist/store-options-yO0V6gRn.js +716 -0
  231. package/dist/{stores-CkG2HrSg.js → stores-4_sqiOA1.js} +10 -63
  232. package/dist/{stores-CvOnu_2T.d.ts → stores-DVR5NHLE.d.ts} +20 -9
  233. package/dist/{stream-Q_xlB6Ko.js → stream-DDpvynSB.js} +16 -2
  234. package/dist/{stream-BhMfZOwr.d.ts → stream-DlvG2hs-.d.ts} +2 -2
  235. package/dist/subject-settings-BwBmCdTR.js +128 -0
  236. package/dist/supabase/index.d.ts +122 -6
  237. package/dist/supabase/index.js +4 -3
  238. package/dist/supabase/middleware.d.ts +32 -27
  239. package/dist/supabase/middleware.js +56 -22
  240. package/dist/{supabase-D8UlBA7Z.js → supabase-CwafwxxF.js} +3 -3
  241. package/dist/{supabase-DTxGtYdi.js → supabase-DTBaC20O.js} +345 -367
  242. package/dist/supabase-config-Bs44dare.js +472 -0
  243. package/dist/{supabase-hook-D_OqGb_V.js → supabase-hook-BuxLQLpU.js} +994 -708
  244. package/dist/supabase-hook-D5qVd_D8.js +2 -0
  245. package/dist/supautils-DYZnzRWV.js +91 -0
  246. package/dist/svelte/PermissionBoundary.svelte +37 -0
  247. package/dist/svelte/Protected.svelte +8 -2
  248. package/dist/svelte/index.d.ts +9 -6
  249. package/dist/svelte/index.js +61 -7
  250. package/dist/svelte/runtime.d.ts +4 -3
  251. package/dist/svelte/runtime.js +4 -3
  252. package/dist/svelte/source.d.ts +9 -6
  253. package/dist/svelte/source.js +7 -4
  254. package/dist/terminal/index.d.ts +6 -14
  255. package/dist/terminal/index.js +44 -32
  256. package/dist/testing/index.d.ts +105 -16
  257. package/dist/testing/index.js +504 -40
  258. package/dist/testing/saas/index.d.ts +4 -4
  259. package/dist/testing/saas/index.js +2 -2
  260. package/dist/testing/saas/permissions.d.ts +1 -1
  261. package/dist/testing/saas/permissions.js +1 -1
  262. package/dist/token-CIWxJOCh.js +50 -0
  263. package/dist/trpc/index.d.ts +7 -26
  264. package/dist/trpc/index.js +17 -100
  265. package/dist/types-9AWO9EGt.d.ts +197 -0
  266. package/dist/{types-D6Z6-rKJ.d.ts → types-BPxgszlT.d.ts} +260 -22
  267. package/dist/{types-BvBk1wgn.d.ts → types-BVyImy5I.d.ts} +5 -3
  268. package/dist/{types-CxquUByI.d.ts → types-Bvc4oWT6.d.ts} +1 -1
  269. package/dist/types-C3s9xVJG.d.ts +48 -0
  270. package/dist/{types-BBK-exvJ.d.ts → types-Dnemwd77.d.ts} +7 -1
  271. package/dist/types-kxznc7cn.d.ts +52 -0
  272. package/dist/{types-B8w5PFtS.d.ts → types-vKyAMtcX.d.ts} +17 -1
  273. package/dist/{types-B9dmiiab.d.ts → types-vNSDF7Dq.d.ts} +1 -1
  274. package/dist/{sources-DOpW5Ila.d.ts → types-yF5LmQVD.d.ts} +86 -127
  275. package/dist/unplugin/index.d.ts +1 -1
  276. package/dist/unplugin/index.js +10 -9
  277. package/dist/{usage-1ozMubLY.js → usage-D07N9QJ3.js} +2 -2
  278. package/dist/usage-D82l1CwK.js +2 -0
  279. package/dist/{usage-CUnK6Ou9.js → usage-DG1oeCca.js} +225 -62
  280. package/dist/validation-error-CnjZ4t92.js +33 -0
  281. package/dist/validation-error-CtF23SrC.d.ts +26 -0
  282. package/dist/{validity-D0uRmJKJ.js → validity-uOp8UpYn.js} +57 -36
  283. package/dist/{verifier-B90agnhl.js → verifier-BxBo6I44.js} +10 -5
  284. package/dist/version-BvacVTZR.js +17 -0
  285. package/dist/views-Soe7bGSC.js +95 -0
  286. package/dist/{vocabulary-Dk0fs-Jk.d.ts → vocabulary-DA8a8zif.d.ts} +1 -1
  287. package/dist/vue/index.d.ts +35 -13
  288. package/dist/vue/index.js +86 -93
  289. package/dist/watch-Etoa_Mvr.js +2 -0
  290. package/dist/watch-UihESpsJ.js +128 -0
  291. package/dist/webmcp/index.d.ts +2 -2
  292. package/dist/webmcp/index.js +7 -13
  293. package/package.json +62 -36
  294. package/schemas/approval-request-v1.json +175 -0
  295. package/schemas/catalog-v1.json +29 -1
  296. package/schemas/supabase-claims-v1.json +6 -1
  297. package/schemas/supabase-manifest-v1.json +150 -6
  298. package/skills/permdock/SKILL.md +7 -7
  299. package/skills/permdock-agents/SKILL.md +5 -5
  300. package/skills/permdock-agents/references/runtimes.md +12 -10
  301. package/skills/permdock-approvals/SKILL.md +4 -4
  302. package/skills/permdock-approvals/references/stores-and-resume.md +15 -4
  303. package/skills/permdock-audit/SKILL.md +3 -3
  304. package/skills/permdock-credentials/SKILL.md +4 -4
  305. package/skills/permdock-credentials/references/tokens-keys-links.md +7 -2
  306. package/skills/permdock-data/SKILL.md +4 -4
  307. package/skills/permdock-data/references/queries-and-rls.md +14 -6
  308. package/skills/permdock-data/references/relationships.md +5 -3
  309. package/skills/permdock-tenancy/SKILL.md +9 -6
  310. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +14 -8
  311. package/skills/permdock-wire/SKILL.md +4 -4
  312. package/skills/permdock-wire/references/adapters.md +42 -30
  313. package/skills/permdock-wire/references/policy-options.md +5 -3
  314. package/dist/approvers-aH0PJkmf.js +0 -20
  315. package/dist/catalog-idsHc0vo.js +0 -2
  316. package/dist/collect-B7_TIfmg.js +0 -49
  317. package/dist/collect-fRPAQIWb.js +0 -2
  318. package/dist/compile-CQbvyIBr.d.ts +0 -30
  319. package/dist/config-BPYmjTOp.js +0 -26
  320. package/dist/context-gtAwAILx.js +0 -6
  321. package/dist/create-BKF3dgFk.d.ts +0 -162
  322. package/dist/create-CSkhDU9T.js +0 -222
  323. package/dist/doctor-BGle8Gqi.js +0 -1314
  324. package/dist/helpers-DnSOrhB9.js +0 -682
  325. package/dist/index-fG6NSXlc.d.ts +0 -9
  326. package/dist/kernel-YOGCWNLf.js +0 -211
  327. package/dist/load-QOOm1z70.js +0 -2
  328. package/dist/manifest-DDQbC6K0.d.ts +0 -118
  329. package/dist/map-error-RJ3ZsUyA.js +0 -16
  330. package/dist/may-use-CnFEjVEp.js +0 -37
  331. package/dist/pg-4GJWDUxG.js +0 -953
  332. package/dist/plugin-4gr7IxFJ.js +0 -65
  333. package/dist/protected-B4K3BKoX.js +0 -138
  334. package/dist/protected-wY7nXhY9.d.ts +0 -23
  335. package/dist/provider-_wx46HpB.js +0 -48
  336. package/dist/rls-CJVja9Ww.js +0 -2119
  337. package/dist/rls-helpers-BxRuif0l.js +0 -1346
  338. package/dist/runtime-DP9ttFh1.js +0 -27
  339. package/dist/skills-Dx3QLnMY.js +0 -110
  340. package/dist/source-DoBBYJi2.js +0 -6
  341. package/dist/sources-DVHM3Mwq.js +0 -284
  342. package/dist/store-C6hFW6ta.js +0 -508
  343. package/dist/subject-settings-xt7V845g.js +0 -82
  344. package/dist/supabase-hook-DW-xP4hU.js +0 -2
  345. package/dist/types-DbWdEfcm.d.ts +0 -87
  346. package/dist/types-bva3i4Gf.d.ts +0 -98
  347. package/dist/types-i4BAOvdb.d.ts +0 -97
  348. package/dist/usage-PyEor6GA.js +0 -2
  349. 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 { l as keptKeys, s as roleColumn } from "./sources-B0UvrJ21.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,287 @@ 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 schema = options.schema ?? "permdock";
323
+ const fn = options.fn ?? "subject_for";
324
+ const membersFn = options.membersFn ?? "members_of";
325
+ const versionFn = options.versionFn ?? "authz_version_for";
326
+ const declared = options.policy === void 0 ? void 0 : options.policy.index.declaredRoles;
327
+ const onlyDeclared = (held) => declared !== void 0 && held?.every((name) => declared.has(name)) === true;
328
+ const loaded = /* @__PURE__ */ new Map();
329
+ const versions = /* @__PURE__ */ new Map();
330
+ const listed = /* @__PURE__ */ new Map();
331
+ const list = (query) => {
332
+ const key = JSON.stringify([query.scope, query.id]);
333
+ const cached = listed.get(key);
334
+ if (cached !== void 0) return cached.then((entries) => [...entries]);
335
+ const pending = Promise.resolve(callRpc(client, schema, membersFn, {
336
+ p_scope: query.scope,
337
+ p_id: query.id
338
+ })).then((result) => {
339
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${membersFn} failed: ${result.error.message}`);
340
+ return readMemberEntries(result.data);
341
+ });
342
+ listed.set(key, pending);
343
+ return pending.then((entries) => [...entries]);
344
+ };
345
+ const record = (userId) => {
346
+ const cached = loaded.get(userId);
347
+ if (cached !== void 0) return cached;
348
+ const pending = Promise.resolve(callRpc(client, schema, fn, { p_user: userId })).then((result) => {
349
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
350
+ return readSubjectRecord(result.data);
351
+ });
352
+ loaded.set(userId, pending);
353
+ return pending;
354
+ };
355
+ const version = (userId) => {
356
+ const read = loaded.get(userId);
357
+ if (read !== void 0) return read.then((found) => found?.authzVersion);
358
+ const cached = versions.get(userId);
359
+ if (cached !== void 0) return cached;
360
+ 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));
361
+ versions.set(userId, pending);
362
+ return pending;
363
+ };
364
+ const live = async (userId) => {
365
+ const found = await record(userId);
366
+ return found?.active === true ? found : void 0;
367
+ };
368
+ return {
369
+ memberships: {
370
+ async membershipsFor(principal) {
371
+ return [...(await live(principal.id))?.memberships ?? []];
372
+ },
373
+ version(principal) {
374
+ return declared !== void 0 && !onlyDeclared([...principal.roles ?? [], ...(principal.memberships ?? []).flatMap((membership) => membership.roles)]) ? record(principal.id).then((found) => found?.authzVersion) : version(principal.id);
375
+ },
376
+ list
377
+ },
378
+ customRoles(principal) {
379
+ return {
380
+ async rolesFor(tenant, context) {
381
+ if (onlyDeclared(context?.held)) return [];
382
+ return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.tenant === tenant);
383
+ },
384
+ async globalRoles(context) {
385
+ if (onlyDeclared(context?.held)) return [];
386
+ return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.scope === "global");
387
+ }
388
+ };
389
+ },
390
+ async subject(userId) {
391
+ const found = await live(userId);
392
+ if (found === void 0) return {
393
+ principal: null,
394
+ context: {}
395
+ };
396
+ return {
397
+ principal: compact({
398
+ id: found.id,
399
+ roles: found.roles,
400
+ memberships: found.memberships,
401
+ authzVersion: found.authzVersion
402
+ }),
403
+ context: {}
404
+ };
405
+ },
406
+ record
407
+ };
408
+ }
409
+ //#endregion
410
+ //#region src/supabase/approval-store.ts
411
+ function isRecord(value) {
412
+ return value !== null && typeof value === "object" && !Array.isArray(value);
413
+ }
414
+ /** A stored body as the request it is; the store wrote it from an `ApprovalRequest`. */
415
+ function requestOf(value) {
416
+ if (!isRecord(value) || value["v"] !== 1 || typeof value["token"] !== "string") return null;
417
+ return value;
418
+ }
419
+ function filterOf(filter) {
420
+ return compact({
421
+ status: filter.status,
422
+ tenant: filter.tenant,
423
+ principalId: filter.principalId,
424
+ actorId: filter.actorId,
425
+ session: filter.session
426
+ });
427
+ }
428
+ /**
429
+ * An `ApprovalStore` over the table and functions `rls.approvals` generates,
430
+ * called through supabase-js (`client.schema(schema).rpc(...)`) with a
431
+ * client that may execute them, such as a `service_role` client. Each method
432
+ * is one atomic statement in the database: a repeated ask keeps the open
433
+ * request, two racing approvers both count towards a quorum, and two racing
434
+ * resumes never both consume an approval.
435
+ */
436
+ function supabaseApprovalStore(client, options = {}) {
437
+ const schema = options.schema ?? "permdock";
438
+ const call = async (fn, args) => {
439
+ const result = await callRpc(client, schema, fn, args);
440
+ if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
441
+ return result.data;
442
+ };
443
+ const get = async (token) => requestOf(await call("permdock_approval_get", { p_token: token }));
444
+ return {
445
+ ...options.ttl === void 0 ? {} : { ttl: options.ttl },
446
+ async create(request) {
447
+ await call("permdock_approval_open", { p_request: request });
448
+ if (options.onOpen !== void 0) {
449
+ const stored = await get(request.token);
450
+ if (stored !== null && canonicalJson(stored) === canonicalJson(request)) await options.onOpen(stored);
451
+ }
452
+ },
453
+ get,
454
+ async resolve(token, verdict) {
455
+ const current = await get(token);
456
+ if (current === null) throw new ApprovalError("approval-not-found", "approval was not found");
457
+ const next = applyApprovalVerdict(current, verdict);
458
+ const written = requestOf(await call("permdock_approval_resolve", {
459
+ p_token: token,
460
+ p_next: next,
461
+ p_seen: current.approvals?.length ?? 0
462
+ }));
463
+ if (written === null) throw new ApprovalError("approval-not-pending", "approval is not pending");
464
+ return written;
465
+ },
466
+ async consume(token, now = /* @__PURE__ */ new Date()) {
467
+ return requestOf(await call("permdock_approval_consume", {
468
+ p_token: token,
469
+ p_now: now.toISOString()
470
+ }));
471
+ },
472
+ async list(query) {
473
+ const after = query.cursor === void 0 ? void 0 : decodeApprovalCursor(query.cursor);
474
+ if (after === null) return { items: [] };
475
+ const size = approvalPageSize(query.limit);
476
+ const data = await call("permdock_approval_list", {
477
+ p_filter: filterOf(query),
478
+ p_after_created: after?.[0] ?? null,
479
+ p_after_token: after?.[1] ?? null,
480
+ p_limit: size + 1
481
+ });
482
+ const rows = Array.isArray(data) ? data.flatMap((row) => {
483
+ const request = requestOf(row);
484
+ return request === null ? [] : [request];
485
+ }) : [];
486
+ const items = rows.slice(0, size);
487
+ const last = items.at(-1);
488
+ return rows.length > size && last !== void 0 ? {
489
+ items,
490
+ next: encodeApprovalCursor(last)
491
+ } : { items };
492
+ },
493
+ async expire(now = /* @__PURE__ */ new Date()) {
494
+ const count = await call("permdock_approval_expire", { p_now: now.toISOString() });
495
+ return typeof count === "number" ? count : 0;
496
+ },
497
+ async cancel(filter, meta) {
498
+ const count = await call("permdock_approval_cancel", {
499
+ p_filter: filterOf(filter),
500
+ p_by: meta.by,
501
+ p_note: meta.note ?? null,
502
+ p_now: (/* @__PURE__ */ new Date()).toISOString()
503
+ });
504
+ return typeof count === "number" ? count : 0;
505
+ }
506
+ };
507
+ }
508
+ //#endregion
226
509
  //#region src/supabase/rls.ts
227
510
  function isTable(value) {
228
511
  return value !== null && typeof value === "object" && "table" in value && typeof value.table === "string";
@@ -236,7 +519,9 @@ function supabaseRls(options = {}) {
236
519
  tenantClaim: options.tenantClaim ?? "tenant_id",
237
520
  tenantType: options.tenantType,
238
521
  memberships,
239
- suspension: options.suspension
522
+ suspension: options.suspension,
523
+ realtime: options.realtime,
524
+ storage: options.storage
240
525
  });
241
526
  }
242
527
  const ident = (name) => quoteSqlIdent(name);
@@ -245,6 +530,13 @@ const literal = quoteSqlLiteral;
245
530
  function qualifiedTable(name) {
246
531
  return table(name.includes(".") ? name : `public.${name}`);
247
532
  }
533
+ /** The memberships table's role key over alias `m`, joined to its roles table when it holds a reference. */
534
+ function tenantRole(memberships) {
535
+ return roleColumn(memberships.role, memberships.table.includes(".") ? memberships.table : `public.${memberships.table}`, "m", {
536
+ label: "authorizeSql tenant.role",
537
+ indent: " "
538
+ });
539
+ }
248
540
  function textArray(values) {
249
541
  return values.length === 0 ? `'{}'::text[]` : `array[${values.map(literal).join(", ")}]::text[]`;
250
542
  }
@@ -258,7 +550,10 @@ function activeRow(row, id, text = false) {
258
550
  if (row.disabledAt === void 0 && row.status === void 0) throw new TypeError("PermDock: a suspension table needs disabledAt or status");
259
551
  return `exists (select 1 from ${qualifiedTable(row.table)} s where ${parts.join(" and ")})`;
260
552
  }
261
- /** Early `return false` for a suspended user, or a tenant request for a suspended instance. */
553
+ /**
554
+ * Early `return false` for a suspended user, or a tenant request for a
555
+ * suspended instance unless its scope keeps the requested permission.
556
+ */
262
557
  function suspendedGuards(suspension, scope, uid) {
263
558
  const lines = [];
264
559
  const users = suspension?.users;
@@ -266,9 +561,13 @@ function suspendedGuards(suspension, scope, uid) {
266
561
  return false; -- suspended user
267
562
  end if;`);
268
563
  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
564
+ if (tenant !== void 0) {
565
+ const keep = keptKeys(tenant);
566
+ const kept = keep.length === 0 ? "" : ` and not (requested_permission::text = any(${textArray(keep)}))`;
567
+ lines.push(` if requested_tenant is not null and not ${activeRow(tenant, "requested_tenant", true)}${kept} then
270
568
  return false; -- suspended ${scope}
271
569
  end if;`);
570
+ }
272
571
  return lines.map((line) => `\n${line}`).join("");
273
572
  }
274
573
  function claimEntries(where, value) {
@@ -289,16 +588,26 @@ function customHolds(q, scope, allows, denies, includes) {
289
588
  ))
290
589
  )`;
291
590
  }
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`;
591
+ function disabledLine(memberships, suspension) {
592
+ if (memberships.disabledAt === void 0) return "";
593
+ const column = `m.${ident(memberships.disabledAt)}`;
594
+ const keep = keptKeys(suspension?.memberships);
595
+ return keep.length === 0 ? `\n and ${column} is null` : `\n and (${column} is null or requested_permission::text = any(${textArray(keep)}))`;
596
+ }
597
+ function claimKept(suspension) {
598
+ 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`;
599
+ }
600
+ function customDatabaseBranch(q, scope, memberships, declared, levels, suspension) {
601
+ const role = tenantRole(memberships);
602
+ 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
603
  const rows = (source, value, extra) => `array(select c.${value} from ${q(source)} c where ${match}${extra})`;
295
604
  return ` or exists (
296
605
  select 1
297
- from ${qualifiedTable(memberships.table)} m
606
+ from ${qualifiedTable(memberships.table)} m${role.join}
298
607
  where m.${ident(memberships.user)} = v_member_user
299
608
  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", ""))}
609
+ 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)}
610
+ 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
611
  )`;
303
612
  }
304
613
  /**
@@ -324,13 +633,14 @@ function databaseBody(q, scope, memberships, custom, suspension) {
324
633
  return false; -- no memberships table configured
325
634
  end if;`;
326
635
  if (memberships !== void 0 && tenantColumn !== void 0) {
636
+ const role = tenantRole(memberships);
327
637
  const held = (effect) => `exists (
328
638
  select 1
329
- from ${qualifiedTable(memberships.table)} m
330
- join ${q("role_permissions")} rp on rp.role = m.${ident(memberships.role)}::text
639
+ from ${qualifiedTable(memberships.table)} m${role.join}
640
+ join ${q("role_permissions")} rp on rp.role = ${role.sql}
331
641
  where m.${ident(memberships.user)} = v_member_user
332
642
  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())`}
643
+ 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
644
  )`;
335
645
  tenantBranch = ` if requested_tenant is not null then
336
646
  begin
@@ -342,7 +652,7 @@ function databaseBody(q, scope, memberships, custom, suspension) {
342
652
  return (${held("allow")}${custom === void 0 ? "" : customDatabaseBranch(q, scope, {
343
653
  ...memberships,
344
654
  tenant: tenantColumn
345
- }, custom.declared)})
655
+ }, custom.declared, custom.levels === true, suspension)})
346
656
  and not ${held("deny")}
347
657
  and not ${global("deny")};
348
658
  end if;`;
@@ -381,7 +691,7 @@ function jwtBody(q, scope, custom, suspension) {
381
691
  cross join lateral (select m -> 'grants' -> r.role as g) cg
382
692
  where m ->> 'scope' = ${literal(scope)}
383
693
  and m ->> 'id' = requested_tenant
384
- and ${CLAIM_UNEXPIRED}
694
+ and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
385
695
  and jsonb_typeof(cg.g) = 'array'
386
696
  and not (r.role = any(${textArray(custom.declared)}))
387
697
  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 +702,7 @@ function jwtBody(q, scope, custom, suspension) {
392
702
  join ${q("role_permissions")} rp on rp.role = r.role
393
703
  where m ->> 'scope' = ${literal(scope)}
394
704
  and m ->> 'id' = requested_tenant
395
- and ${CLAIM_UNEXPIRED}
705
+ and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
396
706
  and ${effectMatch(literal(scope), effect)}
397
707
  )`;
398
708
  const global = (effect) => `exists (
@@ -461,336 +771,4 @@ grant execute on function ${signature} to authenticated;
461
771
  `;
462
772
  }
463
773
  //#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 };
774
+ export { readSubjectRecord as a, postgrestSources as i, supabaseRls as n, supabaseClaims as o, supabaseApprovalStore as r, exchangeCapability as s, authorizeSql as t };