permdock 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/README.md +327 -1
  2. package/dist/a2a/index.d.ts +169 -0
  3. package/dist/a2a/index.js +232 -0
  4. package/dist/adapter-context-mlWsVGGg.js +23 -0
  5. package/dist/ai-sdk/index.d.ts +95 -0
  6. package/dist/ai-sdk/index.js +154 -0
  7. package/dist/approval-required-TzNB9oQA.js +6 -0
  8. package/dist/approvals/index.d.ts +3 -0
  9. package/dist/approvals/index.js +5 -0
  10. package/dist/approvals-DbYAuNkG.js +224 -0
  11. package/dist/approvers-DT4AVyIg.js +52 -0
  12. package/dist/arazzo-BAgw9ap6.js +70 -0
  13. package/dist/arazzo-cmvX2jDe.js +54 -0
  14. package/dist/authzen/index.d.ts +39 -0
  15. package/dist/authzen/index.js +302 -0
  16. package/dist/better-auth/index.d.ts +109 -0
  17. package/dist/better-auth/index.js +344 -0
  18. package/dist/better-supabase/index.d.ts +206 -0
  19. package/dist/better-supabase/index.js +620 -0
  20. package/dist/bind-CVy3Espv.d.ts +25 -0
  21. package/dist/bind-VnYn2HKq.js +97 -0
  22. package/dist/boundary-BM8a_P6E.js +13 -0
  23. package/dist/boundary-BmHxVH1J.d.ts +15 -0
  24. package/dist/budget-JqcRqyhK.d.ts +11 -0
  25. package/dist/budget-NbEtbJC_.js +11 -0
  26. package/dist/canonical-json-DemiK4Vp.js +26 -0
  27. package/dist/capability-4qPdO9gk.js +173 -0
  28. package/dist/capability-Dq43tT1u.d.ts +99 -0
  29. package/dist/catalog/index.d.ts +12 -0
  30. package/dist/catalog/index.js +2 -0
  31. package/dist/catalog-BjZSovXQ.js +2 -0
  32. package/dist/catalog-doc-Dsc9y7sd.js +309 -0
  33. package/dist/catalog-h2tlKFkq.js +48 -0
  34. package/dist/catalog-path-CnI0XTFK.js +12 -0
  35. package/dist/catalog-z8q6bi_r.js +55 -0
  36. package/dist/claude-agent/index.d.ts +72 -0
  37. package/dist/claude-agent/index.js +77 -0
  38. package/dist/clerk/index.d.ts +65 -0
  39. package/dist/clerk/index.js +301 -0
  40. package/dist/cli/bin.d.ts +1 -0
  41. package/dist/cli/bin.js +20 -0
  42. package/dist/cli/index.d.ts +46 -0
  43. package/dist/cli/index.js +5 -0
  44. package/dist/clients-C7zLFuWT.d.ts +12 -0
  45. package/dist/clients-DjU5ABMy.js +23 -0
  46. package/dist/cloud/index.d.ts +90 -0
  47. package/dist/cloud/index.js +404 -0
  48. package/dist/cloud-BGhHS-lY.js +50 -0
  49. package/dist/cloud-Bo3e9Ak3.js +118 -0
  50. package/dist/collect-DDDv_ESs.js +502 -0
  51. package/dist/collect-DLlujdHC.js +83 -0
  52. package/dist/collect-rG2IQ3t0.js +2 -0
  53. package/dist/commands-DWOrSQic.js +97 -0
  54. package/dist/compact-y6vfu2_f.js +19 -0
  55. package/dist/compare-pfyVnBjE.js +12 -0
  56. package/dist/compile/index.d.ts +3 -0
  57. package/dist/compile/index.js +2 -0
  58. package/dist/compile-Ba4blROR.js +613 -0
  59. package/dist/compile-CNnl6uIt.d.ts +94 -0
  60. package/dist/config-BJiM-xAm.js +157 -0
  61. package/dist/config-Bn00Z3ks.js +36 -0
  62. package/dist/config-report-Dw_JcUqT.js +44 -0
  63. package/dist/connection-CU8MQxRi.js +194 -0
  64. package/dist/context-Ttp0ekMT.js +82 -0
  65. package/dist/convex/index.d.ts +45 -0
  66. package/dist/convex/index.js +65 -0
  67. package/dist/create-BWyx3jua.d.ts +245 -0
  68. package/dist/create-CPhDL6qx.js +253 -0
  69. package/dist/credential-8P81ff4u.js +306 -0
  70. package/dist/delegation-D8pUEuce.js +103 -0
  71. package/dist/describe-B_gVZEVi.js +94 -0
  72. package/dist/describe-PdoqESvg.d.ts +36 -0
  73. package/dist/diff-B8Tunc3o.js +451 -0
  74. package/dist/diff-CzqLxZ77.js +48 -0
  75. package/dist/digest-B3kc_PgQ.d.ts +19 -0
  76. package/dist/digest-BI-6aa6d.js +27 -0
  77. package/dist/doctor-WpvG6p4k.js +1194 -0
  78. package/dist/doctor-collect-ByfYlNv1.js +664 -0
  79. package/dist/doctor-rOr-4ZfS.js +53 -0
  80. package/dist/drizzle/index.d.ts +73 -0
  81. package/dist/drizzle/index.js +160 -0
  82. package/dist/duration-xK2jGFVc.js +25 -0
  83. package/dist/elysia/index.d.ts +49 -0
  84. package/dist/elysia/index.js +59 -0
  85. package/dist/errors-CWfoNg9N.js +47 -0
  86. package/dist/errors-Cz5zn0mW.js +123 -0
  87. package/dist/errors-DAqevpNk.d.ts +125 -0
  88. package/dist/errors-DRnGZHzF.js +30 -0
  89. package/dist/evaluation-items-CfCCejQd.js +40 -0
  90. package/dist/evaluations-tz6D9A2G.js +461 -0
  91. package/dist/eve/index.d.ts +86 -0
  92. package/dist/eve/index.js +176 -0
  93. package/dist/expiry-BoBJ8Tvc.js +7 -0
  94. package/dist/express/index.d.ts +23 -0
  95. package/dist/express/index.js +78 -0
  96. package/dist/fastify/index.d.ts +33 -0
  97. package/dist/fastify/index.js +92 -0
  98. package/dist/fields-BMl1RxoX.js +26 -0
  99. package/dist/files-DWUN9PzI.js +125 -0
  100. package/dist/fixtures-ht28Cplr.js +67 -0
  101. package/dist/freeze-CrU8nQeX.js +60 -0
  102. package/dist/from-snapshot-C3sHpZNS.js +569 -0
  103. package/dist/generate-CH7ThJ14.js +173 -0
  104. package/dist/grantee-Cv5Sogfv.js +602 -0
  105. package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
  106. package/dist/headers-BZSDieNT.js +6 -0
  107. package/dist/headers-Cf-zWvsO.d.ts +6 -0
  108. package/dist/helpers-H_KARDVC.js +421 -0
  109. package/dist/hono/index.d.ts +48 -0
  110. package/dist/hono/index.js +99 -0
  111. package/dist/hosted-DJQw46hn.js +266 -0
  112. package/dist/http-BIhmLfCc.js +95 -0
  113. package/dist/http-DPuDaChb.d.ts +13 -0
  114. package/dist/http-SO7qGttf.js +44 -0
  115. package/dist/ids-DC4V4CFu.js +18 -0
  116. package/dist/index-A0YNL8jZ.d.ts +177 -0
  117. package/dist/index-CtE07CBF.d.ts +6 -0
  118. package/dist/index-D3vbkoSI.d.ts +483 -0
  119. package/dist/index-D6_cSa1z.d.ts +201 -0
  120. package/dist/index.d.ts +16 -0
  121. package/dist/index.js +26 -0
  122. package/dist/instance-options-BK_rNOSC.d.ts +11 -0
  123. package/dist/instance-options-Dhhcnm3y.js +22 -0
  124. package/dist/json-schema-BsAflUGW.js +106 -0
  125. package/dist/jwt/index.d.ts +91 -0
  126. package/dist/jwt/index.js +590 -0
  127. package/dist/kernel-GSQnMz3O.js +208 -0
  128. package/dist/kysely/index.d.ts +78 -0
  129. package/dist/kysely/index.js +129 -0
  130. package/dist/live-options-H2eG8dfJ.js +60 -0
  131. package/dist/load-DhWEB9P1.js +75 -0
  132. package/dist/load-DwJUafYN.js +2 -0
  133. package/dist/load-jose-BL6LH4bL.js +11 -0
  134. package/dist/lru-8q4WZjBV.js +28 -0
  135. package/dist/manifest-iaoBXHKc.js +783 -0
  136. package/dist/manifest-uDS9y5de.d.ts +206 -0
  137. package/dist/map-AcxK9o_D.js +147 -0
  138. package/dist/map-claims-Z4QZOiFF.js +369 -0
  139. package/dist/map-error-pgUWNNtG.js +23 -0
  140. package/dist/markers-B0hYLvMD.js +60 -0
  141. package/dist/may-use-DndQ5tQ-.js +77 -0
  142. package/dist/mcp/index.d.ts +159 -0
  143. package/dist/mcp/index.js +603 -0
  144. package/dist/nest/index.d.ts +75 -0
  145. package/dist/nest/index.js +261 -0
  146. package/dist/next/client.d.ts +23 -0
  147. package/dist/next/client.js +33 -0
  148. package/dist/next/index.d.ts +93 -0
  149. package/dist/next/index.js +180 -0
  150. package/dist/next/plugin.d.ts +14 -0
  151. package/dist/next/plugin.js +33 -0
  152. package/dist/node/index.d.ts +24 -0
  153. package/dist/node/index.js +34 -0
  154. package/dist/openai/index.d.ts +62 -0
  155. package/dist/openai/index.js +92 -0
  156. package/dist/openapi/index.d.ts +176 -0
  157. package/dist/openapi/index.js +3 -0
  158. package/dist/openapi-Bbg4wGVL.js +164 -0
  159. package/dist/openapi-BqRBvAng.js +538 -0
  160. package/dist/openapi-CqqEbHsL.js +250 -0
  161. package/dist/openapi-import-cmwetbzw.js +5959 -0
  162. package/dist/openapi-schema--ARjyfQr.js +6902 -0
  163. package/dist/orpc/index.d.ts +51 -0
  164. package/dist/orpc/index.js +145 -0
  165. package/dist/otel/index.d.ts +13 -0
  166. package/dist/otel/index.js +202 -0
  167. package/dist/package-root-zGkxO3oN.js +30 -0
  168. package/dist/parse-BuyjxhZV.js +53 -0
  169. package/dist/parse-local-manifest-BkGQNzAh.d.ts +10 -0
  170. package/dist/parse-local-manifest-BrMozJCo.js +36 -0
  171. package/dist/pdp/index.d.ts +22 -0
  172. package/dist/pdp/index.js +682 -0
  173. package/dist/peer-BOr_kJE1.js +31 -0
  174. package/dist/permdock-CzqXjCpU.js +3471 -0
  175. package/dist/permissions-CDgvKG5L.d.ts +52 -0
  176. package/dist/permissions-CpZrivYv.js +142 -0
  177. package/dist/permissions-DVoF6dMt.js +662 -0
  178. package/dist/permissions-DttnqqxC.d.ts +214 -0
  179. package/dist/pins-8ILTftC9.js +12 -0
  180. package/dist/policy-CFZAr_Al.d.ts +2252 -0
  181. package/dist/policy-D8UFyERw.d.ts +20 -0
  182. package/dist/policy-xyWg7QdR.js +1122 -0
  183. package/dist/powersync-A8x_Yyvh.js +2 -0
  184. package/dist/powersync-C7kLglqX.js +540 -0
  185. package/dist/powersync-yW1UUFzp.js +62 -0
  186. package/dist/prisma/index.d.ts +136 -0
  187. package/dist/prisma/index.js +455 -0
  188. package/dist/problem-B43ztKIm.js +191 -0
  189. package/dist/problem-details-CkL50EEf.d.ts +7 -0
  190. package/dist/problem-details-_AMOYz-w.js +144 -0
  191. package/dist/prompt-CXYhLfsS.js +32 -0
  192. package/dist/protected-CNsMzrVd.d.ts +27 -0
  193. package/dist/protected-Cs6kTaHo.js +100 -0
  194. package/dist/protected-bZs6rbT1.d.ts +40 -0
  195. package/dist/provider-Cjr62YMV.d.ts +6 -0
  196. package/dist/provider-DLzpb2Xz.js +52 -0
  197. package/dist/provider-store-DNyC1y48.js +43 -0
  198. package/dist/react/index.d.ts +8 -0
  199. package/dist/react/index.js +7 -0
  200. package/dist/react/provider-client.d.ts +2 -0
  201. package/dist/react/provider-client.js +3 -0
  202. package/dist/react-native/index.d.ts +198 -0
  203. package/dist/react-native/index.js +696 -0
  204. package/dist/refs-KYb4ntaz.js +91 -0
  205. package/dist/relations-cjOL01hZ.js +505 -0
  206. package/dist/replay-BsOyTrdV.js +28 -0
  207. package/dist/replay-sqBGMnNs.d.ts +5 -0
  208. package/dist/resource-ref-CaS9yVPi.js +20 -0
  209. package/dist/revocations-Bhr0aMIC.js +27 -0
  210. package/dist/revocations-Cy06JNx2.d.ts +21 -0
  211. package/dist/rls-BMNydpHk.js +2521 -0
  212. package/dist/rls-CEvs64Kj.js +238 -0
  213. package/dist/rls-fields-BMasREhR.js +3502 -0
  214. package/dist/rls-graph-pc9fuXYm.js +435 -0
  215. package/dist/rls-import-D8F7j35Q.js +943 -0
  216. package/dist/rls-migrate-7wikfrVI.js +367 -0
  217. package/dist/rls-ownership-B5Lkq62W.js +843 -0
  218. package/dist/rls-shared-aOQ4hGTO.js +493 -0
  219. package/dist/rls-verify-D8B7dOTh.js +745 -0
  220. package/dist/row-check-Dt35czLy.d.ts +40 -0
  221. package/dist/rpc-DOK54_CS.js +89 -0
  222. package/dist/run-YXCJDNYk.js +174 -0
  223. package/dist/runtime-CB8gQFvS.js +11 -0
  224. package/dist/saas-Bj_FFkjN.js +1203 -0
  225. package/dist/schema-D3MnDMxa.js +300 -0
  226. package/dist/scim/index.d.ts +2 -0
  227. package/dist/scim/index.js +2 -0
  228. package/dist/scim-BFGBBAqR.js +1445 -0
  229. package/dist/scopes-CVdPrWN-.js +239 -0
  230. package/dist/server/index.d.ts +134 -0
  231. package/dist/server/index.js +11 -0
  232. package/dist/server-DlZ28Oz5.js +268 -0
  233. package/dist/sha256-BO0swRXL.js +150 -0
  234. package/dist/shared-DRu8VFVM.js +123 -0
  235. package/dist/sink-Bd9PSyfq.js +141 -0
  236. package/dist/sink-Gs6TTVa-.d.ts +104 -0
  237. package/dist/skills-Biq5uup3.js +192 -0
  238. package/dist/skills-JaymNCdK.js +56 -0
  239. package/dist/snapshot-Enxd0n-s.js +975 -0
  240. package/dist/snapshot-cache-D6jLelln.js +44 -0
  241. package/dist/snapshot-cache-DwQH8ufx.d.ts +45 -0
  242. package/dist/solid/index.d.ts +93 -0
  243. package/dist/solid/index.js +188 -0
  244. package/dist/sources-B0UvrJ21.js +534 -0
  245. package/dist/sources-BcJgw0lt.d.ts +192 -0
  246. package/dist/sql-xdg5f4Fi.js +27 -0
  247. package/dist/src-CSbUiozF.js +568 -0
  248. package/dist/ssf/index.d.ts +4 -0
  249. package/dist/ssf/index.js +596 -0
  250. package/dist/store-DMAWwAJV.js +371 -0
  251. package/dist/store-D_pjn91-.d.ts +36 -0
  252. package/dist/store-options-yO0V6gRn.js +716 -0
  253. package/dist/stores-4_sqiOA1.js +87 -0
  254. package/dist/stores-DVR5NHLE.d.ts +52 -0
  255. package/dist/stream-DDpvynSB.js +66 -0
  256. package/dist/stream-DlvG2hs-.d.ts +12 -0
  257. package/dist/style-CTm1AXDT.js +22 -0
  258. package/dist/subject-C6dLxqHU.js +24 -0
  259. package/dist/subject-settings-BwBmCdTR.js +128 -0
  260. package/dist/supabase/index.d.ts +183 -0
  261. package/dist/supabase/index.js +5 -0
  262. package/dist/supabase/middleware.d.ts +82 -0
  263. package/dist/supabase/middleware.js +102 -0
  264. package/dist/supabase-CwafwxxF.js +83 -0
  265. package/dist/supabase-DTBaC20O.js +774 -0
  266. package/dist/supabase-config-Bs44dare.js +472 -0
  267. package/dist/supabase-hook-BuxLQLpU.js +1814 -0
  268. package/dist/supabase-hook-D5qVd_D8.js +2 -0
  269. package/dist/supautils-DYZnzRWV.js +91 -0
  270. package/dist/svelte/PermissionBoundary.svelte +37 -0
  271. package/dist/svelte/Protected.svelte +40 -0
  272. package/dist/svelte/index.d.ts +13 -0
  273. package/dist/svelte/index.js +107 -0
  274. package/dist/svelte/runtime.d.ts +7 -0
  275. package/dist/svelte/runtime.js +4 -0
  276. package/dist/svelte/source.d.ts +13 -0
  277. package/dist/svelte/source.js +11 -0
  278. package/dist/terminal/index.d.ts +163 -0
  279. package/dist/terminal/index.js +833 -0
  280. package/dist/testing/index.d.ts +745 -0
  281. package/dist/testing/index.js +3672 -0
  282. package/dist/testing/saas/index.d.ts +194 -0
  283. package/dist/testing/saas/index.js +3 -0
  284. package/dist/testing/saas/permissions.d.ts +2 -0
  285. package/dist/testing/saas/permissions.js +2 -0
  286. package/dist/text-diff-BdkkYSbi.js +15 -0
  287. package/dist/thenable-okc2xDsj.js +10 -0
  288. package/dist/timeout-D51niuQP.js +8 -0
  289. package/dist/token-CIWxJOCh.js +50 -0
  290. package/dist/trpc/index.d.ts +61 -0
  291. package/dist/trpc/index.js +122 -0
  292. package/dist/types-9AWO9EGt.d.ts +197 -0
  293. package/dist/types-BPxgszlT.d.ts +550 -0
  294. package/dist/types-BVyImy5I.d.ts +120 -0
  295. package/dist/types-Bvc4oWT6.d.ts +9 -0
  296. package/dist/types-C3s9xVJG.d.ts +48 -0
  297. package/dist/types-Dnemwd77.d.ts +183 -0
  298. package/dist/types-kxznc7cn.d.ts +52 -0
  299. package/dist/types-vKyAMtcX.d.ts +157 -0
  300. package/dist/types-vNSDF7Dq.d.ts +66 -0
  301. package/dist/types-yF5LmQVD.d.ts +306 -0
  302. package/dist/unplugin/index.d.ts +7 -0
  303. package/dist/unplugin/index.js +31 -0
  304. package/dist/usage-D07N9QJ3.js +42 -0
  305. package/dist/usage-D82l1CwK.js +2 -0
  306. package/dist/usage-DG1oeCca.js +693 -0
  307. package/dist/validation-error-CnjZ4t92.js +33 -0
  308. package/dist/validation-error-CtF23SrC.d.ts +26 -0
  309. package/dist/validity-uOp8UpYn.js +245 -0
  310. package/dist/verifier-BxBo6I44.js +466 -0
  311. package/dist/version-BvacVTZR.js +17 -0
  312. package/dist/views-Soe7bGSC.js +95 -0
  313. package/dist/vocabulary-DA8a8zif.d.ts +56 -0
  314. package/dist/vue/index.d.ts +79 -0
  315. package/dist/vue/index.js +196 -0
  316. package/dist/watch-Etoa_Mvr.js +2 -0
  317. package/dist/watch-UihESpsJ.js +128 -0
  318. package/dist/webmcp/index.d.ts +75 -0
  319. package/dist/webmcp/index.js +307 -0
  320. package/package.json +450 -5
  321. package/rulesets/permdock.yaml +29 -0
  322. package/schemas/approval-request-v1.json +175 -0
  323. package/schemas/catalog-v1.json +535 -0
  324. package/schemas/openapi/oas-3.1.json +1298 -0
  325. package/schemas/openapi/oas-3.2.json +1516 -0
  326. package/schemas/openapi/overlay-1.1.json +79 -0
  327. package/schemas/supabase-claims-v1.json +144 -0
  328. package/schemas/supabase-manifest-v1.json +361 -0
  329. package/skills/permdock/SKILL.md +66 -0
  330. package/skills/permdock-agents/SKILL.md +77 -0
  331. package/skills/permdock-agents/references/runtimes.md +213 -0
  332. package/skills/permdock-approvals/SKILL.md +80 -0
  333. package/skills/permdock-approvals/references/stores-and-resume.md +94 -0
  334. package/skills/permdock-audit/SKILL.md +67 -0
  335. package/skills/permdock-credentials/SKILL.md +55 -0
  336. package/skills/permdock-credentials/references/tokens-keys-links.md +132 -0
  337. package/skills/permdock-data/SKILL.md +57 -0
  338. package/skills/permdock-data/references/queries-and-rls.md +62 -0
  339. package/skills/permdock-data/references/relationships.md +67 -0
  340. package/skills/permdock-tenancy/SKILL.md +80 -0
  341. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +89 -0
  342. package/skills/permdock-wire/SKILL.md +116 -0
  343. package/skills/permdock-wire/references/adapters.md +492 -0
  344. package/skills/permdock-wire/references/policy-options.md +45 -0
