permdock 0.16.0 → 0.18.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 (384) hide show
  1. package/dist/a2a/index.d.ts +4 -4
  2. package/dist/a2a/index.js +3 -3
  3. package/dist/{adapter-context-CIQpQxbE.js → adapter-context-OHikyRqV.js} +1 -1
  4. package/dist/{adoption-scan-C2BCiUEG.js → adoption-scan-CxExBYSJ.js} +1 -1
  5. package/dist/agent/index.d.ts +2 -2
  6. package/dist/agent/index.js +1 -1
  7. package/dist/ai-sdk/index.d.ts +3 -3
  8. package/dist/ai-sdk/index.js +3 -3
  9. package/dist/approval-normalize-CUjgSsOl.js +189 -0
  10. package/dist/approval-policies-oNnckT12.d.ts +138 -0
  11. package/dist/{approval-prompt-3BqWczTt.d.ts → approval-prompt-Bg7gDSqd.d.ts} +1 -1
  12. package/dist/approvals/index.d.ts +5 -4
  13. package/dist/approvals/index.js +7 -6
  14. package/dist/{approvals-DnIBTuXE.js → approvals-DGId_hgJ.js} +3 -3
  15. package/dist/{approvers-B4r0N_Uz.js → approvers-BaNwKYgd.js} +20 -1
  16. package/dist/{arazzo-ClYz2Z0W.js → arazzo--riLuGY0.js} +4 -4
  17. package/dist/{arazzo-CHoYnQXO.js → arazzo-CEDbb-uM.js} +2 -2
  18. package/dist/{args-0FrVs5EH.js → args-iafbHiXn.js} +2 -5
  19. package/dist/astro/index.d.ts +4 -4
  20. package/dist/astro/index.js +2 -2
  21. package/dist/{audience-DTjR8xet.js → audience-B4YR9UpV.js} +1 -1
  22. package/dist/{auth--yPyZNgr.js → auth-j3Eu-j4h.js} +1 -1
  23. package/dist/authz-topic-Dbc-HDOS.js +15 -0
  24. package/dist/authzen/index.d.ts +5 -5
  25. package/dist/authzen/index.js +2 -2
  26. package/dist/{automation-C6Jg75xq.d.ts → automation-Bfa_wD1h.d.ts} +1 -1
  27. package/dist/better-auth/index.d.ts +1 -1
  28. package/dist/better-auth/index.js +10 -8
  29. package/dist/better-supabase/index.d.ts +335 -38
  30. package/dist/better-supabase/index.js +778 -117
  31. package/dist/{better-supabase-Dirf_8Ec.js → better-supabase-BJtQ-kNf.js} +26 -10
  32. package/dist/{bind-BNQA9JK9.js → bind-B4pMH9bm.js} +6 -6
  33. package/dist/{bind-YYjvfpB9.d.ts → bind-DR6ku3A9.d.ts} +7 -7
  34. package/dist/{budget-BELja5A9.js → budget-BBCPDOGP.js} +1 -1
  35. package/dist/{budget-hYsPz_yE.d.ts → budget-CNLsV2SL.d.ts} +1 -1
  36. package/dist/{build-instance-BWXqwQYU.js → build-instance-BFMFQdE_.js} +3 -2
  37. package/dist/{capability-Di9tiUvi.d.ts → capability-BZ_veK9o.d.ts} +1 -1
  38. package/dist/{capability-BqX94r07.js → capability-zN6T9fxe.js} +2 -3
  39. package/dist/{casbin-D_rVQ31U.js → casbin-DCQHkkyj.js} +2 -2
  40. package/dist/{casbin-C9EvElBb.js → casbin-bKC1FpEx.js} +2 -2
  41. package/dist/{casl-C4OINZHI.js → casl-CjBVJj8R.js} +2 -2
  42. package/dist/{casl-CHHoCldP.js → casl-CkBssiB1.js} +1 -1
  43. package/dist/catalog/index.d.ts +5 -5
  44. package/dist/catalog/index.js +7 -7
  45. package/dist/catalog-Caqhbdix.js +1 -0
  46. package/dist/{catalog-CGlSwU6j.js → catalog-D1fw8qif.js} +5 -5
  47. package/dist/{catalog-doc-DjMKzJp9.js → catalog-doc-C4DGfJCO.js} +3 -3
  48. package/dist/{catalog-operations-DeHTrJSV.js → catalog-operations-BD22drQf.js} +4 -4
  49. package/dist/{catalog-amPDr0JQ.js → catalog-zzNuR3sY.js} +3 -3
  50. package/dist/{challenge-DImNcR7B.js → challenge-B2O2OLEk.js} +2 -2
  51. package/dist/chat/index.d.ts +1 -1
  52. package/dist/chat/index.js +2 -2
  53. package/dist/chat-sdk/index.d.ts +3 -3
  54. package/dist/{checks-CGkP3Z7A.js → checks-fyDOhcz0.js} +33 -1
  55. package/dist/claude-agent/index.d.ts +3 -3
  56. package/dist/claude-agent/index.js +2 -2
  57. package/dist/clerk/index.d.ts +2 -2
  58. package/dist/clerk/index.js +10 -7
  59. package/dist/cli/bin.js +1 -1
  60. package/dist/cli/index.d.ts +5 -5
  61. package/dist/cli/index.js +3 -3
  62. package/dist/client-CH7vzSAY.d.ts +32 -0
  63. package/dist/cloud/index.d.ts +8 -8
  64. package/dist/cloud/index.js +1 -1
  65. package/dist/{cloud-DdaJ7ILM.js → cloud-C0vXBmLG.js} +4 -4
  66. package/dist/{codemod-B1USJS7a.js → codemod-C-L0w-u7.js} +3 -3
  67. package/dist/{codemod-ammy6wv4.js → codemod-eYI1FbeJ.js} +395 -8
  68. package/dist/{collect-DnXL4B8c.js → collect-CU85z6Ta.js} +4 -4
  69. package/dist/{collect-WCl8cJQV.js → collect-D878zLDP.js} +4 -4
  70. package/dist/collect-KCtOigxx.js +1 -0
  71. package/dist/compile/index.d.ts +1 -1
  72. package/dist/compile/index.js +1 -1
  73. package/dist/{compile-EzEMB-7v.js → compile-B_oJqmIg.js} +4 -4
  74. package/dist/{compile-BEklRUYo.d.ts → compile-DBm0ub4p.d.ts} +2 -2
  75. package/dist/{completion--Y4YItFZ.js → completion-Dauc6pVT.js} +3 -3
  76. package/dist/{config-CcLlvEYW.js → config-COHmivz9.js} +4 -4
  77. package/dist/{config-BQ77xMZk.js → config-DWp2PucY.js} +2 -2
  78. package/dist/{config-report-DVMOLJ7F.js → config-report-DKpFm5ID.js} +2 -2
  79. package/dist/{context-BnIzxTNE.js → context-DeammvFl.js} +2 -2
  80. package/dist/convex/index.d.ts +4 -4
  81. package/dist/convex/index.js +3 -3
  82. package/dist/{core-lxoANyai.js → core-B8sLve3z.js} +7 -7
  83. package/dist/{core-CFepFiDP.d.ts → core-D87h2kpR.d.ts} +2 -2
  84. package/dist/{create-BLPKnJKa.js → create-3A7J9KRR.js} +6 -5
  85. package/dist/{create-CDd9c22W.d.ts → create-BrQXL-Wt.d.ts} +6 -6
  86. package/dist/{create-BPUopdfL.d.ts → create-BzwjZuRS.d.ts} +7 -7
  87. package/dist/{create-Coq5fIrq.js → create-C-tm3KIF.js} +5 -5
  88. package/dist/{create-DBvUsgzK.d.ts → create-CtoT1lIQ.d.ts} +4 -4
  89. package/dist/{credential-CyyyvCsL.js → credential-B3Hj4puZ.js} +4 -3
  90. package/dist/{credentials-CdDxp7jN.js → credentials-dkycUsY3.js} +1 -1
  91. package/dist/decision-CaG5_eNJ.js +21 -0
  92. package/dist/{delegation-CDB6_keF.js → delegation-aK4T_5WU.js} +3 -3
  93. package/dist/delivery/index.d.ts +4 -4
  94. package/dist/delivery/index.js +1 -1
  95. package/dist/{denied-text-DHldhVUv.d.ts → denied-text-DlIxt8fh.d.ts} +1 -1
  96. package/dist/{describe-BbFPBSms.d.ts → describe-BKtC_8PG.d.ts} +1 -1
  97. package/dist/{describe-Bb4hGK5d.js → describe-BZAlPHxT.js} +2 -1
  98. package/dist/{diff-DfmYaIhB.js → diff-BnNHqtHj.js} +8 -8
  99. package/dist/{diff-CxtbOi2l.js → diff-CBCzOTWM.js} +2 -2
  100. package/dist/{doctor-D1Xnmy6u.js → doctor-CkYKCuX7.js} +233 -30
  101. package/dist/{doctor-CwYc2lJb.js → doctor-xUpR5rXg.js} +3 -3
  102. package/dist/drizzle/index.d.ts +3 -3
  103. package/dist/drizzle/index.js +1 -1
  104. package/dist/elysia/index.d.ts +4 -4
  105. package/dist/elysia/index.js +3 -3
  106. package/dist/{errors-Vpu6rKHl.js → errors-BhRkoNS7.js} +0 -2
  107. package/dist/{errors-BIM4MFsJ.d.ts → errors-TpzkEKgJ.d.ts} +1 -1
  108. package/dist/{evaluate-BAmf_AQd.js → evaluate-Czbj7thS.js} +18 -15
  109. package/dist/{evaluations-DOWuBpWv.d.ts → evaluations-CisTTURl.d.ts} +3 -3
  110. package/dist/{evaluations-IBceAeKT.js → evaluations-h3KoJAPa.js} +3 -22
  111. package/dist/eve/index.d.ts +4 -4
  112. package/dist/eve/index.js +3 -3
  113. package/dist/express/index.d.ts +4 -4
  114. package/dist/express/index.js +3 -3
  115. package/dist/fastify/index.d.ts +4 -4
  116. package/dist/fastify/index.js +3 -3
  117. package/dist/{fetch-adapter-BIbBAtPZ.d.ts → fetch-adapter-BdmfnbJM.d.ts} +2 -2
  118. package/dist/{fetch-adapter-dPTgJVHd.js → fetch-adapter-DH-NJPbL.js} +2 -2
  119. package/dist/{fields-DI8s3cPl.js → fields-CrjL6A49.js} +3 -3
  120. package/dist/{files-B3AA05f1.js → files-CfiRtQ-m.js} +1 -1
  121. package/dist/{fixtures-Bm4_K1ke.js → fixtures-Cemqurt8.js} +10 -4
  122. package/dist/{flags-DXjoTVbS.js → flags-BlmpmXoY.js} +2 -2
  123. package/dist/{from-snapshot-DCakWRsr.js → from-snapshot-DMlSSo9b.js} +14 -12
  124. package/dist/{gen-DwgCSC6V.js → gen-BEIN-DRM.js} +2 -2
  125. package/dist/{gen-DuAhghDw.js → gen-mf-MRwVr.js} +9 -9
  126. package/dist/{generate-CRVV5V7l.js → generate-BqkZq8Dr.js} +2 -2
  127. package/dist/{grantee-conditions-BrYPe-w0.js → grantee-conditions-DX4K_gGI.js} +1 -1
  128. package/dist/{grantee-match-7RZZvoT_.js → grantee-match-BP-k4vRJ.js} +2 -2
  129. package/dist/h3/index.d.ts +4 -4
  130. package/dist/h3/index.js +3 -3
  131. package/dist/{helpers-DJicaG6f.js → helpers-DmqGy63f.js} +85 -13
  132. package/dist/hono/index.d.ts +4 -4
  133. package/dist/hono/index.js +3 -3
  134. package/dist/{hosted-DVxlLZMe.d.ts → hosted-BFNXwcjd.d.ts} +1 -1
  135. package/dist/{hosted-D0IzESu_.js → hosted-waouw2V-.js} +12 -10
  136. package/dist/{http-DOL33cO0.js → http-DhMWeB_h.js} +1 -1
  137. package/dist/{import-CNBF96hB.js → import-C1XXpG_m.js} +4 -4
  138. package/dist/{import-Dfe2unKO.js → import-DObwEota.js} +3 -3
  139. package/dist/{index-BinlXeU-.d.ts → index-BhnOOnp9.d.ts} +2 -2
  140. package/dist/{index-ymept53A.d.ts → index-CVGio3cH.d.ts} +4 -4
  141. package/dist/{index-DJwEgYzA.d.ts → index-CdMOd-GY.d.ts} +17 -11
  142. package/dist/{index-Cay5-Kvx.d.ts → index-CdUTE6qd.d.ts} +11 -10
  143. package/dist/{index-Dj2qF9VC.d.ts → index-Dfv9Toct.d.ts} +1 -1
  144. package/dist/{index-CV-7DWeD.d.ts → index-rFp6X_QP.d.ts} +4 -4
  145. package/dist/index.d.ts +18 -16
  146. package/dist/index.js +24 -20
  147. package/dist/{init-BUo2G-FI.js → init-CNJ8lLjo.js} +5 -5
  148. package/dist/{init-C6cWP3xW.js → init-DS3PEsCG.js} +5 -5
  149. package/dist/{instance-options-CoHn-0e8.d.ts → instance-options-2sFGSdsf.d.ts} +2 -2
  150. package/dist/{instance-snapshot-DuWf1cT3.js → instance-snapshot-BWa71my8.js} +15 -12
  151. package/dist/jwt/index.d.ts +4 -4
  152. package/dist/jwt/index.js +3 -3
  153. package/dist/{kernel-BD8QuMnv.js → kernel-30Z2zM_d.js} +10 -10
  154. package/dist/kysely/index.d.ts +3 -3
  155. package/dist/kysely/index.js +1 -1
  156. package/dist/{load-DjSU5KXO.js → load-BaEamml-.js} +1 -1
  157. package/dist/load-CjnlPxpL.js +1 -0
  158. package/dist/{login-D1MHOomI.js → login-BgK5Jloo.js} +4 -4
  159. package/dist/{login-DCKE5pVy.js → login-DUVzBLh7.js} +4 -4
  160. package/dist/{manifest-BXTbHNIV.js → manifest-BdzBobNK.js} +1 -1
  161. package/dist/{manifest-schema-DQkBK2Mr.js → manifest-schema-CsFsYLF-.js} +1 -1
  162. package/dist/{manifest-Cft51TLK.js → manifest-wclLWBVH.js} +37 -37
  163. package/dist/{map-claims-C-nv08_n.js → map-claims-PQwHynxV.js} +25 -11
  164. package/dist/{map-error-pasIGqMT.js → map-error-BH16Ah8P.js} +1 -1
  165. package/dist/mcp/index.d.ts +8 -8
  166. package/dist/mcp/index.js +9 -9
  167. package/dist/{migrate-BJHxQqT5.js → migrate-BbY5-Khy.js} +4 -4
  168. package/dist/{module-values-B1EVTkHP.js → module-values-B8tNIxdd.js} +2 -2
  169. package/dist/nest/index.d.ts +4 -4
  170. package/dist/nest/index.js +3 -3
  171. package/dist/next/index.d.ts +45 -13
  172. package/dist/next/index.js +68 -30
  173. package/dist/next/plugin.d.ts +1 -1
  174. package/dist/next/plugin.js +2 -2
  175. package/dist/node/index.d.ts +4 -4
  176. package/dist/node/index.js +2 -2
  177. package/dist/openai/index.d.ts +4 -4
  178. package/dist/openai/index.js +3 -3
  179. package/dist/openapi/index.d.ts +2 -2
  180. package/dist/{openapi-BwWkHxvW.js → openapi-C4gFqeRz.js} +4 -4
  181. package/dist/{openapi-DSzQN7Zu.js → openapi-zMEB9qxn.js} +5 -5
  182. package/dist/{operation-findings-CXtFzlKJ.js → operation-findings-CVwJHEu_.js} +1 -1
  183. package/dist/operation-risks-BKOcTv8J.js +13 -0
  184. package/dist/operations-Bm9HFecz.js +89 -0
  185. package/dist/orpc/index.d.ts +5 -5
  186. package/dist/orpc/index.js +3 -3
  187. package/dist/otel/index.d.ts +3 -3
  188. package/dist/otel/index.js +1 -1
  189. package/dist/{output-DlICTjBh.js → output-BFWLER4r.js} +1 -1
  190. package/dist/output-files-BYscrQl-.js +1 -0
  191. package/dist/{output-files-BIQ_9pIs.js → output-files-CM0BnH05.js} +1 -1
  192. package/dist/{ownership-qqBuGJXr.js → ownership-D-mIt-w0.js} +6 -6
  193. package/dist/{parse-1_ZheTW5.js → parse-UTC-sDrt.js} +2 -2
  194. package/dist/{parse-local-manifest-DEiCF4ah.js → parse-local-manifest-CxcSMQgl.js} +2 -2
  195. package/dist/{parse-local-manifest-CCmbhnxP.d.ts → parse-local-manifest-DvjTQNuO.d.ts} +1 -1
  196. package/dist/{parse-request-CwCZpyjV.js → parse-request-DOBVaeiQ.js} +1 -1
  197. package/dist/pdp/index.d.ts +3 -3
  198. package/dist/pdp/index.js +3 -3
  199. package/dist/{peer-Q0fuZ6hx.js → peer-BuK9F53f.js} +1 -1
  200. package/dist/{peer-C9LvBCcb.js → peer-n-swIV4H.js} +1 -1
  201. package/dist/{permdock-BvjivVb9.js → permdock-D-_WrdKu.js} +205 -102
  202. package/dist/{permdock-CprAPN3w.d.ts → permdock-ffY4CMd9.d.ts} +101 -131
  203. package/dist/{permissions-CYcHj_w7.js → permissions-B3ggI88M.js} +2 -2
  204. package/dist/{permissions-CVXmRILq.js → permissions-BaoLxy66.js} +1 -13
  205. package/dist/{pg-DQTqRrou.js → pg-Ddxsd5ZB.js} +2 -2
  206. package/dist/{policy-BycVKnXv.d.ts → policy-BtKSApSt.d.ts} +1 -1
  207. package/dist/{policy-CLQ8__GF.js → policy-cV_wwPb8.js} +5 -4
  208. package/dist/{policy-from-catalog-CU3An8uP.js → policy-from-catalog-B68hGC0S.js} +9 -8
  209. package/dist/{policy-types-DGIO_gxq.d.ts → policy-types-D-GwfQTc.d.ts} +72 -19
  210. package/dist/{postgrest-DAxFltvO.js → postgrest-BrjrckDG.js} +74 -19
  211. package/dist/{postgrest-D5nUGm-c.d.ts → postgrest-D84p5dbA.d.ts} +12 -7
  212. package/dist/{powersync-CBhTBhG2.js → powersync-9PYOE1wt.js} +158 -21
  213. package/dist/{powersync-DAfo0EL5.js → powersync-DStC_g0B.js} +3 -3
  214. package/dist/powersync-xNRlC4jN.js +1 -0
  215. package/dist/preset/index.js +1 -1
  216. package/dist/{preset-BjLzeFpp.js → preset-pPrVyGU5.js} +74 -7
  217. package/dist/prisma/index.d.ts +2 -2
  218. package/dist/prisma/index.js +1 -1
  219. package/dist/{protected-action-QEA8arRB.js → protected-action-B40tU3yP.js} +15 -5
  220. package/dist/{protected-action-D8x73IGm.d.ts → protected-action-Ds_EUY8B.d.ts} +14 -7
  221. package/dist/{protected-action-DUYqb-Ma.js → protected-action-OpOxtTsN.js} +1 -1
  222. package/dist/{provider-C55OGXJ7.js → provider-CY4TSSJo.js} +2 -2
  223. package/dist/{provider-DfLeek9O.d.ts → provider-OtnIiFWm.d.ts} +1 -1
  224. package/dist/{provider-store-CaTv00tr.js → provider-store-BQP_pp8s.js} +2 -2
  225. package/dist/{pull-CQCGy1gv.js → pull-DLP4I1Kl.js} +7 -7
  226. package/dist/pull-UBjDnf4b.js +1 -0
  227. package/dist/{push-Dq_ca4-j.js → push-BSb8j1EW.js} +8 -8
  228. package/dist/{pushed-policy-CDuOL2de.js → pushed-policy-BecMsTtM.js} +1 -1
  229. package/dist/{pushed-policy-CryQheKq.d.ts → pushed-policy-Ck3FZcoy.d.ts} +1 -1
  230. package/dist/react/index.d.ts +8 -8
  231. package/dist/react/index.js +6 -6
  232. package/dist/react/provider-client.d.ts +1 -1
  233. package/dist/react/provider-client.js +1 -1
  234. package/dist/react-native/index.d.ts +104 -39
  235. package/dist/react-native/index.js +199 -40
  236. package/dist/refresh-on-L9UOwATg.d.ts +49 -0
  237. package/dist/{replay-Bs9Df2fQ.d.ts → replay-E5X9E1lC.d.ts} +1 -1
  238. package/dist/{request-context-Duzdf0cd.js → request-context-DM6_jY1n.js} +2 -2
  239. package/dist/{request-schema-DhX7UbfQ.js → request-schema-CMP8Cmxd.js} +5 -0
  240. package/dist/resend/index.d.ts +4 -4
  241. package/dist/{resolve-names-Y1Cb22cp.js → resolve-names-CBl4r4_r.js} +6 -6
  242. package/dist/{rls-tHu7N_Pe.js → rls-DGBL-jDY.js} +20 -20
  243. package/dist/{rls-C5ZGzR_B.js → rls-pAHGYgTb.js} +4 -4
  244. package/dist/{role-builder-BK2-T6oD.js → role-builder-CMW4wWzn.js} +3 -157
  245. package/dist/{rpc-vHIwyXCp.js → rpc-KwX_Jcxz.js} +2 -2
  246. package/dist/{run-DUq1xU4K.js → run-B7lv3NuK.js} +8 -40
  247. package/dist/run-UPbacxPg.js +1 -0
  248. package/dist/{run-ticket-DfnZCh-u.js → run-ticket-CjvXr6wj.js} +1 -1
  249. package/dist/{run-ticket-ylovhyFQ.d.ts → run-ticket-DPaD27_r.d.ts} +2 -2
  250. package/dist/{runtime-BGnrOkVH.js → runtime-rf0ZuyF3.js} +1 -1
  251. package/dist/{saas-DK4V-3Is.js → saas-B8H1MsQ3.js} +13 -10
  252. package/dist/{scan-C3HRH9Fs.js → scan-0r3OZqqK.js} +1 -1
  253. package/dist/{schema-DvXvxPhQ.js → schema-B_9tXrbG.js} +1 -1
  254. package/dist/{schema-BOJjqlWL.js → schema-CuX70xgH.js} +15 -2
  255. package/dist/scim/index.d.ts +1 -1
  256. package/dist/scim/index.js +1 -1
  257. package/dist/{scim-jJBJ7g1Z.js → scim-C30QBBoF.js} +2 -1
  258. package/dist/{scim-D8YupzX1.js → scim-CovliQUg.js} +2 -2
  259. package/dist/{scopes-0Up_UA2t.js → scopes-BSdYaGHs.js} +9 -40
  260. package/dist/server/index.d.ts +11 -11
  261. package/dist/server/index.js +8 -8
  262. package/dist/{server-3cVlTLde.js → server-D0PW6ZCw.js} +2 -2
  263. package/dist/{server-types-CyRN0-Cd.d.ts → server-types-3OnXjZ2D.d.ts} +8 -8
  264. package/dist/{shared-l0oGGetg.js → shared-BRmCJxDK.js} +2 -2
  265. package/dist/{shared-DrGLwM3s.js → shared-DyYVEjKC.js} +2 -2
  266. package/dist/{sink-B5zoUW_O.d.ts → sink-ogbVkyeo.d.ts} +2 -2
  267. package/dist/{skills-Celu2W6v.js → skills-B4MPRxQd.js} +2 -2
  268. package/dist/{skills-B2qTbaQa.js → skills-C9sTD70r.js} +2 -2
  269. package/dist/{snapshot-CXlzi69u.js → snapshot-DN_8J27z.js} +6 -2
  270. package/dist/{snapshot-cache-BjAWkchD.d.ts → snapshot-cache-B4YvlGG_.d.ts} +20 -6
  271. package/dist/{snapshot-cache-Bx_4xC_6.js → snapshot-cache-B66h7FBK.js} +25 -8
  272. package/dist/solid/index.d.ts +7 -7
  273. package/dist/solid/index.js +6 -6
  274. package/dist/solid-start/index.d.ts +4 -4
  275. package/dist/solid-start/index.js +3 -3
  276. package/dist/{sources-oB1Hg1Fm.d.ts → sources-xdQShLDU.d.ts} +1 -1
  277. package/dist/{src-C_pi2Rnh.js → src-Brzq_0in.js} +193 -128
  278. package/dist/ssf/index.d.ts +3 -3
  279. package/dist/ssf/index.js +1 -1
  280. package/dist/{standard-webhooks-DOYEuOLx.d.ts → standard-webhooks-BfPaZ6T1.d.ts} +2 -2
  281. package/dist/{types-tQB2CEnY.d.ts → store-DYeB-_U3.d.ts} +114 -113
  282. package/dist/{store-RNFvaJJv.js → store-DmVqy74I.js} +13 -7
  283. package/dist/{store-options-Dil3lraY.js → store-options--zWn48PK.js} +76 -7
  284. package/dist/{stores-DxZWDXCs.js → stores-BYFopOm1.js} +3 -3
  285. package/dist/{stores-DZJvxFIZ.d.ts → stores-EPul_8MN.d.ts} +5 -6
  286. package/dist/{stream-9y9qw51m.d.ts → stream-W2RuUYly.d.ts} +1 -1
  287. package/dist/{subject-BGoM5o8B.js → subject-C7RddW0G.js} +8 -1
  288. package/dist/supabase/client.d.ts +2 -0
  289. package/dist/supabase/client.js +21 -0
  290. package/dist/supabase/index.d.ts +37 -6
  291. package/dist/supabase/index.js +6 -5
  292. package/dist/supabase/middleware.d.ts +8 -7
  293. package/dist/supabase/middleware.js +6 -6
  294. package/dist/{supabase-CDHMsDD0.js → supabase-BiViJpQ4.js} +31 -8
  295. package/dist/{supabase-DYWnT800.js → supabase-CogTyJH2.js} +3 -3
  296. package/dist/supabase-hook-BN46IrVI.js +1 -0
  297. package/dist/{supabase-hook-HPgwYb9V.js → supabase-hook-DX38Hj8h.js} +393 -32
  298. package/dist/{supautils-SwE642N1.js → supautils-BGf6zRvM.js} +12 -12
  299. package/dist/svelte/index.d.ts +7 -7
  300. package/dist/svelte/index.js +8 -8
  301. package/dist/svelte/runtime.d.ts +3 -3
  302. package/dist/svelte/runtime.js +3 -3
  303. package/dist/svelte/source.d.ts +7 -7
  304. package/dist/svelte/source.js +5 -5
  305. package/dist/sveltekit/index.d.ts +4 -4
  306. package/dist/sveltekit/index.js +2 -2
  307. package/dist/{tables-DimBcVWY.js → tables-BfOk0ymL.js} +7 -7
  308. package/dist/tanstack-start/index.d.ts +4 -4
  309. package/dist/tanstack-start/index.js +2 -2
  310. package/dist/{tenancy-5d1zVBvK.js → tenancy-DvOHHk3-.js} +1 -1
  311. package/dist/terminal/index.d.ts +5 -5
  312. package/dist/terminal/index.js +6 -6
  313. package/dist/testing/core.d.ts +1 -1
  314. package/dist/testing/core.js +1 -1
  315. package/dist/testing/fixtures/index.d.ts +1 -1
  316. package/dist/testing/fixtures/index.js +2 -2
  317. package/dist/testing/index.d.ts +29 -22
  318. package/dist/testing/index.js +120 -48
  319. package/dist/testing/saas/index.d.ts +3 -3
  320. package/dist/testing/saas/index.js +2 -2
  321. package/dist/testing/saas/permissions.js +1 -1
  322. package/dist/token-D6pWn8Uj.d.ts +11 -0
  323. package/dist/{token-DC9EQiet.js → token-DaMnIU9O.js} +24 -8
  324. package/dist/{tool-refusal-Qpjs_W6M.js → tool-refusal-D4spOJ7I.js} +1 -1
  325. package/dist/trpc/index.d.ts +5 -5
  326. package/dist/trpc/index.js +3 -3
  327. package/dist/{type-helpers-c7Xo_2Cu.d.ts → type-helpers-i1EJ3Eb1.d.ts} +1 -1
  328. package/dist/{types-Cklw5hJo.d.ts → types-3Y8UpFkF.d.ts} +40 -1
  329. package/dist/{types-DlelvQk4.d.ts → types-B8qUkGja.d.ts} +2 -2
  330. package/dist/{types-CN0LsqbK.d.ts → types-CCEeSCMB.d.ts} +3 -3
  331. package/dist/{types-B2efzoSX.d.ts → types-CDVXR6YD.d.ts} +1 -1
  332. package/dist/{types-DsHGPtkR.d.ts → types-Ck1KOfug.d.ts} +2 -2
  333. package/dist/{types-DLvhVm1r.d.ts → types-CqcsNCaN.d.ts} +16 -7
  334. package/dist/{types-BB-zWDcR.d.ts → types-D-JO7lh8.d.ts} +5 -5
  335. package/dist/{types-CEinc15V.d.ts → types-D19MK4t-.d.ts} +3 -4
  336. package/dist/{types-B6ExllNo.d.ts → types-DGf_cpKF.d.ts} +2 -2
  337. package/dist/{types-rCRV4Ge-.d.ts → types-DmbfLu2p.d.ts} +4 -4
  338. package/dist/{types-ZzRGoViD.d.ts → types-NYoj8JBm.d.ts} +2 -2
  339. package/dist/{types-CWBsAwqn.d.ts → types-o1vu6Ks3.d.ts} +4 -4
  340. package/dist/unplugin/index.d.ts +1 -1
  341. package/dist/unplugin/index.js +2 -2
  342. package/dist/usage-Cl5eb-e1.js +1 -0
  343. package/dist/{usage-CPXeuAdT.js → usage-DC0UKe6C.js} +6 -6
  344. package/dist/{usage-CfZCQd0F.js → usage-DYtRVkcN.js} +2 -2
  345. package/dist/{validation-error-uvp-kyfO.d.ts → validation-error-Dx8PipbO.d.ts} +1 -1
  346. package/dist/{verify-DfT0QYNh.js → verify-Bpj0hauG.js} +19 -19
  347. package/dist/{version-cache-Df11C2Qp.d.ts → version-cache-DzNKWiI6.d.ts} +9 -3
  348. package/dist/{views-CD8wuL4Z.js → views-MWmJ6Y4P.js} +1 -1
  349. package/dist/vue/index.d.ts +7 -7
  350. package/dist/vue/index.js +6 -6
  351. package/dist/{waiter-CqUKX6CY.d.ts → waiter-NK_UuZbb.d.ts} +2 -2
  352. package/dist/{watch-DAkjm75Y.js → watch-CBHADqBH.js} +3 -3
  353. package/dist/watch-OYwAPCzx.js +1 -0
  354. package/dist/webmcp/index.d.ts +1 -1
  355. package/dist/webmcp/index.js +1 -1
  356. package/dist/{where-scope-DlCdCM_8.js → where-scope-BKrqUDVk.js} +5 -5
  357. package/dist/{who-can-BoDJm0Nc.js → who-can-KhVWMxtf.js} +4 -4
  358. package/dist/workflow/index.d.ts +3 -3
  359. package/dist/workflow/index.js +5 -4
  360. package/dist/workflow-sdk/index.d.ts +4 -4
  361. package/dist/{wrap-DxXB54Wu.d.ts → wrap-BHGA-SMM.d.ts} +2 -2
  362. package/dist/{wrap-B2wziJI_.js → wrap-C5PWzgkq.js} +1 -1
  363. package/package.json +8 -5
  364. package/schemas/approval-request-v1.json +5 -0
  365. package/schemas/catalog-v1.json +18 -2
  366. package/schemas/cli-result-v1.json +0 -2
  367. package/schemas/snapshot-v1.json +9 -0
  368. package/schemas/supabase-manifest-v1.json +1 -1
  369. package/skills/permdock-approvals/SKILL.md +8 -8
  370. package/skills/permdock-approvals/references/stores-and-resume.md +7 -3
  371. package/skills/permdock-audit/SKILL.md +1 -1
  372. package/skills/permdock-wire/references/adapters.md +3 -1
  373. package/dist/action-result-BcudBQOF.d.ts +0 -19
  374. package/dist/catalog-D3oS2GH3.js +0 -1
  375. package/dist/collect-D-eroIfV.js +0 -1
  376. package/dist/load-Dm0pSYH3.js +0 -1
  377. package/dist/output-files-BHOIlrfD.js +0 -1
  378. package/dist/powersync-0QVP_DuR.js +0 -1
  379. package/dist/pull-CCAChKuy.js +0 -1
  380. package/dist/renames-CGj7YwcQ.js +0 -175
  381. package/dist/run-C5P3x1EI.js +0 -1
  382. package/dist/supabase-hook-qsewAVZY.js +0 -1
  383. package/dist/usage-DmmO_xjJ.js +0 -1
  384. package/dist/watch-CuPz0D2M.js +0 -1
