permdock 0.6.0 → 0.8.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 (507) hide show
  1. package/README.md +2 -3
  2. package/dist/{2020-C9VN-x8c.js → 2020-CJbO8Bvz.js} +1 -3
  3. package/dist/a2a/index.d.ts +7 -7
  4. package/dist/a2a/index.js +9 -9
  5. package/dist/action-result-CL-QCITA.d.ts +19 -0
  6. package/dist/{adapter-context-CRhqyzCk.js → adapter-context-CIQpQxbE.js} +8 -2
  7. package/dist/{adoption-scan-DCYe60Pi.js → adoption-scan-BLs67P1l.js} +5 -5
  8. package/dist/agent/index.d.ts +3 -3
  9. package/dist/agent/index.js +1 -1
  10. package/dist/ai-sdk/index.d.ts +31 -10
  11. package/dist/ai-sdk/index.js +22 -12
  12. package/dist/{app-data-MuyzVqX8.js → app-data-UNNm07jV.js} +10 -7
  13. package/dist/{approval-header-CJACtHkv.js → approval-header-8QV6MU4H.js} +6 -3
  14. package/dist/{approval-prompt-Dg5LeAcT.js → approval-prompt-B8hQY69x.js} +5 -6
  15. package/dist/{approval-prompt-DvSSPQJX.d.ts → approval-prompt-PYagyQUj.d.ts} +13 -11
  16. package/dist/approvals/index.d.ts +5 -5
  17. package/dist/approvals/index.js +7 -7
  18. package/dist/{approvals-p1PGoVjb.js → approvals-DnIBTuXE.js} +128 -78
  19. package/dist/{approvers-CqPOLD-o.js → approvers-B4r0N_Uz.js} +8 -2
  20. package/dist/{arazzo-41WuzHou.js → arazzo-3RhGfkAK.js} +2 -2
  21. package/dist/{arazzo-CaUVBn7D.js → arazzo-B5-ulWif.js} +6 -6
  22. package/dist/{args-IIolxxKA.js → args-0FrVs5EH.js} +125 -8
  23. package/dist/astro/index.d.ts +30 -12
  24. package/dist/astro/index.js +2 -2
  25. package/dist/{audience-DabClFLQ.js → audience-BAkBDMqn.js} +8 -8
  26. package/dist/{auth-DRLEizbL.js → auth--yPyZNgr.js} +21 -10
  27. package/dist/authzen/index.d.ts +171 -25
  28. package/dist/authzen/index.js +321 -149
  29. package/dist/{automation-BNM3TtDo.d.ts → automation-DqEoWHBc.d.ts} +42 -32
  30. package/dist/{automation-DVjOckjV.js → automation-x3KEUusw.js} +22 -21
  31. package/dist/base-url-BQbddZO5.js +9 -0
  32. package/dist/better-auth/index.d.ts +2 -2
  33. package/dist/better-auth/index.js +13 -7
  34. package/dist/better-supabase/index.d.ts +392 -220
  35. package/dist/better-supabase/index.js +293 -152
  36. package/dist/{bind-DOyrv6zi.d.ts → bind-Cp2hBHzP.d.ts} +27 -12
  37. package/dist/{bind-CAvgUuKs.js → bind-D_sZSVA3.js} +22 -10
  38. package/dist/{body-CH5of8Ne.js → body-CJQwYVa8.js} +3 -3
  39. package/dist/{body-text-QcXok_SI.js → body-text-DQhcmqdY.js} +8 -4
  40. package/dist/{boundary-BM8a_P6E.js → boundary-BV3O1eud.js} +8 -2
  41. package/dist/{boundary-BmHxVH1J.d.ts → boundary-C9ck-3uK.d.ts} +13 -4
  42. package/dist/{budget-NbEtbJC_.js → budget-BELja5A9.js} +6 -3
  43. package/dist/{budget-JqcRqyhK.d.ts → budget-hYsPz_yE.d.ts} +6 -3
  44. package/dist/{build-instance-Bu_eDqYw.js → build-instance-CNWaYJyr.js} +3 -3
  45. package/dist/{canonical-json-BC8_nMTw.js → canonical-json-DwilZ1iB.js} +6 -3
  46. package/dist/{capability-N1K9IpqS.js → capability-BqX94r07.js} +31 -25
  47. package/dist/{capability-Drg-1YhL.d.ts → capability-ChuiONQU.d.ts} +41 -29
  48. package/dist/{casbin-Dyu2gnUD.js → casbin-H0rKxBx2.js} +16 -8
  49. package/dist/{casbin-Cr7RLtA3.js → casbin-cbSbhT_k.js} +2 -2
  50. package/dist/{casl-64gpT-8x.js → casl-C4OINZHI.js} +2 -2
  51. package/dist/{casl-DjEDhTCP.js → casl-CHHoCldP.js} +19 -10
  52. package/dist/catalog/index.d.ts +104 -23
  53. package/dist/catalog/index.js +117 -8
  54. package/dist/{catalog-HD2gf5mY.js → catalog-BFpz2EmT.js} +57 -26
  55. package/dist/{catalog-DZVbrF-z.js → catalog-DCspHDc8.js} +3 -3
  56. package/dist/{catalog-doc-Cdn7-0pQ.js → catalog-doc-DjMKzJp9.js} +53 -16
  57. package/dist/{catalog-fingerprint-CCP0-yQS.js → catalog-fingerprint-e6aCWosn.js} +19 -15
  58. package/dist/catalog-mRQQQhNK.js +1 -0
  59. package/dist/catalog-operations-Dadrl7Z-.js +60 -0
  60. package/dist/{create-CQWIpUG-.js → challenge-DImNcR7B.js} +157 -39
  61. package/dist/chat/index.d.ts +1 -1
  62. package/dist/chat/index.js +13 -10
  63. package/dist/chat-sdk/index.d.ts +44 -26
  64. package/dist/chat-sdk/index.js +17 -17
  65. package/dist/checks-CGkP3Z7A.js +40 -0
  66. package/dist/{claims-map-7oQ3ue4X.js → claims-map-CKkoAAYF.js} +5 -2
  67. package/dist/{claims-map-Ca-QX8C6.d.ts → claims-map-D1Pb5oRq.d.ts} +8 -5
  68. package/dist/claude-agent/index.d.ts +6 -6
  69. package/dist/claude-agent/index.js +6 -3
  70. package/dist/clerk/index.d.ts +11 -7
  71. package/dist/clerk/index.js +6 -6
  72. package/dist/cli/bin.js +4 -4
  73. package/dist/cli/index.d.ts +82 -7
  74. package/dist/cli/index.js +6 -6
  75. package/dist/{clients-C7zLFuWT.d.ts → clients-C_NOET3z.d.ts} +5 -5
  76. package/dist/{clients-DjU5ABMy.js → clients-DYr3U86j.js} +3 -3
  77. package/dist/cloud/index.d.ts +186 -38
  78. package/dist/cloud/index.js +293 -31
  79. package/dist/{cloud-ytQ3uviA.js → cloud-BFlGMaak.js} +5 -6
  80. package/dist/{codemod-5mpSpnUY.js → codemod-DLQ9Zpo4.js} +3 -4
  81. package/dist/{codemod-ua2hHy7w.js → codemod-DWSN2erG.js} +523 -201
  82. package/dist/collect-B5BL3klN.js +1 -0
  83. package/dist/{collect-mLTY4nwb.js → collect-B7ZFAJU3.js} +36 -64
  84. package/dist/{collect-Ci6akVwH.js → collect-Bzv3le0A.js} +6 -6
  85. package/dist/{compare-pfyVnBjE.js → compare-DTfyUunF.js} +2 -2
  86. package/dist/compile/index.d.ts +2 -2
  87. package/dist/compile/index.js +1 -1
  88. package/dist/{compile-1bsAezL0.d.ts → compile-BFzysW3o.d.ts} +36 -12
  89. package/dist/{compile-CMqMx_IN.js → compile-EzEMB-7v.js} +77 -33
  90. package/dist/{completion-BTFrHZhX.js → completion-saoYiRFO.js} +17 -8
  91. package/dist/config-BwPBfN0t.js +108 -0
  92. package/dist/{config-Bj2Ixq3d.js → config-DBeXXmBF.js} +2 -2
  93. package/dist/{config-report-DSpsLpCE.js → config-report-BipSWA6V.js} +9 -6
  94. package/dist/config-shape-ykV0Vm2n.js +134 -0
  95. package/dist/{connection-DjhIJSs2.js → connection-B72dg5Q2.js} +23 -22
  96. package/dist/connector-schema-CYLQNMYq.js +434 -0
  97. package/dist/{context-B_u3_bDJ.js → context-BnIzxTNE.js} +4 -3
  98. package/dist/convex/index.d.ts +13 -7
  99. package/dist/convex/index.js +9 -6
  100. package/dist/core-H-mbhpZc.js +341 -0
  101. package/dist/core-hWIARPDz.d.ts +206 -0
  102. package/dist/{create-CBMmFie-.d.ts → create-BSNrVuxh.d.ts} +87 -34
  103. package/dist/{create-B30OMUOJ.d.ts → create-BVq1lNQE.d.ts} +49 -28
  104. package/dist/{create-D_NmPOdH.d.ts → create-CM1FciYG.d.ts} +37 -29
  105. package/dist/{create-CGm28gyI.js → create-Cq4Uox0f.js} +13 -9
  106. package/dist/{create-DCF2SvoT.js → create-_noSrY1T.js} +15 -21
  107. package/dist/{credential-BcoiejpY.js → credential-CyyyvCsL.js} +42 -39
  108. package/dist/{credentials-DPyHmYz5.js → credentials-CdDxp7jN.js} +6 -6
  109. package/dist/{deciding-columns-Sq12mEA6.js → deciding-columns-NB4wcyBf.js} +13 -2
  110. package/dist/{delegation-j6-rc37o.js → delegation-CDB6_keF.js} +31 -22
  111. package/dist/delivery/index.d.ts +5 -5
  112. package/dist/delivery/index.js +6 -5
  113. package/dist/{delivery-DCAgNyCn.js → delivery-BupfvJIV.js} +81 -20
  114. package/dist/{delivery-event-xX4obB8F.js → delivery-event-JioK5YbS.js} +6 -6
  115. package/dist/denied-text-CHNlVInN.d.ts +22 -0
  116. package/dist/{describe-BybMRY7A.js → describe-Bb4hGK5d.js} +6 -5
  117. package/dist/{describe-B5qgDvEW.d.ts → describe-ByS9LgHK.d.ts} +5 -5
  118. package/dist/{device-BARQ8eYG.js → device-BwbJNmb2.js} +11 -8
  119. package/dist/{diff-CmuSD3vc.js → diff-CN8IYhC_.js} +2 -2
  120. package/dist/{diff-3jbx6Rm4.js → diff-iZWV65nC.js} +23 -14
  121. package/dist/{digest-B3kc_PgQ.d.ts → digest-8Yx2CchM.d.ts} +3 -3
  122. package/dist/{doctor-BdZw53-k.js → doctor-CHD1M9R5.js} +485 -141
  123. package/dist/{doctor-3ZqNHX_G.js → doctor-D3wo-yuz.js} +4 -4
  124. package/dist/drizzle/index.d.ts +33 -19
  125. package/dist/drizzle/index.js +17 -9
  126. package/dist/elysia/index.d.ts +17 -11
  127. package/dist/elysia/index.js +5 -5
  128. package/dist/{errors-BKy0EfhN.js → errors-B6R_lg2a.js} +13 -4
  129. package/dist/{errors-BWXBMaKK.d.ts → errors-CHwoRRpB.d.ts} +4 -1
  130. package/dist/{errors-CWTY6uih.js → errors-Vpu6rKHl.js} +14 -10
  131. package/dist/{errors-DH5QEGXh.d.ts → errors-zi_4T-rx.d.ts} +22 -6
  132. package/dist/{evaluate-CNClBvcj.js → evaluate-Dd8Ta0Ie.js} +185 -80
  133. package/dist/{evaluations-beAooV0n.js → evaluations-IBceAeKT.js} +41 -20
  134. package/dist/{evaluations-C_1vdSZc.d.ts → evaluations-z8dQFDaN.d.ts} +12 -6
  135. package/dist/eve/index.d.ts +9 -6
  136. package/dist/eve/index.js +4 -4
  137. package/dist/{event-time-CsegxXxB.js → event-time-BGy48400.js} +8 -4
  138. package/dist/{expiry-D4_YKRKD.js → expiry-6XByK0dm.js} +8 -5
  139. package/dist/express/index.d.ts +9 -6
  140. package/dist/express/index.js +9 -6
  141. package/dist/fastify/index.d.ts +16 -10
  142. package/dist/fastify/index.js +8 -5
  143. package/dist/{fetch-adapter-Dw0MTS3D.d.ts → fetch-adapter-C1DCvpqV.d.ts} +9 -6
  144. package/dist/{fetch-adapter-DD_gfmrC.js → fetch-adapter-JL43jD3E.js} +14 -11
  145. package/dist/fields-D0vUI6dq.js +498 -0
  146. package/dist/{files-C5ZI27eV.js → files-B3AA05f1.js} +21 -5
  147. package/dist/{files-D_JIzUrP.js → files-BSjrtIHw.js} +11 -4
  148. package/dist/{fixtures-B7XrLeY7.js → fixtures-A1_sp_tR.js} +15 -6
  149. package/dist/{flags-C3DktBDY.js → flags-DXjoTVbS.js} +2 -2
  150. package/dist/{freeze-CrU8nQeX.js → freeze-jjan0lCv.js} +4 -1
  151. package/dist/{from-snapshot-CTCMsFZk.js → from-snapshot-DCakWRsr.js} +26 -16
  152. package/dist/gen-B5kvbAoZ.js +58 -0
  153. package/dist/gen-DWCYcMQM.js +827 -0
  154. package/dist/generate-CRVV5V7l.js +165 -0
  155. package/dist/generate-CezbCaTI.js +275 -0
  156. package/dist/{grantee-hxrUsbpM.js → grantee-Dke-9rd1.js} +4 -4
  157. package/dist/{grantee-conditions-CcXf8hMM.js → grantee-conditions-BrYPe-w0.js} +12 -12
  158. package/dist/{grantee-match-DbENBHLB.js → grantee-match-7RZZvoT_.js} +12 -6
  159. package/dist/{graph-sql-B-dsAT6j.d.ts → graph-sql-BwFC4Qjs.d.ts} +3 -3
  160. package/dist/h3/index.d.ts +10 -7
  161. package/dist/h3/index.js +3 -3
  162. package/dist/headers-B9jQxjtW.d.ts +10 -0
  163. package/dist/{helpers-CBYVMjwh.js → helpers-DJicaG6f.js} +40 -28
  164. package/dist/hono/index.d.ts +16 -10
  165. package/dist/hono/index.js +5 -5
  166. package/dist/{hosted-BPk51-kX.d.ts → hosted-Cmtxogd0.d.ts} +44 -20
  167. package/dist/{hosted-B46-5LYE.js → hosted-D0IzESu_.js} +68 -25
  168. package/dist/{http-ujKm0JXE.js → http-DH94eh6f.js} +4 -4
  169. package/dist/{http-BBoKefeS.js → http-DKLXrFGk.js} +13 -7
  170. package/dist/{http-DXJ37RDA.js → http-DOL33cO0.js} +11 -8
  171. package/dist/{import-wyqXUyjm.js → import-CST57XLp.js} +64 -51
  172. package/dist/{import-CNV7I2Dw.js → import-_YqhhwvX.js} +6 -6
  173. package/dist/{index-B8YjkEZ4.d.ts → index-B8s204GL.d.ts} +64 -52
  174. package/dist/{index-Ch8LpNDp.d.ts → index-BT5-1VsX.d.ts} +64 -25
  175. package/dist/{index-DuWxc5dt.d.ts → index-BW_0MZOS.d.ts} +388 -149
  176. package/dist/index-BhxEUY9J.d.ts +233 -0
  177. package/dist/index-Bv5iXPqU.d.ts +210 -0
  178. package/dist/{index-C-6Letxg.d.ts → index-_9UiQIkt.d.ts} +164 -77
  179. package/dist/index.d.ts +22 -21
  180. package/dist/index.js +35 -33
  181. package/dist/{init-GG6Jh8HD.js → init-Dz_PsHdv.js} +5 -5
  182. package/dist/{init-DeMYsnYJ.js → init-cE3A8aXq.js} +10 -10
  183. package/dist/{instance-options-BsVpyGIk.d.ts → instance-options-B0KXqTrJ.d.ts} +4 -4
  184. package/dist/{instance-snapshot-BOEhcqIF.js → instance-snapshot--JWiTrvO.js} +81 -56
  185. package/dist/{instant-BluqDvyS.js → instant-DK3Iz83e.js} +2 -2
  186. package/dist/{internals-Dk8A8fX3.js → internals-B3IgHrvo.js} +6 -3
  187. package/dist/{json-schema-B-vAwlde.js → json-schema-BPGa-RjQ.js} +9 -3
  188. package/dist/{json-schema-CN_iLFH2.d.ts → json-schema-BfXgnRNT.d.ts} +4 -4
  189. package/dist/jwt/index.d.ts +125 -17
  190. package/dist/jwt/index.js +157 -16
  191. package/dist/{kernel-D0NVb1cK.js → kernel-C-fYydV2.js} +151 -16
  192. package/dist/kysely/index.d.ts +49 -33
  193. package/dist/kysely/index.js +9 -7
  194. package/dist/{live-options-BaAFCIiu.js → live-options-BBIT68le.js} +2 -2
  195. package/dist/{load-DFS_ry0W.js → load-DjSU5KXO.js} +6 -6
  196. package/dist/load-Dm0pSYH3.js +1 -0
  197. package/dist/{login-Dfe5RlYk.js → login-D-8tMqzo.js} +4 -4
  198. package/dist/{login-imhuwvn3.js → login-DplQ0s84.js} +18 -15
  199. package/dist/{manifest-dvL2XEe1.js → manifest-Cgiq5oqc.js} +67 -37
  200. package/dist/{manifest-mx5ghSFM.d.ts → manifest-CzzWtnAb.d.ts} +144 -28
  201. package/dist/{manifest-schema-C0kK_8V0.js → manifest-schema-2r37XRhD.js} +80 -9
  202. package/dist/{manifest-C8IzW3Do.js → manifest-wg8WkkpD.js} +11 -7
  203. package/dist/{map-claims-D3oRmTk0.js → map-claims-BNWCJtmP.js} +27 -18
  204. package/dist/{map-error-Dr70oA_3.js → map-error-pasIGqMT.js} +7 -7
  205. package/dist/{markers-C6joDI3o.js → markers-BeHZ4x9Q.js} +20 -5
  206. package/dist/mcp/index.d.ts +154 -47
  207. package/dist/mcp/index.js +200 -41
  208. package/dist/{migrate-CIq4-E9F.js → migrate-B7oP_sQU.js} +102 -31
  209. package/dist/module-values-BJTBdo6y.js +107 -0
  210. package/dist/nest/index.d.ts +23 -13
  211. package/dist/nest/index.js +18 -11
  212. package/dist/next/client.d.ts +5 -2
  213. package/dist/next/client.js +1 -1
  214. package/dist/next/index.d.ts +72 -26
  215. package/dist/next/index.js +110 -6
  216. package/dist/next/plugin.d.ts +1 -1
  217. package/dist/next/plugin.js +4 -3
  218. package/dist/node/index.d.ts +5 -5
  219. package/dist/node/index.js +3 -3
  220. package/dist/{ocsf-BFp-PZZA.js → ocsf-TcjRBgIs.js} +15 -5
  221. package/dist/openai/index.d.ts +13 -7
  222. package/dist/openai/index.js +3 -3
  223. package/dist/openapi/index.d.ts +61 -30
  224. package/dist/openapi/index.js +2 -2
  225. package/dist/{openapi-B7HZ0f-r.js → openapi-BOsx0xn9.js} +34 -24
  226. package/dist/{openapi-C4dDTVEd.js → openapi-CBZUhA3l.js} +4 -5
  227. package/dist/{openapi-DD1SV-5-.js → openapi-VeHHU2l9.js} +23 -14
  228. package/dist/{operation-findings-DgATDpvh.js → operation-findings-CXtFzlKJ.js} +3 -3
  229. package/dist/{operations-X0VM7F3m.d.ts → operations-Ci_rT6Uo.d.ts} +10 -7
  230. package/dist/orpc/index.d.ts +68 -14
  231. package/dist/orpc/index.js +62 -13
  232. package/dist/otel/index.d.ts +7 -4
  233. package/dist/otel/index.js +8 -5
  234. package/dist/output-files-BHOIlrfD.js +1 -0
  235. package/dist/{output-files-DhRBBE4n.js → output-files-BIQ_9pIs.js} +29 -17
  236. package/dist/{output-1im__-08.js → output-tkju6U7R.js} +15 -7
  237. package/dist/ownership-B4L59T9u.js +1054 -0
  238. package/dist/parse-1_ZheTW5.js +151 -0
  239. package/dist/parse-local-manifest-BQhTlLQS.d.ts +10 -0
  240. package/dist/parse-local-manifest-DEiCF4ah.js +69 -0
  241. package/dist/{parse-request-D_tUXG6M.js → parse-request-CwCZpyjV.js} +7 -8
  242. package/dist/{paths-DXSHAMIa.js → paths-CUvURzHp.js} +4 -1
  243. package/dist/pdp/index.d.ts +9 -6
  244. package/dist/pdp/index.js +23 -12
  245. package/dist/{peer-CRvC7Hg1.js → peer-C9LvBCcb.js} +1 -1
  246. package/dist/peer-Q0fuZ6hx.js +982 -0
  247. package/dist/{permdock-SV8ZINYT.d.ts → permdock-B6Sf4T_S.d.ts} +270 -117
  248. package/dist/{permdock-BrAscV28.js → permdock-L-_I_3zP.js} +226 -74
  249. package/dist/{permission-registry-Br4jSNVi.js → permission-registry-B8tYxPIt.js} +24 -11
  250. package/dist/{vocabulary-CN8H_9UF.d.ts → permission-types-CAY-GU7e.d.ts} +130 -104
  251. package/dist/{permissions-u_KHg-sN.d.ts → permissions-Bx6UI8n1.d.ts} +6 -2
  252. package/dist/{permissions-B-wCP5ZC.js → permissions-CVXmRILq.js} +3 -3
  253. package/dist/{permissions-BPxlwVhN.js → permissions-mDcTWoBs.js} +8 -5
  254. package/dist/pg-DQTqRrou.js +60 -0
  255. package/dist/{pins-8ILTftC9.js → pins-nqarl3oE.js} +4 -1
  256. package/dist/pkce-CnmmYqUZ.js +21 -0
  257. package/dist/{policy-77FSAq_V.d.ts → policy-Ba4bDhaj.d.ts} +5 -5
  258. package/dist/{policy-DbM5YYtV.js → policy-CLQ8__GF.js} +49 -20
  259. package/dist/{policy-from-catalog-C2gMa2Dj.js → policy-from-catalog-CJgOm6aq.js} +28 -25
  260. package/dist/{policy-module-CTlwMvLI.js → policy-module-xym9fnSq.js} +12 -6
  261. package/dist/{policy-types-n0uRTsW8.d.ts → policy-types-CCiDRZBH.d.ts} +802 -334
  262. package/dist/postgres-store-DcyrPS-r.js +1028 -0
  263. package/dist/{postgrest-DAjUkF9w.js → postgrest-D4nuPXIQ.js} +88 -36
  264. package/dist/{postgrest-CEgRbefE.d.ts → postgrest-DicQyqm-.d.ts} +60 -30
  265. package/dist/powersync-DHNQX06W.js +1117 -0
  266. package/dist/{powersync-DISt6SUe.js → powersync-DXqGuq9A.js} +3 -3
  267. package/dist/powersync-Djf-zCpB.js +1 -0
  268. package/dist/preset/index.d.ts +38 -28
  269. package/dist/preset/index.js +1 -1
  270. package/dist/{preset-DZdU0tne.js → preset-BjLzeFpp.js} +58 -34
  271. package/dist/{principal-source-pHneukrx.js → principal-source-C6N60GtM.js} +10 -10
  272. package/dist/prisma/index.d.ts +69 -41
  273. package/dist/prisma/index.js +21 -17
  274. package/dist/{problem-CTviyH5L.js → problem-BVLHFK33.js} +41 -21
  275. package/dist/{problem-details-cn5X30gZ.js → problem-details-CLDgX1KV.js} +13 -4
  276. package/dist/{problem-types-CJ2325SZ.js → problem-types-DSsRfONQ.js} +4 -1
  277. package/dist/prompt-BYc6drYW.js +938 -0
  278. package/dist/protected-action-BE7N_Luo.d.ts +58 -0
  279. package/dist/protected-action-DUYqb-Ma.js +80 -0
  280. package/dist/{protected-BlF0F6wL.js → protected-action-QEA8arRB.js} +48 -14
  281. package/dist/{provider-B1al-AZz.js → provider-C55OGXJ7.js} +5 -4
  282. package/dist/{provider-DILL9oPK.d.ts → provider-DXfq5c2d.d.ts} +1 -1
  283. package/dist/{provider-store-DM6DNcta.js → provider-store-CaTv00tr.js} +13 -9
  284. package/dist/pull-B65ndFNZ.js +1 -0
  285. package/dist/{pull-jEwbf80J.js → pull-CwpGaQSi.js} +12 -11
  286. package/dist/{push-BD4f15co.js → push-DgssgzkK.js} +62 -16
  287. package/dist/{pushed-policy-DCW91KQU.d.ts → pushed-policy-D1Eoi6NM.d.ts} +12 -6
  288. package/dist/{pushed-policy-CqtxkV4G.js → pushed-policy-ITwYKvvH.js} +10 -7
  289. package/dist/react/index.d.ts +9 -8
  290. package/dist/react/index.js +7 -6
  291. package/dist/react/provider-client.d.ts +1 -1
  292. package/dist/react/provider-client.js +1 -1
  293. package/dist/react-native/index.d.ts +104 -51
  294. package/dist/react-native/index.js +394 -67
  295. package/dist/{refs-K6eWUJ0H.js → refs-C8BKxc_e.js} +17 -3
  296. package/dist/{relation-walk-3OyDBF0S.js → relation-walk-DK_gkgL7.js} +12 -9
  297. package/dist/{relations-BnCWnJGI.js → relations-BxvRvDHK.js} +3 -3
  298. package/dist/{replay-Du1tJjG7.js → replay-BU09ad4L.js} +1 -1
  299. package/dist/{replay-Bkm-Ne4l.d.ts → replay-DNftIb_R.d.ts} +1 -1
  300. package/dist/{request-context-C81Pip9n.js → request-context-C25ilqiJ.js} +8 -8
  301. package/dist/{request-schema-CMreVuFM.js → request-schema-DhX7UbfQ.js} +4 -1
  302. package/dist/resend/index.d.ts +34 -28
  303. package/dist/resend/index.js +29 -29
  304. package/dist/resolve-names-CF7xXLSG.js +201 -0
  305. package/dist/{resource-relations-D_jw0BFx.js → resource-relations-8-pCScBO.js} +18 -9
  306. package/dist/{retire-CALjIQ7e.js → retire-B2xffQgY.js} +15 -6
  307. package/dist/{revocations-R07lFBnX.d.ts → revocations-BaUXHM1N.d.ts} +6 -3
  308. package/dist/{rls-DTvYd-lI.js → rls-CNEH2_BG.js} +743 -624
  309. package/dist/{rls-BAqP4q66.js → rls-Ca8Jz9b5.js} +41 -10
  310. package/dist/{role-builder-uWQZ4v84.js → role-builder-BK2-T6oD.js} +41 -20
  311. package/dist/rolldown-runtime-C3I60J0A.js +4 -0
  312. package/dist/{row-conditions-h2HythXQ.js → row-conditions-BAGHOmVq.js} +4 -3
  313. package/dist/{rpc-VSl5ylaQ.js → rpc-fNqAIqQk.js} +8 -5
  314. package/dist/{run-CUKuz0A8.js → run-Bz26OTfO.js} +26 -23
  315. package/dist/run-D-JE8QWb.js +1 -0
  316. package/dist/{run-ticket-DocwaTKn.d.ts → run-ticket-DbWI9f99.d.ts} +33 -13
  317. package/dist/{run-ticket-sxFI6LAk.js → run-ticket-Dv7aF7Dk.js} +29 -8
  318. package/dist/{runtime-D3VTAiCA.js → runtime-BGnrOkVH.js} +5 -2
  319. package/dist/{saas-BCXRuXca.js → saas-iWnUdwCt.js} +42 -29
  320. package/dist/{scan-qvOe0hS3.js → scan-DCj1KQfn.js} +1 -1
  321. package/dist/{schema-B4v0Qrac.js → schema-BOJjqlWL.js} +3 -2
  322. package/dist/{schema-yLuBWWsh.js → schema-Dst9I9Gs.js} +9 -5
  323. package/dist/scim/index.d.ts +3 -2
  324. package/dist/scim/index.js +3 -1
  325. package/dist/scim-D8YupzX1.js +44 -0
  326. package/dist/{scim-ClHtpyV3.js → scim-jJBJ7g1Z.js} +35 -551
  327. package/dist/{scopes-CUPSjo9q.js → scopes-0Up_UA2t.js} +42 -24
  328. package/dist/server/index.d.ts +12 -12
  329. package/dist/server/index.js +13 -13
  330. package/dist/{server-C3WXAHZj.js → server-3cVlTLde.js} +31 -31
  331. package/dist/{server-types-CKQiCnON.d.ts → server-types-CIlpSA2G.d.ts} +81 -46
  332. package/dist/{sha256-D9ihqmvd.js → sha256-C-4WXKIu.js} +4 -3
  333. package/dist/{shared-BAK8t4Uo.js → shared-Afctg7B0.js} +100 -61
  334. package/dist/{shared-DvvFzYXe.js → shared-l0oGGetg.js} +9 -6
  335. package/dist/{signals-D3NcTKUS.js → signals-B1vHR3fN.js} +2 -2
  336. package/dist/{sink-BEZSlMS_.js → sink-D9_vh372.js} +32 -21
  337. package/dist/{sink-4-eQIRWf.d.ts → sink-Dvi7YZG_.d.ts} +44 -20
  338. package/dist/{skills-B6lVdD_W.js → skills-Bjj7BNEQ.js} +16 -12
  339. package/dist/{skills-CTYwkl44.js → skills-OuoMR49L.js} +3 -3
  340. package/dist/{snapshot-B7DkYg6g.js → snapshot-CXlzi69u.js} +21 -18
  341. package/dist/{snapshot-cache-PXI-vGpY.d.ts → snapshot-cache-BAXZ0KOp.d.ts} +21 -12
  342. package/dist/{snapshot-cache-DZHQ0KF6.js → snapshot-cache-Bx_4xC_6.js} +14 -11
  343. package/dist/solid/index.d.ts +55 -15
  344. package/dist/solid/index.js +46 -12
  345. package/dist/solid-start/index.d.ts +30 -12
  346. package/dist/solid-start/index.js +3 -3
  347. package/dist/sources-B1Os_YUu.d.ts +312 -0
  348. package/dist/{sources-vs5dGOsS.js → sources-CMAM-2A3.js} +156 -51
  349. package/dist/sources-qoIJQrJv.js +11 -0
  350. package/dist/{sql-B5T1IL83.js → sql-0WjxIp9g.js} +32 -7
  351. package/dist/sql-B80DFdpG.d.ts +10 -0
  352. package/dist/{src-Cu2m75uo.js → src-DZ0l9UAg.js} +305 -123
  353. package/dist/ssf/index.d.ts +4 -4
  354. package/dist/ssf/index.js +665 -224
  355. package/dist/{standard-webhooks-rbD7LS6h.d.ts → standard-webhooks-C-qX4mJW.d.ts} +7 -7
  356. package/dist/{standard-webhooks-DgFFD-Ga.js → standard-webhooks-D67a3nzk.js} +5 -5
  357. package/dist/{store-BDutJkDL.js → store-RNFvaJJv.js} +43 -29
  358. package/dist/{store-options-u0ycEe8s.js → store-options-Dil3lraY.js} +105 -15
  359. package/dist/stores-C0Kta5Ft.d.ts +59 -0
  360. package/dist/{stores-CGhM8BN_.js → stores-DxZWDXCs.js} +42 -5
  361. package/dist/{stream-CvdUS9V1.js → stream-CDvF0sJm.js} +5 -5
  362. package/dist/{stream-CeCMJmBB.d.ts → stream-ltuLdtTG.d.ts} +4 -3
  363. package/dist/{style-DiKWnAvn.js → style-DblOtSga.js} +1 -1
  364. package/dist/{style-Uao76wO7.js → style-Ds11Hmk4.js} +3 -1
  365. package/dist/{subject-settings-CkEwrw3W.js → subject-settings-8sH5HlII.js} +8 -4
  366. package/dist/{row-check-Dt35czLy.d.ts → subject-settings-vNW8qmUH.d.ts} +30 -18
  367. package/dist/supabase/index.d.ts +48 -37
  368. package/dist/supabase/index.js +6 -6
  369. package/dist/supabase/middleware.d.ts +19 -13
  370. package/dist/supabase/middleware.js +7 -7
  371. package/dist/{supabase-x5JtR2tc.js → supabase-BL1qJzzY.js} +82 -36
  372. package/dist/{supabase-By_frk3U.js → supabase-D39cuGPt.js} +3 -3
  373. package/dist/{supabase-hook-BMoEhZir.js → supabase-hook-B-yXnzUl.js} +1206 -286
  374. package/dist/supabase-hook-H-MtE9Wd.js +1 -0
  375. package/dist/supautils-BU-pAEpf.js +808 -0
  376. package/dist/{support-session-C6xJQYut.js → support-session-BsmPCbz8.js} +22 -22
  377. package/dist/svelte/PermissionBoundary.svelte +2 -6
  378. package/dist/svelte/Protected.svelte +2 -8
  379. package/dist/svelte/index.d.ts +9 -8
  380. package/dist/svelte/index.js +10 -9
  381. package/dist/svelte/runtime.d.ts +4 -4
  382. package/dist/svelte/runtime.js +4 -4
  383. package/dist/svelte/source.d.ts +9 -8
  384. package/dist/svelte/source.js +6 -5
  385. package/dist/sveltekit/index.d.ts +30 -12
  386. package/dist/sveltekit/index.js +2 -2
  387. package/dist/{ownership-DqaJNJPn.js → tables-DeMNEy6V.js} +1025 -1085
  388. package/dist/tanstack-start/index.d.ts +22 -10
  389. package/dist/tanstack-start/index.js +2 -2
  390. package/dist/{target-Bw37TFNA.js → target-qdEAnnhU.js} +6 -6
  391. package/dist/{tenancy-DN2QAx9z.js → tenancy-5d1zVBvK.js} +36 -21
  392. package/dist/terminal/index.d.ts +23 -14
  393. package/dist/terminal/index.js +17 -20
  394. package/dist/testing/core.d.ts +2 -0
  395. package/dist/testing/core.js +1 -0
  396. package/dist/testing/fixtures/index.d.ts +15 -0
  397. package/dist/testing/fixtures/index.js +831 -0
  398. package/dist/testing/index.d.ts +235 -285
  399. package/dist/testing/index.js +502 -927
  400. package/dist/testing/saas/index.d.ts +43 -27
  401. package/dist/testing/saas/index.js +2 -2
  402. package/dist/testing/saas/permissions.d.ts +1 -1
  403. package/dist/testing/saas/permissions.js +1 -1
  404. package/dist/text-diff-BtfSmdUo.js +444 -0
  405. package/dist/{thenable-yD7SabqG.js → thenable-BNSM1U2R.js} +12 -3
  406. package/dist/{time-DkWjdL98.js → time-nR1JesoH.js} +32 -8
  407. package/dist/{token-BLZcjQgt.js → token-DC9EQiet.js} +15 -13
  408. package/dist/{tool-refusal-CMLN5xhn.js → tool-refusal-Qpjs_W6M.js} +5 -2
  409. package/dist/trpc/index.d.ts +11 -8
  410. package/dist/trpc/index.js +15 -9
  411. package/dist/type-helpers-BIPIDa6a.d.ts +50 -0
  412. package/dist/{types-8RnwUAvE.d.ts → types-AMJ5qoU_.d.ts} +49 -30
  413. package/dist/{types-C_IiEs64.d.ts → types-B2mlGuhW.d.ts} +14 -11
  414. package/dist/{types-_WhUP7ud.d.ts → types-B4uqKDnp.d.ts} +25 -12
  415. package/dist/{types-CX7AvRqP.d.ts → types-BJk0BKRX.d.ts} +24 -14
  416. package/dist/types-B_d_g7T3.d.ts +262 -0
  417. package/dist/{types-BdtSDbBO.d.ts → types-B_tiYvk8.d.ts} +59 -32
  418. package/dist/{types-DqzsnlSA.js → types-CcUXciSj.js} +17 -5
  419. package/dist/{types-Dfv0aTER.d.ts → types-DC1Loeh3.d.ts} +449 -168
  420. package/dist/{types-lUlG3TVd.d.ts → types-DHKPcqzr.d.ts} +2 -2
  421. package/dist/{types-C791HFu9.d.ts → types-DjuMBNF9.d.ts} +68 -32
  422. package/dist/{types-C863OQiR.d.ts → types-HzqOtvsJ.d.ts} +23 -12
  423. package/dist/{types-Druu9wLM.d.ts → types-ZzRGoViD.d.ts} +77 -24
  424. package/dist/{types-BzzaHxt3.d.ts → types-ah9NlU6j.d.ts} +137 -48
  425. package/dist/{types-CVZSNocA.d.ts → types-djVzLlIV.d.ts} +31 -14
  426. package/dist/{types-BtHtcKMr.d.ts → types-yUuPR5Hy.d.ts} +47 -24
  427. package/dist/unplugin/index.d.ts +1 -1
  428. package/dist/unplugin/index.js +2 -2
  429. package/dist/usage-CYeXek0p.js +1 -0
  430. package/dist/{usage-SveTRTyr.js → usage-CxEzS4ey.js} +50 -26
  431. package/dist/{usage-CRVl9V3t.js → usage-ab0PdusX.js} +2 -2
  432. package/dist/{validation-error-ZfUHbKvf.js → validation-error-CYg2kJEw.js} +4 -1
  433. package/dist/{validation-error-DHUrAkku.d.ts → validation-error-YGg2mXyH.d.ts} +5 -2
  434. package/dist/{validity-CZ7-y0Cj.js → validity-Buc7w8E9.js} +13 -10
  435. package/dist/{verifier-DHuh-okk.js → verifier-DUV6pLqZ.js} +10 -4
  436. package/dist/{verify-BaAKx7t6.js → verify-DZeqoWu5.js} +417 -489
  437. package/dist/version-DMQ0dnN5.js +48 -0
  438. package/dist/version-DizhmD72.js +1 -0
  439. package/dist/{views-DTIIO-oQ.js → views-CD8wuL4Z.js} +19 -6
  440. package/dist/vocabulary-DEJ5j4mR.d.ts +70 -0
  441. package/dist/vue/index.d.ts +71 -21
  442. package/dist/vue/index.js +50 -13
  443. package/dist/{waiter-B986w1oK.d.ts → waiter-Bu9zAlE0.d.ts} +13 -10
  444. package/dist/{waiter-BGUtGYoU.js → waiter-aBLM63_f.js} +1 -1
  445. package/dist/{watch-vea54PRw.js → watch-Cx_WciLE.js} +8 -8
  446. package/dist/watch-DB42U1ib.js +1 -0
  447. package/dist/webmcp/index.d.ts +11 -11
  448. package/dist/webmcp/index.js +8 -5
  449. package/dist/{where-scope-C9vfEphl.js → where-scope-DlCdCM_8.js} +56 -30
  450. package/dist/{who-can-DWBAcaCQ.js → who-can-rI7dCR9Q.js} +23 -20
  451. package/dist/workflow/index.d.ts +3 -3
  452. package/dist/workflow/index.js +13 -13
  453. package/dist/workflow-sdk/index.d.ts +19 -13
  454. package/dist/workflow-sdk/index.js +6 -6
  455. package/dist/{wrap-gX61EtpB.js → wrap-B2wziJI_.js} +11 -5
  456. package/dist/{wrap-C5jC6sKI.d.ts → wrap-DlJE3gS_.d.ts} +8 -5
  457. package/package.json +25 -14
  458. package/schemas/catalog-v1.json +3 -0
  459. package/schemas/cli-result-v1.json +1 -0
  460. package/schemas/cloud-api-v1.json +152 -7
  461. package/schemas/connector-v1.json +8 -0
  462. package/schemas/supabase-claims-v1.json +5 -0
  463. package/schemas/supabase-manifest-v1.json +308 -75
  464. package/skills/permdock/SKILL.md +1 -0
  465. package/skills/permdock-agents/references/runtimes.md +3 -1
  466. package/skills/permdock-approvals/references/stores-and-resume.md +2 -1
  467. package/skills/permdock-credentials/references/tokens-keys-links.md +8 -6
  468. package/skills/permdock-data/references/queries-and-rls.md +6 -2
  469. package/skills/permdock-tenancy/SKILL.md +1 -1
  470. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +2 -1
  471. package/skills/permdock-wire/references/adapters.md +28 -22
  472. package/skills/permdock-wire/references/policy-options.md +1 -0
  473. package/dist/catalog-BoWglDPI.js +0 -1
  474. package/dist/collect-D7eQDffE.js +0 -1
  475. package/dist/config-bs_kZeYq.js +0 -162
  476. package/dist/denied-text-CiFQNuMV.d.ts +0 -19
  477. package/dist/fields-OYG_JR78.js +0 -203
  478. package/dist/generate-CNU1pIOo.js +0 -171
  479. package/dist/headers-BIjfMaoC.js +0 -8
  480. package/dist/headers-CIbDTUTK.d.ts +0 -7
  481. package/dist/index-Cp_ilKi1.d.ts +0 -91
  482. package/dist/index-CueFnxQc.d.ts +0 -110
  483. package/dist/load-BxEtwlBS.js +0 -1
  484. package/dist/output-files-B3IZJksC.js +0 -1
  485. package/dist/package-root-Dk_ETdkp.js +0 -31
  486. package/dist/parse-Cxq0WxrA.js +0 -53
  487. package/dist/parse-local-manifest-5ODwqu8b.d.ts +0 -10
  488. package/dist/parse-local-manifest-CVSs6J9I.js +0 -34
  489. package/dist/peer-C8swJ2GH.js +0 -50
  490. package/dist/policies-DP2nqRoF.js +0 -295
  491. package/dist/powersync-BkWWCS1K.js +0 -538
  492. package/dist/powersync-MMJ2mI2q.js +0 -1
  493. package/dist/problem-details-B45V5d2b.d.ts +0 -7
  494. package/dist/prompt-DfZLJLIn.js +0 -32
  495. package/dist/protected-RFGpakN9.d.ts +0 -38
  496. package/dist/pull-CvpINcMK.js +0 -1
  497. package/dist/run-DDwUaJDU.js +0 -1
  498. package/dist/sources-Xc4zkszI.d.ts +0 -190
  499. package/dist/stores-BUGNbJTt.d.ts +0 -30
  500. package/dist/supabase-hook-CCw5m35C.js +0 -1
  501. package/dist/supautils-B6HYL9eL.js +0 -91
  502. package/dist/text-diff-BQcUapOb.js +0 -15
  503. package/dist/types-B3_ooZgZ.d.ts +0 -172
  504. package/dist/usage-CZpSQP6L.js +0 -1
  505. package/dist/version-CEbQ5UeM.js +0 -18
  506. package/dist/version-DXkYUISx.js +0 -1
  507. package/dist/watch--ovlPOc0.js +0 -1
