permdock 0.4.0 → 0.5.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 (514) hide show
  1. package/README.md +37 -35
  2. package/dist/{schema-Bol6gqXA.js → 2020-C9VN-x8c.js} +5 -130
  3. package/dist/a2a/index.d.ts +6 -6
  4. package/dist/a2a/index.js +14 -17
  5. package/dist/{adapter-context-mlWsVGGg.js → adapter-context-CRhqyzCk.js} +1 -1
  6. package/dist/adoption-scan-B4R5fnMU.js +107 -0
  7. package/dist/agent/index.d.ts +3 -0
  8. package/dist/agent/index.js +1 -0
  9. package/dist/ai-sdk/index.d.ts +18 -35
  10. package/dist/ai-sdk/index.js +37 -23
  11. package/dist/{app-data-CV8pqqMi.js → app-data-MuyzVqX8.js} +2 -1
  12. package/dist/approval-header-CJACtHkv.js +23 -0
  13. package/dist/approval-prompt-Dg5LeAcT.js +62 -0
  14. package/dist/approval-prompt-Djo_PyZc.d.ts +57 -0
  15. package/dist/approvals/index.d.ts +5 -3
  16. package/dist/approvals/index.js +8 -5
  17. package/dist/approvals-DJ6Yd5z1.js +995 -0
  18. package/dist/arazzo-B6lebmiQ.js +36 -0
  19. package/dist/{arazzo-C4BcskbX.js → arazzo-BWhNF-k0.js} +20 -14
  20. package/dist/args-IIolxxKA.js +197 -0
  21. package/dist/astro/index.d.ts +43 -0
  22. package/dist/astro/index.js +27 -0
  23. package/dist/audience-Dg8XsRaO.js +55 -0
  24. package/dist/auth-DRLEizbL.js +178 -0
  25. package/dist/authzen/index.d.ts +26 -6
  26. package/dist/authzen/index.js +94 -79
  27. package/dist/automation-BMZPIVUM.d.ts +114 -0
  28. package/dist/automation-DVjOckjV.js +157 -0
  29. package/dist/better-auth/index.d.ts +8 -6
  30. package/dist/better-auth/index.js +9 -8
  31. package/dist/better-supabase/index.d.ts +357 -30
  32. package/dist/better-supabase/index.js +936 -194
  33. package/dist/{bind-BzqG8SMb.d.ts → bind--9EFVYWF.d.ts} +12 -10
  34. package/dist/{bind-kk-uyCwH.js → bind-CZzhx-Vj.js} +14 -10
  35. package/dist/body-CH5of8Ne.js +10 -0
  36. package/dist/body-text-QcXok_SI.js +52 -0
  37. package/dist/{build-instance-DIIV9DbC.js → build-instance-BMnAudHn.js} +4 -3
  38. package/dist/{canonical-json-CFKyFOke.js → canonical-json-BC8_nMTw.js} +5 -3
  39. package/dist/{capability-CksyCWDH.d.ts → capability-BSslw1QV.d.ts} +44 -25
  40. package/dist/{capability-txATtKV4.js → capability-N1K9IpqS.js} +68 -42
  41. package/dist/casbin-Cr7RLtA3.js +30 -0
  42. package/dist/casbin-Dyu2gnUD.js +234 -0
  43. package/dist/casl-64gpT-8x.js +24 -0
  44. package/dist/casl-DjEDhTCP.js +299 -0
  45. package/dist/catalog/index.d.ts +74 -2
  46. package/dist/catalog/index.js +51 -2
  47. package/dist/{catalog-tZUyOfOv.js → catalog-BECMPrwc.js} +51 -6
  48. package/dist/catalog-DjhMYYCq.js +1 -0
  49. package/dist/catalog-R_A__RsH.js +52 -0
  50. package/dist/{catalog-doc-DWtg0gGR.js → catalog-doc-C9wjsfNY.js} +45 -23
  51. package/dist/catalog-fingerprint-CCP0-yQS.js +153 -0
  52. package/dist/chat/index.d.ts +2 -0
  53. package/dist/chat/index.js +224 -0
  54. package/dist/chat-sdk/index.d.ts +87 -0
  55. package/dist/chat-sdk/index.js +197 -0
  56. package/dist/claims-map-7oQ3ue4X.js +13 -0
  57. package/dist/claims-map-Ca-QX8C6.d.ts +32 -0
  58. package/dist/claude-agent/index.d.ts +7 -14
  59. package/dist/claude-agent/index.js +24 -27
  60. package/dist/clerk/index.d.ts +9 -8
  61. package/dist/clerk/index.js +9 -14
  62. package/dist/cli/bin.js +36 -17
  63. package/dist/cli/index.d.ts +19 -5
  64. package/dist/cli/index.js +164 -4
  65. package/dist/cloud/index.d.ts +102 -63
  66. package/dist/cloud/index.js +239 -340
  67. package/dist/cloud-CIoHNevm.js +87 -0
  68. package/dist/codemod-Bmj9dWMH.js +37 -0
  69. package/dist/codemod-Cxvvc70T.js +2084 -0
  70. package/dist/{collect-2SrB7lfk.js → collect-CrZJJnEF.js} +75 -11
  71. package/dist/collect-DloHbDVa.js +55 -0
  72. package/dist/collect-FlXJlhus.js +1 -0
  73. package/dist/command-L8EstFNm.js +6 -0
  74. package/dist/compile/index.d.ts +1 -1
  75. package/dist/compile/index.js +1 -2
  76. package/dist/{compile-CcEu2ZQ1.js → compile-CMqMx_IN.js} +11 -8
  77. package/dist/{compile-CtTP7eur.d.ts → compile-Ckm2HqBZ.d.ts} +5 -3
  78. package/dist/completion-BqhRBJD8.js +143 -0
  79. package/dist/config-B46rm9sc.js +26 -0
  80. package/dist/{config-BIjREpyE.js → config-bs_kZeYq.js} +12 -7
  81. package/dist/{config-report--Xb9APJS.js → config-report-DUgj62Ai.js} +15 -5
  82. package/dist/{connection-DUsczpB5.js → connection-DjhIJSs2.js} +6 -5
  83. package/dist/{context-DieZVJXu.js → context-bbFHR-0D.js} +2 -2
  84. package/dist/convex/index.d.ts +11 -10
  85. package/dist/convex/index.js +6 -4
  86. package/dist/create-0VZ7Pdiu.d.ts +107 -0
  87. package/dist/create-BDS7wc3y.d.ts +138 -0
  88. package/dist/create-BFfm17UA.d.ts +110 -0
  89. package/dist/create-BWRSXgOF.js +403 -0
  90. package/dist/create-C3b4B5eF.js +130 -0
  91. package/dist/{create-BBO24vj6.js → create-DnrmLnLW.js} +31 -32
  92. package/dist/{credential-kue0qpbm.js → credential-DM2um3ha.js} +152 -31
  93. package/dist/credentials-DPyHmYz5.js +74 -0
  94. package/dist/delegation-DaXVdDhM.js +286 -0
  95. package/dist/delivery/index.d.ts +5 -0
  96. package/dist/delivery/index.js +5 -0
  97. package/dist/delivery-DCAgNyCn.js +499 -0
  98. package/dist/delivery-event-xX4obB8F.js +40 -0
  99. package/dist/{denied-text-DfRk15uw.d.ts → denied-text-D8jDHgsl.d.ts} +5 -5
  100. package/dist/{describe-C3ldA9os.d.ts → describe-BZUsixiL.d.ts} +2 -2
  101. package/dist/{describe-Cgkp7eP0.js → describe-BybMRY7A.js} +6 -2
  102. package/dist/device-BARQ8eYG.js +193 -0
  103. package/dist/diff-CxZo9pTq.js +37 -0
  104. package/dist/{diff-rpqoe7Ag.js → diff-DCePiN6M.js} +60 -54
  105. package/dist/doctor-CxiwSfqH.js +44 -0
  106. package/dist/{doctor-owlv6ddh.js → doctor-DFjUxf2f.js} +245 -50
  107. package/dist/drizzle/index.d.ts +5 -3
  108. package/dist/drizzle/index.js +2 -2
  109. package/dist/elysia/index.d.ts +16 -13
  110. package/dist/elysia/index.js +13 -12
  111. package/dist/env-DJZrPjRi.js +8 -0
  112. package/dist/errors-BDUwg2qC.js +27 -0
  113. package/dist/{errors-drnfxYtm.js → errors-BKy0EfhN.js} +5 -9
  114. package/dist/errors-BWXBMaKK.d.ts +11 -0
  115. package/dist/{errors-OD_4c__H.d.ts → errors-C2PXIv4c.d.ts} +2 -2
  116. package/dist/errors-CWTY6uih.js +143 -0
  117. package/dist/evaluate-_R8QkWaf.js +1732 -0
  118. package/dist/evaluations-16UqqQ6W.d.ts +32 -0
  119. package/dist/{evaluations-C9YJsv3H.js → evaluations-DZ2CbV5k.js} +145 -34
  120. package/dist/eve/index.d.ts +12 -16
  121. package/dist/eve/index.js +22 -28
  122. package/dist/event-time-CsegxXxB.js +23 -0
  123. package/dist/expiry-D4_YKRKD.js +52 -0
  124. package/dist/express/index.d.ts +13 -10
  125. package/dist/express/index.js +12 -11
  126. package/dist/fastify/index.d.ts +25 -22
  127. package/dist/fastify/index.js +13 -12
  128. package/dist/fetch-adapter-g0ypLkID.js +120 -0
  129. package/dist/fetch-adapter-qKJBuRqy.d.ts +31 -0
  130. package/dist/fields-D9tPVUUS.js +203 -0
  131. package/dist/files-C5ZI27eV.js +124 -0
  132. package/dist/{fixtures-h2eG2OZV.js → fixtures-B7XrLeY7.js} +8 -7
  133. package/dist/flags-C3DktBDY.js +86 -0
  134. package/dist/{from-snapshot-7REQZe0H.js → from-snapshot-D2lZt4Dd.js} +55 -52
  135. package/dist/{grantee-CXY-0C87.js → grantee-Cn1HyUsI.js} +3 -3
  136. package/dist/{grantee-conditions-MQs5NIuX.js → grantee-conditions-CcXf8hMM.js} +4 -3
  137. package/dist/{grantee-match-fxYp9Nmt.js → grantee-match-DHArqY82.js} +5 -4
  138. package/dist/h3/index.d.ts +37 -0
  139. package/dist/h3/index.js +35 -0
  140. package/dist/headers-BIjfMaoC.js +8 -0
  141. package/dist/headers-CIbDTUTK.d.ts +7 -0
  142. package/dist/{helpers-C9YmyBIa.js → helpers-DTcZOzhF.js} +45 -38
  143. package/dist/hono/index.d.ts +12 -9
  144. package/dist/hono/index.js +13 -12
  145. package/dist/hosted-BZIAYvon.js +315 -0
  146. package/dist/hosted-DBDX0M-P.d.ts +78 -0
  147. package/dist/{http-DPuDaChb.d.ts → http-B_LphE5Y.d.ts} +1 -2
  148. package/dist/http-DXJ37RDA.js +46 -0
  149. package/dist/{http-BEbdMZ05.js → http-ujKm0JXE.js} +1 -2
  150. package/dist/{import-UHk1N7vH.js → import-CNV7I2Dw.js} +25 -20
  151. package/dist/{import-BFIlhetD.js → import-DMmOG27O.js} +190 -53
  152. package/dist/index-BcHcPyIo.d.ts +110 -0
  153. package/dist/index-CaxrMD1A.d.ts +1 -0
  154. package/dist/index-Chrs5fQ-.d.ts +210 -0
  155. package/dist/index-CxGUswIC.d.ts +431 -0
  156. package/dist/index-D8EovfsP.d.ts +91 -0
  157. package/dist/{index-UdVQgq48.d.ts → index-DOVf7RJv.d.ts} +431 -81
  158. package/dist/{index-BwMe94Xq.d.ts → index-SGdIQyzc.d.ts} +34 -16
  159. package/dist/index.d.ts +19 -15
  160. package/dist/index.js +31 -21
  161. package/dist/init-DeMYsnYJ.js +96 -0
  162. package/dist/init-GG6Jh8HD.js +95 -0
  163. package/dist/{instance-options-plkrsAog.d.ts → instance-options-Omfd793B.d.ts} +2 -2
  164. package/dist/instance-snapshot-Cxq4ygFc.js +600 -0
  165. package/dist/instant-BluqDvyS.js +19 -0
  166. package/dist/internals-Dk8A8fX3.js +17 -0
  167. package/dist/{json-schema-DBkdUuCO.js → json-schema-B-vAwlde.js} +45 -6
  168. package/dist/json-schema-CN_iLFH2.d.ts +40 -0
  169. package/dist/jwt/index.d.ts +18 -11
  170. package/dist/jwt/index.js +156 -135
  171. package/dist/{kernel-CB3LrIJM.js → kernel-5JatXyND.js} +52 -24
  172. package/dist/kysely/index.d.ts +5 -3
  173. package/dist/kysely/index.js +2 -2
  174. package/dist/load-BxEtwlBS.js +1 -0
  175. package/dist/{load-C3_oTHyO.js → load-DFS_ry0W.js} +22 -6
  176. package/dist/{load-jose-BL6LH4bL.js → load-jose-DZ4dnjri.js} +1 -4
  177. package/dist/login-Dfe5RlYk.js +68 -0
  178. package/dist/login-imhuwvn3.js +254 -0
  179. package/dist/manifest-C8IzW3Do.js +42 -0
  180. package/dist/manifest-CtKR3GXL.js +370 -0
  181. package/dist/manifest-json-CAGzls-C.js +9 -0
  182. package/dist/{manifest-uDS9y5de.d.ts → manifest-mx5ghSFM.d.ts} +9 -2
  183. package/dist/manifest-schema-C0kK_8V0.js +399 -0
  184. package/dist/{map-claims-AVlBaJoa.js → map-claims-D3oRmTk0.js} +13 -10
  185. package/dist/{map-error-BE27PYkE.js → map-error-TCAdw-eW.js} +3 -3
  186. package/dist/{markers-CiwAOZtO.js → markers-C6joDI3o.js} +2 -1
  187. package/dist/mcp/index.d.ts +22 -12
  188. package/dist/mcp/index.js +57 -39
  189. package/dist/{migrate-BwlB5-Wk.js → migrate-BShP7Vf4.js} +53 -14
  190. package/dist/nest/index.d.ts +12 -9
  191. package/dist/nest/index.js +15 -14
  192. package/dist/next/index.d.ts +18 -21
  193. package/dist/next/index.js +13 -11
  194. package/dist/next/plugin.d.ts +1 -1
  195. package/dist/next/plugin.js +2 -2
  196. package/dist/node/index.d.ts +10 -10
  197. package/dist/node/index.js +7 -9
  198. package/dist/{ocsf-uYFXGVw2.js → ocsf-BFp-PZZA.js} +22 -11
  199. package/dist/openai/index.d.ts +9 -16
  200. package/dist/openai/index.js +17 -24
  201. package/dist/openapi/index.d.ts +3 -3
  202. package/dist/openapi/index.js +1 -1
  203. package/dist/{openapi-DBzHQbov.js → openapi-B7HZ0f-r.js} +8 -8
  204. package/dist/{openapi-BJdBmYDG.js → openapi-DTaEmTSW.js} +10 -9
  205. package/dist/openapi-ahr8rHu3.js +138 -0
  206. package/dist/operation-findings-DgATDpvh.js +36 -0
  207. package/dist/operations-CxybZErY.d.ts +59 -0
  208. package/dist/orpc/index.d.ts +13 -10
  209. package/dist/orpc/index.js +20 -15
  210. package/dist/otel/index.d.ts +3 -2
  211. package/dist/otel/index.js +30 -7
  212. package/dist/output-Dyw8fyPF.js +88 -0
  213. package/dist/output-files-B3IZJksC.js +1 -0
  214. package/dist/{output-files-CgIsvdSa.js → output-files-DhRBBE4n.js} +24 -26
  215. package/dist/{permission-keys-B26jeyUv.js → ownership-BatFgAA4.js} +1698 -869
  216. package/dist/{package-root-DtNnpmUd.js → package-root-Dk_ETdkp.js} +1 -1
  217. package/dist/{parse-CVFQHk6c.js → parse-Cxq0WxrA.js} +2 -2
  218. package/dist/{parse-local-manifest-C-q02Pal.js → parse-local-manifest-CVSs6J9I.js} +1 -1
  219. package/dist/{parse-local-manifest-DvYUR0QL.d.ts → parse-local-manifest-DgqtruPn.d.ts} +1 -1
  220. package/dist/parse-request-D_tUXG6M.js +26 -0
  221. package/dist/paths-DXSHAMIa.js +42 -0
  222. package/dist/pdp/index.d.ts +7 -3
  223. package/dist/pdp/index.js +45 -26
  224. package/dist/{peer-BOr_kJE1.js → peer-C8swJ2GH.js} +23 -4
  225. package/dist/peer-CRvC7Hg1.js +1 -0
  226. package/dist/permdock-B9JxkBwC.js +868 -0
  227. package/dist/permdock-D7eeLJER.d.ts +502 -0
  228. package/dist/{permission-registry-BsblpB-z.js → permission-registry-Br4jSNVi.js} +3 -3
  229. package/dist/permissions-B-wCP5ZC.js +30 -0
  230. package/dist/{permissions-CCJ6lmxB.js → permissions-CZKiUfFM.js} +4 -3
  231. package/dist/{permissions-COH-KRgT.d.ts → permissions-oEWfl-kl.d.ts} +1 -2
  232. package/dist/policies-CO1oOymN.js +295 -0
  233. package/dist/{policy-ur0BBK_e.d.ts → policy-Czo4n3Hs.d.ts} +2 -2
  234. package/dist/{hosted-CBHgkzDl.js → policy-DLZJ5gAp.js} +17 -273
  235. package/dist/policy-from-catalog-DzhEc3Y9.js +450 -0
  236. package/dist/policy-module-CTlwMvLI.js +89 -0
  237. package/dist/{policy-types-sp9P1iIV.d.ts → policy-types-DzwivBgR.d.ts} +434 -631
  238. package/dist/postgrest-CW0IqC-U.js +566 -0
  239. package/dist/postgrest-NUqZT-RB.d.ts +100 -0
  240. package/dist/powersync-BHfuehf3.js +62 -0
  241. package/dist/powersync-CbzkqL_M.js +1 -0
  242. package/dist/{powersync-cZe4kzhL.js → powersync-bYUDLOAO.js} +23 -24
  243. package/dist/preset/index.d.ts +146 -0
  244. package/dist/preset/index.js +1 -0
  245. package/dist/preset-DZdU0tne.js +1768 -0
  246. package/dist/principal-source-pHneukrx.js +103 -0
  247. package/dist/prisma/index.d.ts +6 -3
  248. package/dist/prisma/index.js +2 -2
  249. package/dist/{problem-CnWraVhC.js → problem-CTviyH5L.js} +13 -23
  250. package/dist/{problem-details-rIIo8B2C.d.ts → problem-details-DXlt-vks.d.ts} +1 -1
  251. package/dist/{problem-details-DECUnXAn.js → problem-details-cn5X30gZ.js} +43 -40
  252. package/dist/problem-types-CJ2325SZ.js +5 -0
  253. package/dist/{prompt-CXYhLfsS.js → prompt-DfZLJLIn.js} +2 -2
  254. package/dist/{protected-B3_P7xuw.d.ts → protected-DEPHc2xV.d.ts} +16 -8
  255. package/dist/{protected-BN7BUdY1.js → protected-DfjY5mLA.js} +21 -4
  256. package/dist/{provider-Bi-0HNL3.js → provider-CC-u3bYP.js} +2 -2
  257. package/dist/{provider-kwHC9CZD.d.ts → provider-DMVt6yYn.d.ts} +1 -1
  258. package/dist/{provider-store-Ctt-81Ni.js → provider-store-B5Yrkhzr.js} +2 -2
  259. package/dist/pull-BgIfno6w.js +256 -0
  260. package/dist/pull-ByOks_Tg.js +1 -0
  261. package/dist/push-CmFVBOeI.js +116 -0
  262. package/dist/pushed-policy-BImMTTIM.d.ts +57 -0
  263. package/dist/pushed-policy-DobP7AHI.js +238 -0
  264. package/dist/react/index.d.ts +8 -8
  265. package/dist/react/index.js +6 -6
  266. package/dist/react/provider-client.d.ts +1 -1
  267. package/dist/react/provider-client.js +1 -2
  268. package/dist/react-native/index.d.ts +24 -72
  269. package/dist/react-native/index.js +24 -22
  270. package/dist/{refs-f3imMjNW.js → refs-K6eWUJ0H.js} +1 -1
  271. package/dist/{relation-walk-BXnlLtg2.js → relation-walk-3OyDBF0S.js} +2 -2
  272. package/dist/{relations-CvmSpG67.js → relations-BnCWnJGI.js} +3 -3
  273. package/dist/renames-CGj7YwcQ.js +175 -0
  274. package/dist/{replay-COpmZUfx.d.ts → replay-D7iKcLFe.d.ts} +1 -1
  275. package/dist/{replay-BsOyTrdV.js → replay-Du1tJjG7.js} +2 -1
  276. package/dist/{request-context-BVM7aWNs.js → request-context-BTRTG7OT.js} +3 -3
  277. package/dist/request-schema-CMreVuFM.js +148 -0
  278. package/dist/resend/index.d.ts +126 -0
  279. package/dist/resend/index.js +379 -0
  280. package/dist/{resource-relations-D1Un3pcz.js → resource-relations-D_jw0BFx.js} +1 -1
  281. package/dist/{retire-BFcxL6un.js → retire-CALjIQ7e.js} +2 -2
  282. package/dist/{revocations-Cy06JNx2.d.ts → revocations-R07lFBnX.d.ts} +2 -0
  283. package/dist/rls-BA8an5Ap.js +336 -0
  284. package/dist/{rls-BEktUaqg.js → rls-j6t43t7n.js} +287 -689
  285. package/dist/{role-builder-B4GbKM-i.js → role-builder-CXbis5-X.js} +14 -207
  286. package/dist/{rpc-nYC3cR_u.js → rpc-aPyNi6tA.js} +7 -7
  287. package/dist/run-CNsApDpd.js +1 -0
  288. package/dist/run-DOfMtc9V.js +723 -0
  289. package/dist/run-ticket-BjhTOi6u.d.ts +124 -0
  290. package/dist/run-ticket-sxFI6LAk.js +337 -0
  291. package/dist/{runtime-D_tMXnsq.js → runtime-D3VTAiCA.js} +1 -1
  292. package/dist/{saas-DtaA4JuW.js → saas-FO-Q8oj0.js} +16 -14
  293. package/dist/scan-BOI5tJ-6.js +29 -0
  294. package/dist/{schema-DjQBcAP9.js → schema-B4v0Qrac.js} +102 -8
  295. package/dist/schema-yLuBWWsh.js +130 -0
  296. package/dist/scim/index.d.ts +2 -2
  297. package/dist/scim/index.js +1 -2
  298. package/dist/{scim-vFR1O5oG.js → scim-ClHtpyV3.js} +208 -76
  299. package/dist/{scopes-tvpa34ep.js → scopes-CUPSjo9q.js} +12 -7
  300. package/dist/server/index.d.ts +12 -143
  301. package/dist/server/index.js +12 -9
  302. package/dist/server-DqCT4CgZ.js +453 -0
  303. package/dist/{server-types-DdqBwZN_.d.ts → server-types-BLd4MnBX.d.ts} +51 -68
  304. package/dist/{sha256-BO0swRXL.js → sha256-D9ihqmvd.js} +8 -1
  305. package/dist/{shared-1uhI-e-b.js → shared-CD11nBbC.js} +18 -8
  306. package/dist/{shared-JhMeOsDF.js → shared-DvvFzYXe.js} +8 -9
  307. package/dist/signals-D3NcTKUS.js +32 -0
  308. package/dist/sink-BEZSlMS_.js +957 -0
  309. package/dist/sink-Bj_lDUDq.d.ts +225 -0
  310. package/dist/{skills-BZdRQkxs.js → skills-B6lVdD_W.js} +13 -6
  311. package/dist/skills-CTYwkl44.js +51 -0
  312. package/dist/snapshot-CXUWfsNy.js +269 -0
  313. package/dist/{snapshot-cache-Cod40D-X.js → snapshot-cache-DZHQ0KF6.js} +11 -5
  314. package/dist/{snapshot-cache-J5T7t_vD.d.ts → snapshot-cache-DqK9eDmM.d.ts} +7 -5
  315. package/dist/solid/index.d.ts +11 -12
  316. package/dist/solid/index.js +7 -7
  317. package/dist/solid-start/index.d.ts +52 -0
  318. package/dist/solid-start/index.js +49 -0
  319. package/dist/{sources-Dljy06zL.d.ts → sources-BV9j0DeZ.d.ts} +7 -13
  320. package/dist/{sources-B1-b-R0t.js → sources-vs5dGOsS.js} +125 -119
  321. package/dist/{sql-t8teWOfo.js → sql-B5T1IL83.js} +13 -1
  322. package/dist/src-DLfUWFAI.js +1851 -0
  323. package/dist/ssf/index.d.ts +4 -4
  324. package/dist/ssf/index.js +384 -47
  325. package/dist/standard-webhooks-6lg8v_is.d.ts +88 -0
  326. package/dist/standard-webhooks-DgFFD-Ga.js +228 -0
  327. package/dist/storage-C2bWdvJH.js +132 -0
  328. package/dist/{store-ILkLUj_o.js → store-4u_hxjWa.js} +40 -53
  329. package/dist/{store-options-CbUHDoSe.js → store-options-BqEakYRa.js} +26 -21
  330. package/dist/{stores-BHXdSbw9.js → stores-BbsD4fAR.js} +2 -2
  331. package/dist/{stores-Cxz_80g-.d.ts → stores-ClZUgeoP.d.ts} +7 -8
  332. package/dist/{stream-Dwsg6WwE.d.ts → stream-7-xmnf3U.d.ts} +2 -2
  333. package/dist/{stream-BMui98KK.js → stream-CvdUS9V1.js} +9 -2
  334. package/dist/style-DiKWnAvn.js +1 -0
  335. package/dist/{style-CTm1AXDT.js → style-Uao76wO7.js} +3 -2
  336. package/dist/subject-BGoM5o8B.js +17 -0
  337. package/dist/supabase/index.d.ts +23 -106
  338. package/dist/supabase/index.js +5 -4
  339. package/dist/supabase/middleware.d.ts +7 -6
  340. package/dist/supabase/middleware.js +13 -11
  341. package/dist/supabase-9pqI57pW.js +92 -0
  342. package/dist/{supabase-C1TWlnYt.js → supabase-Dxlp8A94.js} +98 -205
  343. package/dist/supabase-hook-CXcGpHqq.js +1 -0
  344. package/dist/{supabase-hook-Cva3ikXz.js → supabase-hook-DdDQhMlw.js} +951 -60
  345. package/dist/support-session-C6xJQYut.js +158 -0
  346. package/dist/svelte/Protected.svelte +4 -4
  347. package/dist/svelte/index.d.ts +7 -7
  348. package/dist/svelte/index.js +10 -10
  349. package/dist/svelte/runtime.d.ts +3 -3
  350. package/dist/svelte/runtime.js +3 -3
  351. package/dist/svelte/source.d.ts +7 -7
  352. package/dist/svelte/source.js +4 -4
  353. package/dist/sveltekit/index.d.ts +51 -0
  354. package/dist/sveltekit/index.js +27 -0
  355. package/dist/tanstack-start/index.d.ts +51 -0
  356. package/dist/tanstack-start/index.js +40 -0
  357. package/dist/target-Bw37TFNA.js +51 -0
  358. package/dist/{tenancy-DshjqY0n.js → tenancy-DN2QAx9z.js} +5 -5
  359. package/dist/terminal/index.d.ts +11 -9
  360. package/dist/terminal/index.js +23 -287
  361. package/dist/testing/index.d.ts +311 -38
  362. package/dist/testing/index.js +3475 -201
  363. package/dist/testing/saas/index.d.ts +9 -8
  364. package/dist/testing/saas/index.js +2 -2
  365. package/dist/testing/saas/permissions.d.ts +1 -1
  366. package/dist/testing/saas/permissions.js +1 -2
  367. package/dist/text-BMFRfBqc.js +8 -0
  368. package/dist/{text-diff-BdkkYSbi.js → text-diff-BQcUapOb.js} +1 -1
  369. package/dist/thenable-yD7SabqG.js +31 -0
  370. package/dist/time-DkWjdL98.js +71 -0
  371. package/dist/{token-Bx9qy30p.js → token-BLZcjQgt.js} +15 -6
  372. package/dist/{tool-refusal-CQ7OEia9.js → tool-refusal-CMLN5xhn.js} +2 -2
  373. package/dist/trpc/index.d.ts +12 -9
  374. package/dist/trpc/index.js +16 -14
  375. package/dist/{types-7rJVLWe5.d.ts → types-5Ut_pbKy.d.ts} +61 -11
  376. package/dist/{store-9KO4BlkB.d.ts → types-BNORmDM8.d.ts} +100 -75
  377. package/dist/types-BjV-fqcA.d.ts +57 -0
  378. package/dist/{types-CUcFZfpU.d.ts → types-BqAKcRNW.d.ts} +2 -1
  379. package/dist/types-C8-KNsFf.d.ts +107 -0
  380. package/dist/{types-Br9IXUBG.d.ts → types-CCpc2Dcv.d.ts} +77 -17
  381. package/dist/{types-DpWfQdSh.d.ts → types-CZTnPFzM.d.ts} +46 -11
  382. package/dist/{types-CqrjB9o6.d.ts → types-CdlxsYQh.d.ts} +23 -11
  383. package/dist/{types-CIlTojhq.d.ts → types-ClZaWzfb.d.ts} +9 -6
  384. package/dist/types-DX0LaKTb.d.ts +157 -0
  385. package/dist/types-DiQjupG2.d.ts +332 -0
  386. package/dist/types-DqzsnlSA.js +67 -0
  387. package/dist/types-_sHy8BQf.d.ts +65 -0
  388. package/dist/{types-ByUo56un.d.ts → types-fbZ7JEXr.d.ts} +23 -22
  389. package/dist/{types-DHrmBJLH.d.ts → types-tIgIeIKJ.d.ts} +7 -7
  390. package/dist/unplugin/index.d.ts +1 -1
  391. package/dist/unplugin/index.js +2 -2
  392. package/dist/usage-CHOtwL19.js +1 -0
  393. package/dist/usage-DHtE8j4E.js +32 -0
  394. package/dist/{usage-CG9nOYZw.js → usage-T5mXq98v.js} +54 -11
  395. package/dist/{validation-error-BSSw0l_8.d.ts → validation-error-Bg5Tpluk.d.ts} +1 -1
  396. package/dist/{validity-dVrUEPJt.js → validity-CZ7-y0Cj.js} +32 -15
  397. package/dist/{verifier-DMr_Zmb_.js → verifier-DHuh-okk.js} +18 -7
  398. package/dist/{verify-BztUB3GX.js → verify-DbCL9bnB.js} +645 -50
  399. package/dist/{version-BEogC-rB.js → version-CEbQ5UeM.js} +4 -3
  400. package/dist/version-DXkYUISx.js +1 -0
  401. package/dist/{views-CJsrBS1f.js → views-DTIIO-oQ.js} +22 -5
  402. package/dist/{permission-types-Dg39z9Kv.d.ts → vocabulary-D6lPdb4Z.d.ts} +65 -2
  403. package/dist/vue/index.d.ts +9 -10
  404. package/dist/vue/index.js +8 -8
  405. package/dist/waiter-BGUtGYoU.js +67 -0
  406. package/dist/waiter-CKy4MQSY.d.ts +36 -0
  407. package/dist/watch-Cb-NcaUw.js +1 -0
  408. package/dist/{watch-zeucB7eF.js → watch-CszoTJMq.js} +44 -5
  409. package/dist/webmcp/index.d.ts +2 -2
  410. package/dist/webmcp/index.js +3 -3
  411. package/dist/where-scope-Dv-WTP-w.js +306 -0
  412. package/dist/who-can-D0QoYbEb.js +364 -0
  413. package/dist/wire-delegation-Cv3W2eaM.js +36 -0
  414. package/dist/wire-denial-C7PaVYEM.js +27 -0
  415. package/dist/workflow/index.d.ts +5 -0
  416. package/dist/workflow/index.js +223 -0
  417. package/dist/workflow-sdk/index.d.ts +56 -0
  418. package/dist/workflow-sdk/index.js +78 -0
  419. package/dist/{wrap-Cr93qqdP.d.ts → wrap-Bd1Tejur.d.ts} +2 -1
  420. package/dist/{wrap-DWsU_5Bd.js → wrap-gX61EtpB.js} +7 -6
  421. package/package.json +136 -37
  422. package/schemas/access-event-v1.json +118 -0
  423. package/schemas/approval-request-v1.json +34 -1
  424. package/schemas/approval-signature-v1.json +94 -0
  425. package/schemas/automation-event-v1.json +113 -0
  426. package/schemas/capability-v1.json +84 -0
  427. package/schemas/catalog-event-v1.json +87 -0
  428. package/schemas/catalog-v1.json +123 -12
  429. package/schemas/cli-commands-v1.json +164 -0
  430. package/schemas/cli-result-v1.json +96 -0
  431. package/schemas/cloud-api-v1.json +5407 -0
  432. package/schemas/connector-v1.json +408 -0
  433. package/schemas/credential-event-v1.json +81 -0
  434. package/schemas/credential-v1.json +134 -0
  435. package/schemas/decision-event-v1.json +288 -0
  436. package/schemas/delivery-event-v1.json +117 -0
  437. package/schemas/directory-event-v1.json +85 -0
  438. package/schemas/evidence-export-v1.json +54 -0
  439. package/schemas/membership-event-v1.json +93 -0
  440. package/schemas/policy-v1.json +68 -0
  441. package/schemas/pushed-policy-v1.json +236 -0
  442. package/schemas/run-v1.json +162 -0
  443. package/schemas/snapshot-v1.json +138 -0
  444. package/schemas/supabase-claims-v1.json +4 -4
  445. package/schemas/supabase-manifest-v1.json +5 -1
  446. package/schemas/support-session-v1.json +111 -0
  447. package/skills/permdock/SKILL.md +16 -12
  448. package/skills/permdock-agents/SKILL.md +40 -23
  449. package/skills/permdock-agents/references/operations-automations-chat.md +221 -0
  450. package/skills/permdock-agents/references/runtimes.md +22 -18
  451. package/skills/permdock-approvals/SKILL.md +29 -13
  452. package/skills/permdock-approvals/references/delivery-and-waiters.md +172 -0
  453. package/skills/permdock-approvals/references/stores-and-resume.md +21 -7
  454. package/skills/permdock-audit/SKILL.md +3 -3
  455. package/skills/permdock-credentials/SKILL.md +5 -5
  456. package/skills/permdock-credentials/references/tokens-keys-links.md +14 -10
  457. package/skills/permdock-data/SKILL.md +6 -6
  458. package/skills/permdock-data/references/queries-and-rls.md +9 -8
  459. package/skills/permdock-data/references/relationships.md +3 -3
  460. package/skills/permdock-tenancy/SKILL.md +20 -7
  461. package/skills/permdock-tenancy/references/contacts-and-support-sessions.md +122 -0
  462. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +5 -4
  463. package/skills/permdock-wire/SKILL.md +17 -11
  464. package/skills/permdock-wire/references/adapters.md +139 -51
  465. package/skills/permdock-wire/references/policy-options.md +5 -5
  466. package/skills/permdock-wire/references/presets-and-recipes.md +58 -0
  467. package/dist/approvals-DZL76lKW.js +0 -240
  468. package/dist/arazzo-CD8d0WLb.js +0 -54
  469. package/dist/catalog-6yWAX6Ps.js +0 -2
  470. package/dist/catalog-WHG4kBq7.js +0 -48
  471. package/dist/cloud-C7bSDgX4.js +0 -50
  472. package/dist/cloud-PeBN3IEn.js +0 -118
  473. package/dist/collect-Bw2Jdq1q.js +0 -2
  474. package/dist/collect-CQx4hX4N.js +0 -83
  475. package/dist/commands-Cpip4ULx.js +0 -97
  476. package/dist/config-DLt6BvV7.js +0 -36
  477. package/dist/diff-Cnghh_Ip.js +0 -48
  478. package/dist/doctor-CuVJvhV_.js +0 -53
  479. package/dist/duration-xK2jGFVc.js +0 -25
  480. package/dist/errors-CWfoNg9N.js +0 -47
  481. package/dist/errors-DRnGZHzF.js +0 -30
  482. package/dist/expiry-BoBJ8Tvc.js +0 -7
  483. package/dist/fields-fwfXN01n.js +0 -1016
  484. package/dist/headers-BZSDieNT.js +0 -6
  485. package/dist/headers-Cf-zWvsO.d.ts +0 -6
  486. package/dist/ids-DC4V4CFu.js +0 -18
  487. package/dist/index-DgM7w96K.d.ts +0 -6
  488. package/dist/index-Dz7didpC.d.ts +0 -201
  489. package/dist/load-B_shHrmd.js +0 -2
  490. package/dist/manifest-BngWKryL.js +0 -770
  491. package/dist/may-use-BOn_dR_w.js +0 -78
  492. package/dist/openapi-DcQ1Kg40.js +0 -164
  493. package/dist/ownership-BgnbOJFT.js +0 -851
  494. package/dist/permdock-L26udHSk.js +0 -3646
  495. package/dist/powersync-BFSbSElQ.js +0 -62
  496. package/dist/powersync-DCDgZgfZ.js +0 -2
  497. package/dist/rls-55DQTuf5.js +0 -250
  498. package/dist/run-DMcNW_8T.js +0 -174
  499. package/dist/server-ZYEHtNHS.js +0 -268
  500. package/dist/sink-BTtmfPnE.js +0 -141
  501. package/dist/sink-CPN4zLfs.d.ts +0 -104
  502. package/dist/skills-Dle4ZoLF.js +0 -56
  503. package/dist/snapshot-Dc9CHPME.js +0 -1078
  504. package/dist/src-Bb7no-hS.js +0 -639
  505. package/dist/subject-C6dLxqHU.js +0 -24
  506. package/dist/supabase-Dbqr141s.js +0 -83
  507. package/dist/supabase-hook-BULg7Ut_.js +0 -2
  508. package/dist/thenable-QSmvt-vZ.js +0 -65
  509. package/dist/types-C0dee0Qf.d.ts +0 -197
  510. package/dist/types-DvupZE0w.d.ts +0 -9
  511. package/dist/usage-4G6t643F.js +0 -42
  512. package/dist/usage-iFLJ0-rr.js +0 -2
  513. package/dist/vocabulary-hhEFLFoL.d.ts +0 -65
  514. package/dist/watch-C8TpsAl4.js +0 -2