@@ -1,7 +1,6 @@
1
1
  import { r as isRecord, t as compact } from "../compact-CAf557ZB.js";
2
2
  import { n as freezeDeep } from "../freeze-jjan0lCv.js";
3
- import { l as asApprover } from "../role-builder-BK2-T6oD.js";
4
- import { a as holder, i as flattenApprovers, r as approverLeaves } from "../approvers-B4r0N_Uz.js";
3
+ import { a as flattenApprovers, i as approverManagerKey, o as holder, r as approverLeaves } from "../approvers-BaNwKYgd.js";
5
4
  import { t as loadPrincipal } from "../principal-source-C6N60GtM.js";
6
5
  import { a as isId, r as idList } from "../expiry-6XByK0dm.js";
7
6
  import { c as listPermissions, n as findPermission, o as isPermission } from "../permission-registry-B8tYxPIt.js";
@@ -9,21 +8,33 @@ import { i as dateAt, m as rfc3339, p as nowSeconds, u as isoAt } from "../time-
9
8
  import { t as canonicalJson } from "../canonical-json-DwilZ1iB.js";
10
9
  import { r as sha256Digest } from "../sha256-C-4WXKIu.js";
11
10
  import { t as decideSupportSession } from "../support-session-BsmPCbz8.js";
12
- import { f as scopeList } from "../scopes-0Up_UA2t.js";
11
+ import { d as scopeList } from "../scopes-BSdYaGHs.js";
13
12
  import { o as flattenGrantee } from "../grantee-Dke-9rd1.js";