@@ -1,43 +1,46 @@
1
1
  import { a as sole, r as isRecord } from "./compact-CAf557ZB.js";
2
- import { a as hasConditionOp, c as isConditionRef } from "./refs-K6eWUJ0H.js";
3
- import { E as memoryCustomRoleSource, g as memoryRelationSource } from "./src-Cu2m75uo.js";
4
- import { c as listPermissions, h as formerKeys, n as findPermission } from "./permission-registry-Br4jSNVi.js";
5
- import { a as expandRelation, c as isEdgeRelation, d as isSelfParented, l as isFieldRelation, o as groupEntries, p as restrictedFor, u as isPrincipalRelation } from "./resource-relations-D_jw0BFx.js";
6
- import { f as nowMillis, u as isoAt } from "./time-DkWjdL98.js";
7
- import { t as canonicalJson } from "./canonical-json-BC8_nMTw.js";
8
- import { d as scopeList } from "./scopes-CUPSjo9q.js";
9
- import { o as requiresStandIn } from "./delegation-j6-rc37o.js";
10
- import { o as flattenGrantee } from "./grantee-hxrUsbpM.js";
11
- import { r as relationCondition, t as inheritCondition } from "./grantee-conditions-CcXf8hMM.js";
12
- import { p as scopeField } from "./tenancy-DN2QAx9z.js";
13
- import { s as policyLevels } from "./policy-DbM5YYtV.js";
2
+ import { l as isConditionRef, o as hasConditionOp } from "./refs-C8BKxc_e.js";
3
+ import { A as memoryCustomRoleSource, b as memoryRelationSource } from "./src-DZ0l9UAg.js";
4
+ import { c as listPermissions, h as formerKeys, n as findPermission } from "./permission-registry-B8tYxPIt.js";
5
+ import { c as isEdgeRelation, l as isFieldRelation, u as isPrincipalRelation } from "./resource-relations-8-pCScBO.js";
6
+ import { f as nowMillis, u as isoAt } from "./time-nR1JesoH.js";
7
+ import { t as canonicalJson } from "./canonical-json-DwilZ1iB.js";
8
+ import { f as scopeList, l as rootScope, o as normalizeMemberships } from "./scopes-0Up_UA2t.js";
9
+ import { o as requiresStandIn } from "./delegation-CDB6_keF.js";
10
+ import { p as scopeField } from "./tenancy-5d1zVBvK.js";
11
+ import { l as policyLevels, t as coveredLevels } from "./policy-CLQ8__GF.js";
14
12
  import { t as requiresApproval } from "./approval-required-TzNB9oQA.js";