@@ -0,0 +1,943 @@
1
+ import { o as usageResult } from "./errors-CWfoNg9N.js";
2
+ import { i as quoteSqlLiteral, n as escapeSqlIdent } from "./sql-xdg5f4Fi.js";
3
+ import { B as parseMembershipsFlag, n as HELPERS } from "./rls-shared-aOQ4hGTO.js";
4
+ import { t as FIELD_VIEWS, w as connectPg } from "./rls-fields-BMasREhR.js";
5
+ import { n as emptySchema, r as isSchemaKind, t as emitPermissionsModule } from "./generate-CH7ThJ14.js";
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
+ import { dirname, resolve } from "node:path";
8
+ import { createHash } from "node:crypto";
9
+ import { deparse, parse } from "pgsql-parser";
10
+ //#region src/cli/rls-import-ast.ts
11
+ function asNode$1(value) {
12
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) return value;
13
+ }
14
+ function stringVal(value) {
15
+ const node = asNode$1(value);
16
+ if (node === void 0) return;
17
+ const inner = asNode$1(node["String"]);
18
+ if (inner !== void 0) {
19
+ if (typeof inner["sval"] === "string") return inner["sval"];
20
+ if (typeof inner["str"] === "string") return inner["str"];
21
+ }
22
+ if (typeof node["str"] === "string") return node["str"];
23
+ if (typeof node["sval"] === "string") return node["sval"];
24
+ }
25
+ function unwrap(value) {
26
+ const node = asNode$1(value);
27
+ if (node === void 0) return value;
28
+ const cast = asNode$1(node["TypeCast"]);
29
+ if (cast !== void 0) return unwrap(cast["arg"]);
30
+ return value;
31
+ }
32
+ function columnName(value) {
33
+ const fields = asNode$1(asNode$1(unwrap(value))?.["ColumnRef"])?.["fields"];
34
+ if (!Array.isArray(fields) || fields.length === 0) return;
35
+ return stringVal(fields.at(-1));
36
+ }
37
+ function funcName(value) {
38
+ const names = asNode$1(asNode$1(unwrap(value))?.["FuncCall"])?.["funcname"];
39
+ if (!Array.isArray(names) || names.length === 0) return;
40
+ return names.map((item) => stringVal(item) ?? "").join(".");
41
+ }
42
+ /** The expression of a scalar `(select <expr>)`, the InitPlan form generate writes. */
43
+ function scalarSubselect(value) {
44
+ const targets = asNode$1(asNode$1(asNode$1(asNode$1(unwrap(value))?.["SubLink"])?.["subselect"])?.["SelectStmt"])?.["targetList"];
45
+ if (!Array.isArray(targets) || targets[0] === void 0) return;
46
+ return asNode$1(asNode$1(targets[0])?.["ResTarget"])?.["val"];
47
+ }
48
+ function isAuthUid(value) {
49
+ const inner = scalarSubselect(value);
50
+ if (inner !== void 0) return isAuthUid(inner);
51
+ const name = funcName(value);
52
+ return name === "auth.uid" || name === "auth.user_id" || name === "uid" || name === "user_id" || name?.split(".").at(-1) === "permdock_user_id";
53
+ }
54
+ function isCurrentSettingUserId(value) {
55
+ const inner = scalarSubselect(value);
56
+ if (inner !== void 0) return isCurrentSettingUserId(inner);
57
+ if (funcName(value) !== "current_setting") return false;
58
+ const args = asNode$1(asNode$1(unwrap(value))?.["FuncCall"])?.["args"];
59
+ if (!Array.isArray(args) || args[0] === void 0) return false;
60
+ const literal = constValue(args[0]);
61
+ return typeof literal === "string" && literal.endsWith(".user_id");
62
+ }
63
+ function constValue(value) {
64
+ const constant = asNode$1(asNode$1(unwrap(value))?.["A_Const"]);
65
+ if (constant === void 0) return;
66
+ if (constant["isnull"] === true) return null;
67
+ const sval = asNode$1(constant["sval"]);
68
+ if (sval !== void 0 && typeof sval["sval"] === "string") return sval["sval"];
69
+ if (typeof constant["sval"] === "string") return constant["sval"];
70
+ const ival = asNode$1(constant["ival"]);
71
+ if (ival !== void 0) {
72
+ const number = ival["ival"] ?? 0;
73
+ return typeof number === "number" ? number : void 0;
74
+ }
75
+ if (typeof constant["ival"] === "number") return constant["ival"];
76
+ const boolval = asNode$1(constant["boolval"]);
77
+ if (boolval !== void 0) {
78
+ const flag = boolval["boolval"] ?? false;
79
+ return typeof flag === "boolean" ? flag : void 0;
80
+ }
81
+ if (typeof constant["boolval"] === "boolean") return constant["boolval"];
82
+ }
83
+ function selectFromTable(selectNode) {
84
+ const from = asNode$1(asNode$1(selectNode)?.["SelectStmt"])?.["fromClause"];
85
+ if (!Array.isArray(from) || from[0] === void 0) return;
86
+ const relname = asNode$1(asNode$1(from[0])?.["RangeVar"])?.["relname"];
87
+ return typeof relname === "string" ? relname : void 0;
88
+ }
89
+ function sublinkTable(value, kinds) {
90
+ const sub = asNode$1(asNode$1(unwrap(value))?.["SubLink"]);
91
+ if (sub === void 0) return;
92
+ const kind = sub["subLinkType"];
93
+ if (kind === void 0 || !kinds.has(kind)) return;
94
+ return selectFromTable(sub["subselect"]);
95
+ }
96
+ function membershipTable(value) {
97
+ const exists = sublinkTable(value, /* @__PURE__ */ new Set(["EXISTS_SUBLINK", 0]));
98
+ if (exists !== void 0) return exists;
99
+ const anyDirect = sublinkTable(value, /* @__PURE__ */ new Set([
100
+ "ANY_SUBLINK",
101
+ "IN_SUBLINK",
102
+ 2
103
+ ]));
104
+ if (anyDirect !== void 0) return anyDirect;
105
+ const expr = asNode$1(asNode$1(unwrap(value))?.["A_Expr"]);
106
+ if (expr === void 0) return;
107
+ const fromRight = sublinkTable(unwrap(expr["rexpr"]), /* @__PURE__ */ new Set([
108
+ "ANY_SUBLINK",
109
+ "IN_SUBLINK",
110
+ "EXISTS_SUBLINK",
111
+ 0,
112
+ 2
113
+ ]));
114
+ if (fromRight !== void 0) return fromRight;
115
+ if (Array.isArray(expr["rexpr"]) && expr["rexpr"][0] !== void 0) return selectFromTable(expr["rexpr"][0]);
116
+ }
117
+ function operatorName(value) {
118
+ const names = asNode$1(asNode$1(unwrap(value))?.["A_Expr"])?.["name"];
119
+ if (!Array.isArray(names) || names[0] === void 0) return;
120
+ return stringVal(names[0]);
121
+ }
122
+ function boolOp(value) {
123
+ const op = asNode$1(asNode$1(unwrap(value))?.["BoolExpr"])?.["boolop"];
124
+ if (op === "AND_EXPR" || op === 0) return "and";
125
+ if (op === "OR_EXPR" || op === 1) return "or";
126
+ if (op === "NOT_EXPR" || op === 2) return "not";
127
+ }
128
+ function functionLookupName(name, functions) {
129
+ if (functions === void 0) return;
130
+ if (functions[name] !== void 0) return functions[name];
131
+ return functions[name.includes(".") ? name.slice(name.lastIndexOf(".") + 1) : name];
132
+ }
133
+ function argFromNode(value) {
134
+ const field = columnName(value);
135
+ if (field !== void 0) return { field };
136
+ if (isAuthUid(value) || isCurrentSettingUserId(value)) return { ref: "principal.id" };
137
+ return constValue(value);
138
+ }
139
+ async function canonicalDump(sql) {
140
+ try {
141
+ return await deparse(await parse(sql));
142
+ } catch {
143
+ return;
144
+ }
145
+ }
146
+ function asStmts(parsed) {
147
+ if (Array.isArray(parsed)) return parsed;
148
+ const node = asNode$1(parsed);
149
+ if (Array.isArray(node?.["stmts"])) return node["stmts"];
150
+ return [];
151
+ }
152
+ async function fingerprintSql(sql) {
153
+ try {
154
+ const parsed = await parse(`SELECT 1 WHERE (${sql})`);
155
+ const deparsed = await deparse(parsed);
156
+ return createHash("sha256").update(deparsed).digest("hex").slice(0, 16);
157
+ } catch {
158
+ return createHash("sha256").update(sql.replaceAll(/\s+/g, " ").trim().toLowerCase()).digest("hex").slice(0, 16);
159
+ }
160
+ }
161
+ async function conditionFromAst(sql, memberships, functions, unmapped, joins = [], seeds = []) {
162
+ if (sql === void 0 || sql.trim() === "" || sql.trim() === "true") return {
163
+ op: "eq",
164
+ field: "_",
165
+ value: true
166
+ };
167
+ const where = await whereOf(sql);
168
+ if (where === void 0) return {
169
+ op: "opaque",
170
+ sql,
171
+ fingerprint: await fingerprintSql(sql)
172
+ };
173
+ const mapped = mapNode(where, {
174
+ memberships,
175
+ functions,
176
+ unmapped,
177
+ joins,
178
+ seeds
179
+ });
180
+ if (mapped === void 0) return {
181
+ op: "opaque",
182
+ sql,
183
+ fingerprint: await fingerprintSql(sql)
184
+ };
185
+ return mapped;
186
+ }
187
+ async function whereOf(sql) {
188
+ try {
189
+ return asNode$1(asNode$1(nodeStmt(asNode$1(asStmts(await parse(`SELECT 1 WHERE (${sql})`))[0])))?.["SelectStmt"])?.["whereClause"];
190
+ } catch {
191
+ return;
192
+ }
193
+ }
194
+ const PERMITTED = /^permitted_([a-z][a-z0-9_]*)_ids$/u;
195
+ function helperScope(name) {
196
+ if (name === void 0) return;
197
+ const bare = name.slice(name.lastIndexOf(".") + 1);
198
+ if (bare === HELPERS.has) return "global";
199
+ return PERMITTED.exec(bare)?.[1];
200
+ }
201
+ function helperKey(call) {
202
+ const args = asNode$1(asNode$1(unwrap(call))?.["FuncCall"])?.["args"];
203
+ if (!Array.isArray(args) || args.length !== 1) return;
204
+ const key = constValue(args[0]);
205
+ return typeof key === "string" ? key : void 0;
206
+ }
207
+ function helperCall(value) {
208
+ const node = asNode$1(unwrap(value));
209
+ const sub = asNode$1(node?.["SubLink"]);
210
+ if (sub === void 0) {
211
+ const scope = helperScope(funcName(node));
212
+ const key = helperKey(node);
213
+ return scope === "global" && key !== void 0 ? {
214
+ scope,
215
+ key
216
+ } : void 0;
217
+ }
218
+ const targets = asNode$1(asNode$1(sub["subselect"])?.["SelectStmt"])?.["targetList"];
219
+ if (!Array.isArray(targets) || targets.length !== 1) return;
220
+ const call = asNode$1(asNode$1(targets[0])?.["ResTarget"])?.["val"];
221
+ const scope = helperScope(funcName(call));
222
+ const key = helperKey(call);
223
+ if (scope === void 0 || key === void 0) return;
224
+ const kind = sub["subLinkType"];
225
+ if (scope === "global") return kind === "EXPR_SUBLINK" || kind === 4 ? {
226
+ scope,
227
+ key
228
+ } : void 0;
229
+ const column = columnName(sub["testexpr"]);
230
+ return (kind === "ANY_SUBLINK" || kind === 2) && column !== void 0 ? {
231
+ scope,
232
+ key,
233
+ column
234
+ } : void 0;
235
+ }
236
+ const MEMBER = /^member_([a-z][a-z0-9_]*)_ids$/u;
237
+ /** `col in (select member_<scope>_ids())`: any live membership of the row's instance. */
238
+ function memberCall(value) {
239
+ const sub = asNode$1(asNode$1(unwrap(value))?.["SubLink"]);
240
+ const kind = sub?.["subLinkType"];
241
+ if (sub === void 0 || kind !== "ANY_SUBLINK" && kind !== 2) return;
242
+ const targets = asNode$1(asNode$1(sub["subselect"])?.["SelectStmt"])?.["targetList"];
243
+ if (!Array.isArray(targets) || targets.length !== 1) return;
244
+ const call = asNode$1(asNode$1(targets[0])?.["ResTarget"])?.["val"];
245
+ const name = funcName(asNode$1(unwrap(call)));
246
+ const args = asNode$1(asNode$1(unwrap(call))?.["FuncCall"])?.["args"];
247
+ const scope = name === void 0 ? void 0 : MEMBER.exec(name.slice(name.lastIndexOf(".") + 1))?.[1];
248
+ const column = columnName(sub["testexpr"]);
249
+ return scope === void 0 || column === void 0 || Array.isArray(args) && args.length > 0 ? void 0 : {
250
+ scope,
251
+ column
252
+ };
253
+ }
254
+ function rolesFor(seeds, key, scope) {
255
+ return [...new Set(seeds.filter((seed) => seed.grantKey === key && seed.scope === scope).map((seed) => seed.role))];
256
+ }
257
+ function helperCondition(call, seeds) {
258
+ const roles = rolesFor(seeds, call.key, call.scope);
259
+ if (call.scope === "global" || call.column === void 0) {
260
+ const sql = `(select ${HELPERS.has}(${quoteSqlLiteral(call.key)}))`;
261
+ return {
262
+ op: "opaque",
263
+ sql,
264
+ fingerprint: createHash("sha256").update(sql).digest("hex").slice(0, 16)
265
+ };
266
+ }
267
+ return {
268
+ op: "memberOf",
269
+ scope: call.scope,
270
+ field: call.column,
271
+ roles: [...roles]
272
+ };
273
+ }
274
+ function flatten(value, op) {
275
+ if (boolOp(value) !== op) return [value];
276
+ const args = asNode$1(asNode$1(unwrap(value))?.["BoolExpr"])?.["args"];
277
+ return Array.isArray(args) ? args.flatMap((arg) => flatten(arg, op)) : [];
278
+ }
279
+ function helperCalls(conjunct) {
280
+ const calls = flatten(conjunct, "or").map(helperCall);
281
+ return calls.every((call) => call !== void 0) ? calls : void 0;
282
+ }
283
+ /**
284
+ * The role structure of a policy that calls the helpers: each OR branch's
285
+ * helper calls become grants (roles from the `role_permissions` seeds), the
286
+ * branch's other conjuncts become their `where`. Restrictive policies are
287
+ * read through their outer `not`.
288
+ */
289
+ async function helperGrants(sql, memberships, functions, seeds) {
290
+ if (sql === void 0) return [];
291
+ let where = await whereOf(sql);
292
+ if (boolOp(where) === "not") {
293
+ where = asNode$1(asNode$1(unwrap(where))?.["BoolExpr"])?.["args"];
294
+ where = Array.isArray(where) ? where[0] : void 0;
295
+ }
296
+ const unportable = {
297
+ op: "opaque",
298
+ sql,
299
+ fingerprint: await fingerprintSql(sql)
300
+ };
301
+ const grants = [];
302
+ for (const branch of flatten(where, "or")) {
303
+ const conjuncts = flatten(branch, "and");
304
+ const calls = [];
305
+ const rest = [];
306
+ let portable = true;
307
+ for (const conjunct of conjuncts) {
308
+ const found = helperCalls(conjunct);
309
+ if (found !== void 0) {
310
+ calls.push(...found);
311
+ continue;
312
+ }
313
+ const mapped = mapNode(conjunct, {
314
+ memberships,
315
+ functions,
316
+ unmapped: [],
317
+ joins: [],
318
+ seeds
319
+ });
320
+ if (mapped === void 0) portable = false;
321
+ else rest.push(mapped);
322
+ }
323
+ if (calls.length === 0) continue;
324
+ const condition = !portable ? unportable : rest.length === 0 ? void 0 : rest.length === 1 ? rest[0] : {
325
+ op: "and",
326
+ conditions: rest
327
+ };
328
+ for (const call of calls) {
329
+ const permission = seeds.find((seed) => seed.grantKey === call.key)?.permission ?? call.key.replace(/#[a-z0-9][a-z0-9_-]*$/u, "");
330
+ grants.push({
331
+ key: call.key,
332
+ permission,
333
+ scope: call.scope,
334
+ roles: rolesFor(seeds, call.key, call.scope),
335
+ ...condition === void 0 ? {} : { where: condition }
336
+ });
337
+ }
338
+ }
339
+ return grants;
340
+ }
341
+ const SEED_COLUMNS = [
342
+ "role",
343
+ "permission",
344
+ "grant_key",
345
+ "scope",
346
+ "effect"
347
+ ];
348
+ function asScope(value) {
349
+ return typeof value === "string" && /^[a-z][a-z0-9_]*$/u.test(value) ? value : void 0;
350
+ }
351
+ function seedFromRow(row) {
352
+ const scope = asScope(row["scope"]);
353
+ if (typeof row["role"] !== "string" || typeof row["permission"] !== "string" || typeof row["grant_key"] !== "string" || scope === void 0) return;
354
+ return {
355
+ role: row["role"],
356
+ permission: row["permission"],
357
+ grantKey: row["grant_key"],
358
+ scope,
359
+ effect: row["effect"] === "deny" ? "deny" : "allow"
360
+ };
361
+ }
362
+ /** `role_permissions` rows from the `insert ... values` statements of a SQL dump. */
363
+ async function seedsFromSql(sql) {
364
+ let parsed;
365
+ try {
366
+ parsed = await parse(sql);
367
+ } catch {
368
+ return [];
369
+ }
370
+ const seeds = [];
371
+ for (const item of asStmts(parsed)) {
372
+ const insert = asNode$1(asNode$1(nodeStmt(asNode$1(item)))?.["InsertStmt"]);
373
+ if (asNode$1(insert?.["relation"])?.["relname"] !== "role_permissions") continue;
374
+ const cols = Array.isArray(insert?.["cols"]) ? insert["cols"].map((col) => asNode$1(asNode$1(col)?.["ResTarget"])?.["name"]) : [];
375
+ const values = asNode$1(asNode$1(insert?.["selectStmt"])?.["SelectStmt"])?.["valuesLists"];
376
+ if (!Array.isArray(values)) continue;
377
+ for (const list of values) {
378
+ const items = asNode$1(asNode$1(list)?.["List"])?.["items"];
379
+ if (!Array.isArray(items)) continue;
380
+ const row = {};
381
+ for (const [index, col] of cols.entries()) if (typeof col === "string" && SEED_COLUMNS.includes(col)) row[col] = constValue(items[index]);
382
+ const seed = seedFromRow(row);
383
+ if (seed !== void 0) seeds.push(seed);
384
+ }
385
+ }
386
+ return seeds;
387
+ }
388
+ function nodeStmt(first) {
389
+ const raw = asNode$1(first?.["RawStmt"]);
390
+ if (raw !== void 0) return raw["stmt"];
391
+ return first?.["stmt"];
392
+ }
393
+ function mapNode(value, ctx) {
394
+ if (value === void 0) return;
395
+ const node = asNode$1(unwrap(value));
396
+ if (node === void 0) return;
397
+ const { memberships, functions, unmapped, joins } = ctx;
398
+ const member = memberCall(node);
399
+ if (member !== void 0) return {
400
+ op: "memberOf",
401
+ scope: member.scope,
402
+ field: member.column,
403
+ roles: []
404
+ };
405
+ const helper = helperCall(node);
406
+ if (helper !== void 0) return helperCondition(helper, ctx.seeds);
407
+ if (funcName(scalarSubselect(node) ?? node)?.split(".").at(-1) === "permdock_session_live") return { op: "liveSession" };
408
+ const nullTest = asNode$1(node["NullTest"]);
409
+ if (nullTest !== void 0) {
410
+ const field = columnName(nullTest["arg"]);
411
+ if (field === void 0) return;
412
+ return {
413
+ op: "isNull",
414
+ field,
415
+ value: nullTest["nulltesttype"] === "IS_NULL" || nullTest["nulltesttype"] === 0 || nullTest["nulltesttype"] === void 0
416
+ };
417
+ }
418
+ const compound = boolOp(node);
419
+ if (compound !== void 0) {
420
+ const args = asNode$1(node["BoolExpr"])?.["args"];
421
+ if (!Array.isArray(args)) return;
422
+ if (compound === "not") {
423
+ const inner = mapNode(args[0], ctx);
424
+ return inner === void 0 ? void 0 : {
425
+ op: "not",
426
+ condition: inner
427
+ };
428
+ }
429
+ const children = args.map((arg) => mapNode(arg, ctx)).filter((item) => item !== void 0);
430
+ if (children.length !== args.length) return;
431
+ return {
432
+ op: compound,
433
+ conditions: children
434
+ };
435
+ }
436
+ const table = membershipTable(node);
437
+ if (table !== void 0) {
438
+ for (const [scope, mapped] of Object.entries(memberships?.scopes ?? {})) {
439
+ const column = mapped.columns?.[scope];
440
+ if (mapped.table === table && column !== void 0) return {
441
+ op: "memberOf",
442
+ scope,
443
+ field: column,
444
+ roles: []
445
+ };
446
+ }
447
+ if (memberships?.tenant?.table === table) return {
448
+ op: "memberOf",
449
+ scope: "tenant",
450
+ field: memberships.tenant.tenant ?? "tenant_id",
451
+ roles: []
452
+ };
453
+ if (memberships?.team?.table === table) return {
454
+ op: "memberOf",
455
+ scope: "team",
456
+ field: memberships.team.team ?? "team_id",
457
+ roles: []
458
+ };
459
+ joins.push(table);
460
+ return;
461
+ }
462
+ const name = funcName(node);
463
+ if (name !== void 0 && !isAuthUid(node) && name !== "current_setting") {
464
+ const mapping = functionLookupName(name, functions);
465
+ if (mapping === void 0) {
466
+ unmapped.push(name);
467
+ return;
468
+ }
469
+ const call = asNode$1(node["FuncCall"]);
470
+ const rawArgs = Array.isArray(call?.["args"]) ? call["args"] : [];
471
+ return {
472
+ op: "sqlFunction",
473
+ name,
474
+ args: mapping.args?.map((field) => ({ field })) ?? rawArgs.map((arg) => argFromNode(arg)).filter((item) => item !== void 0),
475
+ twin: mapping.twin
476
+ };
477
+ }
478
+ const op = operatorName(node);
479
+ const expr = asNode$1(node["A_Expr"]);
480
+ if (op === "=" || op === "<>" || op === ">" || op === ">=" || op === "<" || op === "<=") {
481
+ const left = columnName(expr?.["lexpr"]) ?? columnName(expr?.["rexpr"]);
482
+ const right = expr?.["lexpr"];
483
+ const other = columnName(expr?.["lexpr"]) !== void 0 ? expr?.["rexpr"] : right;
484
+ if (left === void 0) return;
485
+ const comparison = op === "=" ? "eq" : op === "<>" ? "ne" : op === ">" ? "gt" : op === ">=" ? "gte" : op === "<" ? "lt" : "lte";
486
+ if (isAuthUid(other) || isCurrentSettingUserId(other)) return {
487
+ op: comparison,
488
+ field: left,
489
+ value: { ref: "principal.id" }
490
+ };
491
+ const literal = constValue(other);
492
+ if (literal === void 0) {
493
+ const claim = jwtClaim(other);
494
+ if (claim !== void 0) return {
495
+ op: comparison,
496
+ field: left,
497
+ value: { ref: `principal.claim.${claim}` }
498
+ };
499
+ return;
500
+ }
501
+ return {
502
+ op: comparison,
503
+ field: left,
504
+ value: literal
505
+ };
506
+ }
507
+ }
508
+ function jwtClaim(value) {
509
+ const node = asNode$1(unwrap(value));
510
+ const expr = asNode$1(node?.["A_Expr"]);
511
+ if (expr === void 0) return;
512
+ const name = operatorName(node);
513
+ if (name !== "->>" && name !== "->" || !isJwtCall(expr["lexpr"])) return;
514
+ const claim = constValue(expr["rexpr"]);
515
+ return typeof claim === "string" ? claim : void 0;
516
+ }
517
+ /** `auth.jwt()` / `auth.session()`, bare or as a scalar `(select …)`; a column's `->>` is row data, not a claim. */
518
+ function isJwtCall(value) {
519
+ const inner = scalarSubselect(value);
520
+ if (inner !== void 0) return isJwtCall(inner);
521
+ const name = funcName(value);
522
+ return name === "auth.jwt" || name === "auth.session";
523
+ }
524
+ //#endregion
525
+ //#region src/cli/rls-import-views.ts
526
+ function asNode(value) {
527
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
528
+ }
529
+ function list(value) {
530
+ return Array.isArray(value) ? value : [];
531
+ }
532
+ function sval(value) {
533
+ const inner = asNode(asNode(value)?.["String"]);
534
+ return typeof inner?.["sval"] === "string" ? inner["sval"] : void 0;
535
+ }
536
+ function optionOn(value) {
537
+ const def = asNode(asNode(value)?.["DefElem"]);
538
+ if (typeof def?.["defname"] !== "string") return;
539
+ const arg = sval(def["arg"]) ?? "true";
540
+ return [
541
+ "true",
542
+ "on",
543
+ "1"
544
+ ].includes(arg.toLowerCase()) ? def["defname"].toLowerCase() : void 0;
545
+ }
546
+ function viewsOf(stmts) {
547
+ const out = [];
548
+ for (const item of stmts) {
549
+ const view = asNode(asNode(asNode(item)?.["stmt"])?.["ViewStmt"]);
550
+ const relation = asNode(view?.["view"]);
551
+ const select = asNode(asNode(view?.["query"])?.["SelectStmt"]);
552
+ if (typeof relation?.["relname"] !== "string" || select === void 0) continue;
553
+ const options = new Set(list(view?.["options"]).flatMap((option) => {
554
+ const on = optionOn(option);
555
+ return on === void 0 ? [] : [on];
556
+ }));
557
+ out.push({
558
+ name: relation["relname"],
559
+ options,
560
+ select
561
+ });
562
+ }
563
+ return out;
564
+ }
565
+ function columnRef(value) {
566
+ const fields = list(asNode(asNode(value)?.["ColumnRef"])?.["fields"]).map(sval);
567
+ const column = fields.at(-1);
568
+ if (column === void 0 || fields.some((field) => field === void 0)) return;
569
+ const from = fields.at(-2);
570
+ return fields.length > 1 && from !== void 0 ? {
571
+ from,
572
+ column
573
+ } : { column };
574
+ }
575
+ function targetOf(value) {
576
+ const target = asNode(asNode(value)?.["ResTarget"]);
577
+ if (target === void 0) return;
578
+ const plain = columnRef(target["val"]);
579
+ const alias = typeof target["name"] === "string" ? target["name"] : void 0;
580
+ if (plain !== void 0) return {
581
+ name: alias ?? plain.column,
582
+ column: plain.column,
583
+ ...plain.from === void 0 ? {} : { from: plain.from }
584
+ };
585
+ const when = asNode(asNode(list(asNode(asNode(target["val"])?.["CaseExpr"])?.["args"])[0])?.["CaseWhen"]);
586
+ const result = when === void 0 ? void 0 : columnRef(when["result"]);
587
+ if (when === void 0 || result === void 0) return;
588
+ return {
589
+ name: alias ?? result.column,
590
+ column: result.column,
591
+ mask: when["expr"]
592
+ };
593
+ }
594
+ function rangeVar(value) {
595
+ const range = asNode(asNode(value)?.["RangeVar"]);
596
+ if (typeof range?.["relname"] !== "string") return;
597
+ const alias = asNode(range["alias"])?.["aliasname"];
598
+ return typeof alias === "string" ? {
599
+ name: range["relname"],
600
+ alias
601
+ } : { name: range["relname"] };
602
+ }
603
+ function sourceOf(select) {
604
+ const from = list(select["fromClause"]);
605
+ if (from.length !== 1) return;
606
+ const direct = rangeVar(from[0]);
607
+ if (direct !== void 0) return direct.alias === void 0 ? { table: direct.name } : {
608
+ table: direct.name,
609
+ alias: direct.alias
610
+ };
611
+ const join = asNode(asNode(from[0])?.["JoinExpr"]);
612
+ const left = rangeVar(join?.["larg"]);
613
+ const right = rangeVar(join?.["rarg"]);
614
+ if (join?.["jointype"] !== "JOIN_LEFT" || left === void 0 || right === void 0) return;
615
+ return {
616
+ table: left.name,
617
+ ...left.alias === void 0 ? {} : { alias: left.alias },
618
+ companion: right
619
+ };
620
+ }
621
+ /** A mask is `allow`, `not deny` or `allow and not deny`; the generator puts the deny last. */
622
+ function splitMask(mask) {
623
+ const bool = asNode(asNode(mask)?.["BoolExpr"]);
624
+ if (bool?.["boolop"] === "NOT_EXPR") return { deny: list(bool["args"])[0] };
625
+ if (bool?.["boolop"] !== "AND_EXPR") return { allow: mask };
626
+ const args = list(bool["args"]);
627
+ const last = asNode(asNode(args.at(-1))?.["BoolExpr"]);
628
+ if (last?.["boolop"] !== "NOT_EXPR") return { allow: mask };
629
+ const rest = args.slice(0, -1);
630
+ return {
631
+ allow: rest.length === 1 ? rest[0] : { BoolExpr: {
632
+ boolop: "AND_EXPR",
633
+ args: rest
634
+ } },
635
+ deny: list(last["args"])[0]
636
+ };
637
+ }
638
+ async function grantsOf(node, memberships, functions, seeds) {
639
+ const expr = asNode(node);
640
+ if (expr === void 0) return [];
641
+ return helperGrants(await deparse(expr), memberships, functions, seeds);
642
+ }
643
+ /**
644
+ * Reads back the field views `rls generate --fields views` writes: a
645
+ * `security_invoker` `<table>_visible` whose restricted columns are
646
+ * `case when <mask> then col end`, either inline or through the
647
+ * `<table>_visible_fields` companion it joins. Other views are ignored.
648
+ */
649
+ async function fieldViewsFromSql(sql, memberships, functions, seeds) {
650
+ let stmts;
651
+ try {
652
+ stmts = list(asNode(await parse(sql))?.["stmts"]);
653
+ } catch {
654
+ return [];
655
+ }
656
+ const views = viewsOf(stmts);
657
+ const byName = new Map(views.map((view) => [view.name, view]));
658
+ const out = [];
659
+ for (const view of views) {
660
+ if (!view.name.endsWith(FIELD_VIEWS.view) || !view.options.has("security_invoker")) continue;
661
+ const source = sourceOf(view.select);
662
+ const targets = list(view.select["targetList"]).map(targetOf);
663
+ if (source === void 0 || targets.some((target) => target === void 0)) continue;
664
+ const companion = source.companion === void 0 ? void 0 : byName.get(source.companion.name);
665
+ const masks = /* @__PURE__ */ new Map();
666
+ if (source.companion !== void 0) {
667
+ if (companion === void 0 || !companion.options.has("security_barrier")) continue;
668
+ for (const target of list(companion.select["targetList"]).map(targetOf)) if (target?.mask !== void 0) masks.set(target.name, target.mask);
669
+ }
670
+ const passthrough = [];
671
+ const restricted = [];
672
+ for (const target of targets) {
673
+ const fromCompanion = source.companion !== void 0 && target.from !== void 0 && target.from === (source.companion.alias ?? source.companion.name);
674
+ const mask = target.mask ?? (fromCompanion ? masks.get(target.name) : void 0);
675
+ if (mask === void 0) {
676
+ if (!fromCompanion) passthrough.push(target.name);
677
+ continue;
678
+ }
679
+ const { allow, deny } = splitMask(mask);
680
+ restricted.push({
681
+ column: target.name,
682
+ grants: await grantsOf(allow, memberships, functions, seeds),
683
+ denies: await grantsOf(deny, memberships, functions, seeds)
684
+ });
685
+ }
686
+ out.push({
687
+ view: view.name,
688
+ table: source.table,
689
+ ...source.companion === void 0 ? {} : { companion: source.companion.name },
690
+ passthrough,
691
+ restricted
692
+ });
693
+ }
694
+ return out;
695
+ }
696
+ const quote = escapeSqlIdent;
697
+ /** `create view` statements for every view in the database, from `pg_get_viewdef` and the view's options. */
698
+ async function viewsSqlFromDb(query) {
699
+ return (await query(`select n.nspname as schema, c.relname as name, c.reloptions as options, pg_get_viewdef(c.oid) as definition
700
+ from pg_class c join pg_namespace n on n.oid = c.relnamespace
701
+ where c.relkind = 'v' and n.nspname not in ('pg_catalog', 'information_schema')
702
+ order by n.nspname, c.relname`)).rows.flatMap((row) => {
703
+ const { schema, name, definition } = row;
704
+ if (typeof schema !== "string" || typeof name !== "string" || typeof definition !== "string") return [];
705
+ const safe = (Array.isArray(row["options"]) ? row["options"].filter((item) => typeof item === "string") : []).filter((item) => /^[a-z_]+=[a-z0-9_]+$/u.test(item));
706
+ const withOptions = safe.length === 0 ? "" : ` with (${safe.join(", ")})`;
707
+ return [`create view ${quote(schema)}.${quote(name)}${withOptions} as ${definition.trim().replace(/;$/u, "")};`];
708
+ }).join("\n");
709
+ }
710
+ //#endregion
711
+ //#region src/cli/rls-import.ts
712
+ const POLICY_RE = /create\s+policy\s+"?([A-Za-z0-9_]+)"?\s+on\s+"?([A-Za-z0-9_]+)"?([\s\S]*?);/gi;
713
+ function extractParenClause(sql, keyword) {
714
+ const match = new RegExp(`\\b${keyword}\\s*\\(`, "i").exec(sql);
715
+ if (match?.index === void 0) return;
716
+ const start = match.index + match[0].length;
717
+ let depth = 1;
718
+ for (let i = start; i < sql.length; i += 1) {
719
+ const ch = sql[i];
720
+ if (ch === "(") depth += 1;
721
+ else if (ch === ")") {
722
+ depth -= 1;
723
+ if (depth === 0) return sql.slice(start, i).trim();
724
+ }
725
+ }
726
+ }
727
+ function splitPolicies(sql) {
728
+ const out = [];
729
+ for (const match of sql.matchAll(POLICY_RE)) {
730
+ const name = match[1] ?? "policy";
731
+ const table = match[2] ?? "table";
732
+ const body = match[3] ?? "";
733
+ const clauses = body.search(/\b(?:using|with\s+check)\s*\(/i);
734
+ const header = clauses === -1 ? body : body.slice(0, clauses);
735
+ const asRestrictive = /\bas\s+restrictive\b/i.test(header);
736
+ const cmdMatch = /\bfor\s+(all|select|insert|update|delete)\b/i.exec(header);
737
+ const toMatch = /\bto\s+([^\n]+)/i.exec(header);
738
+ const using = extractParenClause(body, "using");
739
+ const check = extractParenClause(body, "with\\s+check");
740
+ const roles = (toMatch?.[1] ?? "authenticated").split(",").map((item) => item.trim()).filter((item) => item !== "");
741
+ const cmd = (cmdMatch?.[1] ?? "all").toUpperCase();
742
+ const commands = cmd === "ALL" ? [
743
+ "SELECT",
744
+ "INSERT",
745
+ "UPDATE",
746
+ "DELETE"
747
+ ] : [cmd];
748
+ for (const command of commands) out.push({
749
+ name,
750
+ table,
751
+ cmd: command,
752
+ permissive: !asRestrictive,
753
+ roles,
754
+ ...using === void 0 ? {} : { using },
755
+ ...check === void 0 ? {} : { check }
756
+ });
757
+ }
758
+ return out;
759
+ }
760
+ function actionsFor(cmds) {
761
+ const actions = [];
762
+ const collection = [];
763
+ if (cmds.includes("SELECT")) {
764
+ actions.push("read");
765
+ collection.push("list");
766
+ }
767
+ if (cmds.includes("INSERT")) collection.push("create");
768
+ if (cmds.includes("UPDATE")) actions.push("update");
769
+ if (cmds.includes("DELETE")) actions.push("delete");
770
+ if (actions.length === 0) actions.push("read");
771
+ return {
772
+ actions,
773
+ collection
774
+ };
775
+ }
776
+ function emitGenerated(catalog, fieldViews, schema) {
777
+ const kind = isSchemaKind(schema) ? schema : "zod";
778
+ const tables = [...new Set(catalog.map((item) => item.table))];
779
+ return emitPermissionsModule({
780
+ generator: "rls import",
781
+ schema: kind,
782
+ exports: fieldViews.length === 0 ? { catalog } : {
783
+ catalog,
784
+ fieldViews
785
+ },
786
+ resources: tables.map((table) => {
787
+ const { actions, collection } = actionsFor(catalog.filter((item) => item.table === table).map((item) => item.cmd));
788
+ return {
789
+ path: [table.replaceAll(/[^A-Za-z0-9_]/g, "_")],
790
+ schema: emptySchema(kind),
791
+ actions,
792
+ collection
793
+ };
794
+ })
795
+ });
796
+ }
797
+ function assertNoServiceRole(sql) {
798
+ if (/\bto\s+service_role\b|\bfrom\s+service_role\b/i.test(sql)) throw new Error("PermDock CLI: imported SQL must never target service_role");
799
+ }
800
+ async function seedsFromDb(query) {
801
+ const schema = (await query(`select table_schema from information_schema.tables where table_name = 'role_permissions' order by table_schema = 'permdock' desc, table_schema = 'public' desc, table_schema limit 1`)).rows[0]?.["table_schema"];
802
+ if (typeof schema !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(schema)) return [];
803
+ try {
804
+ return (await query(`select role::text, permission::text, grant_key, scope, effect from "${schema}".role_permissions`)).rows.flatMap((row) => {
805
+ const seed = seedFromRow(row);
806
+ return seed === void 0 ? [] : [seed];
807
+ });
808
+ } catch {
809
+ return [];
810
+ }
811
+ }
812
+ /** `pg_policies.roles` is a `name[]`, which `pg` returns as an array or, untyped, as `{a,b}`. */
813
+ function policyRoles(value) {
814
+ if (Array.isArray(value)) return value.map(String);
815
+ return typeof value === "string" ? value.replaceAll(/[{}]/g, "").split(",").map((item) => item.trim()).filter((item) => item !== "") : [];
816
+ }
817
+ async function policiesFromDb(db, connect) {
818
+ const client = await connect(db);
819
+ const query = (sql) => client.query(sql, []);
820
+ try {
821
+ const result = await query(`select tablename, policyname, permissive, roles, cmd, qual, with_check from pg_policies`);
822
+ const bodies = /* @__PURE__ */ new Map();
823
+ const procs = await query(`select proname, prosrc from pg_proc`);
824
+ for (const row of procs.rows) {
825
+ const { proname, prosrc } = row;
826
+ if (typeof proname === "string" && typeof prosrc === "string") bodies.set(proname, prosrc);
827
+ }
828
+ const seeds = await seedsFromDb(query);
829
+ const views = await viewsSqlFromDb(query);
830
+ const policies = [];
831
+ for (const row of result.rows) {
832
+ const { tablename, policyname, qual, with_check: check } = row;
833
+ if (typeof tablename !== "string" || typeof policyname !== "string") continue;
834
+ const cmd = typeof row["cmd"] === "string" ? row["cmd"].toUpperCase() : "ALL";
835
+ const commands = cmd === "ALL" ? [
836
+ "SELECT",
837
+ "INSERT",
838
+ "UPDATE",
839
+ "DELETE"
840
+ ] : [cmd];
841
+ for (const command of commands) policies.push({
842
+ name: policyname,
843
+ table: tablename,
844
+ cmd: command,
845
+ permissive: row["permissive"] !== "RESTRICTIVE",
846
+ roles: policyRoles(row["roles"]),
847
+ ...typeof qual === "string" ? { using: qual } : {},
848
+ ...typeof check === "string" ? { check } : {}
849
+ });
850
+ }
851
+ return {
852
+ policies,
853
+ bodies,
854
+ seeds,
855
+ views
856
+ };
857
+ } finally {
858
+ await client.end();
859
+ }
860
+ }
861
+ async function runRlsImport(input) {
862
+ let policies = [];
863
+ let bodies = /* @__PURE__ */ new Map();
864
+ let seeds = [];
865
+ let viewsSql = "";
866
+ if (input.sql !== void 0) {
867
+ const sqlPath = resolve(input.cwd, input.sql);
868
+ if (!existsSync(sqlPath)) return {
869
+ code: 2,
870
+ output: `PermDock CLI: SQL dump not found: ${input.sql}`
871
+ };
872
+ const sql = readFileSync(sqlPath, "utf8");
873
+ assertNoServiceRole(sql);
874
+ viewsSql = sql;
875
+ seeds = await seedsFromSql(sql);
876
+ policies = splitPolicies(await canonicalDump(sql) ?? sql);
877
+ if (policies.length === 0) policies = splitPolicies(sql);
878
+ } else if (input.db !== void 0) try {
879
+ const fromDb = await policiesFromDb(input.db, input.connect ?? ((db) => connectPg(db, "permdock rls import --db")));
880
+ policies = fromDb.policies;
881
+ bodies = fromDb.bodies;
882
+ seeds = fromDb.seeds;
883
+ viewsSql = fromDb.views;
884
+ } catch (cause) {
885
+ return usageResult(cause);
886
+ }
887
+ else return {
888
+ code: 2,
889
+ output: "PermDock CLI: rls import needs --sql <file> or --db <url>"
890
+ };
891
+ const memberships = parseMembershipsFlag(input.memberships) ?? input.config.rls?.memberships;
892
+ const functions = input.config.rls?.functions;
893
+ const unmapped = [];
894
+ const joins = [];
895
+ const catalog = [];
896
+ for (const item of policies) {
897
+ const sourceSql = item.using ?? item.check ?? "true";
898
+ const condition = await conditionFromAst(item.using ?? item.check, memberships, functions, unmapped, joins, seeds);
899
+ const grants = await helperGrants(item.using ?? item.check, memberships, functions, seeds);
900
+ catalog.push({
901
+ table: item.table,
902
+ cmd: item.cmd,
903
+ permissive: item.permissive,
904
+ roles: item.roles,
905
+ condition,
906
+ fingerprint: await fingerprintSql(sourceSql),
907
+ sourceSql,
908
+ ...grants.length === 0 ? {} : { grants }
909
+ });
910
+ }
911
+ const fieldViews = viewsSql === "" ? [] : await fieldViewsFromSql(viewsSql, memberships, functions, seeds);
912
+ const outRel = input.out ?? "src/permissions.generated.ts";
913
+ const outPath = resolve(input.cwd, outRel);
914
+ mkdirSync(dirname(outPath), { recursive: true });
915
+ writeFileSync(outPath, emitGenerated(catalog, fieldViews, input.schema));
916
+ const hints = [
917
+ ...uniqueHints([...new Set(unmapped)], bodies),
918
+ ...[...new Set(joins)].map(membershipHint),
919
+ ...fieldViews.map(fieldViewHint)
920
+ ];
921
+ return {
922
+ code: 0,
923
+ output: hints.length === 0 ? `wrote ${outRel}` : `wrote ${outRel}\n${hints.join("\n")}`
924
+ };
925
+ }
926
+ function fieldViewHint(view) {
927
+ return `field view ${view.view} over ${view.table}: ${view.restricted.map((item) => item.column).join(", ")} are field-limited; set fields on the read grants that list them (fieldViews export)`;
928
+ }
929
+ function membershipHint(table) {
930
+ return [`exists over ${table} stayed opaque; if it holds memberships, map it in permdock.config.ts:`, `// rls: { memberships: { tenant: { table: '${table}', user: 'user_id', tenant: 'tenant_id', role: 'role' } } }`].join("\n");
931
+ }
932
+ function uniqueHints(names, bodies) {
933
+ const lines = [];
934
+ for (const name of names) {
935
+ const short = name.includes(".") ? name.slice(name.lastIndexOf(".") + 1) : name;
936
+ lines.push(`add rls.functions.${short} to make this grant portable`);
937
+ const body = bodies.get(short) ?? bodies.get(name);
938
+ if (body !== void 0) lines.push(`-- ${name}: ${body.trim().slice(0, 240)}`);
939
+ }
940
+ return lines;
941
+ }
942
+ //#endregion
943
+ export { runRlsImport };