14
- import { _ as claimsFirst } from "../instance-snapshot-DuWf1cT3.js";
15
- import { a as delegatedScopeMap, s as scopesReaching, t as getPermDock } from "../permdock-BvjivVb9.js";
16
- import { t as anonymousSubject } from "../subject-BGoM5o8B.js";
17
- import { i as linkPolicyViolation, n as capabilityOf, r as capabilitySubject } from "../capability-BqX94r07.js";
18
- import { r as credentialSubject, s as parseCredential } from "../credential-CyyyvCsL.js";
13
+ import { n as asApprover } from "../approval-normalize-CUjgSsOl.js";
14
+ import { n as isOperationEffect } from "../operations-Bm9HFecz.js";
15
+ import { r as isSubject, t as anonymousSubject } from "../subject-C7RddW0G.js";
16
+ import { I as decisionTenant } from "../evaluate-Czbj7thS.js";
17
+ import { _ as claimsFirst } from "../instance-snapshot-BWa71my8.js";
18
+ import { a as permissionStates } from "../checks-fyDOhcz0.js";
19
+ import { a as delegatedScopeMap, s as scopesReaching } from "../permdock-D-_WrdKu.js";
20
+ import { s as ApprovalError } from "../types-CcUXciSj.js";
21
+ import { t as applyApprovalVerdict } from "../store-DmVqy74I.js";
22
+ import { i as linkPolicyViolation, n as capabilityOf, r as capabilitySubject } from "../capability-zN6T9fxe.js";
23
+ import { r as credentialSubject, s as parseCredential } from "../credential-B3Hj4puZ.js";
24
+ import { h as managerKeys, s as resumeDecision } from "../helpers-DmqGy63f.js";
19
25
  import { t as AccessReviewError } from "../errors-BDUwg2qC.js";