15
- import { c as andWhere, m as customRoleScope, v as leveled, y as membershipsClaim } from "./evaluate-CNClBvcj.js";
16
- import { t as getPermDock } from "./permdock-BrAscV28.js";
17
- import { a as describeError, i as configError, u as usageResult } from "./errors-CWTY6uih.js";
18
- import { t as policyRowConditionKeys } from "./row-conditions-h2HythXQ.js";
19
- import { s as jsonSchemaOf } from "./catalog-doc-Cdn7-0pQ.js";
20
- import { o as loadPolicyAt } from "./load-DFS_ry0W.js";
21
- import { c as relationArmSql, u as restrictedRowsSql } from "./compile-CMqMx_IN.js";
22
- import "./budget-NbEtbJC_.js";
23
- import { i as qualifySqlTable, n as defaultSqlCommand } from "./sql-B5T1IL83.js";
24
- import "./sources-vs5dGOsS.js";
13
+ import { c as andWhere, m as customRoleScope, v as leveled, y as membershipsClaim } from "./evaluate-Dd8Ta0Ie.js";
14
+ import { t as getPermDock } from "./permdock-L-_I_3zP.js";
15
+ import { a as describeError, i as configError, u as usageResult } from "./errors-Vpu6rKHl.js";
16
+ import { t as policyRowConditionKeys } from "./row-conditions-BAGHOmVq.js";
17
+ import { s as writeFileEnsuringDir } from "./files-BSjrtIHw.js";
18
+ import { c as jsonSchemaOf } from "./catalog-doc-DjMKzJp9.js";
19
+ import { o as loadPolicyAt } from "./load-DjSU5KXO.js";
20
+ import { i as qualifySqlTable, n as defaultSqlCommand, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
21
+ import { a as scopeMembershipTable, i as scopeColumn } from "./compile-EzEMB-7v.js";
22
+ import "./budget-BELja5A9.js";
23
+ import "./sources-CMAM-2A3.js";
25
24
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
26
- import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-B7XrLeY7.js";
27
- import { F as quoteQualified, I as quoteTable, M as qualified, N as quoteIdent, P as quoteLiteral, T as columnTypesOf, _ as subjectClaimJsonSql, a as customRolesOn, j as helperSchema, r as HELPERS, v as subjectClaimSql, w as arrayColumnsOf } from "./shared-BAK8t4Uo.js";
28
- import { d as connectPgPool, f as pgConnector, l as validitySql, s as andSql, u as wrapSql } from "./policies-DP2nqRoF.js";
29
- import { $ as activeUserSql, A as collectGrants, F as CLOSURE, I as graphHelper, L as graphSqlName, M as compileConditionSql, N as contextRefs, O as breakGlassHolder, P as sqlFunctionNames, R as graphSqlText, T as apiKeyAllowsCall, V as linkHelper, Y as restrictedHelper, Z as scopeTable, _ as capabilityAccessSql, k as breakGlassKey, m as accessSql, p as requiresSql } from "./ownership-DqaJNJPn.js";
30
- import { s as viewName, t as FIELD_VIEWS } from "./fields-OYG_JR78.js";
25
+ import { t as DOCS_BASE } from "./manifest-Cgiq5oqc.js";
26
+ import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-A1_sp_tR.js";
27
+ import { A as quoteQualified, N as arrayColumnsOf, O as quoteIdent, P as columnTypesOf, _ as subjectClaimJsonSql, a as customRolesOn, j as quoteTable, k as quoteLiteral, r as HELPERS, v as subjectClaimSql } from "./shared-Afctg7B0.js";
28
+ import { C as accessSql, D as tokenScopeAllowsCall, S as requiresSql, ht as scopeTable, k as capabilityAccessSql, n as tableNameOf, o as graphPlan, q as apiKeyAllowsCall, r as tableNames } from "./tables-DeMNEy6V.js";
29
+ import { c as breakGlassKey, f as compileConditionSql, l as collectGrants, m as sqlFunctionNames, p as contextRefs, s as breakGlassHolder } from "./ownership-B4L59T9u.js";
30
+ import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
31
+ import { n as pgConnector, t as connectPgPool } from "./pg-DQTqRrou.js";
32
+ import { _ as wrapSql, g as validitySql, m as andSql, s as viewName, t as FIELD_VIEWS } from "./fields-D0vUI6dq.js";
33
+ import { resolve } from "node:path";
31
34
  import { createHash, randomUUID } from "node:crypto";
32
35
  //#region src/cli/rls/indexes.ts
33
36
  /** Postgres truncates identifiers longer than this, in bytes. */
34
37
  const MAX_IDENT = 63;
35
38
  /**
36
- * The row fields `condition` compares with the subject, a claim or a
37
- * membership (`ownerId: principal.id`, `memberOf`), through `and` and `or`:
38
- * the selective comparisons an index serves. A comparison with a constant
39
- * (`status: 'sent'`) narrows rows the scope key already found, a negation
40
- * scans anyway, and a dotted field is a JSON path a plain index does not serve.
39
+ * The row fields `condition` compares with the subject, a claim or a membership
40
+ * (`ownerId: principal.id`, `memberOf`), through `and` and `or`: the selective
41
+ * comparisons an index serves. A comparison with a constant (`status: 'sent'`)
42
+ * narrows rows the scope key already found, a negation scans anyway, and a
43
+ * dotted field is a JSON path a plain index does not serve.
41
44
  */
42
45
  function indexedFields(condition) {
43
46
  if (condition === void 0) return [];
@@ -67,9 +70,9 @@ function plainField(field) {
67
70
  return field.includes(".") ? [] : [field];
68
71
  }
69
72
  /**
70
- * Every index the generated SQL reads through: the row columns policies
71
- * filter on (scope keys and selective condition fields), and the membership
72
- * tables' user column, followed by the scope column the helpers select.
73
+ * Every index the generated SQL reads through: the row columns policies filter
74
+ * on (scope keys and selective condition fields), and the membership tables'
75
+ * user column, followed by the scope column the helpers select.
73
76
  */
74
77
  function indexTargets(ctx, rowColumns) {
75
78
  const targets = /* @__PURE__ */ new Map();
@@ -102,7 +105,10 @@ function indexName(target) {
102
105
  function indexesSql(targets) {
103
106
  return targets.map((target) => `create index if not exists ${quoteIdent(indexName(target))} on ${quoteTable(target.table)} (${target.columns.map(quoteIdent).join(", ")});`).join("\n");
104
107
  }
105
- /** Every live column of the tables in `$1` (`schema.table`), as `target` and `name`. */
108
+ /**
109
+ * Every live column of the tables in `$1` (`schema.table`), as `target` and
110
+ * `name`.
111
+ */
106
112
  const COLUMNS_SQL = `select n.nspname || '.' || c.relname as target, a.attname as name
107
113
  from pg_attribute a
108
114
  join pg_class c on c.oid = a.attrelid
@@ -187,25 +193,30 @@ function levelReachOf(policy, keys) {
187
193
  const { item } = entry;
188
194
  const { grant } = item;
189
195
  if (item.access.kind !== "role" || grant.effect !== "allow" || grant.permission.kind !== "instance" || grant.level !== void 0) continue;
190
- const levels = policyLevels(policy, grant.permission.resource);
196
+ const resource = grant.permission.resource;
197
+ const levels = policyLevels(policy, resource);
191
198
  if (levels.length > 0) {
192
199
  const set = reach.get(grantKey) ?? /* @__PURE__ */ new Set();
193
- for (const name of reachedLevels(grant.where, levels)) set.add(name);
200
+ const reached = coveredLevels(policy, resource, reachedLevels(grant.where, levels));
201
+ for (const name of reached) set.add(name);
194
202
  reach.set(grantKey, set);
195
203
  }
196
204
  }
205
+ const resourceOf = new Map([...keys].map(([entry, grantKey]) => [grantKey, entry.item.grant.permission.resource]));
197
206
  const out = [];
198
207
  for (const grantKey of new Set(keys.values())) {
199
208
  const at = grantKey.lastIndexOf("@");
200
209
  const base = at === -1 ? grantKey : grantKey.slice(0, at);
201
210
  const level = at === -1 ? void 0 : grantKey.slice(at + 1);
202
- for (const name of reach.get(base) ?? []) if (level === void 0 || level === name) out.push([grantKey, name]);
211
+ const covered = level === void 0 ? void 0 : coveredLevels(policy, resourceOf.get(grantKey) ?? "", [level]);
212
+ for (const name of reach.get(base) ?? []) if (covered === void 0 || covered.includes(name)) out.push([grantKey, name]);
203
213
  }
204
214
  return out.toSorted(([a, x], [b, y]) => a === b ? x < y ? -1 : 1 : a < b ? -1 : 1);
205
215
  }
206
216
  /**
207
- * The SQL command `action` compiles to: `rls.actions` first, then the six default verbs.
208
- * Any other verb is `undefined`, as `'none'` is: no policy, and its grants are still seeded.
217
+ * The SQL command `action` compiles to: `rls.actions` first, then the six
218
+ * default verbs. Any other verb is `undefined`, as `'none'` is: no policy, and
219
+ * its grants are still seeded.
209
220
  */
210
221
  function commandFor(action, actions) {
211
222
  if (actions !== void 0 && Object.hasOwn(actions, action)) {
@@ -214,7 +225,7 @@ function commandFor(action, actions) {
214
225
  }
215
226
  return defaultSqlCommand(action);
216
227
  }
217
- function tableFor$1(resource, tables) {
228
+ function tableFor(resource, tables) {
218
229
  return tables?.[resource] ?? resource;
219
230
  }
220
231
  function ancestorsOf(policy, name) {
@@ -262,8 +273,8 @@ function resourceCondition(item, policy, ctx) {
262
273
  }
263
274
  /**
264
275
  * The access a link capability has to a resource-scoped grant, over the same
265
- * holders as `resourceCondition`. It reads the claim, so ancestor hops need
266
- * no memberships table. `undefined` when no holder is on the row's chain.
276
+ * holders as `resourceCondition`. It reads the claim, so ancestor hops need no
277
+ * memberships table. `undefined` when no holder is on the row's chain.
267
278
  */
268
279
  function capabilityAccess(item, policy, ctx) {
269
280
  if (item.access.kind !== "resource") return;
@@ -279,7 +290,7 @@ function capabilityAccess(item, policy, ctx) {
279
290
  if (hops.length === 0) return;
280
291
  return hops.length === 1 ? hops[0] : hops.map(wrapSql).join(" or ");
281
292
  }
282
- function prepare(item, tables, warnings, skipClosures, actions, rowActions = false) {
293
+ function prepare(item, tables, warnings, skipClosures, sql, rowActions = false) {
283
294
  const { grant, label } = item;
284
295
  if (grant.breakGlass !== void 0) {
285
296
  warnings.push(`break-glass grant ${label}/${grant.permission.key} reads through permdock_break_glass_${grant.permission.resource}, not a policy`);
@@ -304,9 +315,14 @@ function prepare(item, tables, warnings, skipClosures, actions, rowActions = fal
304
315
  warnings.push(`skipped approval grant ${label}/${grant.permission.key}`);
305
316
  return;
306
317
  }
307
- const command = commandFor(grant.permission.action, actions);
308
- const table = tableFor$1(grant.permission.resource, tables);
318
+ const tableless = sql.tableless?.has(grant.permission.resource) === true;
319
+ const command = tableless ? void 0 : commandFor(grant.permission.action, sql.actions);
320
+ const table = tableFor(grant.permission.resource, tables);
309
321
  if (command === void 0) {
322
+ if (tableless && item.access.kind !== "role") {
323
+ warnings.push(`skipped ${label}/${grant.permission.key}: rls.tables.${grant.permission.resource} is false, so the resource has no table, and only role grants are seeded`);
324
+ return;
325
+ }
310
326
  if (item.access.kind !== "role" && rowActions) return {
311
327
  item,
312
328
  command: "none",
@@ -350,9 +366,9 @@ function signature(entry, byFields) {
350
366
  /**
351
367
  * Grant keys per permission: the key is the permission, split into
352
368
  * `permission#n` when role grants carry different portable conditions (or
353
- * effects), one key per condition group; a group whose grants set `group`
354
- * is `permission#<group>` instead. With field views, grants that differ
355
- * only in `fields` get their own keys too, so a view can tell them apart.
369
+ * effects), one key per condition group; a group whose grants set `group` is
370
+ * `permission#<group>` instead. With field views, grants that differ only in
371
+ * `fields` get their own keys too, so a view can tell them apart.
356
372
  */
357
373
  function assignKeys(entries, byFields) {
358
374
  const groups = /* @__PURE__ */ new Map();
@@ -372,7 +388,7 @@ function assignKeys(entries, byFields) {
372
388
  const group = groupOf(permission, list);
373
389
  if (group !== void 0 && named.has(group)) throw configError(`PermDock CLI: grants of ${permission} with different conditions share group '${group}'; a group names one condition`);
374
390
  if (group !== void 0) named.add(group);
375
- const grantKey = group !== void 0 ? `${permission}#${group}` : lists.length === 1 ? permission : `${permission}#${index + 1}`;
391
+ const grantKey = group === void 0 ? lists.length === 1 ? permission : `${permission}#${index + 1}` : `${permission}#${group}`;
376
392
  for (const entry of list) keys.set(entry, grantKey);
377
393
  }
378
394
  }
@@ -384,19 +400,19 @@ function groupOf(permission, list) {
384
400
  return names[0];
385
401
  }
386
402
  /**
387
- * One entry per level for every allow of an assignable role on a resource
388
- * with levels, keyed `<grant key>@<level>`. Only `permdock_custom_keys`
389
- * hands these keys out, to a custom role whose stored allow names the level.
403
+ * One entry per level for every allow of a role on a resource with levels,
404
+ * keyed `<grant key>@<level>`, whether or not the role is assignable: every
405
+ * role holds the same leveled keys, and `permdock_ceiling` keeps only the
406
+ * assignable roles'. Only `permdock_custom_keys` hands these keys out, to a
407
+ * custom role whose stored allow names the level.
390
408
  */
391
409
  function levelEntries(policy, ctx, keys, tables, warnings, skipClosures) {
392
- const custom = ctx.customRoles;
393
- if (custom?.levels !== true) return [];
394
- const assignable = new Set(custom.assignable);
410
+ if (ctx.customRoles?.levels !== true) return [];
395
411
  const out = [];
396
412
  for (const [entry, grantKey] of Array.from(keys)) {
397
413
  const { item } = entry;
398
414
  const { grant } = item;
399
- if (item.access.kind !== "role" || grant.effect !== "allow" || grant.permission.kind !== "instance" || !assignable.has(item.access.role)) continue;
415
+ if (item.access.kind !== "role" || grant.effect !== "allow" || grant.permission.kind !== "instance") continue;
400
416
  if (grant.permission.key.includes("@")) throw configError(`PermDock CLI: permission key '${grant.permission.key}' holds '@', which separates a level in custom-role grant keys`);
401
417
  for (const [level, condition] of policyLevels(policy, grant.permission.resource)) {
402
418
  const where = andWhere(item.where, condition);
@@ -404,7 +420,7 @@ function levelEntries(policy, ctx, keys, tables, warnings, skipClosures) {
404
420
  ...item,
405
421
  grant: leveled(grant, level, condition),
406
422
  ...where === void 0 ? {} : { where }
407
- }, tables, warnings, skipClosures, ctx.actions);
423
+ }, tables, warnings, skipClosures, ctx);
408
424
  if (prepared !== void 0) {
409
425
  keys.set(prepared, `${grantKey}@${level}`);
410
426
  out.push(prepared);
@@ -423,19 +439,22 @@ function noteConditions(entry, warnings) {
423
439
  if (hasConditionOp(entry.using, "opaque") || hasConditionOp(entry.check, "opaque")) warnings.push(`opaque SQL on ${label}/${grant.permission.key} is untestable app-side`);
424
440
  }
425
441
  /**
426
- * Compiles every grant (role and top-level) to branches whose role check is
427
- * a helper call keyed by grant key. Nothing in a branch is per-row except the
442
+ * Compiles every grant (role and top-level) to branches whose role check is a
443
+ * helper call keyed by grant key. Nothing in a branch is per-row except the
428
444
  * portable row condition and resource-membership joins.
429
445
  */
430
- /** A Supabase token from a permanent user: anonymous sign-ins carry `is_anonymous: true`. */
446
+ /**
447
+ * A Supabase token from a permanent user: anonymous sign-ins carry
448
+ * `is_anonymous: true`.
449
+ */
431
450
  const PERMANENT_USER = `((select auth.jwt()) ->> 'is_anonymous') is distinct from 'true'`;
432
451
  function compileGrants(policy, ctx, tables, warnings, skipClosures, rowActions = false) {
433
452
  const items = collectGrants(policy);
434
453
  const entries = items.flatMap((item) => {
435
- const entry = prepare(item, tables, warnings, skipClosures, ctx.actions, rowActions);
454
+ const entry = prepare(item, tables, warnings, skipClosures, ctx, rowActions);
436
455
  return entry === void 0 ? [] : [entry];
437
456
  });
438
- const keys = assignKeys(entries, ctx.fields === "views");
457
+ const keys = assignKeys(entries, ctx.fields !== void 0);
439
458
  entries.push(...levelEntries(policy, ctx, keys, tables, warnings, skipClosures));
440
459
  const conditionedKeys = /* @__PURE__ */ new Set();
441
460
  for (const [entry, grantKey] of keys) if (entry.using !== void 0 || entry.check !== void 0 || entry.item.grant.validity !== void 0 || entry.item.grant.requires !== void 0) conditionedKeys.add(grantKey);
@@ -492,7 +511,7 @@ function compileGrants(policy, ctx, tables, warnings, skipClosures, rowActions =
492
511
  };
493
512
  rows.set(`${row.role}\u0000${row.grantKey}\u0000${row.scope}`, row);
494
513
  }
495
- if (!rowActions) continue;
514
+ if (!rowActions || ctx.tableless?.has(grant.permission.resource) === true) continue;
496
515
  }
497
516
  const actionOnly = entry.command === "none";
498
517
  const command = actionOnly ? "select" : entry.command;
@@ -506,8 +525,10 @@ function compileGrants(policy, ctx, tables, warnings, skipClosures, rowActions =
506
525
  const grantKey = keys.get(entry);
507
526
  let accessExpr;
508
527
  if (access.kind === "role" && grantKey !== void 0) {
509
- const column = access.scope === "global" ? void 0 : scopeField(policy.resources.get(grant.permission.resource), access.scope, policy.scopes);
510
- accessExpr = accessSql(ctx, access.scope, grantKey, column);
528
+ const via = ctx.vias?.[grant.permission.resource];
529
+ if (via !== void 0 && access.scope !== "global" && access.scope !== via.scope) throw configError(`PermDock CLI: ${label}/${grant.permission.key} is granted at scope ${access.scope}, but rls.tables.${grant.permission.resource}.via reaches ${via.scope}; map the scope with via.scope or grant at ${via.scope}`);
530
+ const column = access.scope === "global" ? void 0 : via?.key ?? scopeField(policy.resources.get(grant.permission.resource), access.scope, policy.scopes);
531
+ accessExpr = accessSql(ctx, access.scope, grantKey, column, access.scope === "global" ? void 0 : via?.helper);
511
532
  if (column !== void 0) filters(grant.permission.resource, table, column);
512
533
  const row = {
513
534
  role: access.role,
@@ -529,8 +550,10 @@ function compileGrants(policy, ctx, tables, warnings, skipClosures, rowActions =
529
550
  accessExpr = andSql(accessExpr, validity);
530
551
  for (const key of grant.requires ?? []) accessExpr = andSql(accessExpr, requiresSql(ctx, key, policy.resources.get(grant.permission.resource)));
531
552
  if (ctx.anonymousSignIns === "deny" && access.kind !== "anyone") accessExpr = andSql(accessExpr, PERMANENT_USER);
532
- if (ctx.apiKeys !== void 0 && grant.effect === "allow" && access.kind !== "anyone" && access.kind !== "role") {
533
- const calls = (requiresStandIn(grant) ? grant.requires ?? [] : [grant.permission.key, ...grant.requires ?? []]).map((key) => `(select ${apiKeyAllowsCall(ctx, quoteLiteral(key))})`);
553
+ if ((ctx.apiKeys !== void 0 || ctx.tokenScopes !== void 0) && grant.effect === "allow" && access.kind !== "anyone" && access.kind !== "role") {
554
+ const covered = requiresStandIn(grant) ? grant.requires ?? [] : [grant.permission.key, ...grant.requires ?? []];
555
+ const ceilings = [...ctx.apiKeys === void 0 ? [] : [apiKeyAllowsCall], ...ctx.tokenScopes === void 0 ? [] : [tokenScopeAllowsCall]];
556
+ const calls = covered.flatMap((key) => ceilings.map((call) => `(select ${call(ctx, quoteLiteral(key))})`));
534
557
  accessExpr = andSql(accessExpr, calls.length === 1 ? calls[0] ?? "" : `(${calls.join(" and ")})`);
535
558
  }
536
559
  const using = compileOptional(entry.using, rowCtx);
@@ -576,8 +599,8 @@ function compileGrants(policy, ctx, tables, warnings, skipClosures, rowActions =
576
599
  }
577
600
  /**
578
601
  * Each row again under every key its permission was renamed from, so SQL that
579
- * still calls `permdock_has('<old key>')` keeps the access the current key
580
- * has. A split grant key (`key#n`) keeps its suffix; break-glass rows are not
602
+ * still calls `permdock_has('<old key>')` keeps the access the current key has.
603
+ * A split grant key (`key#n`) keeps its suffix; break-glass rows are not
581
604
  * copied.
582
605
  */
583
606
  function withAliasRows(policy, rows) {
@@ -596,8 +619,8 @@ function withAliasRows(policy, rows) {
596
619
  }
597
620
  /**
598
621
  * Postgres needs SELECT access to find rows for UPDATE / DELETE and for
599
- * RETURNING, so a table with only update or delete grants gets matching
600
- * SELECT branches.
622
+ * RETURNING, so a table with only update or delete grants gets matching SELECT
623
+ * branches.
601
624
  */
602
625
  function ensureSelectCoverage(branches, warnings) {
603
626
  const extra = [];
@@ -627,18 +650,21 @@ function ensureSelectCoverage(branches, warnings) {
627
650
  const HELPER_TABLES = ["storage.objects", "realtime.messages"];
628
651
  const HELPER_CALL = new RegExp(String.raw`\b(${HELPERS.has}(?:_permission)?|permitted_[a-z][a-z0-9_]*_ids(?:_by_permission)?)\s*\(\s*'((?:[^']|'')+)'(\s*,\s*(false\b)?)?`, "giu");
629
652
  const ANY_HELPER = new RegExp(String.raw`\b(?:${HELPERS.has}(?:_permission)?(?:_for)?|permitted_[a-z][a-z0-9_]*_ids(?:_by_permission)?(?:_for)?|member_[a-z][a-z0-9_]*_ids(?:_for)?)\s*\(`, "iu");
630
- /** Whether a policy expression calls any generated helper, the key-less `member_<scope>_ids` included. */
653
+ /**
654
+ * Whether a policy expression calls any generated helper, the key-less
655
+ * `member_<scope>_ids` included.
656
+ */
631
657
  function callsHelper(sql) {
632
658
  return ANY_HELPER.test(sql);
633
659
  }
634
660
  /**
635
661
  * The permission keys a policy expression passes to `permdock_has`,
636
662
  * `permitted_<scope>_ids` or their permission-key forms, `#n` stripped. With
637
- * `blind`, only the calls that ignore row conditions: the grant-key forms,
638
- * and a permission-key form asked for conditioned allows. A plain
663
+ * `blind`, only the calls that ignore row conditions: the grant-key forms, and
664
+ * a permission-key form asked for conditioned allows. A plain
639
665
  * `permdock_has_permission(key)` or `permitted_<scope>_ids_by_permission(key)`
640
- * counts only allows without a row condition, so it never grants more than
641
- * the application does.
666
+ * counts only allows without a row condition, so it never grants more than the
667
+ * application does.
642
668
  */
643
669
  function helperCallKeys(sql, blind = false) {
644
670
  const keys = /* @__PURE__ */ new Set();
@@ -658,7 +684,10 @@ function helperTable(name) {
658
684
  const table = tableName(name);
659
685
  return HELPER_TABLES.find((candidate) => candidate === table);
660
686
  }
661
- /** `create policy` statements on {@link HELPER_TABLES} in migration SQL, with the keys their condition-blind helper calls pass. */
687
+ /**
688
+ * `create policy` statements on {@link HELPER_TABLES} in migration SQL, with
689
+ * the keys their condition-blind helper calls pass.
690
+ */
662
691
  function helperTablePolicies(sql) {
663
692
  const text = sql.replaceAll(/--[^\n]*/gu, "").replaceAll(/\/\*[\s\S]*?\*\//gu, "");
664
693
  const found = [];
@@ -673,19 +702,25 @@ function helperTablePolicies(sql) {
673
702
  }
674
703
  return found;
675
704
  }
676
- /** `pg_policies` rows on {@link HELPER_TABLES}, read by `rls verify --db-url-stdin`. */
705
+ /**
706
+ * `pg_policies` rows on {@link HELPER_TABLES}, read by `rls verify
707
+ * --db-url-stdin`.
708
+ */
677
709
  const HELPER_TABLE_POLICIES_SQL = `select schemaname || '.' || tablename as target, policyname, coalesce(qual, '') || ' ' || coalesce(with_check, '') as body
678
710
  from pg_policies
679
711
  where (schemaname, tablename) in (('storage', 'objects'), ('realtime', 'messages'))`;
712
+ function textOf(value) {
713
+ return typeof value === "string" ? value : "";
714
+ }
680
715
  /** The same rows as {@link helperTablePolicies}, from `pg_policies`. */
681
716
  function helperTablePoliciesFromRows(rows) {
682
717
  const found = [];
683
718
  for (const row of rows) {
684
- const table = helperTable(String(row["target"] ?? ""));
685
- const keys = helperCallKeys(String(row["body"] ?? ""), true);
719
+ const table = helperTable(textOf(row["target"]));
720
+ const keys = helperCallKeys(textOf(row["body"]), true);
686
721
  if (table !== void 0 && keys.length > 0) found.push({
687
722
  table,
688
- name: String(row["policyname"] ?? ""),
723
+ name: textOf(row["policyname"]),
689
724
  keys
690
725
  });
691
726
  }
@@ -697,8 +732,196 @@ function rowConditionMessage(policy, keys) {
697
732
  }
698
733
  const ROW_CONDITION_FIX = "call permitted_<scope>_ids_by_permission('<key>') or permdock_has_permission('<key>'), which count only the allows without a row condition (a relationship grant never reaches a topic or a folder), or use a permission whose catalog entry has rowConditions: false";
699
734
  //#endregion
735
+ //#region src/cli/rls/verify-findings.ts
736
+ const VERIFY_DOCS = `${DOCS_BASE}/rls#verify`;
737
+ function rlsFinding(code, table, key, message, severity = "error") {
738
+ return {
739
+ code,
740
+ table,
741
+ key,
742
+ message,
743
+ severity
744
+ };
745
+ }
746
+ /** `<code>:<table>:<key>`: what `--ignore` and `rls.verify.ignore` name. */
747
+ function findingId(finding) {
748
+ return `${finding.code}:${finding.table}:${finding.key}`;
749
+ }
750
+ /** `rls.verify.ignore`, checked, then one entry per `--ignore` id. */
751
+ function verifyIgnores(config, flags = []) {
752
+ const entries = config.rls?.verify?.ignore ?? [];
753
+ if (!Array.isArray(entries)) throw configError("PermDock CLI: rls.verify.ignore must be a list of { id, reason }");
754
+ const out = [];
755
+ for (const [index, entry] of entries.entries()) {
756
+ if (!isRecord(entry) || typeof entry["id"] !== "string" || entry["id"] === "" || typeof entry["reason"] !== "string" || entry["reason"].trim() === "") throw configError(`PermDock CLI: rls.verify.ignore[${String(index)}] needs an id and a non-empty reason`);
757
+ out.push({
758
+ id: entry["id"],
759
+ reason: entry["reason"]
760
+ });
761
+ }
762
+ for (const id of flags) out.push({
763
+ id,
764
+ reason: "--ignore"
765
+ });
766
+ return out;
767
+ }
768
+ /**
769
+ * Splits `findings` by `ignores`; an id listed twice counts once, with its
770
+ * first reason.
771
+ */
772
+ function applyIgnores(findings, ignores) {
773
+ const reasons = /* @__PURE__ */ new Map();
774
+ for (const entry of ignores) if (!reasons.has(entry.id)) reasons.set(entry.id, entry.reason);
775
+ const matched = /* @__PURE__ */ new Set();
776
+ const kept = [];
777
+ const ignored = [];
778
+ for (const finding of findings) {
779
+ const id = findingId(finding);
780
+ const reason = reasons.get(id);
781
+ if (reason === void 0) kept.push({
782
+ ...finding,
783
+ id
784
+ });
785
+ else {
786
+ matched.add(id);
787
+ ignored.push({
788
+ id,
789
+ reason,
790
+ message: finding.message
791
+ });
792
+ }
793
+ }
794
+ return {
795
+ findings: kept,
796
+ ignored,
797
+ stale: [...reasons].filter(([id]) => !matched.has(id)).map(([id, reason]) => ({
798
+ id,
799
+ reason
800
+ }))
801
+ };
802
+ }
803
+ function prefixOf(severity) {
804
+ switch (severity) {
805
+ case "error": return "";
806
+ case "warning": return "warning: ";
807
+ case "info": return "info: ";
808
+ default: return severity;
809
+ }
810
+ }
811
+ /**
812
+ * The `rls verify` result: exit 1 when an error finding is left after the
813
+ * ignores. Text lines carry each finding's id; `--json` data is `{ findings,
814
+ * ignored, stale }`; `--format github|sarif` renders `findings`.
815
+ */
816
+ function verifyResult(input) {
817
+ const report = applyIgnores(input.findings, input.ignore);
818
+ const failed = report.findings.some((item) => item.severity === "error");
819
+ const lines = [
820
+ ...report.findings.map((item) => `${prefixOf(item.severity)}${item.message} [${item.id}]`),
821
+ ...report.ignored.map((item) => `ignored ${item.id}: ${item.reason}`),
822
+ ...report.stale.map((item) => `warning: ignore entry ${item.id} matches no finding; remove it from rls.verify.ignore`),
823
+ ...failed ? [] : [input.summary],
824
+ ...input.notes ?? []
825
+ ];
826
+ return {
827
+ code: failed ? 1 : 0,
828
+ output: lines.join("\n"),
829
+ data: report,
830
+ findings: [...report.findings.map((item) => ({
831
+ code: item.code,
832
+ id: item.id,
833
+ severity: item.severity,
834
+ message: item.message,
835
+ docs: VERIFY_DOCS
836
+ })), ...report.stale.map((item) => ({
837
+ code: "ignore-stale",
838
+ id: `ignore-stale:${item.id}`,
839
+ severity: "warning",
840
+ message: `ignore entry ${item.id} matches no finding`,
841
+ fix: "remove it from rls.verify.ignore",
842
+ docs: VERIFY_DOCS
843
+ }))]
844
+ };
845
+ }
846
+ //#endregion
847
+ //#region src/cli/rls/verify-pgtap-memberships.ts
848
+ function insert(table, columns) {
849
+ return `insert into ${quoteTable(table)} (${columns.map(([name]) => quoteIdent(name)).join(", ")}) values (${columns.map(([, value]) => quoteLiteral(value)).join(", ")}) on conflict do nothing;`;
850
+ }
851
+ /**
852
+ * The rows of a table mapped by `rls.memberships`: one per role, for a plain
853
+ * role column.
854
+ */
855
+ function mappedRows(config, scopes, user, membership) {
856
+ const { scope, id } = membership;
857
+ if (scope === void 0 || id === void 0) return [];
858
+ const table = scopeMembershipTable(config.rls?.memberships, scopes, scope);
859
+ const idColumn = table === void 0 ? void 0 : scopeColumn(table, scopes, scope);
860
+ const roleColumn = table?.role;
861
+ if (table === void 0 || idColumn === void 0 || typeof roleColumn !== "string") return [];
862
+ const rootName = rootScope(scopes);
863
+ const tenantColumn = rootName === void 0 || rootName === scope ? void 0 : scopeColumn(table, scopes, rootName);
864
+ const tenant = rootName === void 0 ? void 0 : membership.within?.[rootName];
865
+ const extra = [];
866
+ for (const [name, value] of Object.entries(membership.within ?? {})) {
867
+ const column = scopeColumn(table, scopes, name);
868
+ if (column !== void 0 && name !== scope) extra.push([column, value]);
869
+ }
870
+ if (tenantColumn !== void 0 && tenant !== void 0 && !extra.some(([column]) => column === tenantColumn)) extra.push([tenantColumn, tenant]);
871
+ return membership.roles.map((role) => insert(table.table, [
872
+ [table.user, user],
873
+ [idColumn, id],
874
+ ...extra,
875
+ [roleColumn, role]
876
+ ]));
877
+ }
878
+ /**
879
+ * The rows of a `membershipSources` source: only a source whose columns are
880
+ * plain, never a `through` or `map`.
881
+ */
882
+ function sourceRows(source, scopes, user, membership) {
883
+ const { scope, id } = membership;
884
+ if (scope === void 0 || id === void 0) return [];
885
+ const names = new Set(scopes.map((entry) => entry.name));
886
+ if ("through" in source.user || !names.has(scope) || "value" in source.scope && source.scope.value !== scope) return [];
887
+ const role = source.role;
888
+ const roleColumns = Array.isArray(role) || !("column" in role) || "through" in role ? void 0 : "map" in role ? void 0 : role.column;
889
+ const fixed = "value" in source.scope ? [] : [[source.scope.column, scope]];
890
+ const within = source.within;
891
+ const ancestors = within === void 0 || !("columns" in within) ? [] : Object.entries(within.columns).flatMap(([name, column]) => {
892
+ const value = membership.within?.[name];
893
+ return value === void 0 ? [] : [[column, value]];
894
+ });
895
+ const base = [
896
+ [source.user.column, user],
897
+ [source.id.column, id],
898
+ ...fixed,
899
+ ...ancestors
900
+ ];
901
+ if (roleColumns === void 0) return [];
902
+ return membership.roles.map((value) => insert(source.table, [...base, [roleColumns, value]]));
903
+ }
904
+ /**
905
+ * The statements that put a fixture's memberships into the configured
906
+ * membership tables and sources, so the helpers of `authorize: 'database'` find
907
+ * them. A membership no plain table or source can hold (a `through` or mapped
908
+ * role column, an `on` membership) is listed in a comment.
909
+ */
910
+ function fixtureMembershipSql(config, scopes, fixture, sources) {
911
+ const lines = [];
912
+ for (const membership of normalizeMemberships(fixture.subject.memberships ?? [], scopes)) {
913
+ const rows = [...mappedRows(config, scopes, fixture.subject.id, membership), ...sources.flatMap((source) => sourceRows(source, scopes, fixture.subject.id, membership))];
914
+ if (rows.length === 0) lines.push(`-- no membership table holds ${membership.scope ?? "on"} ${membership.id ?? ""}: not seeded`);
915
+ lines.push(...rows);
916
+ }
917
+ return lines;
918
+ }
919
+ //#endregion
700
920
  //#region src/cli/rls/verify-pgtap.ts
701
- /** A custom role's scope and pinned instance, as the `custom_role_*` tables store them. */
921
+ /**
922
+ * A custom role's scope and pinned instance, as the `custom_role_*` tables
923
+ * store them.
924
+ */
702
925
  function customRoleAt(role, scopes) {
703
926
  return {
704
927
  scope: customRoleScope(role, scopes),
@@ -751,7 +974,10 @@ function statementFor(fixture, action, table) {
751
974
  function rowId(row) {
752
975
  if (isRecord(row) && "id" in row) return row["id"];
753
976
  }
754
- /** A fixture value as a SQL literal; untyped, so it coerces to the column like a bound parameter. */
977
+ /**
978
+ * A fixture value as a SQL literal; untyped, so it coerces to the column like a
979
+ * bound parameter.
980
+ */
755
981
  function sqlValue(value) {
756
982
  if (value === null || value === void 0) return "null";
757
983
  return quoteLiteral(typeof value === "string" ? value : JSON.stringify(value));
@@ -784,12 +1010,24 @@ function subjectOf(config, customRoles, scopes) {
784
1010
  scopes
785
1011
  };
786
1012
  }
787
- /** The settings that bind a fixture's subject: the GUCs, or the Supabase JWT claims. */
1013
+ /**
1014
+ * The settings that bind a fixture's subject: the GUCs, or the Supabase JWT
1015
+ * claims.
1016
+ */
788
1017
  function subjectSettings(fixture, subject) {
789
1018
  const roles = fixture.subject.roles ?? [];
790
1019
  const memberships = membershipsClaim(fixture.subject.memberships ?? [], subject.customRoles, subject.scopes);
791
1020
  if (subject.dialect === "guc") {
1021
+ const fixed = /* @__PURE__ */ new Set([
1022
+ "user_id",
1023
+ "sub",
1024
+ "role",
1025
+ "memberships",
1026
+ subject.roleClaim,
1027
+ subject.tenantClaim
1028
+ ]);
792
1029
  const settings = [
1030
+ ...Object.entries(fixture.subject.claims ?? {}).flatMap(([name, value]) => fixed.has(name) || !SQL_IDENT.test(name) ? [] : [[`${subject.gucPrefix}.${name}`, typeof value === "string" ? value : JSON.stringify(value)]]),
793
1031
  [`${subject.gucPrefix}.user_id`, fixture.subject.id],
794
1032
  [`${subject.gucPrefix}.${subject.roleClaim}`, roles.join(",")],
795
1033
  [`${subject.gucPrefix}.memberships`, JSON.stringify(memberships)]
@@ -807,7 +1045,10 @@ function subjectSettings(fixture, subject) {
807
1045
  };
808
1046
  return [["request.jwt.claims", JSON.stringify(claims)]];
809
1047
  }
810
- /** The `custom_role_*` rows for the fixtures' custom roles; existing rows are kept. */
1048
+ /**
1049
+ * The `custom_role_*` rows for the fixtures' custom roles; existing rows are
1050
+ * kept.
1051
+ */
811
1052
  function customRoleRows(schema, customRoles, scopes) {
812
1053
  const table = (name) => `${quoteIdent(schema)}.${quoteIdent(name)}`;
813
1054
  const rows = [];
@@ -839,16 +1080,19 @@ function customRoleRows(schema, customRoles, scopes) {
839
1080
  }
840
1081
  return rows;
841
1082
  }
842
- function seedsCustomRoleTables(config) {
1083
+ function databaseMode(config) {
843
1084
  const rls = config.rls;
844
- return customRolesOn(rls) && (rls?.authorize ?? rls?.rbac?.authorize ?? "jwt") === "database";
1085
+ return (rls?.authorize ?? rls?.rbac?.authorize ?? "jwt") === "database";
1086
+ }
1087
+ function seedsCustomRoleTables(config) {
1088
+ return customRolesOn(config.rls) && databaseMode(config);
845
1089
  }
846
1090
  function customRoleSchema(config) {
847
1091
  return config.rls?.schema ?? config.rls?.rbac?.schema ?? "permdock";
848
1092
  }
849
1093
  /**
850
- * A pgTAP script that runs each fixture's statement under the fixture's
851
- * subject and asserts the outcome `can()` gave in-process.
1094
+ * A pgTAP script that runs each fixture's statement under the fixture's subject
1095
+ * and asserts the outcome `can()` gave in-process.
852
1096
  */
853
1097
  function emitPgtap(input) {
854
1098
  const scopes = scopeList(input.policy.scopes);
@@ -859,6 +1103,7 @@ function emitPgtap(input) {
859
1103
  PGTAP_DECISION_SQL
860
1104
  ];
861
1105
  if (seedsCustomRoleTables(input.config)) for (const row of customRoleRows(customRoleSchema(input.config), input.customRoles, scopes)) lines.push(`${inlineStatement(row)};`);
1106
+ const sources = membershipSourcesOf(input.config).map((source) => source.sql.manifest);
862
1107
  for (const [index, fixture] of input.fixtures.entries()) {
863
1108
  const permission = findPermission(input.policy.permissions, fixture.action);
864
1109
  const status = input.inProcess[index];
@@ -868,359 +1113,19 @@ function emitPgtap(input) {
868
1113
  lines.push(`select skip(${quoteLiteral(`${label}: opaque grant untestable app-side`)}, 1);`);
869
1114
  continue;
870
1115
  }
1116
+ if (input.config.rls?.tables?.[permission.resource] === false) {
1117
+ lines.push(`select skip(${quoteLiteral(`${label}: rls.tables.${permission.resource} is false, so there is no table`)}, 1);`);
1118
+ continue;
1119
+ }
871
1120
  const outcome = status.granted ? "granted" : "denied";
872
- const table = input.config.rls?.tables?.[permission.resource] ?? permission.resource;
1121
+ const table = tableNameOf(input.config.rls?.tables?.[permission.resource], permission.resource);
873
1122
  const statement = inlineStatement(statementFor(fixture, permission.action, table));
874
- lines.push(`-- ${label}`, "savepoint permdock_fixture;", "set local role \"authenticated\";", ...subjectSettings(fixture, subject).map(([name, value]) => `select set_config(${quoteLiteral(name)}, ${quoteLiteral(value)}, true);`), `select is(${PGTAP_DECISION}(${quoteLiteral(statement)}), ${quoteLiteral(outcome)}, ${quoteLiteral(`${label} ${outcome}`)});`, "rollback to savepoint permdock_fixture;");
1123
+ lines.push(`-- ${label}`, "savepoint permdock_fixture;", ...databaseMode(input.config) ? fixtureMembershipSql(input.config, scopes, fixture, sources) : [], "set local role \"authenticated\";", ...subjectSettings(fixture, subject).map(([name, value]) => `select set_config(${quoteLiteral(name)}, ${quoteLiteral(value)}, true);`), `select is(${PGTAP_DECISION}(${quoteLiteral(statement)}), ${quoteLiteral(outcome)}, ${quoteLiteral(`${label} ${outcome}`)});`, "rollback to savepoint permdock_fixture;");
875
1124
  }
876
1125
  lines.push("select * from finish();", "rollback;");
877
1126
  return `${lines.join("\n")}\n`;
878
1127
  }
879
1128
  //#endregion
880
- //#region src/cli/rls/graph.ts
881
- function tableFor(resource, tables) {
882
- return tables?.[resource] ?? resource;
883
- }
884
- /** Every `related` condition the policy's grants compile to, with the resource graph they need, groups included. */
885
- function graphPlan(policy) {
886
- const scopes = scopeList(policy.scopes);
887
- const plan = /* @__PURE__ */ new Map();
888
- const entryFor = (node) => {
889
- const entry = plan.get(node.name) ?? {
890
- node,
891
- relations: /* @__PURE__ */ new Set(),
892
- links: /* @__PURE__ */ new Set()
893
- };
894
- plan.set(node.name, entry);
895
- return entry;
896
- };
897
- const addRelation = (node, relation) => {
898
- const entry = entryFor(node);
899
- if (entry.relations.has(relation)) return;
900
- entry.relations.add(relation);
901
- for (const name of expandRelation(node, relation)) {
902
- const spec = node.relations[name];
903
- if (!isEdgeRelation(spec) || spec.groups === void 0) continue;
904
- for (const { resource, relation: groupRelation } of groupEntries(spec)) {
905
- const target = policy.resources.get(resource);
906
- if (target !== void 0 && target.name !== node.name) addRelation(target, groupRelation);
907
- }
908
- }
909
- };
910
- const addLinks = (hops) => {
911
- for (let index = 1; index < hops.length; index += 1) {
912
- const from = policy.resources.get(hops[index - 1]?.resource ?? "");
913
- const hop = hops[index];
914
- if (from !== void 0 && hop !== void 0) entryFor(from).links.add(hop.link);
915
- }
916
- };
917
- const addAbove = (above) => {
918
- const node = above === void 0 ? void 0 : policy.resources.get(above.resource);
919
- if (above === void 0 || node === void 0) return;
920
- const entry = entryFor(node);
921
- entry.closure = Math.max(entry.closure ?? 0, above.depth);
922
- entry.restrictedAncestors = above;
923
- };
924
- for (const grant of policy.grants) {
925
- const row = policy.resources.get(grant.permission.resource);
926
- for (const item of flattenGrantee(grant.to)) {
927
- if (item.kind === "inherit") {
928
- const inherited = inheritCondition(item, row, policy.resources);
929
- addLinks(inherited?.hops ?? []);
930
- addAbove(inherited?.restrictedAncestors);
931
- continue;
932
- }
933
- if (item.kind !== "relation") continue;
934
- const condition = relationCondition(item, row, scopes, { resources: policy.resources });
935
- if (condition?.op !== "related") continue;
936
- const node = policy.resources.get(condition.resource);
937
- if (node === void 0) continue;
938
- addRelation(node, condition.relation);
939
- const entry = entryFor(node);
940
- if (condition.depth > 0 && isSelfParented(node)) entry.closure = Math.max(entry.closure ?? 0, condition.depth);
941
- addLinks(condition.hops ?? []);
942
- addAbove(condition.restrictedAncestors);
943
- }
944
- }
945
- return plan;
946
- }
947
- /** The closure depth per walked resource, as `RlsSqlContext.graph` carries it. */
948
- function closureDepths(plan) {
949
- const out = {};
950
- for (const [name, entry] of plan) if (entry.closure !== void 0) out[name] = entry.closure;
951
- return out;
952
- }
953
- /**
954
- * The `permitted_<resource>_ids(relation)` arm for one concrete relation:
955
- * ids of `resource` the subject holds it on, directly or through a group.
956
- * `asked` are the relation names that include it, so a call for any of them
957
- * (or for all, with null) reads this arm.
958
- */
959
- function relationArm(ctx, plan, node, relation, asked, tables) {
960
- const spec = node.relations[relation];
961
- if (!isEdgeRelation(spec) && !isPrincipalRelation(spec) && (!isFieldRelation(spec) || spec.memberOf !== void 0)) throw configError(`PermDock CLI: relation '${relation}' on ${node.name} is not a graph relation RLS can compile`);
962
- const guard = asked.length === 1 ? `(p_relation is null or p_relation = ${quoteLiteral(asked[0] ?? relation)})` : `(p_relation is null or p_relation in (${asked.map(quoteLiteral).join(", ")}))`;
963
- return ` select a.id from (${graphSqlText(relationArmSql(node.name, relation, {
964
- resources: new Map([...plan].map(([name, item]) => [name, item.node])),
965
- ...tables === void 0 ? {} : { tables },
966
- qualify: qualifySqlTable,
967
- holders: (resource, groupRelation) => [{ text: `select ${qualified(ctx, graphHelper(resource))}(${quoteLiteral(groupRelation)})` }]
968
- }), ctx)}) a\n where ${guard}${activeUserSql(ctx).map((part) => ` and ${part}`).join("")}`;
969
- }
970
- function permittedSql(ctx, plan, entry, tables) {
971
- const fn = qualified(ctx, graphHelper(entry.node.name));
972
- const asked = [...entry.relations].toSorted();
973
- const arms = [...new Set(asked.flatMap((name) => expandRelation(entry.node, name)))].toSorted().map((relation) => relationArm(ctx, plan, entry.node, relation, asked.filter((name) => expandRelation(entry.node, name).includes(relation)), tables));
974
- if (arms.length === 0) arms.push(" select null::text where false");
975
- return `-- ${entry.node.name}: ids the subject holds a relation on (all relations when p_relation is null)
976
- create or replace function ${fn}(p_relation text)
977
- returns setof text
978
- language sql
979
- stable
980
- security definer
981
- set search_path = ''
982
- as $$
983
- ${arms.join("\n union\n")}
984
- $$;
985
- revoke execute on function ${fn}(text) from public, anon;
986
- grant execute on function ${fn}(text) to authenticated;`;
987
- }
988
- /** `permdock_link_<resource>_<link>(ids)`: ids of `resource` whose link points into `ids`, read past the table's own policies. */
989
- function linkSql(ctx, node, link, tables) {
990
- const spec = Object.hasOwn(node.links, link) ? node.links[link] : void 0;
991
- if (spec === void 0) throw configError(`PermDock CLI: ${node.name} has no link '${link}'`);
992
- const fn = qualified(ctx, linkHelper(node.name, link));
993
- return `-- ${node.name}.${link}: rows whose ${spec.field} points at one of the given ${spec.resource} ids
994
- create or replace function ${fn}(p_ids text[])
995
- returns setof text
996
- language sql
997
- stable
998
- security definer
999
- set search_path = ''
1000
- as $$
1001
- select t.${quoteIdent(node.id)}::text from ${quoteQualified(tableFor(node.name, tables))} t
1002
- where t.${quoteIdent(spec.field)}::text = any(p_ids)
1003
- $$;
1004
- revoke execute on function ${fn}(text[]) from public, anon;
1005
- grant execute on function ${fn}(text[]) to authenticated;`;
1006
- }
1007
- function closureTableSql(ctx) {
1008
- const table = qualified(ctx, CLOSURE.table);
1009
- return `-- the object graph: one row per (ancestor, descendant) within each walked resource's depth,
1010
- -- never crossing a restricted row; kept current by statement triggers on each self-parented table
1011
- create table if not exists ${table} (
1012
- resource text not null,
1013
- ancestor text not null,
1014
- descendant text not null,
1015
- depth integer not null check (depth >= 0),
1016
- primary key (resource, descendant, ancestor)
1017
- );
1018
- create index if not exists ${quoteIdent(`${CLOSURE.table}_ancestor`)} on ${table} (resource, ancestor);
1019
- alter table ${table} enable row level security;
1020
- revoke all on table ${table} from anon, authenticated, public;
1021
- grant select on table ${table} to authenticated;`;
1022
- }
1023
- function closureObjectsSql(ctx, entry, depth, tables) {
1024
- const { node } = entry;
1025
- const parent = node.parent;
1026
- if (parent === void 0) return "";
1027
- const name = node.name;
1028
- const sqlName = graphSqlName(name) ?? name;
1029
- const closure = qualified(ctx, CLOSURE.table);
1030
- const table = quoteQualified(tableFor(name, tables));
1031
- const id = quoteIdent(node.id);
1032
- const up = quoteIdent(parent.field);
1033
- const restricted = restrictedFor(node, "parent");
1034
- const stop = restricted === void 0 ? "false" : `coalesce(t.${quoteIdent(restricted)}, false)`;
1035
- const stopParent = restricted === void 0 ? "false" : `coalesce(p.${quoteIdent(restricted)}, false)`;
1036
- const refresh = qualified(ctx, `${CLOSURE.table}_${sqlName}`);
1037
- const changed = qualified(ctx, `${CLOSURE.table}_${sqlName}_changed`);
1038
- const literal = quoteLiteral(name);
1039
- const restrictedChanged = restricted === void 0 ? "" : ` or n.${quoteIdent(restricted)} is distinct from o.${quoteIdent(restricted)}`;
1040
- const trigger = (suffix) => quoteIdent(`${CLOSURE.table}_${sqlName}_${suffix}`);
1041
- return `-- ${name}: ${restricted === void 0 ? `rows reach their ancestors up to depth ${String(depth)}` : `rows reach their ancestors up to depth ${String(depth)}, stopping at a restricted row`}
1042
- drop policy if exists ${quoteIdent(`${CLOSURE.table}_${sqlName}`)} on ${closure};
1043
- create policy ${quoteIdent(`${CLOSURE.table}_${sqlName}`)} on ${closure}
1044
- for select to authenticated
1045
- using (resource = ${literal} and ancestor in (select ${qualified(ctx, graphHelper(name))}(null)));
1046
- create or replace function ${refresh}(p_ids text[])
1047
- returns void
1048
- language plpgsql
1049
- security definer
1050
- set search_path = ''
1051
- as $$
1052
- declare
1053
- v_cycle text;
1054
- v_affected text[];
1055
- begin
1056
- with recursive walk(start, next, path) as (
1057
- select t.${id}, t.${up}, array[t.${id}::text]
1058
- from ${table} t
1059
- where t.${id}::text = any(p_ids)
1060
- union all
1061
- select walk.start, t.${up}, walk.path || t.${id}::text
1062
- from walk join ${table} t on t.${id} = walk.next
1063
- where not (walk.next::text = any(walk.path))
1064
- )
1065
- select walk.start::text into v_cycle
1066
- from walk
1067
- where walk.next::text = any(walk.path)
1068
- limit 1;
1069
- if v_cycle is not null then
1070
- raise exception 'permdock: % % is its own ancestor', ${literal}, v_cycle
1071
- using errcode = 'check_violation';
1072
- end if;
1073
- with recursive down(id, level) as (
1074
- select t.${id}, 0
1075
- from ${table} t
1076
- where t.${id}::text = any(p_ids) or t.${up}::text = any(p_ids)
1077
- union
1078
- select t.${id}, down.level + 1
1079
- from down join ${table} t on t.${up} = down.id
1080
- where down.level < ${String(depth)}
1081
- )
1082
- select coalesce(array_agg(distinct down.id::text), '{}') into v_affected from down;
1083
- delete from ${closure} c
1084
- where c.resource = ${literal}
1085
- and (c.descendant = any(p_ids) or c.descendant = any(v_affected));
1086
- insert into ${closure} (resource, ancestor, descendant, depth)
1087
- with recursive walk(descendant, ancestor, parent, depth, stop) as (
1088
- select t.${id}::text, t.${id}, t.${up}, 0, ${stop}
1089
- from ${table} t
1090
- where t.${id}::text = any(v_affected)
1091
- union all
1092
- select walk.descendant, p.${id}, p.${up}, walk.depth + 1, ${stopParent}
1093
- from walk join ${table} p on p.${id} = walk.parent
1094
- where not walk.stop and walk.depth < ${String(depth)}
1095
- )
1096
- select ${literal}, walk.ancestor::text, walk.descendant, walk.depth from walk
1097
- on conflict do nothing;
1098
- end
1099
- $$;
1100
- revoke execute on function ${refresh}(text[]) from public, anon, authenticated;
1101
- create or replace function ${changed}()
1102
- returns trigger
1103
- language plpgsql
1104
- security definer
1105
- set search_path = ''
1106
- as $$
1107
- begin
1108
- if tg_op = 'TRUNCATE' then
1109
- delete from ${closure} where resource = ${literal};
1110
- elsif tg_op = 'INSERT' then
1111
- perform ${refresh}(array(select n.${id}::text from new_rows n));
1112
- elsif tg_op = 'DELETE' then
1113
- perform ${refresh}(array(select o.${id}::text from old_rows o));
1114
- else
1115
- perform ${refresh}(array(
1116
- select n.${id}::text
1117
- from new_rows n left join old_rows o on o.${id} = n.${id}
1118
- where o.${id} is null or n.${up} is distinct from o.${up}${restrictedChanged}
1119
- union
1120
- select o.${id}::text
1121
- from old_rows o left join new_rows n on n.${id} = o.${id}
1122
- where n.${id} is null
1123
- ));
1124
- end if;
1125
- return null;
1126
- end
1127
- $$;
1128
- revoke execute on function ${changed}() from public, anon, authenticated;
1129
- drop trigger if exists ${trigger("insert")} on ${table};
1130
- create trigger ${trigger("insert")} after insert on ${table}
1131
- referencing new table as new_rows
1132
- for each statement execute function ${changed}();
1133
- drop trigger if exists ${trigger("update")} on ${table};
1134
- create trigger ${trigger("update")} after update on ${table}
1135
- referencing old table as old_rows new table as new_rows
1136
- for each statement execute function ${changed}();
1137
- drop trigger if exists ${trigger("delete")} on ${table};
1138
- create trigger ${trigger("delete")} after delete on ${table}
1139
- referencing old table as old_rows
1140
- for each statement execute function ${changed}();
1141
- drop trigger if exists ${trigger("truncate")} on ${table};
1142
- create trigger ${trigger("truncate")} after truncate on ${table}
1143
- for each statement execute function ${changed}();
1144
- select ${refresh}(array(select t.${id}::text from ${table} t));`;
1145
- }
1146
- function restrictedRowsHelperSql(ctx, plan, entry, tables) {
1147
- const above = entry.restrictedAncestors;
1148
- if (above === void 0) return "";
1149
- const fn = qualified(ctx, restrictedHelper(entry.node.name));
1150
- const body = graphSqlText(restrictedRowsSql(above, {
1151
- resources: new Map([...plan].map(([name, item]) => [name, item.node])),
1152
- ...tables === void 0 ? {} : { tables },
1153
- qualify: qualifySqlTable,
1154
- closure: `${helperSchema(ctx)}.${CLOSURE.table}`,
1155
- closureDepths: closureDepths(plan)
1156
- }), ctx);
1157
- return `-- ${entry.node.name}: rows a stopped link does not reach below: restricted, under a restricted row within ${String(above.depth - 1)} levels, or deeper
1158
- create or replace function ${fn}()
1159
- returns setof text
1160
- language sql
1161
- stable
1162
- security definer
1163
- set search_path = ''
1164
- as $$
1165
- ${body}
1166
- $$;
1167
- revoke execute on function ${fn}() from public, anon;
1168
- grant execute on function ${fn}() to authenticated;`;
1169
- }
1170
- /** Group resources a resource's asked relations name, other than itself. */
1171
- function groupTargets(entry) {
1172
- const out = /* @__PURE__ */ new Set();
1173
- for (const asked of entry.relations) for (const name of expandRelation(entry.node, asked)) {
1174
- const spec = entry.node.relations[name];
1175
- const resources = isEdgeRelation(spec) ? groupEntries(spec).map((group) => group.resource) : [];
1176
- for (const resource of resources) if (resource !== entry.node.name) out.add(resource);
1177
- }
1178
- return [...out].toSorted();
1179
- }
1180
- /** Plan entries by name, each after the group resources its helper calls (SQL function bodies are checked on create). */
1181
- function dependencyOrder(plan) {
1182
- const out = [];
1183
- const done = /* @__PURE__ */ new Set();
1184
- const visit = (name) => {
1185
- const entry = plan.get(name);
1186
- if (entry === void 0 || done.has(name)) return;
1187
- done.add(name);
1188
- for (const target of groupTargets(entry)) visit(target);
1189
- out.push(entry);
1190
- };
1191
- for (const name of [...plan.keys()].toSorted()) visit(name);
1192
- return out;
1193
- }
1194
- /**
1195
- * The graph preamble: `permitted_<resource>_ids` for every resource a graph
1196
- * grant reads, and the closure table with its triggers for every
1197
- * self-parented resource a grant walks. Empty when no grant is a graph grant.
1198
- */
1199
- function graphSql(ctx, plan, tables) {
1200
- if (plan.size === 0) return "";
1201
- const sqlNames = /* @__PURE__ */ new Map();
1202
- for (const name of plan.keys()) {
1203
- const helper = graphHelper(name);
1204
- const sql = graphSqlName(name) ?? name;
1205
- if (ctx.scopes.some((scope) => scope.name === sql)) throw configError(`PermDock CLI: resource '${name}' has graph relations and shares its SQL name with the ${sql} scope, so ${helper} would replace the scope helper; rename the resource (permdock doctor PD032)`);
1206
- const other = sqlNames.get(sql);
1207
- if (other !== void 0) throw configError(`PermDock CLI: resources '${other}' and '${name}' both name the SQL helper ${helper}; rename one (permdock doctor PD032)`);
1208
- sqlNames.set(sql, name);
1209
- }
1210
- const entries = dependencyOrder(plan);
1211
- const chunks = entries.flatMap((entry) => [...entry.relations.size === 0 && entry.closure === void 0 ? [] : [permittedSql(ctx, plan, entry, tables)], ...[...entry.links].toSorted().map((link) => linkSql(ctx, entry.node, link, tables))]);
1212
- const walked = entries.filter((entry) => entry.closure !== void 0);
1213
- if (walked.length > 0) {
1214
- chunks.push(closureTableSql(ctx));
1215
- for (const entry of walked) chunks.push(closureObjectsSql(ctx, entry, entry.closure ?? 0, tables));
1216
- for (const entry of walked) {
1217
- const helper = restrictedRowsHelperSql(ctx, plan, entry, tables);
1218
- if (helper !== "") chunks.push(helper);
1219
- }
1220
- }
1221
- return `${chunks.join("\n\n")}\n`;
1222
- }
1223
- //#endregion
1224
1129
  //#region src/cli/rls/verify-tree.ts
1225
1130
  const SYSTEM_ENTROPY = Object.freeze({
1226
1131
  now: () => nowMillis(),
@@ -1236,9 +1141,9 @@ function idFactory(node, entropy) {
1236
1141
  } : () => entropy.randomUUID();
1237
1142
  }
1238
1143
  /**
1239
- * Two spines one level deeper than the walk depth, so the depth cap is
1240
- * crossed; side branches under the first levels alternate restricted, and
1241
- * the second spine is restricted two levels down.
1144
+ * Two spines one level deeper than the walk depth, so the depth cap is crossed;
1145
+ * side branches under the first levels alternate restricted, and the second
1146
+ * spine is restricted two levels down.
1242
1147
  */
1243
1148
  function generateTree(node, depth, entropy) {
1244
1149
  const id = idFactory(node, entropy);
@@ -1359,9 +1264,9 @@ function asRequiredColumn(row) {
1359
1264
  };
1360
1265
  }
1361
1266
  /**
1362
- * Values for the required columns a generated row leaves out, such as a
1363
- * tenant column or a name: an existing value of the referenced table for a
1364
- * foreign key, a placeholder of the column's type otherwise.
1267
+ * Values for the required columns a generated row leaves out, such as a tenant
1268
+ * column or a name: an existing value of the referenced table for a foreign
1269
+ * key, a placeholder of the column's type otherwise.
1365
1270
  */
1366
1271
  async function requiredValues(query, table, set, entropy) {
1367
1272
  const columns = (await query(REQUIRED_COLUMNS_SQL, [table])).rows.map(asRequiredColumn).filter((column) => column !== void 0 && !set.has(column.name));
@@ -1391,15 +1296,15 @@ async function seedRows(query, table, rows, given, entropy) {
1391
1296
  }
1392
1297
  /**
1393
1298
  * Parity between `decide` and RLS on a generated object graph: for every
1394
- * self-parented resource a graph grant walks, a tree with restricted
1395
- * branches and a chain past the walk depth, child rows under it, and edges
1396
- * for a few generated principals. Everything runs in one transaction that
1397
- * is rolled back.
1299
+ * self-parented resource a graph grant walks, a tree with restricted branches
1300
+ * and a chain past the walk depth, child rows under it, and edges for a few
1301
+ * generated principals. Everything runs in one transaction that is rolled
1302
+ * back.
1398
1303
  */
1399
1304
  async function verifyTree(input) {
1400
1305
  const { policy, query } = input;
1401
1306
  const entropy = input.entropy ?? SYSTEM_ENTROPY;
1402
- const tables = input.config.rls?.tables;
1307
+ const tables = tableNames(input.config.rls?.tables);
1403
1308
  const treeValues = input.config.rls?.treeValues ?? {};
1404
1309
  const seed = (table, list) => seedRows(query, table, list, treeValues[table] ?? {}, entropy);
1405
1310
  const walked = [...graphPlan(policy).values()].filter((entry) => entry.closure !== void 0);
@@ -1506,7 +1411,7 @@ async function verifyTree(input) {
1506
1411
  checked += 1;
1507
1412
  const id = String(row[node.id]);
1508
1413
  const allowed = permdock.can(permission, row);
1509
- if (allowed !== seen.has(id)) mismatches.push(`${permission.key} ${id}: in-process ${allowed ? "granted" : "denied"}, database ${seen.has(id) ? "allowed" : "filtered"}`);
1414
+ if (allowed !== seen.has(id)) mismatches.push(rlsFinding("tree-mismatch", node.name, permission.key, `${permission.key} ${id}: in-process ${allowed ? "granted" : "denied"}, database ${seen.has(id) ? "allowed" : "filtered"}`));
1510
1415
  else if (allowed) granted += 1;
1511
1416
  }
1512
1417
  }
@@ -1520,6 +1425,10 @@ async function verifyTree(input) {
1520
1425
  }
1521
1426
  //#endregion
1522
1427
  //#region src/cli/rls/verify-database.ts
1428
+ /** A fixture's part of a finding id: its subject and row. */
1429
+ function fixtureKey(fixture) {
1430
+ return `${fixture.subject.id}/${String(rowId(fixture.row))}`;
1431
+ }
1523
1432
  /** Columns of `row` that hold a value; a masked column reads as null. */
1524
1433
  function valuedColumns(row) {
1525
1434
  return isRecord(row) ? Object.keys(row).filter((name) => row[name] !== null && row[name] !== void 0).toSorted() : [];
@@ -1536,10 +1445,14 @@ function expectedFields(granted, picked, key, row) {
1536
1445
  }
1537
1446
  function fieldsMismatch(fixture, want, seen) {
1538
1447
  const kept = want.join(", ");
1539
- if (typeof seen === "string") return [`${fixture.action}: field view read failed (${seen}), pick keeps [${kept}]`];
1540
- return seen.join(", ") === kept ? [] : [`${fixture.action} ${String(rowId(fixture.row))}: field view returns [${seen.join(", ")}], pick keeps [${kept}]`];
1448
+ const mismatch = (message) => rlsFinding("field-mismatch", fixture.action, fixtureKey(fixture), message);
1449
+ if (typeof seen === "string") return [mismatch(`${fixture.action}: field view read failed (${seen}), pick keeps [${kept}]`)];
1450
+ return seen.join(", ") === kept ? [] : [mismatch(`${fixture.action} ${String(rowId(fixture.row))}: field view returns [${seen.join(", ")}], pick keeps [${kept}]`)];
1541
1451
  }
1542
- /** The field view's columns for the fixture's row: the view, or the table itself when no grant limits its fields. */
1452
+ /**
1453
+ * The field view's columns for the fixture's row: the view, or the table itself
1454
+ * when no grant limits its fields.
1455
+ */
1543
1456
  async function viewFields(query, table, key) {
1544
1457
  const view = quoteTable(viewName(table, FIELD_VIEWS.view));
1545
1458
  const id = quoteIdent("id");
@@ -1551,7 +1464,10 @@ async function viewFields(query, table, key) {
1551
1464
  const base = await query(`select * from ${quoteTable(table)} where ${id} = $1`, [key]);
1552
1465
  return base.code ?? valuedColumns(base.rows[0]);
1553
1466
  }
1554
- /** Writes the custom roles into the `database`-mode tables; the fixture transaction rolls them back. */
1467
+ /**
1468
+ * Writes the custom roles into the `database`-mode tables; the fixture
1469
+ * transaction rolls them back.
1470
+ */
1555
1471
  async function seedCustomRoles(query, schema, customRoles, scopes) {
1556
1472
  for (const row of customRoleRows(schema, customRoles, scopes)) {
1557
1473
  const result = await query(row.sql, row.values);
@@ -1590,7 +1506,7 @@ async function verifyAgainstDatabase(input) {
1590
1506
  const conditioned = policyRowConditionKeys(input.policy);
1591
1507
  for (const found of helperTablePoliciesFromRows((await query(HELPER_TABLE_POLICIES_SQL)).rows)) {
1592
1508
  const keys = found.keys.filter((key) => conditioned.has(key));
1593
- if (keys.length > 0) mismatches.push(`PD037 ${rowConditionMessage(found, keys)}`);
1509
+ if (keys.length > 0) mismatches.push(rlsFinding("condition-blind", found.table, found.name, `PD037 ${rowConditionMessage(found, keys)}`));
1594
1510
  }
1595
1511
  for (const [index, fixture] of input.fixtures.entries()) {
1596
1512
  const permission = findPermission(input.policy.permissions, fixture.action);
@@ -1600,7 +1516,11 @@ async function verifyAgainstDatabase(input) {
1600
1516
  notes.push(`${fixture.action}: opaque grant untestable app-side`);
1601
1517
  continue;
1602
1518
  }
1603
- const table = input.config.rls?.tables?.[permission.resource] ?? permission.resource;
1519
+ if (input.config.rls?.tables?.[permission.resource] === false) {
1520
+ notes.push(`${fixture.action}: rls.tables.${permission.resource} is false, so there is no table`);
1521
+ continue;
1522
+ }
1523
+ const table = tableNameOf(input.config.rls?.tables?.[permission.resource], permission.resource);
1604
1524
  await query("begin");
1605
1525
  try {
1606
1526
  if (seedsTables) await seedCustomRoles(query, schema, input.customRoles, scopes);
@@ -1609,7 +1529,7 @@ async function verifyAgainstDatabase(input) {
1609
1529
  const result = await query(statement.sql, statement.values);
1610
1530
  const count = result.rowCount ?? result.rows.length;
1611
1531
  const database = result.code === "42501" ? "rejected" : count > 0 ? "allowed" : "filtered";
1612
- if (!(status.granted ? database === "allowed" : database === "filtered" || database === "rejected")) mismatches.push(`${fixture.action}: in-process ${status.granted ? "granted" : "denied"}, database ${database}`);
1532
+ if (!(status.granted ? database === "allowed" : database === "filtered" || database === "rejected")) mismatches.push(rlsFinding("parity-mismatch", fixture.action, fixtureKey(fixture), `${fixture.action}: in-process ${status.granted ? "granted" : "denied"}, database ${database}`));
1613
1533
  else if (status.kind === "sqlFunction") notes.push(`${fixture.action}: verified through twin`);
1614
1534
  mismatches.push(...status.fields === void 0 ? [] : fieldsMismatch(fixture, status.fields, await viewFields(query, table, rowId(fixture.row))));
1615
1535
  } finally {
@@ -1624,8 +1544,11 @@ async function verifyAgainstDatabase(input) {
1624
1544
  notes
1625
1545
  };
1626
1546
  }
1627
- /** `--tree`: seeds a generated object graph in a rolled-back transaction and compares `can()` with RLS. */
1628
- async function verifyTreeAgainstDatabase(db, policy, config, connect) {
1547
+ /**
1548
+ * `--tree`: seeds a generated object graph in a rolled-back transaction and
1549
+ * compares `can()` with RLS.
1550
+ */
1551
+ async function verifyTreeAgainstDatabase(db, policy, config, connect, ignore) {
1629
1552
  const client = await connect(db);
1630
1553
  const scopes = scopeList(policy.scopes);
1631
1554
  const query = async (sql, values) => {
@@ -1647,15 +1570,12 @@ async function verifyTreeAgainstDatabase(db, policy, config, connect) {
1647
1570
  action: "read"
1648
1571
  }, subjectOf(config, [], scopes))
1649
1572
  });
1650
- if (result.mismatches.length > 0) return {
1651
- code: 1,
1652
- output: [...result.mismatches, ...result.notes].join("\n")
1653
- };
1654
- const verified = `verified ${String(result.checked)} tree check(s) against the database (${String(result.granted)} granted)`;
1655
- return {
1656
- code: 0,
1657
- output: result.notes.length === 0 ? verified : `${verified}\n${result.notes.join("\n")}`
1658
- };
1573
+ return verifyResult({
1574
+ findings: result.mismatches,
1575
+ ignore,
1576
+ notes: result.notes,
1577
+ summary: `verified ${String(result.checked)} tree check(s) against the database (${String(result.granted)} granted)`
1578
+ });
1659
1579
  } catch (cause) {
1660
1580
  return {
1661
1581
  code: 2,
@@ -1668,6 +1588,8 @@ async function verifyTreeAgainstDatabase(db, policy, config, connect) {
1668
1588
  }
1669
1589
  //#endregion
1670
1590
  //#region src/cli/rls/verify.ts
1591
+ /** Where `rls verify --kind pgtap` writes, the folder `supabase test db` reads. */
1592
+ const PGTAP_OUT = "supabase/tests/permdock_rls.test.sql";
1671
1593
  function canFixture(permdock, permission, row) {
1672
1594
  if (permission.kind === "collection") return permdock.can(permission, row);
1673
1595
  return permdock.can(permission, row);
@@ -1679,6 +1601,11 @@ function grantKind(policy, key) {
1679
1601
  return "portable";
1680
1602
  }
1681
1603
  async function runRlsVerify(input) {
1604
+ const ignore = input.ignore ?? [];
1605
+ if (input.out !== void 0 && input.format !== "pgtap") return {
1606
+ code: 2,
1607
+ output: "PermDock CLI: rls verify --out needs --kind pgtap"
1608
+ };
1682
1609
  const connect = input.connect ?? pgConnector("permdock rls verify --db-url-stdin", input.cwd);
1683
1610
  const policyPath = input.from ?? input.config.policy;
1684
1611
  if (policyPath === void 0) return {
@@ -1692,7 +1619,7 @@ async function runRlsVerify(input) {
1692
1619
  output: "PermDock CLI: rls verify --tree needs a database: --db-url-stdin, DATABASE_URL or SUPABASE_DB_URL"
1693
1620
  };
1694
1621
  try {
1695
- return await verifyTreeAgainstDatabase(input.db, policy, input.config, connect);
1622
+ return await verifyTreeAgainstDatabase(input.db, policy, input.config, connect, ignore);
1696
1623
  } catch (cause) {
1697
1624
  return usageResult(cause);
1698
1625
  }
@@ -1702,11 +1629,11 @@ async function runRlsVerify(input) {
1702
1629
  const mismatches = [];
1703
1630
  const notes = [];
1704
1631
  const inProcess = [];
1705
- const fieldsMode = input.config.rls?.fields === "views";
1632
+ const fieldsMode = input.config.rls?.fields !== void 0;
1706
1633
  for (const fixture of fixtures) {
1707
1634
  const permission = findPermission(policy.permissions, fixture.action);
1708
1635
  if (permission === void 0) {
1709
- mismatches.push(`${fixture.action}: unknown permission`);
1636
+ mismatches.push(rlsFinding("unknown-permission", fixture.action, fixtureKey(fixture), `${fixture.action}: unknown permission`));
1710
1637
  inProcess.push({
1711
1638
  action: fixture.action,
1712
1639
  granted: false,
@@ -1718,7 +1645,7 @@ async function runRlsVerify(input) {
1718
1645
  const permdock = await getPermDock(policy, fixtureSubject(fixture.subject), { customRoles: memoryCustomRoleSource(customRoles) });
1719
1646
  const granted = canFixture(permdock, permission, fixtureRow(fixture, permission.kind));
1720
1647
  const outcome = granted ? "granted" : "denied";
1721
- if (fixture.expected !== void 0 && fixture.expected !== outcome) mismatches.push(`${fixture.action}: in-process ${outcome}, expected ${fixture.expected}`);
1648
+ if (fixture.expected !== void 0 && fixture.expected !== outcome) mismatches.push(rlsFinding("expected-mismatch", fixture.action, fixtureKey(fixture), `${fixture.action}: in-process ${outcome}, expected ${fixture.expected}`));
1722
1649
  if (kind === "opaque") notes.push(`${fixture.action}: opaque grant untestable app-side`);
1723
1650
  const fields = fieldsMode && permission.kind === "instance" && commandFor(permission.action, input.config.rls?.actions) === "select" ? expectedFields(granted, permdock.pick(permission, fixture.row), policy.resources.get(permission.resource)?.id ?? "id", fixture.row) : void 0;
1724
1651
  inProcess.push({
@@ -1728,19 +1655,23 @@ async function runRlsVerify(input) {
1728
1655
  ...fields === void 0 ? {} : { fields }
1729
1656
  });
1730
1657
  }
1731
- if (input.format === "pgtap") return mismatches.length > 0 ? {
1732
- code: 1,
1733
- output: mismatches.join("\n")
1734
- } : {
1735
- code: 0,
1736
- output: emitPgtap({
1658
+ if (input.format === "pgtap") {
1659
+ const outRel = input.out ?? PGTAP_OUT;
1660
+ const result = verifyResult({
1661
+ findings: mismatches,
1662
+ ignore,
1663
+ summary: `wrote ${outRel}`
1664
+ });
1665
+ if (result.code !== 0) return result;
1666
+ writeFileEnsuringDir(resolve(input.cwd, outRel), emitPgtap({
1737
1667
  fixtures,
1738
1668
  inProcess,
1739
1669
  policy,
1740
1670
  config: input.config,
1741
1671
  customRoles
1742
- })
1743
- };
1672
+ }));
1673
+ return result;
1674
+ }
1744
1675
  if (input.db !== void 0) try {
1745
1676
  const database = await verifyAgainstDatabase({
1746
1677
  db: input.db,
@@ -1756,15 +1687,12 @@ async function runRlsVerify(input) {
1756
1687
  } catch (cause) {
1757
1688
  return usageResult(cause);
1758
1689
  }
1759
- if (mismatches.length > 0) return {
1760
- code: 1,
1761
- output: [...mismatches, ...notes].join("\n")
1762
- };
1763
- const verified = `verified ${String(fixtures.length)} fixture(s) ${input.db === void 0 ? "in-process" : "in-process and against the database"}`;
1764
- return {
1765
- code: 0,
1766
- output: notes.length === 0 ? verified : `${verified}\n${notes.join("\n")}`
1767
- };
1690
+ return verifyResult({
1691
+ findings: mismatches,
1692
+ ignore,
1693
+ notes,
1694
+ summary: `verified ${String(fixtures.length)} fixture(s) ${input.db === void 0 ? "in-process" : "in-process and against the database"}`
1695
+ });
1768
1696
  }
1769
1697
  //#endregion
1770
- export { indexesSql as _, graphSql as a, callsHelper as c, rowConditionMessage as d, commandFor as f, indexTargets as g, COLUMNS_SQL as h, graphPlan as i, helperCallKeys as l, tableFor$1 as m, runRlsVerify as n, HELPER_TABLES as o, compileGrants as p, closureDepths as r, ROW_CONDITION_FIX as s, canFixture as t, helperTablePolicies as u, pruneIndexTargets as v, readTableIndexFacts as y };
1698
+ export { indexTargets as _, verifyResult as a, readTableIndexFacts as b, callsHelper as c, rowConditionMessage as d, commandFor as f, INDEX_COLUMNS_SQL as g, COLUMNS_SQL as h, verifyIgnores as i, helperCallKeys as l, tableFor as m, runRlsVerify as n, HELPER_TABLES as o, compileGrants as p, rlsFinding as r, ROW_CONDITION_FIX as s, canFixture as t, helperTablePolicies as u, indexesSql as v, pruneIndexTargets as y };