@@ -1,851 +0,0 @@
1
- import { l as scopeChain, o as resolveScope } from "./scopes-tvpa34ep.js";
2
- import { m as findRole } from "./grantee-CXY-0C87.js";
3
- import { r as qualifySqlTable } from "./sql-t8teWOfo.js";
4
- import { l as roleColumn } from "./sources-B1-b-R0t.js";
5
- import { A as declaredArray, F as quoteQualified, M as qualified, N as quoteIdent, O as tenantTypeOf, P as quoteLiteral, f as kindFilterSql, h as roleKindSql, m as memberVia, s as signedIn, t as CUSTOM_ROLES, u as globalKindFilterSql, y as subjectIdSql } from "./shared-1uhI-e-b.js";
6
- import { G as scopeSources, K as scopeTable, R as memberForSources, V as memberRoleOf, d as memberColumn, f as sourceFilters, g as roleRows, h as membershipRows, l as claimKeptLines, m as globalRoleRows, p as sourcesKeep, u as disabledColumn, y as hasCustomRoleChecksFor, z as memberForTable } from "./permission-keys-B26jeyUv.js";
7
- //#region src/cli/rls/ownership-names.ts
8
- /** Objects the ownership rules add next to the helpers. Names are part of the SQL contract. */
9
- const OWNERSHIP = {
10
- canAssign: "permdock_can_assign",
11
- canAssignFor: "permdock_can_assign_for",
12
- canAssignAny: "permdock_can_assign_any",
13
- canAssignAnyFor: "permdock_can_assign_any_for",
14
- holders: "permdock_holders",
15
- transferOnly: "permdock_transfer_only"
16
- };
17
- /** Objects `rls.assignments` adds. Names are part of the SQL contract. */
18
- const ASSIGNMENTS = {
19
- custom: "permdock_can_assign_custom_role",
20
- customFor: "permdock_can_assign_custom_role_for",
21
- trigger: "permdock_assignment"
22
- };
23
- //#endregion
24
- //#region src/cli/rls/assignments.ts
25
- /** The client roles whose writes the assignment triggers check; any other role is a trusted path. */
26
- const CLIENT_ROLES = [
27
- "anon",
28
- "anonymous",
29
- "authenticated"
30
- ];
31
- /** The mapped membership tables, `rls.assignments.tables` and the global-roles table `rls.roles`. */
32
- function assignedTables(ctx) {
33
- const out = [];
34
- for (const { name } of ctx.scopes) {
35
- const mapped = scopeTable(ctx, name);
36
- if (mapped === void 0) continue;
37
- out.push({
38
- table: mapped.table.table,
39
- scope: name,
40
- id: mapped.column,
41
- tenant: mapped.tenantColumn ?? mapped.column,
42
- role: mapped.table.role,
43
- user: mapped.table.user
44
- });
45
- }
46
- if (ctx.roles !== void 0) out.push({
47
- table: ctx.roles.table,
48
- scope: "global",
49
- role: ctx.roles.role ?? "role",
50
- user: ctx.roles.user ?? "user_id"
51
- });
52
- for (const extra of ctx.assignments?.tables ?? []) {
53
- const scope = resolveScope(ctx.scopes, extra.scope);
54
- if (scope === void 0) throw new Error(`PermDock CLI: rls.assignments.tables names scope '${extra.scope}', which the policy does not declare`);
55
- if (scope !== ctx.scopes[0]?.name && extra.tenant === void 0) throw new Error(`PermDock CLI: rls.assignments.tables entry ${extra.table} assigns at ${scope}, below the first scope: name its tenant column`);
56
- out.push({
57
- table: extra.table,
58
- scope,
59
- id: extra.id,
60
- tenant: extra.tenant ?? extra.id,
61
- role: extra.role,
62
- ...extra.user === void 0 ? {} : { user: extra.user }
63
- });
64
- }
65
- return out;
66
- }
67
- /** The tables `rls.assignments.ownRole` refuses a caller's own rows on, by table key. */
68
- function ownRoleTables(ctx, tables) {
69
- const own = ctx.assignments?.ownRole;
70
- if (own === void 0) return /* @__PURE__ */ new Set();
71
- if (own === "refuse") return new Set(tables.filter((entry) => entry.user !== void 0).map((entry) => qualifySqlTable(entry.table)));
72
- const out = /* @__PURE__ */ new Set();
73
- for (const [name, value] of Object.entries(own)) {
74
- const entry = tables.find((table) => qualifySqlTable(table.table) === qualifySqlTable(name));
75
- if (entry === void 0) throw new Error(`PermDock CLI: rls.assignments.ownRole names ${name}, which no assignment trigger guards`);
76
- if (value !== "refuse") throw new Error(`PermDock CLI: rls.assignments.ownRole.${name} must be 'refuse'`);
77
- if (entry.user === void 0) throw new Error(`PermDock CLI: rls.assignments.ownRole names ${name}, which has no user column: set its user in rls.assignments.tables`);
78
- out.add(qualifySqlTable(entry.table));
79
- }
80
- return out;
81
- }
82
- /**
83
- * The tables `rls.assignments` guards, schema-qualified: each scope's mapped
84
- * membership table, the global-roles table (`rls.roles`, else
85
- * `supabase.hook.roles`) and `rls.assignments.tables`. Empty without
86
- * `rls.assignments`.
87
- */
88
- function guardedTables(config, scopes) {
89
- const rls = config.rls;
90
- if (rls?.assignments === void 0) return [];
91
- const hook = config.supabase?.hook?.roles;
92
- const roles = rls.roles ?? (hook === false ? void 0 : hook);
93
- const tables = [
94
- ...scopes.flatMap((scope) => {
95
- const mapped = memberForTable({
96
- scopes,
97
- ...rls.memberships === void 0 ? {} : { memberships: rls.memberships }
98
- }, scope.name);
99
- return mapped === void 0 ? [] : [mapped.table];
100
- }),
101
- ...roles === void 0 ? [] : [roles.table],
102
- ...(rls.assignments === true ? [] : rls.assignments.tables ?? []).map((entry) => entry.table)
103
- ];
104
- return [...new Set(tables.map(qualifySqlTable))];
105
- }
106
- function isRoleList(role) {
107
- return Array.isArray(role);
108
- }
109
- /** The role keys a row variable holds, one scalar per role source. */
110
- function rowRoles(entry, row) {
111
- return (isRoleList(entry.role) ? entry.role : [entry.role]).map((part) => roleColumn(part, qualifySqlTable(entry.table), row, {
112
- label: `rls.assignments ${entry.table} role`,
113
- prefix: "PermDock CLI"
114
- }).lookup);
115
- }
116
- /**
117
- * `permdock_can_assign_custom_role`: whether the signed-in caller may assign a
118
- * custom role of the tenant at the instance, by the checks the custom-role
119
- * write functions run on its stored definition.
120
- */
121
- function canAssignCustomSql(ctx, forUser = false) {
122
- const tenantType = tenantTypeOf(ctx);
123
- const fn = qualified(ctx, forUser ? ASSIGNMENTS.customFor : ASSIGNMENTS.custom);
124
- const perms = qualified(ctx, CUSTOM_ROLES.permissions);
125
- const includes = qualified(ctx, CUSTOM_ROLES.includes);
126
- const guard = qualified(ctx, forUser ? CUSTOM_ROLES.guardFor : CUSTOM_ROLES.guard);
127
- const userParam = forUser ? "p_user uuid, " : "";
128
- const userArg = forUser ? "uuid, " : "";
129
- const stored = `c.tenant_id is not distinct from p_tenant and c.scope = p_scope and c.role = p_role and (c.scope_id is null or c.scope_id = p_scope_id)`;
130
- const grants = forUser ? `revoke execute on function ${fn}(${userArg}${tenantType}, text, text, text) from public, anon, authenticated;` : `revoke execute on function ${fn}(${tenantType}, text, text, text) from public, anon;
131
- grant execute on function ${fn}(${tenantType}, text, text, text) to authenticated;`;
132
- return `-- whether ${forUser ? "user p_user" : "the caller"} may assign custom role p_role at instance p_scope_id (a platform role: null tenant, scope global): the custom-role write checks on its stored definition${forUser ? "; no client role may execute it" : ""}
133
- create or replace function ${fn}(${userParam}p_tenant ${tenantType}, p_scope text, p_scope_id text, p_role text)
134
- returns boolean
135
- language plpgsql
136
- stable
137
- security definer
138
- set search_path = ''
139
- as $$
140
- declare
141
- v_scope_id text;
142
- v_found boolean := false;
143
- begin
144
- select true, c.scope_id into v_found, v_scope_id
145
- from (
146
- select c.scope_id from ${perms} c where ${stored}
147
- union all
148
- select c.scope_id from ${includes} c where ${stored}
149
- ) c
150
- order by c.scope_id nulls first
151
- limit 1;
152
- if not coalesce(v_found, false) then
153
- return false;
154
- end if;
155
- perform ${guard}(${forUser ? "p_user, " : ""}p_tenant, p_scope, v_scope_id, p_role);
156
- return true;
157
- exception
158
- when insufficient_privilege or invalid_parameter_value then
159
- return false;
160
- end;
161
- $$;
162
- ${grants}`;
163
- }
164
- /**
165
- * The assignment triggers (\`rls.assignments\`): before a client role inserts,
166
- * updates or deletes a row that assigns a role, every role the old and new
167
- * row hold must be one the caller may assign at that instance, by
168
- * \`permdock_can_assign\` for a declared role and
169
- * \`permdock_can_assign_custom_role\` for a custom one. The functions run as
170
- * the invoker, so \`current_user\` tells a client write from a trusted one.
171
- */
172
- function assignmentSql(ctx) {
173
- const own = ctx.ownership;
174
- if (ctx.assignments === void 0 || own === void 0 || own.assigns.length === 0) return "";
175
- const canAssign = qualified(ctx, OWNERSHIP.canAssign);
176
- const custom = ctx.customRoles !== void 0 && ctx.authorize === "database";
177
- const declared = ctx.customRoles?.declared;
178
- const tenantType = tenantTypeOf(ctx);
179
- const chunks = [];
180
- const clients = `current_user::text = any(array[${CLIENT_ROLES.map(quoteLiteral).join(", ")}])`;
181
- const tables = assignedTables(ctx);
182
- const ownRole = ownRoleTables(ctx, tables);
183
- for (const entry of tables) {
184
- const table = quoteQualified(entry.table);
185
- const suffix = entry.table.replaceAll(/[^a-z0-9_]/gu, "_");
186
- const fn = qualified(ctx, quoteIdent(`${ASSIGNMENTS.trigger}_${suffix}`));
187
- const ownUser = entry.user !== void 0 && ownRole.has(qualifySqlTable(entry.table)) ? entry.user : void 0;
188
- const ownCheck = (row, reason) => ownUser === void 0 ? "" : ` if ${row}.${quoteIdent(ownUser)}::text = (${subjectIdSql(ctx)})::text then
189
- raise exception using
190
- errcode = '42501',
191
- message = 'permdock: the caller may not change their own roles',
192
- hint = '${reason}';
193
- end if;
194
- `;
195
- const check = (row) => {
196
- const id = entry.id === void 0 ? "null::text" : `${row}.${quoteIdent(entry.id)}::text`;
197
- const customFn = qualified(ctx, ASSIGNMENTS.custom);
198
- let allowed = `${canAssign}(v_role, ${id})`;
199
- if (custom && declared !== void 0) {
200
- const platform = `${customFn}(null, 'global', null, v_role)`;
201
- allowed = entry.id === void 0 || entry.tenant === void 0 ? `case when v_role = any(${declaredArray(declared)}) then ${canAssign}(v_role, ${id}) else ${platform} end` : `case when v_role = any(${declaredArray(declared)}) then ${canAssign}(v_role, ${id}) when ${id} is null then ${platform} else ${customFn}(${row}.${quoteIdent(entry.tenant)}::${tenantType}, ${quoteLiteral(entry.scope)}, ${id}, v_role) end`;
202
- }
203
- return ` foreach v_role in array array[${rowRoles(entry, row).join(", ")}]::text[] loop
204
- if v_role is not null and not coalesce(${allowed}, false) then
205
- raise exception using
206
- errcode = '42501',
207
- message = 'permdock: the caller may not assign ' || v_role || ' in ' || coalesce(${id}, 'null'),
208
- hint = 'not-assignable-by';
209
- end if;
210
- end loop;`;
211
- };
212
- const what = entry.id === void 0 ? "global roles" : `${entry.scope} roles`;
213
- chunks.push(`-- ${entry.table}: a client role may write only the ${what} it may assign${ownUser === void 0 ? "" : ", and none on its own rows"}
214
- create or replace function ${fn}()
215
- returns trigger
216
- language plpgsql
217
- volatile
218
- set search_path = ''
219
- as $$
220
- declare
221
- v_role text;
222
- begin
223
- if not (${clients}) then
224
- return coalesce(new, old);
225
- end if;
226
- if tg_op in ('UPDATE', 'DELETE') then
227
- ${ownCheck("old", "self-demotion")}${check("old")}
228
- end if;
229
- if tg_op in ('INSERT', 'UPDATE') then
230
- ${ownCheck("new", "not-assignable-by")}${check("new")}
231
- end if;
232
- return coalesce(new, old);
233
- end;
234
- $$;
235
- revoke execute on function ${fn}() from public, anon, authenticated;
236
- drop trigger if exists "permdock_assignment" on ${table};
237
- create trigger "permdock_assignment"
238
- before insert or update or delete on ${table}
239
- for each row execute function ${fn}();`);
240
- }
241
- return `${chunks.join("\n\n")}\n`;
242
- }
243
- //#endregion
244
- //#region src/cli/rls/ownership-triggers.ts
245
- function objectName(prefix, scope) {
246
- return quoteIdent(`${prefix}_${scope}`);
247
- }
248
- /** Live holders of `roleExpr` in instance `idExpr`, with the same kind and expiry rules as the helpers. */
249
- function holdersSql(ctx, table, column, idExpr, role, into) {
250
- const roleExpr = typeof role === "string" ? quoteLiteral(role) : role.expr;
251
- const held = memberRoleOf(table, "m", " ");
252
- const filters = [`m.${quoteIdent(column)} = ${idExpr}`, `${held.sql} = ${roleExpr}`];
253
- if (table.expiresAt !== void 0) {
254
- const expires = memberColumn(table.expiresAt);
255
- filters.push(`(${expires} is null or ${expires} > now())`);
256
- }
257
- const disabled = disabledColumn(table);
258
- if (disabled !== void 0) filters.push(`${disabled} is null`);
259
- const via = memberVia(table);
260
- const kind = typeof role === "string" ? roleKindSql(ctx, role, via) : kindFilterSql(ctx, roleExpr, via);
261
- if (kind !== void 0) filters.push(kind);
262
- return `select count(distinct m.${quoteIdent(table.user)}) into ${into}
263
- from ${quoteQualified(table.table)} m${held.join}
264
- where ${filters.join("\n and ")}`;
265
- }
266
- /**
267
- * `min` and `max` as a deferred constraint trigger: checked at commit, so a
268
- * transfer (demote one holder, promote another) passes in one transaction. An
269
- * instance with no memberships left is being torn down and skips `min`.
270
- */
271
- function holdersTriggerSql(ctx, scope, table, column, counted) {
272
- const fn = qualified(ctx, `${OWNERSHIP.holders}_${scope}`);
273
- const col = quoteIdent(column);
274
- const checks = counted.map((rule) => {
275
- const lines = [` select count(*) into v_total from ${quoteQualified(table.table)} m where m.${col} = v_key;`, ` ${holdersSql(ctx, table, column, "v_key", rule.role, "v_count")};`];
276
- if (rule.min > 0) lines.push(` if v_total > 0 and v_count < ${String(rule.min)} then
277
- raise exception using
278
- errcode = '23514',
279
- message = ${quoteLiteral(`permdock: ${scope} `)} || v_id || ${quoteLiteral(` keeps at least ${String(rule.min)} ${rule.role}`)},
280
- hint = 'last-holder';
281
- end if;`);
282
- if (rule.max !== void 0) lines.push(` if v_count > ${String(rule.max)} then
283
- raise exception using
284
- errcode = '23514',
285
- message = ${quoteLiteral(`permdock: ${scope} `)} || v_id || ${quoteLiteral(` has at most ${String(rule.max)} ${rule.role}`)},
286
- hint = 'max-holders';
287
- end if;`);
288
- return lines.join("\n");
289
- });
290
- return `-- ${scope}: holder counts (min / max), checked at commit
291
- create or replace function ${fn}()
292
- returns trigger
293
- language plpgsql
294
- security definer
295
- set search_path = ''
296
- as $$
297
- declare
298
- v_ids text[] := '{}';
299
- v_id text;
300
- v_key ${quoteQualified(table.table)}.${col}%type;
301
- v_total bigint;
302
- v_count bigint;
303
- begin
304
- if tg_op in ('UPDATE', 'DELETE') then
305
- v_ids := v_ids || old.${col}::text;
306
- end if;
307
- if tg_op in ('INSERT', 'UPDATE') then
308
- v_ids := v_ids || new.${col}::text;
309
- end if;
310
- foreach v_id in array v_ids loop
311
- continue when v_id is null;
312
- v_key := v_id;
313
- ${checks.join("\n")}
314
- end loop;
315
- return null;
316
- end;
317
- $$;
318
- drop trigger if exists ${objectName(OWNERSHIP.holders, scope)} on ${quoteQualified(table.table)};
319
- create constraint trigger ${objectName(OWNERSHIP.holders, scope)}
320
- after insert or update or delete on ${quoteQualified(table.table)}
321
- deferrable initially deferred
322
- for each row execute function ${fn}();`;
323
- }
324
- /**
325
- * `transferOnly` as statement triggers over transition tables: a statement
326
- * that changes a role's holder count in an instance that had holders before
327
- * and still has some after is refused. Creating the first holder and removing
328
- * the last (which `min` guards) are not transfers.
329
- */
330
- function transferTriggerSql(ctx, scope, table, column, roles) {
331
- const fn = qualified(ctx, `${OWNERSHIP.transferOnly}_${scope}`);
332
- const col = quoteIdent(column);
333
- const list = `array[${roles.map(quoteLiteral).join(", ")}]::text[]`;
334
- const rows = (alias, source, delta) => {
335
- const role = memberRoleOf(table, alias);
336
- return `select ${alias}.${col} as id, ${role.sql} as role, ${delta} as delta from ${source} ${alias}${role.join} where ${role.sql} = any(${list})`;
337
- };
338
- const loop = (source) => ` for v_change in
339
- select c.id, c.role, sum(c.delta) as delta
340
- from (${source}) c
341
- group by c.id, c.role
342
- loop
343
- continue when v_change.delta = 0 or v_change.id is null;
344
- ${holdersSql(ctx, table, column, "v_change.id", { expr: "v_change.role" }, "v_after")};
345
- if v_after > 0 and v_after - v_change.delta > 0 then
346
- raise exception using
347
- errcode = '23514',
348
- message = 'permdock: ' || v_change.role || ${quoteLiteral(` in ${scope} `)} || v_change.id || ' moves only by transfer',
349
- hint = 'transfer-only';
350
- end if;
351
- end loop;`;
352
- const inserted = rows("n", "permdock_new", "1");
353
- const deleted = rows("o", "permdock_old", "-1");
354
- const target = quoteQualified(table.table);
355
- const trigger = (op) => {
356
- const name = quoteIdent(`${OWNERSHIP.transferOnly}_${scope}_${op}`);
357
- return `drop trigger if exists ${name} on ${target};
358
- create trigger ${name}
359
- after ${op} on ${target}
360
- referencing ${op === "insert" ? "new table as permdock_new" : op === "delete" ? "old table as permdock_old" : "old table as permdock_old new table as permdock_new"}
361
- for each statement execute function ${fn}();`;
362
- };
363
- return `-- ${scope}: transfer-only roles (${roles.join(", ")}) keep their holder count per statement
364
- create or replace function ${fn}()
365
- returns trigger
366
- language plpgsql
367
- security definer
368
- set search_path = ''
369
- as $$
370
- declare
371
- v_change record;
372
- v_after bigint;
373
- begin
374
- if tg_op = 'INSERT' then
375
- ${loop(inserted)}
376
- elsif tg_op = 'DELETE' then
377
- ${loop(deleted)}
378
- else
379
- ${loop(`${inserted} union all ${deleted}`)}
380
- end if;
381
- return null;
382
- end;
383
- $$;
384
- ${trigger("insert")}
385
- ${trigger("update")}
386
- ${trigger("delete")}`;
387
- }
388
- //#endregion
389
- //#region src/cli/rls/ownership-sources.ts
390
- /**
391
- * The membership sources holding scope `name`: `undefined` when there are
392
- * none, `'not-tables'` when one of them carries no table to put a trigger on.
393
- */
394
- function holderSources(ctx, name) {
395
- const sources = memberForSources(ctx, name);
396
- if (sources.length === 0) return;
397
- const held = [];
398
- for (const source of sources) {
399
- if (source.sql.holders === void 0) return "not-tables";
400
- held.push({
401
- table: source.sql.table,
402
- holders: source.sql.holders
403
- });
404
- }
405
- return held;
406
- }
407
- function indent(sql, by) {
408
- return sql.replaceAll(/^/gmu, by);
409
- }
410
- /** Every source's rows of one instance, each compared with its own typed `v_key_<n>`. */
411
- function sourceRowsOf(scope, sources) {
412
- return sources.map((source, index) => indent(source.holders.rows(scope, { id: `v_key_${String(index)}` }), " ")).join("\n union all\n");
413
- }
414
- function sourceKeys(sources) {
415
- return {
416
- declare: sources.map((source, index) => ` v_key_${String(index)} ${source.holders.idType};`).join("\n"),
417
- assign: (value, by) => sources.map((_, index) => `${by}v_key_${String(index)} := ${value};`).join("\n")
418
- };
419
- }
420
- function regclassOf(table) {
421
- return `${quoteLiteral(quoteQualified(table))}::regclass`;
422
- }
423
- function sourceTables(sources) {
424
- return [...new Set(sources.map((source) => quoteQualified(source.table)))];
425
- }
426
- /** `min` and `max` over membership sources: the same commit-time check as on a mapped table, counted over every source of the scope. */
427
- function sourceHoldersTriggerSql(ctx, scope, sources, counted) {
428
- const fn = qualified(ctx, `${OWNERSHIP.holders}_${scope}`);
429
- const keys = sourceKeys(sources);
430
- const rows = sourceRowsOf(scope, sources);
431
- const collect = sources.map((source) => ` if tg_relid = ${regclassOf(source.table)} then
432
- if tg_op in ('UPDATE', 'DELETE') then
433
- v_ids := v_ids || ${source.holders.id(scope, "old")};
434
- end if;
435
- if tg_op in ('INSERT', 'UPDATE') then
436
- v_ids := v_ids || ${source.holders.id(scope, "new")};
437
- end if;
438
- end if;`);
439
- const checks = counted.map((rule) => {
440
- const filters = ["h.live", `h.role = ${quoteLiteral(rule.role)}`];
441
- const kind = roleKindSql(ctx, rule.role, "h.via");
442
- if (kind !== void 0) filters.push(kind);
443
- const lines = [` select count(distinct h.user_id) into v_count
444
- from (
445
- ${rows}
446
- ) h
447
- where ${filters.join("\n and ")};`];
448
- if (rule.min > 0) lines.push(` if v_total > 0 and v_count < ${String(rule.min)} then
449
- raise exception using
450
- errcode = '23514',
451
- message = ${quoteLiteral(`permdock: ${scope} `)} || v_id || ${quoteLiteral(` keeps at least ${String(rule.min)} ${rule.role}`)},
452
- hint = 'last-holder';
453
- end if;`);
454
- if (rule.max !== void 0) lines.push(` if v_count > ${String(rule.max)} then
455
- raise exception using
456
- errcode = '23514',
457
- message = ${quoteLiteral(`permdock: ${scope} `)} || v_id || ${quoteLiteral(` has at most ${String(rule.max)} ${rule.role}`)},
458
- hint = 'max-holders';
459
- end if;`);
460
- return lines.join("\n");
461
- });
462
- const triggers = sourceTables(sources).map((table) => `drop trigger if exists ${objectName(OWNERSHIP.holders, scope)} on ${table};
463
- create constraint trigger ${objectName(OWNERSHIP.holders, scope)}
464
- after insert or update or delete on ${table}
465
- deferrable initially deferred
466
- for each row execute function ${fn}();`);
467
- return `-- ${scope}: holder counts (min / max) over the membership sources, checked at commit
468
- create or replace function ${fn}()
469
- returns trigger
470
- language plpgsql
471
- security definer
472
- set search_path = ''
473
- as $$
474
- declare
475
- v_ids text[] := '{}';
476
- v_id text;
477
- ${keys.declare}
478
- v_total bigint;
479
- v_count bigint;
480
- begin
481
- ${collect.join("\n")}
482
- foreach v_id in array v_ids loop
483
- continue when v_id is null;
484
- ${keys.assign("v_id", " ")}
485
- select count(*) into v_total
486
- from (
487
- ${rows}
488
- ) h;
489
- ${checks.join("\n")}
490
- end loop;
491
- return null;
492
- end;
493
- $$;
494
- ${triggers.join("\n")}`;
495
- }
496
- function collectChangesSql(changed) {
497
- return ` v_changes := v_changes || coalesce((select jsonb_agg(to_jsonb(c)) from (${changed}) c), '[]'::jsonb);`;
498
- }
499
- /** `transferOnly` over membership sources: each source table's statement triggers diff its transition tables, and the count after reads every source. */
500
- function sourceTransferTriggerSql(ctx, scope, sources, roles) {
501
- const fn = qualified(ctx, `${OWNERSHIP.transferOnly}_${scope}`);
502
- const keys = sourceKeys(sources);
503
- const list = `array[${roles.map(quoteLiteral).join(", ")}]::text[]`;
504
- const kind = kindFilterSql(ctx, "h.role", "h.via");
505
- const changes = (source, from, delta) => `select h.id, h.role, ${delta} as delta from (${source.holders.rows(scope, { from }).replaceAll("\n", " ")}) h where h.role = any(${list})`;
506
- const branches = sources.map((source) => ` if tg_relid = ${regclassOf(source.table)} then
507
- if tg_op in ('INSERT', 'UPDATE') then
508
- ${collectChangesSql(changes(source, "permdock_new", "1"))}
509
- end if;
510
- if tg_op in ('UPDATE', 'DELETE') then
511
- ${collectChangesSql(changes(source, "permdock_old", "-1"))}
512
- end if;
513
- end if;`);
514
- const triggers = sourceTables(sources).flatMap((table) => [
515
- "insert",
516
- "update",
517
- "delete"
518
- ].map((op) => {
519
- const name = quoteIdent(`${OWNERSHIP.transferOnly}_${scope}_${op}`);
520
- return `drop trigger if exists ${name} on ${table};
521
- create trigger ${name}
522
- after ${op} on ${table}
523
- referencing ${op === "insert" ? "new table as permdock_new" : op === "delete" ? "old table as permdock_old" : "old table as permdock_old new table as permdock_new"}
524
- for each statement execute function ${fn}();`;
525
- }));
526
- return `-- ${scope}: transfer-only roles (${roles.join(", ")}) keep their holder count per statement, over the membership sources
527
- create or replace function ${fn}()
528
- returns trigger
529
- language plpgsql
530
- security definer
531
- set search_path = ''
532
- as $$
533
- declare
534
- v_changes jsonb := '[]'::jsonb;
535
- v_change record;
536
- v_after bigint;
537
- ${keys.declare}
538
- begin
539
- ${branches.join("\n")}
540
- for v_change in
541
- select x.id, x.role, sum(x.delta) as delta
542
- from jsonb_to_recordset(v_changes) x(id text, role text, delta bigint)
543
- group by x.id, x.role
544
- loop
545
- continue when v_change.delta = 0 or v_change.id is null;
546
- ${keys.assign("v_change.id", " ")}
547
- select count(distinct h.user_id) into v_after
548
- from (
549
- ${sourceRowsOf(scope, sources)}
550
- ) h
551
- where h.live
552
- and h.role = v_change.role${kind === void 0 ? "" : `\n and ${kind}`};
553
- if v_after > 0 and v_after - v_change.delta > 0 then
554
- raise exception using
555
- errcode = '23514',
556
- message = 'permdock: ' || v_change.role || ${quoteLiteral(` in ${scope} `)} || v_change.id || ' moves only by transfer',
557
- hint = 'transfer-only';
558
- end if;
559
- end loop;
560
- return null;
561
- end;
562
- $$;
563
- ${triggers.join("\n")}`;
564
- }
565
- function pairsSql(pairs) {
566
- return `values ${pairs.map((pair) => `(${quoteLiteral(pair.assigner)}, ${quoteLiteral(pair.role)})`).join(", ")}`;
567
- }
568
- /**
569
- * Membership rows of the membership sources for scope `name`, each source's
570
- * `select` comparing its user column with a variable `user` names.
571
- */
572
- function sourceRowsSql(sources, user) {
573
- const keep = sources.some((source) => source.sql.keeps);
574
- return sources.map((source) => source.sql.select(user(source), keep).replaceAll(/^/gmu, " ")).join("\n union all\n");
575
- }
576
- //#endregion
577
- //#region src/cli/rls/can-assign.ts
578
- /** Whether the signed-in user (or `p_user` in the `_for` form) holds, in instance `p_scope_id`, a role whose `assigns` lists `p_role`. */
579
- function canAssignSql(base, own, forUser = false) {
580
- const ctx = forUser ? {
581
- ...base,
582
- subjectId: "p_user",
583
- tenants: "all"
584
- } : base;
585
- const fn = qualified(ctx, forUser ? OWNERSHIP.canAssignFor : OWNERSHIP.canAssign);
586
- const parts = [];
587
- const used = [];
588
- const userOf = (source) => {
589
- const index = used.includes(source) ? used.indexOf(source) : used.push(source) - 1;
590
- return `v_user_${String(index)}`;
591
- };
592
- const global = own.assigns.filter((pair) => pair.scope === "global");
593
- for (const [instance, pairs] of [["p_scope_id is not null", global.filter((pair) => pair.at !== "global")], ["p_scope_id is null", global.filter((pair) => pair.at === "global")]]) {
594
- if (pairs.length === 0) continue;
595
- if (ctx.authorize === "database") {
596
- const ur = globalRoleRows(ctx);
597
- const kind = globalKindFilterSql(ctx, ur.roleSql);
598
- parts.push(`${instance} and exists (
599
- select 1 from ${ur.from}
600
- where ${ur.userSql} = ${subjectIdSql(ctx)}
601
- and (${ur.roleSql}, p_role) in (${pairsSql(pairs)})${kind === void 0 ? "" : `\n and ${kind}`}
602
- )`);
603
- } else {
604
- const kind = globalKindFilterSql(ctx, "r.role");
605
- parts.push(`${instance} and exists (
606
- select 1 from ${roleRows(ctx)}
607
- where (r.role, p_role) in (${pairsSql(pairs)})${kind === void 0 ? "" : `\n and ${kind}`}
608
- )`);
609
- }
610
- }
611
- for (const { name } of ctx.scopes) {
612
- const pairs = own.assigns.filter((pair) => pair.scope === name);
613
- if (pairs.length === 0) continue;
614
- const sources = scopeSources(ctx, name);
615
- if (sources.length > 0) {
616
- const kind = kindFilterSql(ctx, "r.role", "ms.via");
617
- parts.push(`exists (
618
- select 1
619
- from (
620
- ${sourceRowsSql(sources, userOf)}
621
- ) ms
622
- cross join lateral jsonb_array_elements_text(
623
- case jsonb_typeof(ms.roles) when 'array' then ms.roles else '[]'::jsonb end
624
- ) r(role)
625
- where ms.scope = ${quoteLiteral(name)}
626
- and ms.id = p_scope_id
627
- and (r.role, p_role) in (${pairsSql(pairs)})${kind === void 0 ? "" : `\n and ${kind}`}${sourceFilters(ctx, name, void 0, void 0, sourcesKeep(sources)).replaceAll("\n and ", "\n and ")}
628
- )`);
629
- continue;
630
- }
631
- if (ctx.authorize === "database") {
632
- const mapped = scopeTable(ctx, name);
633
- if (mapped === void 0) continue;
634
- const { table, column } = mapped;
635
- const role = memberRoleOf(table, "m", " ");
636
- const filters = [
637
- `${memberColumn(table.user)} = ${subjectIdSql(ctx)}`,
638
- `${memberColumn(column)}::text = p_scope_id`,
639
- `(${role.sql}, p_role) in (${pairsSql(pairs)})`
640
- ];
641
- if (table.expiresAt !== void 0) {
642
- const expires = memberColumn(table.expiresAt);
643
- filters.push(`(${expires} is null or ${expires} > now())`);
644
- }
645
- const disabled = disabledColumn(table);
646
- if (disabled !== void 0) filters.push(`${disabled} is null`);
647
- const kind = kindFilterSql(ctx, role.sql, memberVia(table));
648
- if (kind !== void 0) filters.push(kind);
649
- parts.push(`exists (
650
- select 1 from ${quoteQualified(table.table)} m${role.join}
651
- where ${filters.join("\n and ")}
652
- )`);
653
- } else {
654
- const kind = kindFilterSql(ctx, "r.role", "m ->> 'via'");
655
- parts.push(`exists (
656
- select 1 from ${membershipRows(ctx)}
657
- where m ->> 'scope' = ${quoteLiteral(name)}
658
- and m ->> 'id' = p_scope_id
659
- and (r.role, p_role) in (${pairsSql(pairs)})
660
- and case jsonb_typeof(m -> 'expiresAt')
661
- when 'number' then (m ->> 'expiresAt')::numeric > extract(epoch from now())
662
- else true
663
- end${kind === void 0 ? "" : `\n and ${kind}`}${claimKeptLines(ctx, " ").map((line) => `\n${line}`).join("")}
664
- )`);
665
- }
666
- }
667
- const body = parts.length === 0 ? "false" : parts.join("\n or ");
668
- const language = used.length === 0 ? `language sql
669
- stable
670
- security definer
671
- set search_path = ''
672
- as $$
673
- select ${signedIn(ctx)} and (
674
- ${body}
675
- )
676
- $$;` : `language plpgsql
677
- stable
678
- security definer
679
- set search_path = ''
680
- as $$
681
- declare
682
- ${used.map((source, index) => ` v_user_${String(index)} ${source.sql.userType} := ${subjectIdSql(ctx)};`).join("\n")}
683
- begin
684
- return ${signedIn(ctx)} and (
685
- ${body}
686
- );
687
- end;
688
- $$;`;
689
- if (forUser) {
690
- const user = ctx.dialect === "supabase" ? "uuid" : "text";
691
- return `-- who may assign, for a user the caller names: trusted SQL acting later for a stored user; no client role may execute it
692
- create or replace function ${fn}(p_user ${user}, p_role text, p_scope_id text)
693
- returns boolean
694
- ${language}
695
- revoke execute on function ${fn}(${user}, text, text) from public, anon, authenticated;`;
696
- }
697
- return `-- who may assign: a held role whose assigns lists p_role, in instance p_scope_id (its scope or an ancestor's); a null p_scope_id assigns a global role, which only global assigners may
698
- create or replace function ${fn}(p_role text, p_scope_id text)
699
- returns boolean
700
- ${language}
701
- revoke execute on function ${fn}(text, text) from public, anon;
702
- grant execute on function ${fn}(text, text) to authenticated;`;
703
- }
704
- /** Whether the helpers keep custom roles in tables, so assigning one is checked against its stored definition. */
705
- function assignsCustomRoles(ctx) {
706
- return ctx.customRoles !== void 0 && ctx.authorize === "database";
707
- }
708
- /** Whether `permdock_can_assign_any_for` is written: every function it calls has a `_for` form. */
709
- function hasCanAssignAnyFor(ctx) {
710
- return ctx.authorize === "database" && (!assignsCustomRoles(ctx) || hasCustomRoleChecksFor(ctx));
711
- }
712
- /**
713
- * `permdock_can_assign_any`: one check for a declared or a custom role, so
714
- * SQL that assigns roles calls one function: `permdock_can_assign` for a
715
- * declared role, `permdock_can_assign_custom_role` for a custom one. `p_scope`
716
- * `'global'` (no tenant, no instance) assigns a platform role.
717
- */
718
- function canAssignAnySql(ctx, custom, forUser = false) {
719
- const tenantType = tenantTypeOf(ctx);
720
- const fn = qualified(ctx, forUser ? OWNERSHIP.canAssignAnyFor : OWNERSHIP.canAssignAny);
721
- const declaredFn = qualified(ctx, forUser ? OWNERSHIP.canAssignFor : OWNERSHIP.canAssign);
722
- const customFn = qualified(ctx, forUser ? ASSIGNMENTS.customFor : ASSIGNMENTS.custom);
723
- const userType = ctx.dialect === "supabase" ? "uuid" : "text";
724
- const userParam = forUser ? `p_user ${userType}, ` : "";
725
- const userArg = forUser ? `${userType}, ` : "";
726
- const user = forUser ? "p_user, " : "";
727
- const declared = `${declaredFn}(${user}p_role, case when p_scope = 'global' then null else p_scope_id end)`;
728
- const body = custom && ctx.customRoles !== void 0 ? `case
729
- when p_role = any(${declaredArray(ctx.customRoles.declared)}) then ${declared}
730
- when p_scope = 'global' then ${customFn}(${user}null, 'global', null, p_role)
731
- else ${customFn}(${user}p_tenant, p_scope, p_scope_id, p_role)
732
- end` : declared;
733
- const grants = forUser ? `revoke execute on function ${fn}(${userArg}text, ${tenantType}, text, text) from public, anon, authenticated;` : `revoke execute on function ${fn}(text, ${tenantType}, text, text) from public, anon;
734
- grant execute on function ${fn}(text, ${tenantType}, text, text) to authenticated;`;
735
- return `-- whether ${forUser ? "user p_user" : "the caller"} may assign p_role at instance p_scope_id of p_scope in tenant p_tenant, declared or custom (p_scope 'global' for a platform role)${forUser ? "; no client role may execute it" : ""}
736
- create or replace function ${fn}(${userParam}p_role text, p_tenant ${tenantType}, p_scope text, p_scope_id text)
737
- returns boolean
738
- language sql
739
- stable
740
- security definer
741
- set search_path = ''
742
- as $$
743
- select coalesce(${body}, false)
744
- $$;
745
- ${grants}`;
746
- }
747
- //#endregion
748
- //#region src/cli/rls/ownership.ts
749
- function roleScope(policy, scopes, name) {
750
- const on = policy.rolesByName.get(name)?.on ?? findRole(policy.vocabulary.roles, name)?.on;
751
- return typeof on === "string" ? resolveScope(scopes, on) : void 0;
752
- }
753
- function isGlobalRole(policy, name) {
754
- const binding = policy.rolesByName.get(name);
755
- if (binding !== void 0) return binding.on === void 0;
756
- const leaf = findRole(policy.vocabulary.roles, name);
757
- return leaf !== void 0 && leaf.on === void 0;
758
- }
759
- /** The rules `rls generate` enforces; `undefined` when no role declares one. */
760
- function ownershipRules(policy, scopes) {
761
- const kinds = {};
762
- const assigns = [];
763
- const counted = [];
764
- for (const binding of policy.roles) {
765
- const scope = roleScope(policy, scopes, binding.name);
766
- if (binding.for !== void 0) kinds[binding.name] = binding.for;
767
- const assigner = scope ?? (binding.on === void 0 ? "global" : void 0);
768
- for (const target of binding.assigns ?? []) {
769
- const at = roleScope(policy, scopes, target);
770
- if (assigner !== void 0 && at !== void 0 && (assigner === "global" || scopeChain(scopes, at).includes(assigner))) assigns.push({
771
- assigner: binding.name,
772
- scope: assigner,
773
- role: target,
774
- at
775
- });
776
- else if (assigner === "global" && isGlobalRole(policy, target)) assigns.push({
777
- assigner: binding.name,
778
- scope: "global",
779
- role: target,
780
- at: "global"
781
- });
782
- }
783
- const min = binding.min ?? 0;
784
- const transferOnly = binding.transferOnly === true;
785
- if (scope !== void 0 && (min > 0 || binding.max !== void 0 || transferOnly)) counted.push(binding.max === void 0 ? {
786
- role: binding.name,
787
- scope,
788
- min,
789
- transferOnly
790
- } : {
791
- role: binding.name,
792
- scope,
793
- min,
794
- max: binding.max,
795
- transferOnly
796
- });
797
- }
798
- if (Object.keys(kinds).length === 0 && assigns.length === 0 && counted.length === 0) return;
799
- return {
800
- kinds,
801
- assigns,
802
- counted
803
- };
804
- }
805
- /**
806
- * The ownership objects: holder-count and transfer-only triggers on each
807
- * scope's membership table, and `permdock_can_assign` for the application's
808
- * own policies on those tables. Empty when no role declares a rule.
809
- */
810
- function ownershipSql(ctx) {
811
- const own = ctx.ownership;
812
- if (own === void 0) return "";
813
- const chunks = [];
814
- const skipped = ctx.skipOwnershipTriggers;
815
- for (const { name } of ctx.scopes) {
816
- const counted = own.counted.filter((rule) => rule.scope === name);
817
- if (counted.length === 0) continue;
818
- if (skipped === "all" || skipped?.includes(name) === true) {
819
- chunks.push(`-- ${name}: rls.ownershipTriggers leaves out the triggers, so min, max and transferOnly are checked only by decideRoleChange`);
820
- continue;
821
- }
822
- const transfer = counted.filter((rule) => rule.transferOnly).map((rule) => rule.role);
823
- const mapped = scopeTable(ctx, name);
824
- if (mapped === void 0) {
825
- const sources = holderSources(ctx, name);
826
- if (sources === void 0) chunks.push(`-- ${name}: no memberships table configured, so min, max and transferOnly are checked only by decideRoleChange`);
827
- else if (sources === "not-tables") chunks.push(`-- ${name}: a membership source is not a table, so min, max and transferOnly are checked only by decideRoleChange`);
828
- else {
829
- chunks.push(sourceHoldersTriggerSql(ctx, name, sources, counted));
830
- if (transfer.length > 0) chunks.push(sourceTransferTriggerSql(ctx, name, sources, transfer));
831
- }
832
- continue;
833
- }
834
- chunks.push(holdersTriggerSql(ctx, name, mapped.table, mapped.column, counted));
835
- if (transfer.length > 0) chunks.push(transferTriggerSql(ctx, name, mapped.table, mapped.column, transfer));
836
- }
837
- if (own.assigns.length > 0) {
838
- chunks.push(canAssignSql(ctx, own));
839
- if (ctx.authorize === "database") chunks.push(canAssignSql(ctx, own, true));
840
- const custom = assignsCustomRoles(ctx);
841
- if (custom) {
842
- chunks.push(canAssignCustomSql(ctx));
843
- if (hasCustomRoleChecksFor(ctx)) chunks.push(canAssignCustomSql(ctx, true));
844
- }
845
- chunks.push(canAssignAnySql(ctx, custom));
846
- if (hasCanAssignAnyFor(ctx)) chunks.push(canAssignAnySql(ctx, custom, true));
847
- }
848
- return chunks.length === 0 ? "" : `${chunks.join("\n\n")}\n`;
849
- }
850
- //#endregion
851
- export { ASSIGNMENTS as a, guardedTables as i, ownershipSql as n, OWNERSHIP as o, assignmentSql as r, ownershipRules as t };