26
+ import { t as parseApprovalRequest } from "../parse-request-DOBVaeiQ.js";
27
+ import { n as parseApprovalHeader } from "../approval-header-8QV6MU4H.js";
28
+ import { i as snapshotTag } from "../snapshot-cache-B66h7FBK.js";
29
+ import { t as buildInstance } from "../build-instance-BFMFQdE_.js";
30
+ import { n as NO_GRANT } from "../decision-CaG5_eNJ.js";
20
31
  import { t as policyRowConditionKeys } from "../row-conditions-BAGHOmVq.js";
21
- import { n as subscribersFor } from "../audience-DTjR8xet.js";
32
+ import { n as subscribersFor } from "../audience-B4YR9UpV.js";
22
33
  import { i as qualifySqlTable, l as sqlIdent, s as quoteSqlLiteral } from "../sql-0WjxIp9g.js";
23
34
  import { o as junctionMembershipSource } from "../sources-C4vkzZJV.js";
24
- import { c as subjectFromSupabaseSession, t as callRpc } from "../postgrest-DAxFltvO.js";
25
- import { n as parseSupabaseManifest, t as hasTokenHook } from "../manifest-BXTbHNIV.js";
26
- import { t as parseCatalog } from "../parse-1_ZheTW5.js";
35
+ import { c as subjectFromSupabaseSession, t as callRpc } from "../postgrest-BrjrckDG.js";
36
+ import { n as parseSupabaseManifest, t as hasTokenHook } from "../manifest-BdzBobNK.js";
37
+ import { t as parseCatalog } from "../parse-UTC-sDrt.js";
27
38
  import { n as activeTenantMismatch, t as activeOrganizationFrom } from "../active-tenant-DVee32-T.js";
28
39
  import { AsyncResult, dbError } from "better-supabase";
29
40
  //#region src/better-supabase/access-reviews.ts
@@ -155,6 +166,439 @@ function accessReviewApplier(options) {
155
166
  };
156
167
  }
157
168
  //#endregion
169
+ //#region src/better-supabase/approvals-block.ts
170
+ const PAGE = 100;
171
+ const MAX_SCANNED = 2e3;
172
+ function statusOf(status) {
173
+ switch (status) {
174
+ case "pending":
175
+ case "approved":
176
+ case "rejected":
177
+ case "expired": return status;
178
+ case "cancelled": return "rejected";
179
+ default: return status;
180
+ }
181
+ }
182
+ function instantOf(value) {
183
+ if (value === void 0) return;
184
+ const ms = Date.parse(value.toJSON());
185
+ return Number.isNaN(ms) ? void 0 : isoAt(ms);
186
+ }
187
+ /** The PermDock request a block record carries, with the block's state. */
188
+ function requestOf(record) {
189
+ const stored = parseApprovalRequest(record.payload["permdock"]);
190
+ if (stored === null) return null;
191
+ const status = statusOf(record.status);
192
+ return freezeDeep(compact({
193
+ ...stored,
194
+ status,
195
+ expiresAt: instantOf(record.expiresAt) ?? stored.expiresAt,
196
+ resolvedAt: status === "pending" ? void 0 : instantOf(record.decidedAt),
197
+ consumedAt: instantOf(record.consumedAt),
198
+ fingerprint: record.fingerprint ?? stored.fingerprint
199
+ }));
200
+ }
201
+ async function unwrap(result, call) {
202
+ const awaited = await result;
203
+ if (!awaited.ok) throw new Error(`PermDock: the approvals block's ${call} failed`, { cause: awaited.error });
204
+ return awaited.data;
205
+ }
206
+ /** Every block record carrying a PermDock request, newest first, capped. */
207
+ async function scan(approvals, found, tenantless) {
208
+ const out = [];
209
+ let before;
210
+ for (let scanned = 0; scanned < MAX_SCANNED; scanned += PAGE) {
211
+ const page = await unwrap(approvals.list({
212
+ status: null,
213
+ pageSize: PAGE,
214
+ ...before === void 0 ? {} : { before },
215
+ ...tenantless ? { tenantless } : {}
216
+ }), "list");
217
+ for (const record of page) {
218
+ const request = requestOf(record);
219
+ if (request !== null) {
220
+ const pair = {
221
+ record,
222
+ request
223
+ };
224
+ out.push(pair);
225
+ if (found(pair)) return out;
226
+ }
227
+ }
228
+ const last = page.at(-1);
229
+ if (page.length < PAGE || last === void 0) break;
230
+ before = last.createdAt;
231
+ }
232
+ return out;
233
+ }
234
+ function actionOf(permission) {
235
+ const dot = permission.lastIndexOf(".");
236
+ return dot === -1 ? permission : permission.slice(dot + 1);
237
+ }
238
+ function matchesQuery(request, query) {
239
+ return (query.status === void 0 || request.status === query.status) && (query.principalId === void 0 || request.subject.principal?.id === query.principalId) && (query.actorId === void 0 || request.subject.actor?.id === query.actorId) && (query.tenant === void 0 || decisionTenant(request.subject, request.membership) === query.tenant) && (query.session === void 0 || request.subject.session === query.session);
240
+ }
241
+ /**
242
+ * An `ApprovalStore` over better-supabase's approvals block, so a PermDock
243
+ * `approval-required` decision files a block request and is decided in the
244
+ * block's own approve and reject flow. `create` files the request on the
245
+ * resource under the permission's action, with the PermDock request in
246
+ * `payload.permdock` and its `fingerprint`. `get`, `getById` and `list` read
247
+ * the block's latest 2,000 requests in the block's tenant, and with
248
+ * `tenantless` the latest 2,000 without one. `consume` calls the block's
249
+ * `consume`, which refuses a second use and another fingerprint. `resolve`
250
+ * checks the verdict against the PermDock request, then calls the block's
251
+ * `approve` or `reject` with `decidedBy` set to the approver, so a service-role
252
+ * client records the user who decided; without `approve` and `reject` on the
253
+ * client it throws. `expire` answers 0, since the block expires requests
254
+ * itself.
255
+ */
256
+ function blockApprovalStore(approvals, options = {}) {
257
+ const tenantless = options.tenantless === true;
258
+ const scanAll = async (found) => {
259
+ const inTenant = await scan(approvals, found, false);
260
+ if (!tenantless || inTenant.some(found)) return inTenant;
261
+ return [...inTenant, ...await scan(approvals, found, true)];
262
+ };
263
+ const byToken = async (token) => (await scanAll(({ request }) => request.token === token)).find(({ request }) => request.token === token);
264
+ return Object.freeze({
265
+ name: "better-supabase-approvals",
266
+ async create(request) {
267
+ await unwrap(approvals.request({
268
+ type: request.resource.type,
269
+ id: request.resource.id ?? request.id
270
+ }, compact({
271
+ action: actionOf(request.permission),
272
+ reason: request.detail,
273
+ payload: { permdock: request },
274
+ fingerprint: request.fingerprint,
275
+ tenantless: tenantless && decisionTenant(request.subject, request.membership) === void 0 ? true : void 0
276
+ })), "request");
277
+ },
278
+ async get(token) {
279
+ return (await byToken(token))?.request ?? null;
280
+ },
281
+ async getById(id) {
282
+ return (await scanAll(({ request }) => request.id === id)).find(({ request }) => request.id === id)?.request ?? null;
283
+ },
284
+ async resolve(token, verdict) {
285
+ const decide = verdict.status === "approved" ? approvals.approve : approvals.reject;
286
+ if (decide === void 0) throw new Error("PermDock: blockApprovalStore resolves only with the approvals block's approve and reject on the client");
287
+ const found = await byToken(token);
288
+ if (found === void 0) throw new ApprovalError("approval-not-found", "approval was not found");
289
+ applyApprovalVerdict(found.request, verdict);
290
+ const by = verdict.by.principal?.id;
291
+ const next = requestOf(await unwrap(decide(found.record.id, verdict.note, compact({ decidedBy: by })), verdict.status === "approved" ? "approve" : "reject"));
292
+ if (next === null) throw new ApprovalError("approval-not-found", "approval was not found");
293
+ return next;
294
+ },
295
+ async list(query) {
296
+ const limit = Math.min(Math.max(query.limit ?? 50, 1), 200);
297
+ const offset = query.cursor === void 0 ? 0 : Number(query.cursor);
298
+ if (!Number.isSafeInteger(offset) || offset < 0) return { items: [] };
299
+ const all = (await scanAll(() => false)).map(({ request }) => request).filter((request) => matchesQuery(request, query)).toReversed().toSorted((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt));
300
+ const items = all.slice(offset, offset + limit);
301
+ return offset + limit < all.length ? {
302
+ items,
303
+ next: String(offset + limit)
304
+ } : { items };
305
+ },
306
+ expire() {
307
+ return 0;
308
+ },
309
+ async consume(token) {
310
+ const found = await byToken(token);
311
+ if (found === void 0) return null;
312
+ const consumed = await approvals.consume(found.record.id, found.request.fingerprint);
313
+ return consumed.ok ? requestOf(consumed.data) : null;
314
+ }
315
+ });
316
+ }
317
+ const INTERVAL_UNITS = {
318
+ second: 1,
319
+ minute: 60,
320
+ hour: 3600,
321
+ day: 86400,
322
+ week: 604800
323
+ };
324
+ /** Seconds in a Postgres interval such as `3 days` or `1 day 2 hours`. */
325
+ function intervalSeconds(interval) {
326
+ const parts = interval.trim().toLowerCase().split(/\s+/u);
327
+ let seconds = 0;
328
+ for (let index = 0; index < parts.length; index += 2) {
329
+ const amount = Number(parts[index]);
330
+ const unit = parts[index + 1]?.replace(/s$/u, "");
331
+ const size = unit === void 0 ? void 0 : INTERVAL_UNITS[unit];
332
+ if (!Number.isSafeInteger(amount) || amount < 0 || size === void 0) throw new TypeError(`PermDock: the approval policy interval '${interval}' is not whole seconds, minutes, hours, days or weeks`);
333
+ seconds += amount * size;
334
+ }
335
+ if (seconds === 0) throw new TypeError(`PermDock: the approval policy interval '${interval}' is empty`);
336
+ return seconds;
337
+ }
338
+ function stageApprovers(approvers, roleScope) {
339
+ const leaves = [
340
+ ...approvers.permission === void 0 ? [] : [{
341
+ kind: "permission",
342
+ permission: approvers.permission
343
+ }],
344
+ ...approvers.role === void 0 ? [] : [{
345
+ kind: "role",
346
+ role: approvers.role,
347
+ scope: roleScope
348
+ }],
349
+ ...(approvers.users ?? []).map((id) => ({
350
+ kind: "user",
351
+ id
352
+ })),
353
+ ...approvers.manager === true ? [{ kind: "manager" }] : []
354
+ ];
355
+ if (leaves.length === 0) throw new TypeError("PermDock: an approval policy step names no approver PermDock can check (team approvers are not supported)");
356
+ return {
357
+ kind: "any-of",
358
+ of: leaves
359
+ };
360
+ }
361
+ function quorumOf(step) {
362
+ if (step.required !== "all") return step.required;
363
+ const { users = [], permission, role, team, manager } = step.approvers;
364
+ if (users.length === 0 || permission !== void 0 || role !== void 0 || team !== void 0 || manager === true) throw new TypeError("PermDock: an approval policy step with required \"all\" needs users and no other approvers, since the block counts other holders when a request is filed");
365
+ return users.length;
366
+ }
367
+ const NUMERIC = /^-?\d+(?:\.\d+)?$/u;
368
+ function isScalar(value) {
369
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
370
+ }
371
+ function variants(value) {
372
+ if (typeof value === "string" && NUMERIC.test(value)) return [value, Number(value)];
373
+ return typeof value === "number" ? [value, String(value)] : [value];
374
+ }
375
+ function numberOf(value) {
376
+ if (typeof value === "number" && Number.isFinite(value)) return value;
377
+ return typeof value === "string" && NUMERIC.test(value) ? Number(value) : void 0;
378
+ }
379
+ const ORDER = {
380
+ gt: "gt",
381
+ gte: "gte",
382
+ lt: "lt",
383
+ lte: "lte"
384
+ };
385
+ function ruleCondition(field, operator, value) {
386
+ const list = Array.isArray(value) && value.every(isScalar) ? value : [];
387
+ const contains = (item) => ({
388
+ op: "contains",
389
+ field,
390
+ value: item
391
+ });
392
+ switch (operator) {
393
+ case "": return true;
394
+ case "is":
395
+ case "eq": return isScalar(value) ? {
396
+ op: "or",
397
+ conditions: variants(value).map((item) => ({
398
+ op: "eq",
399
+ field,
400
+ value: item
401
+ }))
402
+ } : void 0;
403
+ case "is_not":
404
+ case "neq": return isScalar(value) ? {
405
+ op: "and",
406
+ conditions: variants(value).map((item) => ({
407
+ op: "ne",
408
+ field,
409
+ value: item
410
+ }))
411
+ } : void 0;
412
+ case "gt":
413
+ case "gte":
414
+ case "lt":
415
+ case "lte": {
416
+ const bound = numberOf(value);
417
+ return bound === void 0 ? void 0 : {
418
+ op: ORDER[operator],
419
+ field,
420
+ value: bound
421
+ };
422
+ }
423
+ case "between":
424
+ case "not_between": {
425
+ const [low, high] = Array.isArray(value) ? value.map(numberOf) : [void 0, void 0];
426
+ if (low === void 0 || high === void 0) return;
427
+ const between = {
428
+ op: "and",
429
+ conditions: [{
430
+ op: "gte",
431
+ field,
432
+ value: low
433
+ }, {
434
+ op: "lte",
435
+ field,
436
+ value: high
437
+ }]
438
+ };
439
+ return operator === "between" ? between : {
440
+ op: "not",
441
+ condition: between
442
+ };
443
+ }
444
+ case "is_any_of":
445
+ case "is_none_of": return list.length === 0 ? void 0 : {
446
+ op: operator === "is_any_of" ? "in" : "notIn",
447
+ field,
448
+ value: list.flatMap(variants)
449
+ };
450
+ case "contains": return typeof value === "string" ? contains(value) : void 0;
451
+ case "not_contains": return typeof value === "string" ? {
452
+ op: "not",
453
+ condition: contains(value)
454
+ } : void 0;
455
+ case "has_any_of":
456
+ case "has_all_of":
457
+ case "has_none_of": {
458
+ if (list.length === 0) return;
459
+ const each = list.map(contains);
460
+ if (operator === "has_all_of") return {
461
+ op: "and",
462
+ conditions: each
463
+ };
464
+ const any = {
465
+ op: "or",
466
+ conditions: each
467
+ };
468
+ return operator === "has_any_of" ? any : {
469
+ op: "not",
470
+ condition: any
471
+ };
472
+ }
473
+ case "empty": return {
474
+ op: "isNull",
475
+ field,
476
+ value: true
477
+ };
478
+ case "not_empty": return {
479
+ op: "isNull",
480
+ field,
481
+ value: false
482
+ };
483
+ default: return;
484
+ }
485
+ }
486
+ function treeCondition(node) {
487
+ if (!isRecord(node)) return;
488
+ let condition;
489
+ if (node["type"] === "group") {
490
+ const rules = node["rules"];
491
+ const combinator = node["combinator"];
492
+ if (!Array.isArray(rules) || combinator !== "and" && combinator !== "or") return;
493
+ const parts = [];
494
+ for (const rule of rules) {
495
+ const part = treeCondition(rule);
496
+ if (part === void 0) return;
497
+ if (part === true) {
498
+ if (combinator === "or") return true;
499
+ continue;
500
+ }
501
+ parts.push(part);
502
+ }
503
+ condition = parts.length === 0 ? true : {
504
+ op: combinator,
505
+ conditions: parts
506
+ };
507
+ } else if (node["type"] === "rule") {
508
+ const path = node["path"];
509
+ const operator = node["operator"];
510
+ if (!Array.isArray(path) || path.length !== 1 || typeof path[0] !== "string" || typeof operator !== "string") return;
511
+ condition = ruleCondition(path[0], operator, node["value"]);
512
+ }
513
+ if (node["negated"] !== true || condition === void 0) return condition;
514
+ return condition === true ? void 0 : {
515
+ op: "not",
516
+ condition
517
+ };
518
+ }
519
+ function effectsOf(effect, options) {
520
+ if (effect === void 0) return;
521
+ const mapped = options.effects !== void 0 && Object.hasOwn(options.effects, effect) ? options.effects[effect] : void 0;
522
+ if (mapped !== void 0) return mapped.length === 0 ? void 0 : mapped;
523
+ return isOperationEffect(effect) ? [effect] : void 0;
524
+ }
525
+ function keysOf(entry, permissions) {
526
+ if (permissions === void 0) throw new TypeError("PermDock: an approval policy for every subject type or action needs blockApprovalPolicySource's permissions, or an effect PermDock knows");
527
+ return listPermissions(permissions).map((permission) => permission.key).filter((key) => {
528
+ const dot = key.lastIndexOf(".");
529
+ return dot > 0 && (entry.subjectType === "*" || key.slice(0, dot) === entry.subjectType) && (entry.action === "*" || key.slice(dot + 1) === entry.action);
530
+ });
531
+ }
532
+ function policiesOf(entry, options) {
533
+ const roleScope = options.roleScope ?? "tenant";
534
+ const approval = compact({
535
+ stages: entry.steps.length === 0 ? void 0 : entry.steps.map((step) => ({
536
+ by: stageApprovers(step.approvers, roleScope),
537
+ quorum: quorumOf(step)
538
+ })),
539
+ combine: entry.steps.length > 1 ? "sequential" : void 0,
540
+ mode: entry.mode === "confirm" && entry.selfApproval ? "confirm" : void 0,
541
+ ttl: entry.expiresIn === void 0 ? void 0 : intervalSeconds(entry.expiresIn)
542
+ });
543
+ const tree = entry.conditions === void 0 || entry.conditions === null ? true : treeCondition(entry.conditions);
544
+ const shared = compact({
545
+ tenant: entry.organizationId ?? void 0,
546
+ check: tree === true || tree === void 0 ? void 0 : tree,
547
+ approval
548
+ });
549
+ if (!(entry.subjectType === "*" || entry.action === "*")) return [{
550
+ ...shared,
551
+ permission: `${entry.subjectType}.${entry.action}`
552
+ }];
553
+ const effects = effectsOf(entry.effect, options);
554
+ if (effects !== void 0) return [{
555
+ ...shared,
556
+ effects
557
+ }];
558
+ return keysOf(entry, options.permissions).map((permission) => ({
559
+ ...shared,
560
+ permission
561
+ }));
562
+ }
563
+ function enabledIn(tenants) {
564
+ return (entry) => isRecord(entry) && entry["enabled"] === true && (entry["organizationId"] === null || typeof entry["organizationId"] === "string" && tenants.includes(entry["organizationId"]));
565
+ }
566
+ async function listed(approvals, platform) {
567
+ const entries = await unwrap(approvals.listPolicies(platform ? {
568
+ pageSize: 200,
569
+ platform
570
+ } : { pageSize: 200 }), "listPolicies");
571
+ if (!Array.isArray(entries)) throw new TypeError("PermDock: listPolicies answered no list");
572
+ return entries.map((entry) => entry);
573
+ }
574
+ /**
575
+ * An `ApprovalPolicySource` over the approvals block's tenant policies, and
576
+ * with `platform` its platform policies, so a PermDock decision asks for
577
+ * approval wherever the block would. A policy keys the permission
578
+ * `<subjectType>.<action>`; a platform policy has no tenant. Its steps become
579
+ * sequential stages whose approvers are any of the step's permission, role,
580
+ * users and manager; `required: "all"` over users needs each of them. `confirm`
581
+ * with `selfApproval` lets the principal approve; `expiresIn` caps the
582
+ * request's `ttl`. `conditions` become a `check` over the call's input, or the
583
+ * row without one; a tree PermDock cannot express is dropped, so the policy
584
+ * applies to every call: stricter, never looser. A `*` subject type or action
585
+ * with an effect PermDock knows matches every operation with that effect, and
586
+ * without one expands over `permissions`. A concrete policy's `effect` is
587
+ * ignored, so it applies to every call of its permission. A step with only a
588
+ * `team` approver, `required: "all"` over anything but users, an interval it
589
+ * cannot read or a failed read makes the source fail, and every call an allow
590
+ * would grant denies.
591
+ */
592
+ function blockApprovalPolicySource(approvals, options = {}) {
593
+ return Object.freeze({
594
+ name: "better-supabase-approvals",
595
+ async approvalPoliciesFor(query) {
596
+ const [own, platform] = await Promise.all([listed(approvals, false), options.platform === true ? listed(approvals, true) : []]);
597
+ return [...platform, ...own].filter(enabledIn(query.tenants)).flatMap((entry) => policiesOf(entry, options));
598
+ }
599
+ });
600
+ }
601
+ //#endregion
158
602
  //#region src/better-supabase/api-keys.ts
159
603
  const EPOCH = "1970-01-01T00:00:00.000Z";
160
604
  const rfc3339Of = (instant) => isoAt(instant.epochMilliseconds);
@@ -341,6 +785,127 @@ function subjectFromBetterSupabase(session, options = {}) {
341
785
  });
342
786
  }
343
787
  //#endregion
788
+ //#region src/better-supabase/permdock-for.ts
789
+ /** The options a `permdockFor` resolver already holds. */
790
+ const RESOLVER_OWNS = [
791
+ "subject",
792
+ "memberships",
793
+ "version",
794
+ "versions",
795
+ "instances",
796
+ "options"
797
+ ];
798
+ function isResult(source) {
799
+ return isRecord(source) && Object.hasOwn(source, "session") && Object.hasOwn(source, "authzVersion") && !Object.hasOwn(source, "kind");
800
+ }
801
+ function knownVersion(value) {
802
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
803
+ }
804
+ function subjectOf(source, result, signedOut, options) {
805
+ if (isSubject(source)) return source;
806
+ if (result !== void 0) return subjectFromBetterSupabase(signedOut ? null : result.session, options);
807
+ return subjectFromBetterSupabase(source, options);
808
+ }
809
+ /**
810
+ * The resolver behind `permdockFor`, the authorizer and the hooks: one sources
811
+ * object per version cache, so every instance of one subject at one version
812
+ * shares an `instances` entry.
813
+ */
814
+ function permdockResolver(options) {
815
+ const byCache = /* @__PURE__ */ new WeakMap();
816
+ let uncached;
817
+ const sourcesOf = (versions) => ({
818
+ ...options.options,
819
+ ...options.instances === void 0 ? {} : { instances: options.instances },
820
+ ...options.memberships === void 0 ? {} : { memberships: claimsFirst(options.memberships, {
821
+ onStale: "reread",
822
+ ...options.version === void 0 ? {} : { version: options.version },
823
+ ...versions === void 0 ? {} : { versions }
824
+ }) }
825
+ });
826
+ const sourcesFor = (versions) => {
827
+ if (versions === void 0) {
828
+ uncached ??= sourcesOf(void 0);
829
+ return uncached;
830
+ }
831
+ const known = byCache.get(versions);
832
+ if (known !== void 0) return known;
833
+ const created = sourcesOf(versions);
834
+ byCache.set(versions, created);
835
+ return created;
836
+ };
837
+ const resolve = async (source, query, runtimeVersions) => {
838
+ const result = isResult(source) ? source : void 0;
839
+ const signedOut = result?.sessionActive === false;
840
+ const user = subjectOf(source, result, signedOut, options.subject);
841
+ const tenant = query.tenant ?? result?.tenant ?? void 0;
842
+ const known = signedOut ? void 0 : knownVersion(result?.authzVersion);
843
+ const sources = sourcesFor(runtimeVersions ?? options.versions);
844
+ const { permdock } = await buildInstance({
845
+ policy: options.policy,
846
+ user,
847
+ sources,
848
+ scope: {
849
+ ...options.options,
850
+ memberships: sources.memberships,
851
+ intent: query.intent ?? "read",
852
+ tenant: tenant ?? void 0,
853
+ version: known === void 0 ? void 0 : { known }
854
+ }
855
+ });
856
+ return permdock;
857
+ };
858
+ const sources = (versions) => sourcesFor(versions ?? options.versions);
859
+ return Object.freeze(Object.assign(resolve, { sources }));
860
+ }
861
+ /**
862
+ * The resolver an adapter builds instances with: the app's `permdockFor`, or
863
+ * one built from the adapter's own options. `permdockFor` with any option it
864
+ * already holds throws a `TypeError`, since two sources of the same option
865
+ * would disagree.
866
+ */
867
+ function resolverOf(options, adapter) {
868
+ const shared = options.permdockFor;
869
+ if (shared === void 0) return permdockResolver(options);
870
+ const clash = RESOLVER_OWNS.find((key) => options[key] !== void 0);
871
+ if (clash !== void 0) throw new TypeError(`PermDock: ${adapter} takes ${clash} from permdockFor; pass it to permdockFor instead`);
872
+ const resolve = (source, query, versions) => shared(source, query, versions);
873
+ return Object.freeze(Object.assign(resolve, { sources: shared.sources }));
874
+ }
875
+ /**
876
+ * One resolver for every instance of the app: `permdockFor(await
877
+ * bsb.claims())`, `permdockFor(await bsb.bootstrap(...))` or `permdockFor(await
878
+ * bsb.getAccess(...))`. A bootstrap or access result passes its `authzVersion`
879
+ * as `version.known`, so the instance reads no version, and a `sessionActive:
880
+ * false` bootstrap is anonymous. With `instances`, a subject at an unchanged
881
+ * version reuses its instance across requests. Pass the same resolver to
882
+ * `authorizer({ permdockFor })`, `authorizationHooks({ permdockFor })` and,
883
+ * through `permdockFor.sources()`, to every other adapter's options, so they
884
+ * share one instance per subject and version.
885
+ */
886
+ function permdockFor(options) {
887
+ const resolve = permdockResolver(options);
888
+ const call = (source, query, versions) => resolve(source, typeof query === "string" || query === null ? { tenant: query } : query ?? {}, versions);
889
+ return Object.freeze(Object.assign(call, { sources: resolve.sources }));
890
+ }
891
+ /**
892
+ * One `{ allowed, outcome, reason? }` per named check for `input`, from one
893
+ * `permdockFor` instance: frozen plain JSON an island returns from `'use cache:
894
+ * private'`. A check that throws denies its entry; an instance that cannot be
895
+ * built denies them all.
896
+ */
897
+ async function getPermissions(resolve, input, checks, query) {
898
+ let permdock;
899
+ try {
900
+ permdock = await resolve(input, query);
901
+ } catch {
902
+ permdock = void 0;
903
+ }
904
+ if (permdock === void 0) return permissionStates(() => NO_GRANT, checks);
905
+ const decide = permdock.decide;
906
+ return permissionStates(decide, checks);
907
+ }
908
+ //#endregion
344
909
  //#region src/better-supabase/subscribers.ts
345
910
  function permissionFor(events, type) {
346
911
  if (Object.hasOwn(events, type)) return events[type];
@@ -356,6 +921,14 @@ function permissionFor(events, type) {
356
921
  * tenant and a throw reach no one.
357
922
  */
358
923
  function subscriberPolicy(options) {
924
+ const resolve = permdockFor({
925
+ policy: options.policy,
926
+ options: {
927
+ ...options.options,
928
+ principals: options.principals
929
+ },
930
+ ...options.instances === void 0 ? {} : { instances: options.instances }
931
+ });
359
932
  return async (event, subscribers) => {
360
933
  try {
361
934
  const permission = permissionFor(options.events, event.type);
@@ -364,14 +937,10 @@ function subscriberPolicy(options) {
364
937
  if (permission === void 0 || tenant === null || senderId === null || senderId === void 0) return [];
365
938
  const sender = await loadPrincipal(options.principals, senderId, tenant);
366
939
  if (sender === null) return [];
367
- const permdock = await getPermDock(options.policy, {
940
+ const permdock = await resolve({
368
941
  principal: sender,
369
942
  context: {}
370
- }, {
371
- ...options.options,
372
- principals: options.principals,
373
- tenant
374
- });
943
+ }, tenant);
375
944
  if (permdock.subject.principal?.tenant !== tenant) return [];
376
945
  return await subscribersFor(permdock, {
377
946
  permission,
@@ -407,12 +976,13 @@ function requestId(input) {
407
976
  * is `false`.
408
977
  */
409
978
  function supportPolicy(options) {
979
+ const resolve = permdockFor(options);
410
980
  return async (input) => {
411
981
  try {
412
- const base = await getPermDock(options.policy, subjectFromBetterSupabase({
982
+ const base = await resolve({
413
983
  kind: "user",
414
984
  claims: input.admin.claims
415
- }, options.subject), options.options);
985
+ });
416
986
  if (base.subject.principal?.id !== input.admin.user.id) return false;
417
987
  if (!input.readOnly && options.writable === void 0) return false;
418
988
  const permdock = input.tenant === void 0 ? base : base.tenant(input.tenant);
@@ -468,16 +1038,17 @@ function grants$1(permdock, key) {
468
1038
  return permission !== void 0 && permdock.decide(permission, void 0).outcome === "granted";
469
1039
  }
470
1040
  /**
471
- * A list matches when every entry does, `anyOf` when one does; other leaves
472
- * match nobody, as in SQL.
1041
+ * A list matches when every entry does, `anyOf` when one does; `manager` when
1042
+ * its key is in `managed`; other leaves match nobody, as in SQL.
473
1043
  */
474
- function matches(approvers, userId, permdock) {
1044
+ function matches(approvers, userId, permdock, managed) {
475
1045
  const items = flattenApprovers(approvers);
476
1046
  return items.length > 0 && items.every((item) => {
477
1047
  switch (item.kind) {
478
1048
  case "user": return item.id === userId;
479
1049
  case "permission": return grants$1(permdock, item.permission);
480
- case "any-of": return item.of.some((entry) => matches(entry, userId, permdock));
1050
+ case "any-of": return item.of.some((entry) => matches(entry, userId, permdock, managed));
1051
+ case "manager": return managed.has(approverManagerKey(item));
481
1052
  case "actor":
482
1053
  case "anyone":
483
1054
  case "assurance":
@@ -495,25 +1066,23 @@ function matches(approvers, userId, permdock) {
495
1066
  * authorization })`), decided by `policy`. Every hook builds the principal's
496
1067
  * instance from the claims `claims` loads now, never from the request, and
497
1068
  * fails closed: a throw, an unknown key and `approval-required` refuse.
498
- * `automation` and `delegation` are always set; `identities`, `delivery`,
499
- * `approverOf`, `support` and `tickets` only with the options they read.
500
- * `delegation.permissions` maps each scope to the keys whose `.scope` it is,
501
- * was renamed from, or that a policy `oauthScopes` entry covers, and reads no
502
- * `authorization_details`.
1069
+ * `automation`, `delegation` and `sessionTags` (`snapshotTag(userId)`, so
1070
+ * `evictSession` and sign-out clear PermDock snapshots) are always set;
1071
+ * `identities`, `delivery`, `approverOf`, `support` and `tickets` only with the
1072
+ * options they read. `delegation.permissions` maps each scope to the keys whose
1073
+ * `.scope` it is, was renamed from, or that a policy `oauthScopes` entry
1074
+ * covers, and reads no `authorization_details`.
503
1075
  */
504
1076
  function authorizationHooks(options) {
505
1077
  const { policy } = options;
1078
+ const resolve = resolverOf(options, "authorizationHooks");
506
1079
  const instance = async (claims, tenant) => {
507
- const subject = subjectFromBetterSupabase({
1080
+ const permdock = await resolve({
508
1081
  kind: "user",
509
1082
  claims
510
- }, options.subject);
511
- if (subject.principal === null) return null;
512
- const permdock = await getPermDock(policy, subject, {
513
- ...options.options,
514
- ...tenant === null || tenant === void 0 ? {} : { tenant }
515
- });
516
- return tenant === null || tenant === void 0 || permdock.subject.principal?.tenant === tenant ? permdock : null;
1083
+ }, { tenant: tenant ?? null });
1084
+ if (permdock.subject.principal === null) return null;
1085
+ return tenant === null || tenant === void 0 || permdock.subject.principal.tenant === tenant ? permdock : null;
517
1086
  };
518
1087
  const holdsAll = async (claims, automation) => {
519
1088
  const permdock = await instance(claims, automation.tenant);
@@ -559,7 +1128,10 @@ function authorizationHooks(options) {
559
1128
  const given = approvers[request.kind];
560
1129
  if (given === void 0 || approver.claims["sub"] !== approver.userId) return false;
561
1130
  const permdock = await instance(approver.claims, request.tenant);
562
- return permdock !== null && matches(asApprover(given), approver.userId, permdock);
1131
+ if (permdock === null) return false;
1132
+ const wanted = asApprover(given);
1133
+ const managed = request.requester === void 0 ? [] : await managerKeys(approverLeaves(wanted), request.requester, approver.userId, compact({ relations: resolve.sources().relations }));
1134
+ return matches(wanted, approver.userId, permdock, new Set(managed));
563
1135
  } catch {
564
1136
  return false;
565
1137
  }
@@ -589,6 +1161,7 @@ function authorizationHooks(options) {
589
1161
  return Object.freeze({
590
1162
  apiVersion: 1,
591
1163
  name: "PermDock",
1164
+ sessionTags: (userId) => [snapshotTag(userId)],
592
1165
  automation: Object.freeze(automation),
593
1166
  delegation: Object.freeze(delegation),
594
1167
  ...approverOf === void 0 ? {} : { approverOf },
@@ -620,6 +1193,8 @@ function authorizationHooks(options) {
620
1193
  //#region src/better-supabase/approvers.ts
621
1194
  /** `rls.approvals`' approver check, executable by `authenticated`. */
622
1195
  const IS_APPROVER = "permdock_is_approver";
1196
+ /** The manager walk `rls.approvals.managers` writes. */
1197
+ const MANAGES = "permdock_manages";
623
1198
  /**
624
1199
  * The resource a cover's `resources` names for a request kind: `job` for
625
1200
  * `job.update`, else the kind.
@@ -631,14 +1206,20 @@ function resourceOf(kind) {
631
1206
  /**
632
1207
  * better-supabase's `isApprover` template: one `case` over `{kind}` whose
633
1208
  * branches call `permdock_is_approver` with the kind's approvers as JSON. A
634
- * kind with no branch is `false`. Only `user`, `holder` and `anyOf` approvers
635
- * match in SQL; other leaves are reported and match nobody.
1209
+ * kind with no branch is `false`. With `requestApprovers`, every call is the
1210
+ * five-argument form, which also gets better-supabase's `{approvers}`, the
1211
+ * request's current approvers. Only `user`, `holder` and `anyOf` approvers, and
1212
+ * `manager` with `rls.approvals.managers`, match in SQL; other leaves are
1213
+ * reported and match nobody.
636
1214
  */
637
1215
  function isApproverTemplate(input) {
638
1216
  const problems = [];
639
1217
  if (!input.listed) return { problems: [`approvers needs ${input.schema}.${IS_APPROVER}, which \`permdock rls generate\` writes with rls.approvals. Run it, then \`permdock supabase inspect --out\`.`] };
640
1218
  const fn = `${sqlIdent(input.schema)}.${sqlIdent(IS_APPROVER)}`;
641
1219
  const keys = input.catalog === void 0 ? void 0 : new Set(input.catalog.permissions.map((permission) => permission.key));
1220
+ const current = input.requestApprovers === true;
1221
+ if (current && input.covers !== true) return { problems: [`requestApprovers needs the five-argument ${IS_APPROVER}, which \`permdock rls generate\` writes with rls.approvals.delegations or rls.approvals.managers. Set one, run it, then \`permdock supabase inspect --out\`.`] };
1222
+ const passed = current ? ", ({approvers})::jsonb" : "";
642
1223
  const branches = [];
643
1224
  for (const [kind, given] of Object.entries(input.approvers)) {
644
1225
  if (kind === "") {
@@ -646,24 +1227,28 @@ function isApproverTemplate(input) {
646
1227
  continue;
647
1228
  }
648
1229
  const approvers = asApprover(given);
1230
+ const managers = input.managers === true && input.covers === true;
649
1231
  for (const leaf of approverLeaves(approvers)) {
650
1232
  if (leaf.kind === "user") continue;
651
- if (leaf.kind !== "permission") problems.push(`The ${kind} approvers name a ${leaf.kind} approver, which ${IS_APPROVER} cannot check in SQL, so it matches nobody. Use user(), holder() or anyOf().`);
1233
+ if (leaf.kind === "manager") {
1234
+ if (!managers) problems.push(`The ${kind} approvers name a manager approver, which ${IS_APPROVER} checks only with rls.approvals.managers, so it matches nobody. Set rls.approvals.managers, run \`permdock rls generate\`, then \`permdock supabase inspect --out\`.`);
1235
+ } else if (leaf.kind !== "permission") problems.push(`The ${kind} approvers name a ${leaf.kind} approver, which ${IS_APPROVER} cannot check in SQL, so it matches nobody. Use user(), holder(), manager() or anyOf().`);
652
1236
  else if (keys !== void 0 && !keys.has(leaf.permission)) problems.push(`The ${kind} approver permission ${leaf.permission} is not in the catalog. Run \`permdock catalog\` after adding it to the policy.`);
653
1237
  }
654
1238
  const json = `${quoteSqlLiteral(JSON.stringify(approvers))}::jsonb`;
655
- branches.push(input.covers === true ? `when ${quoteSqlLiteral(kind)} then ${fn}(${json}, ({tenant})::text, ({requester})::text, ${quoteSqlLiteral(resourceOf(kind))})` : `when ${quoteSqlLiteral(kind)} then ${fn}(${json}, ({tenant})::text)`);
1239
+ branches.push(input.covers === true ? `when ${quoteSqlLiteral(kind)} then ${fn}(${json}, ({tenant})::text, ({requester})::text, ${quoteSqlLiteral(resourceOf(kind))}${passed})` : `when ${quoteSqlLiteral(kind)} then ${fn}(${json}, ({tenant})::text)`);
656
1240
  }
657
- if (branches.length === 0) {
1241
+ if (branches.length === 0 && !current) {
658
1242
  problems.push("approvers names no kind, so isApprover is not set.");
659
1243
  return { problems };
660
1244
  }
661
1245
  if (!input.rootTenant) problems.push(`The tenant scope "${input.tenantScope}" is not a root scope, and ${IS_APPROVER} checks holder() approvers at the root scope, so they match nobody.`);
1246
+ const otherwise = current ? `${fn}(null::jsonb, ({tenant})::text, ({requester})::text, split_part({kind}, '.', 1)${passed})` : "false";
662
1247
  return {
663
- template: `case {kind} ${branches.join(" ")} else false end`,
1248
+ template: branches.length === 0 ? otherwise : `case {kind} ${branches.join(" ")} else ${otherwise} end`,
664
1249
  requires: {
665
1250
  function: fn,
666
- args: input.covers === true ? "jsonb, text, text, text" : "jsonb, text",
1251
+ args: current ? "jsonb, text, text, text, jsonb" : input.covers === true ? "jsonb, text, text, text" : "jsonb, text",
667
1252
  role: "postgres"
668
1253
  },
669
1254
  problems
@@ -879,12 +1464,14 @@ function tokenHookOf(manifest, activeTenant) {
879
1464
  const owned = manifest.claims.filter((claim) => claim.source === "permdock");
880
1465
  const registered = manifest.claims.filter((claim) => claim.source !== "permdock");
881
1466
  const budgeted = manifest.claims.filter((claim) => claim.budget);
1467
+ const truncated = owned.some((claim) => claim.name === "memberships_truncated") ? "memberships_truncated" : void 0;
882
1468
  const activeFrom = activeTenant === "resolver" || manifest.hook.activeFrom === void 0 ? void 0 : activeOrganizationFrom(manifest.hook.activeFrom, manifest.tenantClaim);
883
1469
  return {
884
1470
  function: `${manifest.hook.schema}.${manifest.hook.function}`,
885
1471
  tenantClaim: manifest.tenantClaim,
886
1472
  ...activeFrom === void 0 ? {} : { activeOrganizationFrom: activeFrom },
887
1473
  ownedClaims: owned.map((claim) => claim.name),
1474
+ ...truncated === void 0 ? {} : { truncatedClaim: truncated },
888
1475
  ...registered.length > 0 ? { registeredClaims: registered.map((claim) => ({
889
1476
  name: claim.name,
890
1477
  function: claim.source
@@ -892,7 +1479,7 @@ function tokenHookOf(manifest, activeTenant) {
892
1479
  budget: {
893
1480
  claims: budgeted.map((claim) => claim.name),
894
1481
  bytes: manifest.budget.bytes,
895
- ...owned.some((claim) => claim.name === "memberships_truncated") ? { truncatedClaim: "memberships_truncated" } : {}
1482
+ ...truncated === void 0 ? {} : { truncatedClaim: truncated }
896
1483
  },
897
1484
  markers: {
898
1485
  hook: `-- permdock:hook ${manifest.markers.hook}`,
@@ -1073,12 +1660,14 @@ function authorizationProvider(options) {
1073
1660
  ...options.approvers
1074
1661
  };
1075
1662
  let isApprover;
1076
- if (approvers !== void 0) {
1663
+ if (approvers !== void 0 || options.requestApprovers === true) {
1077
1664
  const built = isApproverTemplate({
1078
- approvers,
1665
+ approvers: approvers ?? {},
1666
+ requestApprovers: options.requestApprovers === true,
1079
1667
  schema: rls.schema,
1080
1668
  listed: helpers.has(IS_APPROVER),
1081
1669
  covers: /\bp_requester\b/u.test(helpers.get("permdock_is_approver")?.args ?? ""),
1670
+ managers: helpers.has(MANAGES),
1082
1671
  tenantScope,
1083
1672
  rootTenant,
1084
1673
  catalog
@@ -1197,9 +1786,6 @@ const denied = (reason) => ({
1197
1786
  outcome: "denied",
1198
1787
  reason
1199
1788
  });
1200
- function isVersionCache(value) {
1201
- return isRecord(value) && typeof value["maxStaleMs"] === "number" && typeof value["current"] === "function" && typeof value["evict"] === "function";
1202
- }
1203
1789
  function outcomeOf(decision, key) {
1204
1790
  switch (decision.outcome) {
1205
1791
  case "granted": return { outcome: "granted" };
@@ -1211,10 +1797,31 @@ function outcomeOf(decision, key) {
1211
1797
  default: return decision;
1212
1798
  }
1213
1799
  }
1214
- function decideWith(permdock, request) {
1215
- const { action } = request;
1216
- if (!isPermission(action)) return denied("Unknown permission.");
1217
- return outcomeOf(permdock.decide(action, request.resource.properties), action.key);
1800
+ /**
1801
+ * The row a check decides on. A write is `change`: a create checks the new
1802
+ * values, an update the stored row against the stored row with the new values
1803
+ * over it. Only a row better-supabase loaded itself, with no change, skips
1804
+ * schema validation.
1805
+ */
1806
+ function dataOf(resource) {
1807
+ const { change } = resource;
1808
+ if (change !== void 0) return change.current === void 0 ? {
1809
+ data: change.next,
1810
+ trusted: false
1811
+ } : {
1812
+ data: {
1813
+ current: change.current,
1814
+ next: {
1815
+ ...change.current,
1816
+ ...change.next
1817
+ }
1818
+ },
1819
+ trusted: false
1820
+ };
1821
+ return {
1822
+ data: resource.properties,
1823
+ trusted: resource.source === "loaded"
1824
+ };
1218
1825
  }
1219
1826
  /**
1220
1827
  * The verified claims better-supabase passes in `subject.properties.claims`,
@@ -1227,7 +1834,7 @@ function claimsOf(request) {
1227
1834
  return isRecord(claims) ? claims : void 0;
1228
1835
  }
1229
1836
  const tenantOf = (request) => {
1230
- const tenant = request.context["tenant"];
1837
+ const { tenant } = request.context;
1231
1838
  return typeof tenant === "string" ? tenant : null;
1232
1839
  };
1233
1840
  const keyOf = (request) => isPermission(request.action) ? request.action.key : null;
@@ -1241,38 +1848,61 @@ const keyOf = (request) => isPermission(request.action) ? request.action.key : n
1241
1848
  * request scope share an instance per claims, tenant and intent.
1242
1849
  */
1243
1850
  function authorizer(options) {
1244
- const { operations } = options;
1851
+ const { operations, store } = options;
1245
1852
  const intentOf = (request, batch) => {
1246
1853
  if (options.intent !== void 0) return options.intent(request);
1854
+ const { intent } = request.context;
1855
+ if (intent === "read" || intent === "write") return intent;
1247
1856
  if (batch) return "read";
1248
1857
  return isPermission(request.action) && READ_ACTIONS.has(request.action.action) ? "read" : "write";
1249
1858
  };
1250
- const membershipsFor = (runtime) => {
1251
- if (options.memberships === void 0) return {};
1252
- const versions = isVersionCache(runtime?.versions) ? runtime.versions : options.versions;
1253
- return { memberships: claimsFirst(options.memberships, {
1254
- onStale: "reread",
1255
- ...options.version === void 0 ? {} : { version: options.version },
1256
- ...versions === void 0 ? {} : { versions }
1257
- }) };
1258
- };
1259
- const instanceFor = async (claims, tenant, intent, runtime) => {
1260
- const session = claims === void 0 ? null : {
1261
- kind: "user",
1262
- claims
1263
- };
1264
- const base = await getPermDock(options.policy, subjectFromBetterSupabase(session, options.subject), {
1265
- ...options.options,
1266
- ...membershipsFor(runtime),
1859
+ const resolve = resolverOf(options, "authorizer");
1860
+ const instanceFor = (claims, tenant, intent, runtime) => resolve(claims === void 0 ? null : {
1861
+ kind: "user",
1862
+ claims
1863
+ }, {
1864
+ tenant,
1865
+ intent
1866
+ }, runtime?.versions);
1867
+ const scoped = (claims, tenant, intent, runtime, batch) => {
1868
+ const key = `permdock:authorizer:${canonicalJson([
1869
+ claims ?? null,
1870
+ tenant,
1267
1871
  intent
1872
+ ])}`;
1873
+ const build = () => instanceFor(claims, tenant, intent, runtime);
1874
+ if (runtime?.memo !== void 0) return runtime.memo.once(key, build);
1875
+ if (batch === void 0) return build();
1876
+ const known = batch.get(key);
1877
+ if (known !== void 0) return known;
1878
+ const created = build();
1879
+ batch.set(key, created);
1880
+ return created;
1881
+ };
1882
+ const decideWith = async (permdock, request, consume) => {
1883
+ const { action } = request;
1884
+ if (!isPermission(action)) return denied("Unknown permission.");
1885
+ const { data, trusted } = dataOf(request.resource);
1886
+ const decision = permdock.decide(action, data, {
1887
+ trusted,
1888
+ adapter: "better-supabase"
1268
1889
  });
1269
- return tenant === null ? base : base.tenant(tenant);
1890
+ if (store === void 0 || decision.outcome !== "approval-required") return outcomeOf(decision, action.key);
1891
+ const { id } = request.resource;
1892
+ return outcomeOf(await resumeDecision({
1893
+ decision,
1894
+ permission: action,
1895
+ subject: permdock.subject,
1896
+ store,
1897
+ resource: id === void 0 ? { type: action.resource } : {
1898
+ type: action.resource,
1899
+ id
1900
+ },
1901
+ adapter: "better-supabase",
1902
+ token: parseApprovalHeader(request.context.approval ?? null),
1903
+ consume
1904
+ }), action.key);
1270
1905
  };
1271
- const scoped = (claims, tenant, intent, runtime) => runtime?.memo === void 0 ? instanceFor(claims, tenant, intent, runtime) : runtime.memo.once(`permdock:authorizer:${JSON.stringify([
1272
- claims ?? null,
1273
- tenant,
1274
- intent
1275
- ])}`, () => instanceFor(claims, tenant, intent, runtime));
1276
1906
  const failed = (error, request) => {
1277
1907
  report(options.onError, error, {
1278
1908
  permission: keyOf(request),
@@ -1293,33 +1923,17 @@ function authorizer(options) {
1293
1923
  } },
1294
1924
  async evaluate(request, runtime) {
1295
1925
  try {
1296
- return decideWith(await scoped(claimsOf(request), tenantOf(request), intentOf(request, false), runtime), request);
1926
+ return await decideWith(await scoped(claimsOf(request), tenantOf(request), intentOf(request, false), runtime), request, true);
1297
1927
  } catch (error) {
1298
1928
  return failed(error, request);
1299
1929
  }
1300
1930
  },
1301
1931
  evaluations(requests, runtime) {
1302
- const cache = /* @__PURE__ */ new Map();
1303
- const shared = (request) => {
1304
- const claims = claimsOf(request);
1305
- const tenant = tenantOf(request);
1306
- const intent = intentOf(request, true);
1307
- let byKey = cache.get(claims);
1308
- if (byKey === void 0) {
1309
- byKey = /* @__PURE__ */ new Map();
1310
- cache.set(claims, byKey);
1311
- }
1312
- const key = JSON.stringify([tenant, intent]);
1313
- let instance = byKey.get(key);
1314
- if (instance === void 0) {
1315
- instance = scoped(claims, tenant, intent, runtime);
1316
- byKey.set(key, instance);
1317
- }
1318
- return instance;
1319
- };
1932
+ const batch = /* @__PURE__ */ new Map();
1933
+ const shared = (request) => scoped(claimsOf(request), tenantOf(request), intentOf(request, true), runtime, batch);
1320
1934
  return Promise.all(requests.map(async (request) => {
1321
1935
  try {
1322
- return decideWith(await shared(request), request);
1936
+ return await decideWith(await shared(request), request, false);
1323
1937
  } catch (error) {
1324
1938
  return failed(error, request);
1325
1939
  }
@@ -1332,14 +1946,17 @@ function authorizer(options) {
1332
1946
  function roleOf(options, columns) {
1333
1947
  const column = columns.role;
1334
1948
  if (options.roles !== void 0 && options.roleThrough !== void 0) throw new TypeError("PermDock: blockMembershipSource takes roles or roleThrough, not both; a junction holds role keys");
1335
- if (options.roles === "many") return {
1336
- through: `${qualifySqlTable(columns.table).split(".")[0] ?? "better_supabase"}.membership_roles`,
1337
- on: {
1338
- [columns.tenant]: columns.tenant,
1339
- [columns.user]: columns.user
1340
- },
1341
- column: "role"
1342
- };
1949
+ if (options.roles === "many") {
1950
+ const junction = options.tables?.membershipRoles;
1951
+ return {
1952
+ through: junction?.table ?? `${qualifySqlTable(columns.table).split(".")[0] ?? "better_supabase"}.membership_roles`,
1953
+ on: {
1954
+ [columns.tenant]: junction?.columns.tenant ?? columns.tenant,
1955
+ [columns.user]: junction?.columns.user ?? columns.user
1956
+ },
1957
+ column: junction?.columns.role ?? "role"
1958
+ };
1959
+ }
1343
1960
  if (options.roles !== void 0) return {
1344
1961
  through: options.roles.table,
1345
1962
  on: { [options.roles.id ?? "id"]: options.roles.membership },
@@ -1361,11 +1978,14 @@ function roleOf(options, columns) {
1361
1978
  */
1362
1979
  function blockMembershipSource(options = {}) {
1363
1980
  const c = options.columns ?? {};
1981
+ const block = options.tables?.memberships;
1364
1982
  const scope = options.scope ?? "organization";
1365
- const disabledAt = c.disabledAt === null ? void 0 : c.disabledAt ?? "disabled_at";
1366
- const table = options.table ?? "better_supabase.memberships";
1367
- const tenant = c.tenant ?? "organization_id";
1368
- const user = c.user ?? "user_id";
1983
+ const disabled = c.disabledAt === void 0 ? block?.columns.disabledAt : c.disabledAt;
1984
+ const disabledAt = disabled === null ? void 0 : disabled ?? "disabled_at";
1985
+ const table = options.table ?? block?.table ?? "better_supabase.memberships";
1986
+ const tenant = c.tenant ?? block?.columns.tenant ?? "organization_id";
1987
+ const user = c.user ?? block?.columns.user ?? "user_id";
1988
+ const role = c.role ?? block?.columns.role ?? "role";
1369
1989
  return junctionMembershipSource({
1370
1990
  table,
1371
1991
  scope,
@@ -1373,7 +1993,7 @@ function blockMembershipSource(options = {}) {
1373
1993
  user,
1374
1994
  roles: roleOf(options, {
1375
1995
  table,
1376
- role: c.role ?? "role",
1996
+ role,
1377
1997
  tenant,
1378
1998
  user
1379
1999
  }),
@@ -1515,9 +2135,10 @@ const refused = (reason) => ({
1515
2135
  * The `authorize` and `visible` hooks of better-supabase's `createMcp`, for
1516
2136
  * tools whose `meta` is a PermDock permission. A tool without a permission is
1517
2137
  * hidden and refused. `authorize` grants only a `granted` decision: an
1518
- * approval-required call is refused, because `createMcp` has no approval flow.
1519
- * A denial's text names the first denial reason. A throw anywhere refuses and
1520
- * reaches `onError`.
2138
+ * approval-required call is refused, because `authorize` has no approval
2139
+ * outcome. A tool whose `permission` goes through `authorizer` with a `store`
2140
+ * returns the approval id and resumes it instead. A denial's text names the
2141
+ * first denial reason. A throw anywhere refuses and reaches `onError`.
1521
2142
  */
1522
2143
  function toolPolicy(options) {
1523
2144
  return Object.freeze({
@@ -1828,4 +2449,44 @@ function handlerCan(source, options = {}) {
1828
2449
  };
1829
2450
  }
1830
2451
  //#endregion
1831
- export { accessReviewApplier, apiKeyClaimOptions, apiKeyVerifier, authorizationHooks, authorizationProvider, authorizer, blockMembershipSource, bucketPolicy, credentialGuard, handlerCan, hookCan, principalFromMemberships, principalSource, roleOrderFromCatalog, subjectFromBetterSupabase, subjectFromShareLink, subscriberPolicy, supportPolicy, toolPolicy, topicPolicy };
2452
+ //#region src/better-supabase/workflow-resource.ts
2453
+ const MAX_ID_LENGTH = 256;
2454
+ function invalid(detail) {
2455
+ return freezeDeep({
2456
+ ok: false,
2457
+ cause: "validation",
2458
+ decision: {
2459
+ outcome: "denied",
2460
+ denials: [{
2461
+ role: null,
2462
+ reason: "validation",
2463
+ detail
2464
+ }],
2465
+ alternatives: []
2466
+ }
2467
+ });
2468
+ }
2469
+ /**
2470
+ * The resource a `workflow.start` check decides on for a run started on
2471
+ * `subject`: `{ type, id }`, with the type `types` maps the subject type to. A
2472
+ * subject type `types` does not name, a missing or empty id, or an id over 256
2473
+ * characters is `{ ok: false, cause: 'validation' }` with the denial to
2474
+ * return.
2475
+ */
2476
+ function workflowResource(subject, types) {
2477
+ if (!isRecord(subject)) return invalid("subject is not a { type, id } record");
2478
+ const { type, id } = subject;
2479
+ if (typeof type !== "string" || !Object.hasOwn(types, type)) return invalid(`unknown subject type ${JSON.stringify(type) ?? "undefined"}`);
2480
+ if (typeof id !== "string" || id === "" || id.length > MAX_ID_LENGTH) return invalid("subject id is not a non-empty string of at most 256 characters");
2481
+ const resource = types[type];
2482
+ if (typeof resource !== "string" || resource === "") return invalid(`subject type ${type} maps to no resource`);
2483
+ return freezeDeep({
2484
+ ok: true,
2485
+ resource: {
2486
+ type: resource,
2487
+ id
2488
+ }
2489
+ });
2490
+ }
2491
+ //#endregion
2492
+ export { accessReviewApplier, apiKeyClaimOptions, apiKeyVerifier, authorizationHooks, authorizationProvider, authorizer, blockApprovalPolicySource, blockApprovalStore, blockMembershipSource, bucketPolicy, credentialGuard, getPermissions, handlerCan, hookCan, permdockFor, principalFromMemberships, principalSource, roleOrderFromCatalog, subjectFromBetterSupabase, subjectFromShareLink, subscriberPolicy, supportPolicy, toolPolicy, topicPolicy, workflowResource };