permdock 0.4.0 → 0.6.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 (515) hide show
  1. package/README.md +37 -35
  2. package/dist/{schema-Bol6gqXA.js → 2020-C9VN-x8c.js} +5 -130
  3. package/dist/a2a/index.d.ts +6 -6
  4. package/dist/a2a/index.js +14 -17
  5. package/dist/{adapter-context-mlWsVGGg.js → adapter-context-CRhqyzCk.js} +1 -1
  6. package/dist/adoption-scan-DCYe60Pi.js +107 -0
  7. package/dist/agent/index.d.ts +3 -0
  8. package/dist/agent/index.js +1 -0
  9. package/dist/ai-sdk/index.d.ts +18 -35
  10. package/dist/ai-sdk/index.js +37 -23
  11. package/dist/{app-data-CV8pqqMi.js → app-data-MuyzVqX8.js} +2 -1
  12. package/dist/approval-header-CJACtHkv.js +23 -0
  13. package/dist/approval-prompt-Dg5LeAcT.js +62 -0
  14. package/dist/approval-prompt-DvSSPQJX.d.ts +57 -0
  15. package/dist/approvals/index.d.ts +5 -3
  16. package/dist/approvals/index.js +8 -5
  17. package/dist/approvals-p1PGoVjb.js +995 -0
  18. package/dist/arazzo-41WuzHou.js +36 -0
  19. package/dist/{arazzo-C4BcskbX.js → arazzo-CaUVBn7D.js} +20 -14
  20. package/dist/args-IIolxxKA.js +197 -0
  21. package/dist/astro/index.d.ts +43 -0
  22. package/dist/astro/index.js +27 -0
  23. package/dist/audience-DabClFLQ.js +55 -0
  24. package/dist/auth-DRLEizbL.js +178 -0
  25. package/dist/authzen/index.d.ts +26 -6
  26. package/dist/authzen/index.js +94 -79
  27. package/dist/automation-BNM3TtDo.d.ts +114 -0
  28. package/dist/automation-DVjOckjV.js +157 -0
  29. package/dist/better-auth/index.d.ts +8 -6
  30. package/dist/better-auth/index.js +9 -8
  31. package/dist/better-supabase/index.d.ts +357 -30
  32. package/dist/better-supabase/index.js +936 -194
  33. package/dist/{bind-kk-uyCwH.js → bind-CAvgUuKs.js} +14 -10
  34. package/dist/{bind-BzqG8SMb.d.ts → bind-DOyrv6zi.d.ts} +12 -10
  35. package/dist/body-CH5of8Ne.js +10 -0
  36. package/dist/body-text-QcXok_SI.js +52 -0
  37. package/dist/{build-instance-DIIV9DbC.js → build-instance-Bu_eDqYw.js} +4 -3
  38. package/dist/{canonical-json-CFKyFOke.js → canonical-json-BC8_nMTw.js} +5 -3
  39. package/dist/{capability-CksyCWDH.d.ts → capability-Drg-1YhL.d.ts} +44 -25
  40. package/dist/{capability-txATtKV4.js → capability-N1K9IpqS.js} +68 -42
  41. package/dist/casbin-Cr7RLtA3.js +30 -0
  42. package/dist/casbin-Dyu2gnUD.js +234 -0
  43. package/dist/casl-64gpT-8x.js +24 -0
  44. package/dist/casl-DjEDhTCP.js +299 -0
  45. package/dist/catalog/index.d.ts +74 -2
  46. package/dist/catalog/index.js +51 -2
  47. package/dist/catalog-BoWglDPI.js +1 -0
  48. package/dist/catalog-DZVbrF-z.js +52 -0
  49. package/dist/{catalog-tZUyOfOv.js → catalog-HD2gf5mY.js} +51 -6
  50. package/dist/{catalog-doc-DWtg0gGR.js → catalog-doc-Cdn7-0pQ.js} +45 -23
  51. package/dist/catalog-fingerprint-CCP0-yQS.js +153 -0
  52. package/dist/chat/index.d.ts +2 -0
  53. package/dist/chat/index.js +224 -0
  54. package/dist/chat-sdk/index.d.ts +87 -0
  55. package/dist/chat-sdk/index.js +197 -0
  56. package/dist/claims-map-7oQ3ue4X.js +13 -0
  57. package/dist/claims-map-Ca-QX8C6.d.ts +32 -0
  58. package/dist/claude-agent/index.d.ts +7 -14
  59. package/dist/claude-agent/index.js +24 -27
  60. package/dist/clerk/index.d.ts +9 -8
  61. package/dist/clerk/index.js +9 -14
  62. package/dist/cli/bin.js +36 -17
  63. package/dist/cli/index.d.ts +19 -5
  64. package/dist/cli/index.js +164 -4
  65. package/dist/cloud/index.d.ts +102 -63
  66. package/dist/cloud/index.js +239 -340
  67. package/dist/cloud-ytQ3uviA.js +87 -0
  68. package/dist/codemod-5mpSpnUY.js +37 -0
  69. package/dist/codemod-ua2hHy7w.js +2084 -0
  70. package/dist/collect-Ci6akVwH.js +55 -0
  71. package/dist/collect-D7eQDffE.js +1 -0
  72. package/dist/{collect-2SrB7lfk.js → collect-mLTY4nwb.js} +75 -11
  73. package/dist/command-L8EstFNm.js +6 -0
  74. package/dist/compile/index.d.ts +1 -1
  75. package/dist/compile/index.js +1 -2
  76. package/dist/{compile-CtTP7eur.d.ts → compile-1bsAezL0.d.ts} +5 -3
  77. package/dist/{compile-CcEu2ZQ1.js → compile-CMqMx_IN.js} +11 -8
  78. package/dist/completion-BTFrHZhX.js +143 -0
  79. package/dist/config-Bj2Ixq3d.js +26 -0
  80. package/dist/{config-BIjREpyE.js → config-bs_kZeYq.js} +12 -7
  81. package/dist/{config-report--Xb9APJS.js → config-report-DSpsLpCE.js} +15 -5
  82. package/dist/{connection-DUsczpB5.js → connection-DjhIJSs2.js} +6 -5
  83. package/dist/{context-DieZVJXu.js → context-B_u3_bDJ.js} +2 -2
  84. package/dist/convex/index.d.ts +11 -10
  85. package/dist/convex/index.js +6 -4
  86. package/dist/create-B30OMUOJ.d.ts +107 -0
  87. package/dist/create-CBMmFie-.d.ts +138 -0
  88. package/dist/create-CGm28gyI.js +130 -0
  89. package/dist/create-CQWIpUG-.js +403 -0
  90. package/dist/{create-BBO24vj6.js → create-DCF2SvoT.js} +31 -32
  91. package/dist/create-D_NmPOdH.d.ts +110 -0
  92. package/dist/{credential-kue0qpbm.js → credential-BcoiejpY.js} +152 -31
  93. package/dist/credentials-DPyHmYz5.js +74 -0
  94. package/dist/delegation-j6-rc37o.js +286 -0
  95. package/dist/delivery/index.d.ts +5 -0
  96. package/dist/delivery/index.js +5 -0
  97. package/dist/delivery-DCAgNyCn.js +499 -0
  98. package/dist/delivery-event-xX4obB8F.js +40 -0
  99. package/dist/{denied-text-DfRk15uw.d.ts → denied-text-CiFQNuMV.d.ts} +5 -5
  100. package/dist/{describe-C3ldA9os.d.ts → describe-B5qgDvEW.d.ts} +2 -2
  101. package/dist/{describe-Cgkp7eP0.js → describe-BybMRY7A.js} +6 -2
  102. package/dist/device-BARQ8eYG.js +193 -0
  103. package/dist/{diff-rpqoe7Ag.js → diff-3jbx6Rm4.js} +60 -54
  104. package/dist/diff-CmuSD3vc.js +37 -0
  105. package/dist/doctor-3ZqNHX_G.js +44 -0
  106. package/dist/{doctor-owlv6ddh.js → doctor-BdZw53-k.js} +245 -50
  107. package/dist/drizzle/index.d.ts +5 -3
  108. package/dist/drizzle/index.js +2 -2
  109. package/dist/elysia/index.d.ts +16 -13
  110. package/dist/elysia/index.js +13 -12
  111. package/dist/env-DJZrPjRi.js +8 -0
  112. package/dist/errors-BDUwg2qC.js +27 -0
  113. package/dist/{errors-drnfxYtm.js → errors-BKy0EfhN.js} +5 -9
  114. package/dist/errors-BWXBMaKK.d.ts +11 -0
  115. package/dist/errors-CWTY6uih.js +143 -0
  116. package/dist/{errors-OD_4c__H.d.ts → errors-DH5QEGXh.d.ts} +2 -2
  117. package/dist/evaluate-CNClBvcj.js +1785 -0
  118. package/dist/evaluations-C_1vdSZc.d.ts +32 -0
  119. package/dist/{evaluations-C9YJsv3H.js → evaluations-beAooV0n.js} +145 -34
  120. package/dist/eve/index.d.ts +12 -16
  121. package/dist/eve/index.js +22 -28
  122. package/dist/event-time-CsegxXxB.js +23 -0
  123. package/dist/expiry-D4_YKRKD.js +52 -0
  124. package/dist/express/index.d.ts +13 -10
  125. package/dist/express/index.js +12 -11
  126. package/dist/fastify/index.d.ts +25 -22
  127. package/dist/fastify/index.js +13 -12
  128. package/dist/fetch-adapter-DD_gfmrC.js +120 -0
  129. package/dist/fetch-adapter-Dw0MTS3D.d.ts +31 -0
  130. package/dist/fields-OYG_JR78.js +203 -0
  131. package/dist/files-C5ZI27eV.js +124 -0
  132. package/dist/{fixtures-h2eG2OZV.js → fixtures-B7XrLeY7.js} +8 -7
  133. package/dist/flags-C3DktBDY.js +86 -0
  134. package/dist/{from-snapshot-7REQZe0H.js → from-snapshot-CTCMsFZk.js} +55 -52
  135. package/dist/{grantee-conditions-MQs5NIuX.js → grantee-conditions-CcXf8hMM.js} +4 -3
  136. package/dist/{grantee-CXY-0C87.js → grantee-hxrUsbpM.js} +16 -6
  137. package/dist/{grantee-match-fxYp9Nmt.js → grantee-match-DbENBHLB.js} +5 -4
  138. package/dist/h3/index.d.ts +37 -0
  139. package/dist/h3/index.js +35 -0
  140. package/dist/headers-BIjfMaoC.js +8 -0
  141. package/dist/headers-CIbDTUTK.d.ts +7 -0
  142. package/dist/{helpers-C9YmyBIa.js → helpers-CBYVMjwh.js} +45 -38
  143. package/dist/hono/index.d.ts +12 -9
  144. package/dist/hono/index.js +13 -12
  145. package/dist/hosted-B46-5LYE.js +315 -0
  146. package/dist/hosted-BPk51-kX.d.ts +78 -0
  147. package/dist/{http-DPuDaChb.d.ts → http-B_LphE5Y.d.ts} +1 -2
  148. package/dist/http-DXJ37RDA.js +46 -0
  149. package/dist/{http-BEbdMZ05.js → http-ujKm0JXE.js} +1 -2
  150. package/dist/{import-UHk1N7vH.js → import-CNV7I2Dw.js} +25 -20
  151. package/dist/{import-BFIlhetD.js → import-wyqXUyjm.js} +190 -53
  152. package/dist/index-B8YjkEZ4.d.ts +210 -0
  153. package/dist/index-C-6Letxg.d.ts +431 -0
  154. package/dist/index-CaxrMD1A.d.ts +1 -0
  155. package/dist/{index-BwMe94Xq.d.ts → index-Ch8LpNDp.d.ts} +34 -16
  156. package/dist/index-Cp_ilKi1.d.ts +91 -0
  157. package/dist/index-CueFnxQc.d.ts +110 -0
  158. package/dist/index-DuWxc5dt.d.ts +909 -0
  159. package/dist/index.d.ts +19 -15
  160. package/dist/index.js +31 -21
  161. package/dist/init-DeMYsnYJ.js +96 -0
  162. package/dist/init-GG6Jh8HD.js +95 -0
  163. package/dist/{instance-options-plkrsAog.d.ts → instance-options-BsVpyGIk.d.ts} +2 -2
  164. package/dist/instance-snapshot-BOEhcqIF.js +601 -0
  165. package/dist/instant-BluqDvyS.js +19 -0
  166. package/dist/internals-Dk8A8fX3.js +17 -0
  167. package/dist/{json-schema-DBkdUuCO.js → json-schema-B-vAwlde.js} +45 -6
  168. package/dist/json-schema-CN_iLFH2.d.ts +40 -0
  169. package/dist/jwt/index.d.ts +18 -11
  170. package/dist/jwt/index.js +156 -135
  171. package/dist/{kernel-CB3LrIJM.js → kernel-D0NVb1cK.js} +52 -24
  172. package/dist/kysely/index.d.ts +5 -3
  173. package/dist/kysely/index.js +2 -2
  174. package/dist/load-BxEtwlBS.js +1 -0
  175. package/dist/{load-C3_oTHyO.js → load-DFS_ry0W.js} +22 -6
  176. package/dist/{load-jose-BL6LH4bL.js → load-jose-DZ4dnjri.js} +1 -4
  177. package/dist/login-Dfe5RlYk.js +68 -0
  178. package/dist/login-imhuwvn3.js +254 -0
  179. package/dist/manifest-C8IzW3Do.js +42 -0
  180. package/dist/manifest-dvL2XEe1.js +370 -0
  181. package/dist/manifest-json-CAGzls-C.js +9 -0
  182. package/dist/{manifest-uDS9y5de.d.ts → manifest-mx5ghSFM.d.ts} +9 -2
  183. package/dist/manifest-schema-C0kK_8V0.js +399 -0
  184. package/dist/{map-claims-AVlBaJoa.js → map-claims-D3oRmTk0.js} +13 -10
  185. package/dist/{map-error-BE27PYkE.js → map-error-Dr70oA_3.js} +3 -3
  186. package/dist/{markers-CiwAOZtO.js → markers-C6joDI3o.js} +2 -1
  187. package/dist/mcp/index.d.ts +22 -12
  188. package/dist/mcp/index.js +57 -39
  189. package/dist/{migrate-BwlB5-Wk.js → migrate-CIq4-E9F.js} +53 -14
  190. package/dist/nest/index.d.ts +12 -9
  191. package/dist/nest/index.js +15 -14
  192. package/dist/next/index.d.ts +18 -21
  193. package/dist/next/index.js +13 -11
  194. package/dist/next/plugin.d.ts +1 -1
  195. package/dist/next/plugin.js +2 -2
  196. package/dist/node/index.d.ts +10 -10
  197. package/dist/node/index.js +7 -9
  198. package/dist/{ocsf-uYFXGVw2.js → ocsf-BFp-PZZA.js} +22 -11
  199. package/dist/openai/index.d.ts +9 -16
  200. package/dist/openai/index.js +17 -24
  201. package/dist/openapi/index.d.ts +3 -3
  202. package/dist/openapi/index.js +1 -1
  203. package/dist/{openapi-DBzHQbov.js → openapi-B7HZ0f-r.js} +8 -8
  204. package/dist/openapi-C4dDTVEd.js +138 -0
  205. package/dist/{openapi-BJdBmYDG.js → openapi-DD1SV-5-.js} +10 -9
  206. package/dist/operation-findings-DgATDpvh.js +36 -0
  207. package/dist/operations-X0VM7F3m.d.ts +59 -0
  208. package/dist/orpc/index.d.ts +13 -10
  209. package/dist/orpc/index.js +20 -15
  210. package/dist/otel/index.d.ts +3 -2
  211. package/dist/otel/index.js +30 -7
  212. package/dist/output-1im__-08.js +88 -0
  213. package/dist/output-files-B3IZJksC.js +1 -0
  214. package/dist/{output-files-CgIsvdSa.js → output-files-DhRBBE4n.js} +24 -26
  215. package/dist/{permission-keys-B26jeyUv.js → ownership-DqaJNJPn.js} +1045 -153
  216. package/dist/{package-root-DtNnpmUd.js → package-root-Dk_ETdkp.js} +1 -1
  217. package/dist/{parse-CVFQHk6c.js → parse-Cxq0WxrA.js} +2 -2
  218. package/dist/{parse-local-manifest-DvYUR0QL.d.ts → parse-local-manifest-5ODwqu8b.d.ts} +1 -1
  219. package/dist/{parse-local-manifest-C-q02Pal.js → parse-local-manifest-CVSs6J9I.js} +1 -1
  220. package/dist/parse-request-D_tUXG6M.js +26 -0
  221. package/dist/paths-DXSHAMIa.js +42 -0
  222. package/dist/pdp/index.d.ts +7 -3
  223. package/dist/pdp/index.js +45 -26
  224. package/dist/{peer-BOr_kJE1.js → peer-C8swJ2GH.js} +23 -4
  225. package/dist/peer-CRvC7Hg1.js +1 -0
  226. package/dist/permdock-BrAscV28.js +868 -0
  227. package/dist/permdock-SV8ZINYT.d.ts +502 -0
  228. package/dist/{permission-registry-BsblpB-z.js → permission-registry-Br4jSNVi.js} +3 -3
  229. package/dist/permissions-B-wCP5ZC.js +30 -0
  230. package/dist/{permissions-CCJ6lmxB.js → permissions-BPxlwVhN.js} +4 -3
  231. package/dist/{permissions-COH-KRgT.d.ts → permissions-u_KHg-sN.d.ts} +1 -2
  232. package/dist/policies-DP2nqRoF.js +295 -0
  233. package/dist/{policy-ur0BBK_e.d.ts → policy-77FSAq_V.d.ts} +2 -2
  234. package/dist/{hosted-CBHgkzDl.js → policy-DbM5YYtV.js} +17 -273
  235. package/dist/policy-from-catalog-C2gMa2Dj.js +450 -0
  236. package/dist/policy-module-CTlwMvLI.js +89 -0
  237. package/dist/{policy-types-sp9P1iIV.d.ts → policy-types-n0uRTsW8.d.ts} +460 -632
  238. package/dist/postgrest-CEgRbefE.d.ts +100 -0
  239. package/dist/postgrest-DAjUkF9w.js +575 -0
  240. package/dist/{powersync-cZe4kzhL.js → powersync-BkWWCS1K.js} +23 -24
  241. package/dist/powersync-DISt6SUe.js +62 -0
  242. package/dist/powersync-MMJ2mI2q.js +1 -0
  243. package/dist/preset/index.d.ts +146 -0
  244. package/dist/preset/index.js +1 -0
  245. package/dist/preset-DZdU0tne.js +1768 -0
  246. package/dist/principal-source-pHneukrx.js +103 -0
  247. package/dist/prisma/index.d.ts +6 -3
  248. package/dist/prisma/index.js +2 -2
  249. package/dist/{problem-CnWraVhC.js → problem-CTviyH5L.js} +13 -23
  250. package/dist/{problem-details-rIIo8B2C.d.ts → problem-details-B45V5d2b.d.ts} +1 -1
  251. package/dist/{problem-details-DECUnXAn.js → problem-details-cn5X30gZ.js} +43 -40
  252. package/dist/problem-types-CJ2325SZ.js +5 -0
  253. package/dist/{prompt-CXYhLfsS.js → prompt-DfZLJLIn.js} +2 -2
  254. package/dist/{protected-BN7BUdY1.js → protected-BlF0F6wL.js} +21 -4
  255. package/dist/{protected-B3_P7xuw.d.ts → protected-RFGpakN9.d.ts} +16 -8
  256. package/dist/{provider-Bi-0HNL3.js → provider-B1al-AZz.js} +2 -2
  257. package/dist/{provider-kwHC9CZD.d.ts → provider-DILL9oPK.d.ts} +1 -1
  258. package/dist/{provider-store-Ctt-81Ni.js → provider-store-DM6DNcta.js} +2 -2
  259. package/dist/pull-CvpINcMK.js +1 -0
  260. package/dist/pull-jEwbf80J.js +256 -0
  261. package/dist/push-BD4f15co.js +116 -0
  262. package/dist/pushed-policy-CqtxkV4G.js +238 -0
  263. package/dist/pushed-policy-DCW91KQU.d.ts +57 -0
  264. package/dist/react/index.d.ts +8 -8
  265. package/dist/react/index.js +6 -6
  266. package/dist/react/provider-client.d.ts +1 -1
  267. package/dist/react/provider-client.js +1 -2
  268. package/dist/react-native/index.d.ts +24 -72
  269. package/dist/react-native/index.js +29 -25
  270. package/dist/{refs-f3imMjNW.js → refs-K6eWUJ0H.js} +1 -1
  271. package/dist/{relation-walk-BXnlLtg2.js → relation-walk-3OyDBF0S.js} +2 -2
  272. package/dist/{relations-CvmSpG67.js → relations-BnCWnJGI.js} +3 -3
  273. package/dist/renames-CGj7YwcQ.js +175 -0
  274. package/dist/{replay-COpmZUfx.d.ts → replay-Bkm-Ne4l.d.ts} +1 -1
  275. package/dist/{replay-BsOyTrdV.js → replay-Du1tJjG7.js} +2 -1
  276. package/dist/{request-context-BVM7aWNs.js → request-context-C81Pip9n.js} +3 -3
  277. package/dist/request-schema-CMreVuFM.js +148 -0
  278. package/dist/resend/index.d.ts +126 -0
  279. package/dist/resend/index.js +379 -0
  280. package/dist/{resource-relations-D1Un3pcz.js → resource-relations-D_jw0BFx.js} +1 -1
  281. package/dist/{retire-BFcxL6un.js → retire-CALjIQ7e.js} +2 -2
  282. package/dist/{revocations-Cy06JNx2.d.ts → revocations-R07lFBnX.d.ts} +2 -0
  283. package/dist/rls-BAqP4q66.js +336 -0
  284. package/dist/{rls-BEktUaqg.js → rls-DTvYd-lI.js} +288 -690
  285. package/dist/{role-builder-B4GbKM-i.js → role-builder-uWQZ4v84.js} +14 -207
  286. package/dist/{rpc-nYC3cR_u.js → rpc-VSl5ylaQ.js} +7 -7
  287. package/dist/run-CUKuz0A8.js +723 -0
  288. package/dist/run-DDwUaJDU.js +1 -0
  289. package/dist/run-ticket-DocwaTKn.d.ts +124 -0
  290. package/dist/run-ticket-sxFI6LAk.js +337 -0
  291. package/dist/{runtime-D_tMXnsq.js → runtime-D3VTAiCA.js} +1 -1
  292. package/dist/{saas-DtaA4JuW.js → saas-BCXRuXca.js} +16 -14
  293. package/dist/scan-qvOe0hS3.js +29 -0
  294. package/dist/{schema-DjQBcAP9.js → schema-B4v0Qrac.js} +102 -8
  295. package/dist/schema-yLuBWWsh.js +130 -0
  296. package/dist/scim/index.d.ts +2 -2
  297. package/dist/scim/index.js +1 -2
  298. package/dist/{scim-vFR1O5oG.js → scim-ClHtpyV3.js} +208 -76
  299. package/dist/{scopes-tvpa34ep.js → scopes-CUPSjo9q.js} +12 -7
  300. package/dist/server/index.d.ts +12 -143
  301. package/dist/server/index.js +12 -9
  302. package/dist/server-C3WXAHZj.js +453 -0
  303. package/dist/{server-types-DdqBwZN_.d.ts → server-types-CKQiCnON.d.ts} +51 -68
  304. package/dist/{sha256-BO0swRXL.js → sha256-D9ihqmvd.js} +8 -1
  305. package/dist/{shared-1uhI-e-b.js → shared-BAK8t4Uo.js} +20 -9
  306. package/dist/{shared-JhMeOsDF.js → shared-DvvFzYXe.js} +8 -9
  307. package/dist/signals-D3NcTKUS.js +32 -0
  308. package/dist/sink-4-eQIRWf.d.ts +225 -0
  309. package/dist/sink-BEZSlMS_.js +957 -0
  310. package/dist/{skills-BZdRQkxs.js → skills-B6lVdD_W.js} +13 -6
  311. package/dist/skills-CTYwkl44.js +51 -0
  312. package/dist/snapshot-B7DkYg6g.js +269 -0
  313. package/dist/{snapshot-cache-Cod40D-X.js → snapshot-cache-DZHQ0KF6.js} +11 -5
  314. package/dist/{snapshot-cache-J5T7t_vD.d.ts → snapshot-cache-PXI-vGpY.d.ts} +7 -5
  315. package/dist/solid/index.d.ts +11 -12
  316. package/dist/solid/index.js +7 -7
  317. package/dist/solid-start/index.d.ts +52 -0
  318. package/dist/solid-start/index.js +49 -0
  319. package/dist/{sources-Dljy06zL.d.ts → sources-Xc4zkszI.d.ts} +7 -13
  320. package/dist/{sources-B1-b-R0t.js → sources-vs5dGOsS.js} +125 -119
  321. package/dist/{sql-t8teWOfo.js → sql-B5T1IL83.js} +13 -1
  322. package/dist/src-Cu2m75uo.js +1860 -0
  323. package/dist/ssf/index.d.ts +4 -4
  324. package/dist/ssf/index.js +384 -47
  325. package/dist/standard-webhooks-DgFFD-Ga.js +228 -0
  326. package/dist/standard-webhooks-rbD7LS6h.d.ts +88 -0
  327. package/dist/storage-C2bWdvJH.js +132 -0
  328. package/dist/{store-ILkLUj_o.js → store-BDutJkDL.js} +40 -53
  329. package/dist/{store-options-CbUHDoSe.js → store-options-u0ycEe8s.js} +26 -21
  330. package/dist/{stores-Cxz_80g-.d.ts → stores-BUGNbJTt.d.ts} +7 -8
  331. package/dist/{stores-BHXdSbw9.js → stores-CGhM8BN_.js} +2 -2
  332. package/dist/{stream-Dwsg6WwE.d.ts → stream-CeCMJmBB.d.ts} +2 -2
  333. package/dist/{stream-BMui98KK.js → stream-CvdUS9V1.js} +9 -2
  334. package/dist/style-DiKWnAvn.js +1 -0
  335. package/dist/{style-CTm1AXDT.js → style-Uao76wO7.js} +3 -2
  336. package/dist/subject-BGoM5o8B.js +17 -0
  337. package/dist/supabase/index.d.ts +23 -106
  338. package/dist/supabase/index.js +5 -4
  339. package/dist/supabase/middleware.d.ts +7 -6
  340. package/dist/supabase/middleware.js +13 -11
  341. package/dist/supabase-By_frk3U.js +92 -0
  342. package/dist/{supabase-hook-Cva3ikXz.js → supabase-hook-BMoEhZir.js} +960 -64
  343. package/dist/supabase-hook-CCw5m35C.js +1 -0
  344. package/dist/{supabase-C1TWlnYt.js → supabase-x5JtR2tc.js} +99 -206
  345. package/dist/support-session-C6xJQYut.js +158 -0
  346. package/dist/svelte/Protected.svelte +4 -4
  347. package/dist/svelte/index.d.ts +7 -7
  348. package/dist/svelte/index.js +10 -10
  349. package/dist/svelte/runtime.d.ts +3 -3
  350. package/dist/svelte/runtime.js +3 -3
  351. package/dist/svelte/source.d.ts +7 -7
  352. package/dist/svelte/source.js +4 -4
  353. package/dist/sveltekit/index.d.ts +51 -0
  354. package/dist/sveltekit/index.js +27 -0
  355. package/dist/tanstack-start/index.d.ts +51 -0
  356. package/dist/tanstack-start/index.js +40 -0
  357. package/dist/target-Bw37TFNA.js +51 -0
  358. package/dist/{tenancy-DshjqY0n.js → tenancy-DN2QAx9z.js} +5 -5
  359. package/dist/terminal/index.d.ts +11 -9
  360. package/dist/terminal/index.js +23 -287
  361. package/dist/testing/index.d.ts +311 -38
  362. package/dist/testing/index.js +3475 -201
  363. package/dist/testing/saas/index.d.ts +9 -8
  364. package/dist/testing/saas/index.js +2 -2
  365. package/dist/testing/saas/permissions.d.ts +1 -1
  366. package/dist/testing/saas/permissions.js +1 -2
  367. package/dist/text-BMFRfBqc.js +8 -0
  368. package/dist/{text-diff-BdkkYSbi.js → text-diff-BQcUapOb.js} +1 -1
  369. package/dist/thenable-yD7SabqG.js +31 -0
  370. package/dist/time-DkWjdL98.js +71 -0
  371. package/dist/{token-Bx9qy30p.js → token-BLZcjQgt.js} +15 -6
  372. package/dist/{tool-refusal-CQ7OEia9.js → tool-refusal-CMLN5xhn.js} +2 -2
  373. package/dist/trpc/index.d.ts +12 -9
  374. package/dist/trpc/index.js +16 -14
  375. package/dist/types-8RnwUAvE.d.ts +107 -0
  376. package/dist/{store-9KO4BlkB.d.ts → types-B3_ooZgZ.d.ts} +100 -75
  377. package/dist/{types-Br9IXUBG.d.ts → types-BdtSDbBO.d.ts} +77 -17
  378. package/dist/types-BtHtcKMr.d.ts +157 -0
  379. package/dist/{types-CqrjB9o6.d.ts → types-BzzaHxt3.d.ts} +23 -11
  380. package/dist/types-C791HFu9.d.ts +332 -0
  381. package/dist/types-C863OQiR.d.ts +57 -0
  382. package/dist/{types-ByUo56un.d.ts → types-CVZSNocA.d.ts} +23 -22
  383. package/dist/{types-DHrmBJLH.d.ts → types-CX7AvRqP.d.ts} +7 -7
  384. package/dist/types-C_IiEs64.d.ts +65 -0
  385. package/dist/{types-7rJVLWe5.d.ts → types-Dfv0aTER.d.ts} +63 -11
  386. package/dist/types-DqzsnlSA.js +67 -0
  387. package/dist/{types-DpWfQdSh.d.ts → types-Druu9wLM.d.ts} +46 -11
  388. package/dist/{types-CIlTojhq.d.ts → types-_WhUP7ud.d.ts} +9 -6
  389. package/dist/{types-CUcFZfpU.d.ts → types-lUlG3TVd.d.ts} +2 -1
  390. package/dist/unplugin/index.d.ts +1 -1
  391. package/dist/unplugin/index.js +2 -2
  392. package/dist/usage-CRVl9V3t.js +32 -0
  393. package/dist/usage-CZpSQP6L.js +1 -0
  394. package/dist/{usage-CG9nOYZw.js → usage-SveTRTyr.js} +54 -11
  395. package/dist/{validation-error-BSSw0l_8.d.ts → validation-error-DHUrAkku.d.ts} +1 -1
  396. package/dist/{validity-dVrUEPJt.js → validity-CZ7-y0Cj.js} +32 -15
  397. package/dist/{verifier-DMr_Zmb_.js → verifier-DHuh-okk.js} +18 -7
  398. package/dist/{verify-BztUB3GX.js → verify-BaAKx7t6.js} +645 -50
  399. package/dist/{version-BEogC-rB.js → version-CEbQ5UeM.js} +4 -3
  400. package/dist/version-DXkYUISx.js +1 -0
  401. package/dist/{views-CJsrBS1f.js → views-DTIIO-oQ.js} +22 -5
  402. package/dist/{permission-types-Dg39z9Kv.d.ts → vocabulary-CN8H_9UF.d.ts} +67 -2
  403. package/dist/vue/index.d.ts +9 -10
  404. package/dist/vue/index.js +8 -8
  405. package/dist/waiter-B986w1oK.d.ts +36 -0
  406. package/dist/waiter-BGUtGYoU.js +67 -0
  407. package/dist/watch--ovlPOc0.js +1 -0
  408. package/dist/{watch-zeucB7eF.js → watch-vea54PRw.js} +44 -5
  409. package/dist/webmcp/index.d.ts +2 -2
  410. package/dist/webmcp/index.js +3 -3
  411. package/dist/where-scope-C9vfEphl.js +306 -0
  412. package/dist/who-can-DWBAcaCQ.js +364 -0
  413. package/dist/wire-delegation-Cv3W2eaM.js +36 -0
  414. package/dist/wire-denial-C7PaVYEM.js +27 -0
  415. package/dist/workflow/index.d.ts +5 -0
  416. package/dist/workflow/index.js +223 -0
  417. package/dist/workflow-sdk/index.d.ts +56 -0
  418. package/dist/workflow-sdk/index.js +78 -0
  419. package/dist/{wrap-Cr93qqdP.d.ts → wrap-C5jC6sKI.d.ts} +2 -1
  420. package/dist/{wrap-DWsU_5Bd.js → wrap-gX61EtpB.js} +7 -6
  421. package/package.json +136 -37
  422. package/schemas/access-event-v1.json +118 -0
  423. package/schemas/approval-request-v1.json +34 -1
  424. package/schemas/approval-signature-v1.json +94 -0
  425. package/schemas/automation-event-v1.json +113 -0
  426. package/schemas/capability-v1.json +84 -0
  427. package/schemas/catalog-event-v1.json +87 -0
  428. package/schemas/catalog-v1.json +123 -12
  429. package/schemas/cli-commands-v1.json +164 -0
  430. package/schemas/cli-result-v1.json +96 -0
  431. package/schemas/cloud-api-v1.json +5407 -0
  432. package/schemas/connector-v1.json +408 -0
  433. package/schemas/credential-event-v1.json +81 -0
  434. package/schemas/credential-v1.json +134 -0
  435. package/schemas/decision-event-v1.json +288 -0
  436. package/schemas/delivery-event-v1.json +117 -0
  437. package/schemas/directory-event-v1.json +85 -0
  438. package/schemas/evidence-export-v1.json +54 -0
  439. package/schemas/membership-event-v1.json +93 -0
  440. package/schemas/policy-v1.json +68 -0
  441. package/schemas/pushed-policy-v1.json +236 -0
  442. package/schemas/run-v1.json +162 -0
  443. package/schemas/snapshot-v1.json +138 -0
  444. package/schemas/supabase-claims-v1.json +4 -4
  445. package/schemas/supabase-manifest-v1.json +5 -1
  446. package/schemas/support-session-v1.json +111 -0
  447. package/skills/permdock/SKILL.md +16 -12
  448. package/skills/permdock-agents/SKILL.md +40 -23
  449. package/skills/permdock-agents/references/operations-automations-chat.md +221 -0
  450. package/skills/permdock-agents/references/runtimes.md +22 -18
  451. package/skills/permdock-approvals/SKILL.md +29 -13
  452. package/skills/permdock-approvals/references/delivery-and-waiters.md +172 -0
  453. package/skills/permdock-approvals/references/stores-and-resume.md +21 -7
  454. package/skills/permdock-audit/SKILL.md +3 -3
  455. package/skills/permdock-credentials/SKILL.md +5 -5
  456. package/skills/permdock-credentials/references/tokens-keys-links.md +14 -10
  457. package/skills/permdock-data/SKILL.md +6 -6
  458. package/skills/permdock-data/references/queries-and-rls.md +10 -9
  459. package/skills/permdock-data/references/relationships.md +3 -3
  460. package/skills/permdock-tenancy/SKILL.md +20 -7
  461. package/skills/permdock-tenancy/references/contacts-and-support-sessions.md +122 -0
  462. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +6 -4
  463. package/skills/permdock-wire/SKILL.md +17 -11
  464. package/skills/permdock-wire/references/adapters.md +139 -51
  465. package/skills/permdock-wire/references/policy-options.md +5 -5
  466. package/skills/permdock-wire/references/presets-and-recipes.md +58 -0
  467. package/dist/approvals-DZL76lKW.js +0 -240
  468. package/dist/arazzo-CD8d0WLb.js +0 -54
  469. package/dist/catalog-6yWAX6Ps.js +0 -2
  470. package/dist/catalog-WHG4kBq7.js +0 -48
  471. package/dist/cloud-C7bSDgX4.js +0 -50
  472. package/dist/cloud-PeBN3IEn.js +0 -118
  473. package/dist/collect-Bw2Jdq1q.js +0 -2
  474. package/dist/collect-CQx4hX4N.js +0 -83
  475. package/dist/commands-Cpip4ULx.js +0 -97
  476. package/dist/config-DLt6BvV7.js +0 -36
  477. package/dist/diff-Cnghh_Ip.js +0 -48
  478. package/dist/doctor-CuVJvhV_.js +0 -53
  479. package/dist/duration-xK2jGFVc.js +0 -25
  480. package/dist/errors-CWfoNg9N.js +0 -47
  481. package/dist/errors-DRnGZHzF.js +0 -30
  482. package/dist/expiry-BoBJ8Tvc.js +0 -7
  483. package/dist/fields-fwfXN01n.js +0 -1016
  484. package/dist/headers-BZSDieNT.js +0 -6
  485. package/dist/headers-Cf-zWvsO.d.ts +0 -6
  486. package/dist/ids-DC4V4CFu.js +0 -18
  487. package/dist/index-DgM7w96K.d.ts +0 -6
  488. package/dist/index-Dz7didpC.d.ts +0 -201
  489. package/dist/index-UdVQgq48.d.ts +0 -550
  490. package/dist/load-B_shHrmd.js +0 -2
  491. package/dist/manifest-BngWKryL.js +0 -770
  492. package/dist/may-use-BOn_dR_w.js +0 -78
  493. package/dist/openapi-DcQ1Kg40.js +0 -164
  494. package/dist/ownership-BgnbOJFT.js +0 -851
  495. package/dist/permdock-L26udHSk.js +0 -3646
  496. package/dist/powersync-BFSbSElQ.js +0 -62
  497. package/dist/powersync-DCDgZgfZ.js +0 -2
  498. package/dist/rls-55DQTuf5.js +0 -250
  499. package/dist/run-DMcNW_8T.js +0 -174
  500. package/dist/server-ZYEHtNHS.js +0 -268
  501. package/dist/sink-BTtmfPnE.js +0 -141
  502. package/dist/sink-CPN4zLfs.d.ts +0 -104
  503. package/dist/skills-Dle4ZoLF.js +0 -56
  504. package/dist/snapshot-Dc9CHPME.js +0 -1078
  505. package/dist/src-Bb7no-hS.js +0 -639
  506. package/dist/subject-C6dLxqHU.js +0 -24
  507. package/dist/supabase-Dbqr141s.js +0 -83
  508. package/dist/supabase-hook-BULg7Ut_.js +0 -2
  509. package/dist/thenable-QSmvt-vZ.js +0 -65
  510. package/dist/types-C0dee0Qf.d.ts +0 -197
  511. package/dist/types-DvupZE0w.d.ts +0 -9
  512. package/dist/usage-4G6t643F.js +0 -42
  513. package/dist/usage-iFLJ0-rr.js +0 -2
  514. package/dist/vocabulary-hhEFLFoL.d.ts +0 -65
  515. package/dist/watch-C8TpsAl4.js +0 -2
@@ -0,0 +1,1860 @@
1
+ import { n as isReadonlyArray, r as isRecord, t as compact } from "./compact-CAf557ZB.js";
2
+ import { n as freezeDeep } from "./freeze-CrU8nQeX.js";
3
+ import { n as isForbiddenKey, r as ownGet } from "./paths-DXSHAMIa.js";
4
+ import { f as normalizeApproval, g as assertSqlFunctionName, h as assertSqlFunctionArg, m as assertPortableTwin, p as normalizeWhere, u as assertApprovalRelations } from "./role-builder-uWQZ4v84.js";
5
+ import { n as PermDockDeniedError } from "./errors-BKy0EfhN.js";
6
+ import { o as sameId } from "./expiry-D4_YKRKD.js";
7
+ import { n as internalsOf } from "./internals-Dk8A8fX3.js";
8
+ import { c as listPermissions, i as getRegistry, n as findPermission, o as isPermission } from "./permission-registry-Br4jSNVi.js";
9
+ import { n as isThenable$1 } from "./thenable-yD7SabqG.js";
10
+ import { c as isEdgeRelation, m as restrictedStops, o as groupEntries, s as isComputedRelation, u as isPrincipalRelation } from "./resource-relations-D_jw0BFx.js";
11
+ import { a as durationOf, g as secondsOf, m as rfc3339, p as nowSeconds } from "./time-DkWjdL98.js";
12
+ import { d as scopeList, l as scopeChain, m as tenantOf, o as resolveScope, u as scopeIdOf } from "./scopes-CUPSjo9q.js";
13
+ import { u as evaluateCondition } from "./delegation-j6-rc37o.js";
14
+ import { _ as listPlans, a as authenticated, m as findRole, o as flattenGrantee } from "./grantee-hxrUsbpM.js";
15
+ import { m as tenantsOf, r as isMembershipExpired } from "./tenancy-DN2QAx9z.js";
16
+ import { o as levelNames, r as grantList, t as declaredRoleNames } from "./policy-DbM5YYtV.js";
17
+ import { r as isPortableCondition } from "./hosted-B46-5LYE.js";
18
+ import { n as OPERATION_RISKS, r as isOperationRisk } from "./permissions-B-wCP5ZC.js";
19
+ import { S as tenantCustomRoles, b as resolveCustomRole, f as customRoleId, l as ceilingGrants, m as customRoleScope, p as customRoleOf } from "./evaluate-CNClBvcj.js";
20
+ import { d as rankRoles, f as usesAssigns, i as collectSnapshotGrants, n as snapshotScopes, t as snapshotOf, u as bindingOf } from "./instance-snapshot-BOEhcqIF.js";
21
+ import { n as relationId } from "./relations-BnCWnJGI.js";
22
+ import { r as snapshotGrant, t as buildSnapshot } from "./snapshot-B7DkYg6g.js";
23
+ import { n as LOCAL_CUSTOM_ROLE } from "./parse-local-manifest-CVSs6J9I.js";
24
+ import { r as resolveSubject, s as APP } from "./permdock-BrAscV28.js";
25
+ import { i as memoryApprovalStore } from "./store-BDutJkDL.js";
26
+ import { n as wrapPermDock } from "./wrap-gX61EtpB.js";
27
+ //#region src/conditions/sql-function.ts
28
+ function sqlFunction(name, options) {
29
+ assertSqlFunctionName(name);
30
+ const args = options.args ?? [];
31
+ for (const arg of args) assertSqlFunctionArg(arg);
32
+ const twin = normalizeWhere(options.twin);
33
+ assertPortableTwin(twin);
34
+ return freezeDeep({
35
+ op: "sqlFunction",
36
+ name,
37
+ args,
38
+ twin
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region src/core/memory-sources.ts
43
+ function memoryEntitlementSource(entries) {
44
+ return { entitlementsFor(_principal, options) {
45
+ return options.tenant === void 0 ? [] : [...entries[options.tenant] ?? []];
46
+ } };
47
+ }
48
+ function memorySettingsSource(settings) {
49
+ const byTenant = new Map(Object.entries(settings));
50
+ return Object.freeze({ settingsFor(tenant) {
51
+ return byTenant.get(tenant);
52
+ } });
53
+ }
54
+ /** Memberships keyed by principal id; `tenant` is not a filter, as for a database source. */
55
+ function memoryMembershipSource(entries) {
56
+ const byPrincipal = new Map(Object.entries(entries));
57
+ return Object.freeze({
58
+ membershipsFor(principal) {
59
+ return [...byPrincipal.get(principal.id) ?? []];
60
+ },
61
+ list(query) {
62
+ const members = [];
63
+ for (const [id, memberships] of byPrincipal) for (const membership of memberships) if (membership.scope === query.scope && membership.id === query.id) members.push({
64
+ principal: { id },
65
+ membership
66
+ });
67
+ return members;
68
+ }
69
+ });
70
+ }
71
+ /** A snapshot held in memory; `set` replaces it and notifies every subscriber. */
72
+ function memorySnapshotSource(initial) {
73
+ let current = initial;
74
+ const listeners = /* @__PURE__ */ new Set();
75
+ return Object.freeze({
76
+ get: () => current,
77
+ subscribe(listener) {
78
+ listeners.add(listener);
79
+ return () => {
80
+ listeners.delete(listener);
81
+ };
82
+ },
83
+ set(snapshot) {
84
+ current = snapshot;
85
+ for (const listener of listeners) listener();
86
+ }
87
+ });
88
+ }
89
+ function memoryCustomRoleSource(customRoles) {
90
+ const byTenant = /* @__PURE__ */ new Map();
91
+ const global = [];
92
+ const shared = [];
93
+ for (const role of customRoles) {
94
+ if (role.shared === true) {
95
+ shared.push(role);
96
+ continue;
97
+ }
98
+ if (role.tenant === void 0) {
99
+ global.push(role);
100
+ continue;
101
+ }
102
+ const list = byTenant.get(role.tenant) ?? [];
103
+ list.push(role);
104
+ byTenant.set(role.tenant, list);
105
+ }
106
+ return {
107
+ rolesFor(tenant) {
108
+ return [...byTenant.get(tenant) ?? []];
109
+ },
110
+ globalRoles() {
111
+ return [...global];
112
+ },
113
+ sharedRoles() {
114
+ return [...shared];
115
+ }
116
+ };
117
+ }
118
+ //#endregion
119
+ //#region src/core/operations.ts
120
+ const OPERATION_EFFECTS = Object.freeze([
121
+ "read",
122
+ "write",
123
+ "delete",
124
+ "send",
125
+ "spend",
126
+ "external"
127
+ ]);
128
+ /** MCP tool-name characters (MCP 2025-11-25, Tools: Tool names), so a name works as a tool name unchanged. */
129
+ const NAME = /^[A-Za-z0-9_.-]{1,128}$/u;
130
+ const META_KEYS = /* @__PURE__ */ new Set([
131
+ "risk",
132
+ "effects",
133
+ "title"
134
+ ]);
135
+ function isOperationEffect(value) {
136
+ return OPERATION_EFFECTS.some((effect) => effect === value);
137
+ }
138
+ function readMeta(name, value) {
139
+ if (value === void 0) return Object.freeze({});
140
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`Operation "${name}": meta must be an object.`);
141
+ for (const key of Object.keys(value)) if (!META_KEYS.has(key)) throw new TypeError(`Operation "${name}": meta.${key} is not one of risk, effects, title.`);
142
+ const meta = {};
143
+ const risk = Reflect.get(value, "risk");
144
+ if (risk !== void 0) {
145
+ if (!isOperationRisk(risk)) throw new TypeError(`Operation "${name}": meta.risk must be one of ${OPERATION_RISKS.join(", ")}.`);
146
+ meta.risk = risk;
147
+ }
148
+ const effects = Reflect.get(value, "effects");
149
+ if (effects !== void 0) {
150
+ if (!Array.isArray(effects) || !effects.every(isOperationEffect) || new Set(effects).size !== effects.length) throw new TypeError(`Operation "${name}": meta.effects must list distinct values of ${OPERATION_EFFECTS.join(", ")}.`);
151
+ meta.effects = Object.freeze([...effects]);
152
+ }
153
+ const title = Reflect.get(value, "title");
154
+ if (title !== void 0) {
155
+ if (typeof title !== "string" || title.trim() === "") throw new TypeError(`Operation "${name}": meta.title must be a non-empty string.`);
156
+ meta.title = title;
157
+ }
158
+ return Object.freeze(meta);
159
+ }
160
+ function treeLeaf(keys, name, field, value) {
161
+ if (!isPermission(value)) throw new TypeError(`Operation "${name}": ${field} must be a permission from the tree.`);
162
+ if (!keys.has(value.key)) throw new TypeError(`Operation "${name}": ${field} ${value.key} is not a permission of the tree passed to defineOperations.`);
163
+ return value;
164
+ }
165
+ /**
166
+ * Binds each named operation to a permission of `permissions`. Throws at
167
+ * definition time for a permission or `results` outside the tree, a name that
168
+ * is not 1 to 128 of `A-Z a-z 0-9 _ . -` or repeats another case-insensitively,
169
+ * a `data` that is not a function, or meta outside the closed lists.
170
+ */
171
+ function defineOperations(permissions, definitions) {
172
+ const keys = new Map(listPermissions(permissions).map((leaf) => [leaf.key, leaf]));
173
+ const seen = /* @__PURE__ */ new Map();
174
+ const out = {};
175
+ for (const name of Object.keys(definitions)) {
176
+ if (!NAME.test(name) || isForbiddenKey(name)) throw new TypeError(`Operation name "${name}" must be 1 to 128 of A-Z a-z 0-9 _ . -.`);
177
+ const folded = name.toLowerCase();
178
+ const previous = seen.get(folded);
179
+ if (previous !== void 0) throw new TypeError(`Operation name "${name}" is a duplicate of "${previous}".`);
180
+ seen.set(folded, name);
181
+ const definition = definitions[name];
182
+ if (definition === null || typeof definition !== "object" || Array.isArray(definition)) throw new TypeError(`Operation "${name}" must be an object.`);
183
+ const permission = treeLeaf(keys, name, "permission", Reflect.get(definition, "permission"));
184
+ const value = Reflect.get(definition, "data");
185
+ if (value !== void 0 && typeof value !== "function") throw new TypeError(`Operation "${name}": data must be a function.`);
186
+ const data = value;
187
+ const resultsValue = Reflect.get(definition, "results");
188
+ const results = resultsValue === void 0 ? void 0 : treeLeaf(keys, name, "results", resultsValue);
189
+ const meta = readMeta(name, Reflect.get(definition, "meta"));
190
+ out[name] = Object.freeze({
191
+ name,
192
+ permission,
193
+ ...data === void 0 ? {} : { data },
194
+ ...results === void 0 ? {} : { results },
195
+ meta
196
+ });
197
+ }
198
+ return Object.freeze(out);
199
+ }
200
+ //#endregion
201
+ //#region src/core/approval-policies.ts
202
+ /** The denial detail when an `ApprovalPolicySource` fails: every call an allow would grant denies with reason `approval`. */
203
+ /**
204
+ * The in-process `ApprovalPolicySource`, usable directly as the
205
+ * `approvalPolicies` option: it is the source and its feature at once.
206
+ */
207
+ function memoryApprovalPolicySource(policies) {
208
+ const entries = [...policies];
209
+ const source = { approvalPoliciesFor(query) {
210
+ return entries.filter((entry) => entry.tenant === void 0 || query.tenants.includes(entry.tenant));
211
+ } };
212
+ return Object.freeze({
213
+ ...source,
214
+ ...approvalPolicies(source)
215
+ });
216
+ }
217
+ function approvalPolicies(source) {
218
+ return Object.freeze({
219
+ feature: "approval-policies",
220
+ load: (policy, tenants, auth) => approvalPoliciesFor(policy, source, tenants, auth)
221
+ });
222
+ }
223
+ function isStringList(value) {
224
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
225
+ }
226
+ function metaList(value, is) {
227
+ if (value === void 0) return;
228
+ if (!Array.isArray(value) || value.length === 0 || !value.every(is)) return "invalid";
229
+ return new Set(value);
230
+ }
231
+ /** An entry with no permission, matched on operation meta alone. */
232
+ function checkMetaOnly(raw, risk, effects) {
233
+ const { tenant, actors, where, check, approval } = raw;
234
+ if (risk === void 0 && effects === void 0 || where !== void 0 || tenant !== void 0 && typeof tenant !== "string" || actors !== void 0 && !isStringList(actors) || check !== void 0 && !isPortableCondition(check) || approval !== "human" && !isRecord(approval)) return { problem: "invalid" };
235
+ let normalized;
236
+ try {
237
+ normalized = normalizeApproval(approval);
238
+ } catch {
239
+ return { problem: "invalid" };
240
+ }
241
+ if (normalized === void 0 || normalized !== "human" && normalized.staleOn !== void 0) return { problem: "invalid" };
242
+ return { entry: compact({
243
+ risk,
244
+ effects,
245
+ tenant,
246
+ actors: actors === void 0 ? void 0 : new Set(actors),
247
+ check: check === void 0 ? void 0 : normalizeWhere(check),
248
+ approval: normalized
249
+ }) };
250
+ }
251
+ function checkOne(policy, raw) {
252
+ if (!isRecord(raw)) return { problem: "invalid" };
253
+ const risk = metaList(raw["risk"], isOperationRisk);
254
+ const effects = metaList(raw["effects"], isOperationEffect);
255
+ if (risk === "invalid" || effects === "invalid") return { problem: "invalid" };
256
+ if (raw["permission"] === void 0) return checkMetaOnly(raw, risk, effects);
257
+ if (typeof raw["permission"] !== "string") return { problem: "invalid" };
258
+ const permission = findPermission(policy.permissions, raw["permission"]);
259
+ if (permission === void 0) return { problem: "unknown-permission" };
260
+ const { tenant, actors, where, check, approval } = raw;
261
+ if (tenant !== void 0 && typeof tenant !== "string" || actors !== void 0 && !isStringList(actors) || where !== void 0 && !isPortableCondition(where) || check !== void 0 && !isPortableCondition(check) || approval !== "human" && !isRecord(approval)) return { problem: "invalid" };
262
+ if (where !== void 0 && permission.kind !== "instance") return { problem: "where-on-collection" };
263
+ let normalized;
264
+ try {
265
+ normalized = normalizeApproval(approval, permission.key);
266
+ if (normalized !== void 0) assertApprovalRelations([{
267
+ permission,
268
+ approval: normalized
269
+ }], policy.resources);
270
+ } catch {
271
+ return { problem: "invalid" };
272
+ }
273
+ if (normalized === void 0) return { problem: "invalid" };
274
+ if (normalized !== "human" && normalized.staleOn !== void 0 && (permission.kind !== "instance" || policy.resources.get(permission.resource)?.version === void 0)) return { problem: "stale-on-without-version" };
275
+ return { entry: compact({
276
+ permission: permission.key,
277
+ risk,
278
+ effects,
279
+ tenant,
280
+ actors: actors === void 0 ? void 0 : new Set(actors),
281
+ where: where === void 0 ? void 0 : normalizeWhere(where),
282
+ check: check === void 0 ? void 0 : normalizeWhere(check),
283
+ approval: normalized
284
+ }) };
285
+ }
286
+ /**
287
+ * Checks one entry against the policy the way `approvalPoliciesFor` loads
288
+ * it, for an application to refuse a bad entry when it is saved instead of
289
+ * finding every call denied. Never throws.
290
+ */
291
+ function validateApprovalPolicy(policy, entry) {
292
+ try {
293
+ const checked = checkOne(policy, entry);
294
+ return "problem" in checked ? {
295
+ ok: false,
296
+ problem: checked.problem
297
+ } : { ok: true };
298
+ } catch {
299
+ return {
300
+ ok: false,
301
+ problem: "invalid"
302
+ };
303
+ }
304
+ }
305
+ /**
306
+ * One raw entry checked against the policy: `null` when it names no
307
+ * permission the policy declares (it applies to nothing), `undefined` when
308
+ * it does not load.
309
+ */
310
+ function loadOne(policy, raw) {
311
+ const checked = checkOne(policy, raw);
312
+ if ("entry" in checked) return checked.entry;
313
+ return checked.problem === "unknown-permission" ? null : void 0;
314
+ }
315
+ function loadAll(policy, raw) {
316
+ if (!Array.isArray(raw)) return "failed";
317
+ const out = [];
318
+ for (const item of raw) {
319
+ const loaded = loadOne(policy, item);
320
+ if (loaded === void 0) return "failed";
321
+ if (loaded !== null) out.push(loaded);
322
+ }
323
+ return Object.freeze({ tighten: (code, input) => tightenApproval(code, out, input) });
324
+ }
325
+ /** Reads the source once for `tenants`; a throw or an invalid entry loads as `"failed"`. */
326
+ function approvalPoliciesFor(policy, source, tenants, auth) {
327
+ const threw = () => {
328
+ auth.push({
329
+ reason: "source-threw",
330
+ source: "approvalPolicies"
331
+ });
332
+ return "failed";
333
+ };
334
+ let raw;
335
+ try {
336
+ raw = source.approvalPoliciesFor({ tenants });
337
+ } catch {
338
+ return threw();
339
+ }
340
+ if (isThenable$1(raw)) return Promise.resolve(raw).then((value) => loadAll(policy, value), threw);
341
+ return loadAll(policy, raw);
342
+ }
343
+ function metaMatches(entry, operation) {
344
+ if (entry.risk === void 0 && entry.effects === void 0) return true;
345
+ if (operation === void 0) return false;
346
+ if (entry.risk !== void 0 && (operation.risk === void 0 || !entry.risk.has(operation.risk))) return false;
347
+ const effects = entry.effects;
348
+ return effects === void 0 || (operation.effects ?? []).some((effect) => effects.has(effect));
349
+ }
350
+ function matches(entry, tenant, subject, current, next, now, scopes) {
351
+ if (entry.tenant !== void 0 && entry.tenant !== tenant) return false;
352
+ if (entry.actors !== void 0 && (subject.actor === void 0 || !entry.actors.has(subject.actor.kind))) return false;
353
+ if (entry.where !== void 0 && !evaluateCondition(entry.where, current, subject, now, scopes)) return false;
354
+ return entry.check === void 0 || evaluateCondition(entry.check, next ?? current, subject, now, scopes);
355
+ }
356
+ function asStages(approval) {
357
+ if (approval === "human") return [{ by: authenticated() }];
358
+ if (approval.stages !== void 0) return approval.stages;
359
+ return [compact({
360
+ by: approval.by ?? authenticated(),
361
+ quorum: approval.quorum
362
+ })];
363
+ }
364
+ /** An entry's stages, each carrying the entry's escalation unless it has its own. */
365
+ function entryStages(approval) {
366
+ const stages = asStages(approval);
367
+ if (approval === "human" || approval.escalation === void 0) return stages;
368
+ const escalation = approval.escalation;
369
+ return stages.map((stage) => stage.escalation === void 0 ? compact({
370
+ by: stage.by,
371
+ quorum: stage.quorum,
372
+ escalation
373
+ }) : stage);
374
+ }
375
+ function shorter(a, b) {
376
+ if (a === void 0) return b;
377
+ if (b === void 0) return a;
378
+ return (durationOf(b) ?? Infinity) < (durationOf(a) ?? Infinity) ? b : a;
379
+ }
380
+ /**
381
+ * `code` with every matching entry added as further stages: the result
382
+ * needs all of them (`'sequential'` when any part is ordered), keeps the
383
+ * code's escalation, the shortest `ttl`, and `distinct` unless every part
384
+ * opts out. Without a matching entry, `code` unchanged.
385
+ */
386
+ function tightenApproval(code, entries, input) {
387
+ const extra = entries.filter((entry) => (entry.permission === void 0 || entry.permission === input.permission) && metaMatches(entry, input.operation) && matches(entry, input.tenant, input.subject, input.current, input.next, input.now, input.scopes));
388
+ if (extra.length === 0) return code;
389
+ const parts = [...code === void 0 ? [] : [code], ...extra.map((entry) => entry.approval)];
390
+ const stages = [];
391
+ const seen = /* @__PURE__ */ new Set();
392
+ let sequential = false;
393
+ let distinct = false;
394
+ let staleOn;
395
+ let ttl;
396
+ for (const [index, part] of parts.entries()) {
397
+ const fromCode = code !== void 0 && index === 0;
398
+ for (const stage of fromCode ? asStages(part) : entryStages(part)) {
399
+ const key = JSON.stringify(stage);
400
+ if (!seen.has(key)) {
401
+ seen.add(key);
402
+ stages.push(stage);
403
+ }
404
+ }
405
+ if (part === "human") {
406
+ distinct = true;
407
+ continue;
408
+ }
409
+ sequential ||= part.mode === "sequential";
410
+ distinct ||= part.distinct !== false;
411
+ staleOn ??= part.staleOn;
412
+ ttl = shorter(ttl, part.ttl);
413
+ }
414
+ return compact({
415
+ mode: sequential ? "sequential" : "all",
416
+ stages,
417
+ distinct: distinct ? void 0 : false,
418
+ staleOn,
419
+ ttl,
420
+ escalation: code === void 0 || code === "human" ? void 0 : code.escalation
421
+ });
422
+ }
423
+ //#endregion
424
+ //#region src/core/stripe-entitlements.ts
425
+ const PAGE = 100;
426
+ const MAX_PAGES = 10;
427
+ /**
428
+ * Plan names from Stripe Entitlements: the `lookup_key` of every active
429
+ * entitlement of the tenant's Stripe customer. `customer` maps the active
430
+ * tenant to its customer id; no tenant or no customer means no entitlements.
431
+ * Pass it as `entitlements`, and grant with `plan('<lookup_key>')`.
432
+ */
433
+ function stripeEntitlementSource(options) {
434
+ return { async entitlementsFor(principal, query) {
435
+ if (query.tenant === void 0) return [];
436
+ const customer = await options.customer(query.tenant, principal);
437
+ if (customer === void 0 || customer === "") return [];
438
+ const keys = /* @__PURE__ */ new Set();
439
+ let after;
440
+ for (let page = 0; page < MAX_PAGES; page += 1) {
441
+ const result = await options.stripe.entitlements.activeEntitlements.list(after === void 0 ? {
442
+ customer,
443
+ limit: PAGE
444
+ } : {
445
+ customer,
446
+ limit: PAGE,
447
+ starting_after: after
448
+ });
449
+ for (const item of result.data) if (typeof item.lookup_key === "string" && item.lookup_key !== "") keys.add(item.lookup_key);
450
+ const last = result.data.at(-1);
451
+ if (!result.has_more || last === void 0) break;
452
+ after = last.id;
453
+ }
454
+ return [...keys].toSorted();
455
+ } };
456
+ }
457
+ //#endregion
458
+ //#region src/core/limits.ts
459
+ function isThenable(value) {
460
+ return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
461
+ }
462
+ function limitWindowId(per, now) {
463
+ const seconds = durationOf(per);
464
+ return seconds === void 0 ? void 0 : String(Math.floor(now / seconds));
465
+ }
466
+ function limitCacheKey(input, now) {
467
+ const window = limitWindowId(input.per, now);
468
+ return window === void 0 ? void 0 : JSON.stringify([
469
+ input.tenant ?? null,
470
+ input.subjectId,
471
+ input.key,
472
+ input.per,
473
+ window
474
+ ]);
475
+ }
476
+ function locate$1(input) {
477
+ const now = nowSeconds(input.now);
478
+ const seconds = durationOf(input.per);
479
+ const id = limitCacheKey(input, now);
480
+ if (seconds === void 0 || id === void 0) return;
481
+ return {
482
+ id,
483
+ until: (Math.floor(now / seconds) + 1) * seconds,
484
+ now
485
+ };
486
+ }
487
+ function memoryLimitStore() {
488
+ const used = /* @__PURE__ */ new Map();
489
+ let earliest = Number.POSITIVE_INFINITY;
490
+ const sweep = (now) => {
491
+ if (now < earliest) return;
492
+ earliest = Number.POSITIVE_INFINITY;
493
+ for (const [id, entry] of used) if (entry.until <= now) used.delete(id);
494
+ else earliest = Math.min(earliest, entry.until);
495
+ };
496
+ return {
497
+ remaining(input) {
498
+ const cap = input.count;
499
+ const slot = locate$1(input);
500
+ if (!Number.isFinite(cap) || cap <= 0 || slot === void 0) return { remaining: -1 };
501
+ return { remaining: cap - (used.get(slot.id)?.count ?? 0) };
502
+ },
503
+ consume(input) {
504
+ const cap = input.count;
505
+ const slot = locate$1(input);
506
+ if (!Number.isFinite(cap) || cap <= 0 || slot === void 0) return { remaining: -1 };
507
+ sweep(slot.now);
508
+ const seen = used.get(slot.id)?.count ?? 0;
509
+ if (seen >= cap) return { remaining: -1 };
510
+ used.set(slot.id, {
511
+ count: seen + 1,
512
+ until: slot.until
513
+ });
514
+ earliest = Math.min(earliest, slot.until);
515
+ return { remaining: cap - seen - 1 };
516
+ },
517
+ size() {
518
+ return used.size;
519
+ }
520
+ };
521
+ }
522
+ /**
523
+ * `left` is what remains once this call counts: the store's answer after
524
+ * `consume`, or one less than `remaining` when only peeking. Below zero the
525
+ * call is past the count.
526
+ */
527
+ function verdictFor(limit, left, now) {
528
+ const seconds = durationOf(limit.per);
529
+ if (seconds === void 0) return {
530
+ ok: false,
531
+ reason: "limit-unavailable"
532
+ };
533
+ const resetsAt = rfc3339((Math.floor(now / seconds) + 1) * seconds);
534
+ if (left < 0) return limit.mode === "soft" ? {
535
+ ok: true,
536
+ quota: {
537
+ remaining: 0,
538
+ resetsAt
539
+ },
540
+ obligations: [{ kind: "over-limit" }]
541
+ } : {
542
+ ok: false,
543
+ reason: "limit",
544
+ detail: {
545
+ count: limit.count,
546
+ per: seconds,
547
+ resetsAt
548
+ }
549
+ };
550
+ return limit.alertAt !== void 0 && (limit.count - left) / limit.count >= limit.alertAt ? {
551
+ ok: true,
552
+ quota: {
553
+ remaining: left,
554
+ resetsAt
555
+ },
556
+ obligations: [{ kind: "near-limit" }]
557
+ } : {
558
+ ok: true,
559
+ quota: {
560
+ remaining: left,
561
+ resetsAt
562
+ }
563
+ };
564
+ }
565
+ function limits(store) {
566
+ return Object.freeze({
567
+ feature: "limits",
568
+ quota: (input) => applyQuota(store, input)
569
+ });
570
+ }
571
+ function applyQuota(store, input) {
572
+ const limit = input.limit;
573
+ const payload = {
574
+ key: input.permissionKey,
575
+ subjectId: input.subjectId,
576
+ count: limit.count,
577
+ per: limit.per,
578
+ now: { epochMilliseconds: input.now * 1e3 },
579
+ ...input.tenant === void 0 ? {} : { tenant: input.tenant }
580
+ };
581
+ const cacheKey = limitCacheKey(payload, input.now);
582
+ if (cacheKey === void 0) return {
583
+ ok: false,
584
+ reason: "limit-unavailable"
585
+ };
586
+ if (!input.consume) {
587
+ try {
588
+ const peeked = store.remaining(payload);
589
+ if (isThenable(peeked)) return {
590
+ ok: false,
591
+ reason: "limit-unavailable"
592
+ };
593
+ if (peeked !== void 0) return verdictFor(limit, peeked.remaining - 1, input.now);
594
+ } catch {
595
+ return {
596
+ ok: false,
597
+ reason: "limit-unavailable"
598
+ };
599
+ }
600
+ const cached = input.cache.get(cacheKey);
601
+ if (cached === void 0) return {
602
+ ok: false,
603
+ reason: "limit-unavailable"
604
+ };
605
+ return verdictFor(limit, cached - 1, input.now);
606
+ }
607
+ try {
608
+ const consumed = store.consume(payload);
609
+ if (isThenable(consumed)) return {
610
+ ok: false,
611
+ reason: "limit-unavailable"
612
+ };
613
+ input.cache.set(cacheKey, consumed.remaining);
614
+ return verdictFor(limit, consumed.remaining, input.now);
615
+ } catch {
616
+ return {
617
+ ok: false,
618
+ reason: "limit-unavailable"
619
+ };
620
+ }
621
+ }
622
+ //#endregion
623
+ //#region src/core/memory-relations.ts
624
+ /** The holders one edge-table row names for `spec`: none when the row does not belong to it. */
625
+ function tableHolders(resourceName, spec, row, id) {
626
+ if (relationId(ownGet(row, spec.object ?? `${resourceName}_id`)) !== id) return [];
627
+ for (const [column, value] of Object.entries(spec.match ?? {})) if (ownGet(row, column) !== value) return [];
628
+ const expiresAt = spec.expiresAt === void 0 ? void 0 : seconds(ownGet(row, spec.expiresAt));
629
+ const period = expiresAt === void 0 ? {} : { expiresAt };
630
+ const groups = spec.groups;
631
+ const direct = relationId(ownGet(row, spec.subject ?? "user_id"));
632
+ if (groups === void 0) return direct === void 0 ? [] : [{
633
+ principal: { id: direct },
634
+ ...period
635
+ }];
636
+ if (groups.column === void 0) {
637
+ const out = direct === void 0 ? [] : [{
638
+ principal: { id: direct },
639
+ ...period
640
+ }];
641
+ for (const group of groupEntries(spec)) {
642
+ const groupId = relationId(ownGet(row, group.subject));
643
+ if (groupId !== void 0) out.push({
644
+ group: {
645
+ resource: group.resource,
646
+ id: groupId,
647
+ relation: group.relation
648
+ },
649
+ ...period
650
+ });
651
+ }
652
+ return out;
653
+ }
654
+ const kind = ownGet(row, groups.column);
655
+ if (kind === null || kind === void 0 || kind === groups.direct) return direct === void 0 ? [] : [{
656
+ principal: { id: direct },
657
+ ...period
658
+ }];
659
+ const group = groupEntries(spec).find((entry) => entry.resource === kind);
660
+ const groupId = group === void 0 ? void 0 : relationId(ownGet(row, group.subject));
661
+ return group === void 0 || groupId === void 0 ? [] : [{
662
+ group: {
663
+ resource: group.resource,
664
+ id: groupId,
665
+ relation: group.relation
666
+ },
667
+ ...period
668
+ }];
669
+ }
670
+ function seconds(value) {
671
+ if (value instanceof Date) {
672
+ const time = value.getTime();
673
+ return Number.isNaN(time) ? void 0 : time / 1e3;
674
+ }
675
+ if (typeof value === "number" && Number.isFinite(value)) return value;
676
+ if (typeof value === "string") {
677
+ const parsed = Date.parse(value);
678
+ return Number.isNaN(parsed) ? void 0 : parsed / 1e3;
679
+ }
680
+ }
681
+ function restrictedOf(node, row) {
682
+ return node.restricted !== void 0 && row !== void 0 && ownGet(row, node.restricted) === true;
683
+ }
684
+ function edgeHolder(edge) {
685
+ const holder = { principal: { id: edge.principal } };
686
+ if (edge.startsAt !== void 0) holder.startsAt = edge.startsAt;
687
+ if (edge.expiresAt !== void 0) holder.expiresAt = edge.expiresAt;
688
+ return holder;
689
+ }
690
+ /**
691
+ * An in-process `RelationSource` over plain rows and edges, read against the
692
+ * resource definitions in `permissions`. For tests, fixtures and small apps.
693
+ */
694
+ function memoryRelationSource(permissions, data = {}) {
695
+ const registry = getRegistry(permissions);
696
+ const byId = /* @__PURE__ */ new Map();
697
+ for (const [name, rows] of Object.entries(data.rows ?? {})) {
698
+ const node = registry.get(name);
699
+ const index = /* @__PURE__ */ new Map();
700
+ for (const row of rows) {
701
+ const id = relationId(ownGet(row, node?.id ?? "id"));
702
+ if (id !== void 0) index.set(id, row);
703
+ }
704
+ byId.set(name, index);
705
+ }
706
+ const rowOf = (resource, id) => byId.get(resource)?.get(id);
707
+ return {
708
+ row({ resource, id }) {
709
+ return rowOf(resource, id) ?? null;
710
+ },
711
+ ancestors({ resource, id, depth, through }) {
712
+ const node = registry.get(resource);
713
+ const start = rowOf(resource, id);
714
+ if (node === void 0 || start === void 0) return { ancestors: [] };
715
+ if (through !== "parent") {
716
+ const link = Object.hasOwn(node.links, through) ? node.links[through] : void 0;
717
+ const next = link === void 0 ? void 0 : relationId(ownGet(start, link.field));
718
+ if (next === void 0 || depth < 1) return { ancestors: [] };
719
+ return { ancestors: [{ id: next }] };
720
+ }
721
+ const restricted = restrictedOf(node, start);
722
+ const stops = restrictedStops(node, "parent");
723
+ if (restricted && stops || node.parent === void 0 || node.parent.resource !== resource) return restricted ? {
724
+ restricted: true,
725
+ ancestors: []
726
+ } : { ancestors: [] };
727
+ const field = node.parent.field;
728
+ const seen = /* @__PURE__ */ new Set([id]);
729
+ const ancestors = [];
730
+ let next = relationId(ownGet(start, field));
731
+ while (next !== void 0 && ancestors.length < depth) {
732
+ const row = rowOf(resource, next);
733
+ if (row === void 0) {
734
+ next = void 0;
735
+ break;
736
+ }
737
+ const hidden = restrictedOf(node, row);
738
+ ancestors.push(hidden ? {
739
+ id: next,
740
+ restricted: true
741
+ } : { id: next });
742
+ if (seen.has(next) || hidden && stops) {
743
+ next = void 0;
744
+ break;
745
+ }
746
+ seen.add(next);
747
+ next = relationId(ownGet(row, field));
748
+ }
749
+ const chain = restricted ? {
750
+ restricted: true,
751
+ ancestors
752
+ } : { ancestors };
753
+ return next === void 0 || rowOf(resource, next) === void 0 ? chain : {
754
+ ...chain,
755
+ truncated: true
756
+ };
757
+ },
758
+ related({ resource, id, relation }) {
759
+ const spec = registry.get(resource)?.relations[relation];
760
+ if (spec === void 0 || isComputedRelation(spec)) return [];
761
+ if (isEdgeRelation(spec)) {
762
+ const table = data.tables?.[spec.edge];
763
+ if (table !== void 0) return table.flatMap((row) => tableHolders(resource, spec, row, id));
764
+ return (data.edges?.[resource]?.[relation] ?? []).filter((edge) => edge.id === id).map(edgeHolder);
765
+ }
766
+ const row = rowOf(resource, id);
767
+ if (row === void 0) return [];
768
+ if (isPrincipalRelation(spec)) {
769
+ const holder = relationId(ownGet(row, spec.principal));
770
+ if (holder === void 0) return [];
771
+ const startsAt = spec.period?.startsAt === void 0 ? void 0 : seconds(ownGet(row, spec.period.startsAt));
772
+ const expiresAt = spec.period?.expiresAt === void 0 ? void 0 : seconds(ownGet(row, spec.period.expiresAt));
773
+ return [{
774
+ principal: { id: holder },
775
+ ...startsAt === void 0 ? {} : { startsAt },
776
+ ...expiresAt === void 0 ? {} : { expiresAt }
777
+ }];
778
+ }
779
+ if (spec.memberOf !== void 0) return [];
780
+ const holder = relationId(ownGet(row, spec.field));
781
+ return holder === void 0 ? [] : [{ principal: { id: holder } }];
782
+ }
783
+ };
784
+ }
785
+ //#endregion
786
+ //#region src/core/policy-sign.ts
787
+ /**
788
+ * Signs `document` as a `vnd.permdock.policy+jwt`: the `policy` claim holds
789
+ * every field but `id` and `issuedAt`, which become `jti` and `iat`, so
790
+ * `policyDocumentFromClaims` reads it back. `iss` is the signer's own.
791
+ */
792
+ function signPolicyDocument(document, signer, options) {
793
+ const { id, issuedAt, ...policy } = document;
794
+ const iat = secondsOf(issuedAt);
795
+ return signer.sign({ policy }, {
796
+ typ: "vnd.permdock.policy+jwt",
797
+ audience: options.audience,
798
+ jti: id,
799
+ ...iat === void 0 ? {} : { issuedAt: iat },
800
+ ...options.expiresAt === void 0 ? {} : { expiresAt: options.expiresAt }
801
+ });
802
+ }
803
+ //#endregion
804
+ //#region src/core/arazzo.ts
805
+ const VERSION = /^1\.[01]\.\d+(?:-.+)?$/u;
806
+ const STEP_TARGETS = [
807
+ "operationId",
808
+ "operationPath",
809
+ "workflowId",
810
+ "channelPath"
811
+ ];
812
+ const denied = (reason) => freezeDeep({
813
+ outcome: "denied",
814
+ denials: [{
815
+ role: null,
816
+ reason
817
+ }],
818
+ alternatives: []
819
+ });
820
+ function asString(value) {
821
+ return typeof value === "string" && value.length > 0 ? value : void 0;
822
+ }
823
+ function parseParameters(raw, components, where) {
824
+ if (raw === void 0) return [];
825
+ if (!Array.isArray(raw)) return `${where}: parameters must be an array`;
826
+ const out = [];
827
+ for (const item of raw) {
828
+ if (!isRecord(item)) return `${where}: a parameter is not an object`;
829
+ const reference = asString(item["reference"]);
830
+ if (reference !== void 0) {
831
+ const match = /^\$components\.parameters\.(.+)$/u.exec(reference);
832
+ const target = match?.[1] === void 0 ? void 0 : components[match[1]];
833
+ const name = isRecord(target) ? asString(target["name"]) : void 0;
834
+ if (!isRecord(target) || name === void 0 || !("value" in target)) return `${where}: unresolved parameter reference ${reference}`;
835
+ out.push({
836
+ name,
837
+ value: "value" in item ? item["value"] : target["value"]
838
+ });
839
+ continue;
840
+ }
841
+ const name = asString(item["name"]);
842
+ if (name === void 0 || !("value" in item)) return `${where}: a parameter needs a name and a value`;
843
+ out.push({
844
+ name,
845
+ value: item["value"]
846
+ });
847
+ }
848
+ return out;
849
+ }
850
+ function parseDocument(arazzo) {
851
+ if (!isRecord(arazzo)) return "Arazzo document is not an object";
852
+ const version = arazzo["arazzo"];
853
+ if (typeof version !== "string" || !VERSION.test(version)) return "arazzo must be a 1.0.x or 1.1.x version";
854
+ if (!isRecord(arazzo["info"])) return "info is required";
855
+ const rawSources = arazzo["sourceDescriptions"];
856
+ if (!Array.isArray(rawSources) || rawSources.length === 0) return "sourceDescriptions needs at least one entry";
857
+ const sources = [];
858
+ for (const source of rawSources) {
859
+ const name = isRecord(source) ? asString(source["name"]) : void 0;
860
+ if (!isRecord(source) || name === void 0 || asString(source["url"]) === void 0) return "a sourceDescription needs a name and a url";
861
+ if (sources.some((item) => item.name === name)) return `duplicate sourceDescription ${name}`;
862
+ sources.push({
863
+ name,
864
+ type: asString(source["type"]) ?? "openapi"
865
+ });
866
+ }
867
+ const components = isRecord(arazzo["components"]) && isRecord(arazzo["components"]["parameters"]) ? arazzo["components"]["parameters"] : {};
868
+ const rawWorkflows = arazzo["workflows"];
869
+ if (!Array.isArray(rawWorkflows) || rawWorkflows.length === 0) return "workflows needs at least one entry";
870
+ const workflows = [];
871
+ for (const item of rawWorkflows) {
872
+ const workflowId = isRecord(item) ? asString(item["workflowId"]) : void 0;
873
+ if (!isRecord(item) || workflowId === void 0) return "a workflow needs a workflowId";
874
+ if (workflows.some((workflow) => workflow.workflowId === workflowId)) return `duplicate workflowId ${workflowId}`;
875
+ const parameters = parseParameters(item["parameters"], components, workflowId);
876
+ if (typeof parameters === "string") return parameters;
877
+ const rawSteps = item["steps"];
878
+ if (!Array.isArray(rawSteps) || rawSteps.length === 0) return `${workflowId}: steps needs at least one entry`;
879
+ const steps = [];
880
+ for (const step of rawSteps) {
881
+ const stepId = isRecord(step) ? asString(step["stepId"]) : void 0;
882
+ if (!isRecord(step) || stepId === void 0) return `${workflowId}: a step needs a stepId`;
883
+ if (steps.some((other) => other.stepId === stepId)) return `${workflowId}: duplicate stepId ${stepId}`;
884
+ const targets = STEP_TARGETS.filter((field) => asString(step[field]) !== void 0);
885
+ if (targets.length !== 1 && !(targets.length === 2 && targets.includes("operationId") && targets.includes("channelPath"))) return `${workflowId}.${stepId}: a step needs exactly one of operationId, operationPath or workflowId`;
886
+ const stepParameters = parseParameters(step["parameters"], components, `${workflowId}.${stepId}`);
887
+ if (typeof stepParameters === "string") return stepParameters;
888
+ steps.push(compact({
889
+ stepId,
890
+ operationId: asString(step["operationId"]),
891
+ operationPath: asString(step["operationPath"]),
892
+ workflowId: asString(step["workflowId"]),
893
+ channelPath: asString(step["channelPath"]),
894
+ parameters: stepParameters
895
+ }));
896
+ }
897
+ workflows.push({
898
+ workflowId,
899
+ parameters,
900
+ steps
901
+ });
902
+ }
903
+ return {
904
+ sources,
905
+ workflows
906
+ };
907
+ }
908
+ function unescapePointer(token) {
909
+ return token.replaceAll("~1", "/").replaceAll("~0", "~");
910
+ }
911
+ function readPointer(doc, pointer) {
912
+ if (!pointer.startsWith("#/")) return;
913
+ let current = doc;
914
+ for (const raw of pointer.slice(2).split("/")) {
915
+ if (!isRecord(current)) return;
916
+ let token;
917
+ try {
918
+ token = unescapePointer(decodeURIComponent(raw));
919
+ } catch {
920
+ return;
921
+ }
922
+ if (!Object.hasOwn(current, token)) return;
923
+ current = current[token];
924
+ }
925
+ return current;
926
+ }
927
+ function findOperation(openapi, operationId) {
928
+ if (!isRecord(openapi) || !isRecord(openapi["paths"])) return;
929
+ for (const pathItem of Object.values(openapi["paths"])) {
930
+ if (!isRecord(pathItem)) continue;
931
+ for (const [method, operation] of Object.entries(pathItem)) if (!method.startsWith("x-") && isRecord(operation) && operation["operationId"] === operationId) return operation;
932
+ }
933
+ }
934
+ /** One description, or a map of descriptions keyed by source `name`. */
935
+ function descriptionFor(openapi, name) {
936
+ if (isRecord(openapi) && !("openapi" in openapi) && !("paths" in openapi) && isRecord(openapi[name])) return openapi[name];
937
+ return openapi;
938
+ }
939
+ function permissionKeysOf(node) {
940
+ if (!isRecord(node)) return [];
941
+ const raw = node["x-permdock-permissions"];
942
+ if (!Array.isArray(raw)) return [];
943
+ return raw.filter((item) => typeof item === "string");
944
+ }
945
+ /** `$inputs.a.b` against the frame's inputs; anything else that is a runtime expression is unknown. */
946
+ function valueOf(value, inputs) {
947
+ if (typeof value !== "string" || !value.includes("$")) return {
948
+ known: true,
949
+ value
950
+ };
951
+ const match = /^\$inputs\.([^#{}]+)$/u.exec(value);
952
+ if (match?.[1] === void 0) return value.startsWith("$") || value.includes("{$") ? { known: false } : {
953
+ known: true,
954
+ value
955
+ };
956
+ let current = inputs;
957
+ for (const part of match[1].split(".")) {
958
+ if (!isRecord(current) || !Object.hasOwn(current, part)) return { known: false };
959
+ current = current[part];
960
+ }
961
+ return {
962
+ known: true,
963
+ value: current
964
+ };
965
+ }
966
+ function bind(parameters, inputs) {
967
+ const record = {};
968
+ let provisional = false;
969
+ for (const parameter of parameters) {
970
+ const bound = valueOf(parameter.value, inputs);
971
+ if (!bound.known) {
972
+ provisional = true;
973
+ continue;
974
+ }
975
+ Object.defineProperty(record, parameter.name, {
976
+ value: bound.value,
977
+ enumerable: true,
978
+ writable: true,
979
+ configurable: true
980
+ });
981
+ }
982
+ return {
983
+ record,
984
+ provisional
985
+ };
986
+ }
987
+ function flatten(doc, workflowId, inputs, seen, out) {
988
+ if (seen.has(workflowId)) return "workflowId cycle";
989
+ const workflow = doc.workflows.find((item) => item.workflowId === workflowId);
990
+ if (workflow === void 0) return `unknown workflowId ${workflowId}`;
991
+ seen.add(workflowId);
992
+ for (const step of workflow.steps) {
993
+ if (step.workflowId === void 0 || step.workflowId.startsWith("$sourceDescriptions.")) {
994
+ out.push({
995
+ step,
996
+ workflow,
997
+ inputs
998
+ });
999
+ continue;
1000
+ }
1001
+ const nested = flatten(doc, step.workflowId, bind(step.parameters, inputs).record, seen, out);
1002
+ if (nested !== void 0) return nested;
1003
+ }
1004
+ seen.delete(workflowId);
1005
+ }
1006
+ function locate(doc, openapi, step) {
1007
+ if (step.workflowId !== void 0) return {
1008
+ reason: "unsupported",
1009
+ detail: "workflows in another Arazzo document are not resolved"
1010
+ };
1011
+ let sourceName;
1012
+ let operationId = step.operationId;
1013
+ let pointer;
1014
+ if (step.operationPath !== void 0) {
1015
+ const match = /^\{?\$sourceDescriptions\.([^.}#]+)(?:\.url)?\}?(#.*)?$/u.exec(step.operationPath);
1016
+ if (match?.[1] === void 0) return {
1017
+ reason: "undocumented",
1018
+ detail: "operationPath is not a $sourceDescriptions reference"
1019
+ };
1020
+ sourceName = match[1];
1021
+ pointer = match[2] ?? "";
1022
+ } else if (operationId !== void 0) {
1023
+ const match = /^\$sourceDescriptions\.([^.]+)\.(.+)$/u.exec(operationId);
1024
+ if (match?.[1] !== void 0 && match[2] !== void 0) {
1025
+ sourceName = match[1];
1026
+ operationId = match[2];
1027
+ }
1028
+ }
1029
+ const candidates = sourceName === void 0 ? doc.sources.filter((source) => source.type !== "arazzo") : doc.sources.filter((source) => source.name === sourceName);
1030
+ if (candidates.length === 0) return {
1031
+ reason: "undocumented",
1032
+ detail: sourceName === void 0 ? "no API sourceDescription" : `unknown sourceDescription ${sourceName}`
1033
+ };
1034
+ if (step.channelPath !== void 0) return {
1035
+ reason: "unsupported",
1036
+ detail: "AsyncAPI steps are not evaluated"
1037
+ };
1038
+ const found = [];
1039
+ for (const source of candidates) {
1040
+ const description = descriptionFor(openapi, source.name);
1041
+ const node = pointer === void 0 ? operationId === void 0 ? void 0 : findOperation(description, operationId) : readPointer(description, pointer);
1042
+ if (node !== void 0 || candidates.length === 1) found.push({
1043
+ source,
1044
+ node
1045
+ });
1046
+ }
1047
+ if (found.length > 1) return {
1048
+ reason: "undocumented",
1049
+ detail: "operationId matches several sources; qualify it with $sourceDescriptions"
1050
+ };
1051
+ const [hit] = found;
1052
+ if (hit?.source.type === "asyncapi") return {
1053
+ reason: "unsupported",
1054
+ detail: "AsyncAPI steps are not evaluated"
1055
+ };
1056
+ if (hit === void 0 || hit.source.type === "arazzo" || !isRecord(hit.node)) return {
1057
+ reason: "undocumented",
1058
+ detail: "operation not found"
1059
+ };
1060
+ return compact({
1061
+ node: hit.node,
1062
+ operationId: asString(hit.node["operationId"]) ?? operationId
1063
+ });
1064
+ }
1065
+ function resolve(doc, openapi, tree, flat) {
1066
+ const { step, workflow, inputs } = flat;
1067
+ const base = {
1068
+ stepId: step.stepId,
1069
+ workflowId: workflow.workflowId
1070
+ };
1071
+ const located = locate(doc, openapi, step);
1072
+ const { record, provisional } = bind([...workflow.parameters.filter((parameter) => !step.parameters.some((own) => own.name === parameter.name)), ...step.parameters], inputs);
1073
+ const data = Object.keys(inputs).length + Object.keys(record).length === 0 ? void 0 : {
1074
+ ...inputs,
1075
+ ...record
1076
+ };
1077
+ if ("reason" in located) return {
1078
+ ...base,
1079
+ ...compact({ operationId: step.operationId }),
1080
+ keys: [],
1081
+ finding: located,
1082
+ data,
1083
+ provisional
1084
+ };
1085
+ const keys = permissionKeysOf(located.node);
1086
+ const unknown = tree === void 0 ? void 0 : keys.find((key) => findPermission(tree, key) === void 0);
1087
+ return {
1088
+ ...base,
1089
+ ...compact({ operationId: located.operationId }),
1090
+ keys,
1091
+ ...keys.length === 0 ? { finding: {
1092
+ reason: "undocumented",
1093
+ detail: "operation has no x-permdock-permissions"
1094
+ } } : unknown === void 0 ? {} : { finding: {
1095
+ reason: "unknown-key",
1096
+ detail: unknown
1097
+ } },
1098
+ data,
1099
+ provisional
1100
+ };
1101
+ }
1102
+ function resolveAll(input, tree) {
1103
+ const doc = parseDocument(input.arazzo);
1104
+ if (typeof doc === "string") return {
1105
+ workflowId: input.workflowId ?? "",
1106
+ error: doc
1107
+ };
1108
+ const workflowId = input.workflowId ?? doc.workflows[0]?.workflowId ?? "";
1109
+ const flat = [];
1110
+ const error = flatten(doc, workflowId, input.inputs ?? {}, /* @__PURE__ */ new Set(), flat);
1111
+ if (error !== void 0) return {
1112
+ workflowId,
1113
+ error
1114
+ };
1115
+ return {
1116
+ workflowId,
1117
+ steps: flat.map((item) => resolve(doc, input.openapi, tree, item))
1118
+ };
1119
+ }
1120
+ function arazzoFindings(input, tree) {
1121
+ const resolved = resolveAll(input, tree);
1122
+ if ("error" in resolved) return [{
1123
+ stepId: "document",
1124
+ workflowId: resolved.workflowId,
1125
+ reason: "validation",
1126
+ detail: resolved.error
1127
+ }];
1128
+ return resolved.steps.flatMap((step) => step.finding === void 0 ? [] : [{
1129
+ stepId: step.stepId,
1130
+ workflowId: step.workflowId,
1131
+ reason: step.finding.reason,
1132
+ detail: step.finding.detail
1133
+ }]);
1134
+ }
1135
+ function worst(outcomes) {
1136
+ if (outcomes.includes("denied")) return "denied";
1137
+ if (outcomes.includes("approval-required")) return "approval-required";
1138
+ return "granted";
1139
+ }
1140
+ function combine(decisions) {
1141
+ const outcome = worst(decisions.map((item) => item.outcome));
1142
+ return decisions.find((item) => item.outcome === outcome) ?? denied("undocumented");
1143
+ }
1144
+ /**
1145
+ * Walks an Arazzo workflow against `permdock`: each step's operation is
1146
+ * decided as `permdock.simulate` would, and a server instance emits one
1147
+ * simulate event for the whole plan. Works on an instance built from a
1148
+ * snapshot too.
1149
+ */
1150
+ function simulateArazzo(permdock, input) {
1151
+ const tree = input.permissions ?? permdock.permissions;
1152
+ const internals = internalsOf(permdock);
1153
+ if (internals !== void 0) return internals.simulateWith((decide) => planArazzo(input, tree, decide));
1154
+ return planArazzo(input, tree, (permission, data) => permdock.simulate([[permission, data]])[0] ?? unknownStep(permission));
1155
+ }
1156
+ function unknownStep(permission) {
1157
+ return {
1158
+ outcome: "denied",
1159
+ denials: [{
1160
+ role: null,
1161
+ reason: "no-grant",
1162
+ detail: permission.key
1163
+ }],
1164
+ alternatives: []
1165
+ };
1166
+ }
1167
+ function planArazzo(input, tree, decide) {
1168
+ const resolved = resolveAll(input, tree);
1169
+ if ("error" in resolved) return freezeDeep({
1170
+ workflowId: resolved.workflowId === "" ? "unknown" : resolved.workflowId,
1171
+ outcome: "denied",
1172
+ steps: [{
1173
+ stepId: "document",
1174
+ permissions: [],
1175
+ decision: denied("validation")
1176
+ }]
1177
+ });
1178
+ const steps = resolved.steps.map((step) => {
1179
+ const owner = step.workflowId === resolved.workflowId ? void 0 : step.workflowId;
1180
+ if (step.finding !== void 0) return compact({
1181
+ stepId: step.stepId,
1182
+ workflowId: owner,
1183
+ operationId: step.operationId,
1184
+ permissions: [],
1185
+ decision: denied(step.finding.reason === "unsupported" ? "unsupported" : "undocumented")
1186
+ });
1187
+ const permissions = step.keys.flatMap((key) => {
1188
+ const leaf = tree === void 0 ? void 0 : findPermission(tree, key);
1189
+ return leaf === void 0 ? [] : [leaf];
1190
+ });
1191
+ return compact({
1192
+ stepId: step.stepId,
1193
+ workflowId: owner,
1194
+ operationId: step.operationId,
1195
+ permissions,
1196
+ decision: combine(permissions.map((permission) => decide(permission, step.data))),
1197
+ provisional: step.provisional ? true : void 0
1198
+ });
1199
+ });
1200
+ return freezeDeep({
1201
+ workflowId: resolved.workflowId,
1202
+ outcome: worst(steps.map((step) => step.decision.outcome)),
1203
+ steps
1204
+ });
1205
+ }
1206
+ //#endregion
1207
+ //#region src/core/local-manifest.ts
1208
+ /** A relation grantee needs the relation graph, which a device does not hold: the grant decides on the server only. */
1209
+ function localGrant(grant) {
1210
+ const relational = flattenGrantee(grant.to).some((item) => item.kind === "relation");
1211
+ return snapshotGrant(relational ? {
1212
+ ...grant,
1213
+ portable: false
1214
+ } : grant, void 0);
1215
+ }
1216
+ function customTable(policy, scope, roles) {
1217
+ const keys = [...new Set(ceilingGrants(policy, scope).map((grant) => grant.permission.key))];
1218
+ if (keys.length === 0) return;
1219
+ const resolve = (body) => resolveCustomRole(policy, scope === "global" ? {
1220
+ name: LOCAL_CUSTOM_ROLE,
1221
+ scope: "global",
1222
+ ...body
1223
+ } : {
1224
+ name: LOCAL_CUSTOM_ROLE,
1225
+ tenant: LOCAL_CUSTOM_ROLE,
1226
+ scope,
1227
+ ...body
1228
+ }).grants.map(localGrant);
1229
+ const permissions = {};
1230
+ for (const key of keys) {
1231
+ const leaf = findPermission(policy.permissions, key);
1232
+ const names = leaf?.kind === "instance" ? levelNames(policy, leaf.resource) : [];
1233
+ permissions[key] = compact({
1234
+ all: resolve({ grants: [{ permission: key }] }),
1235
+ levels: names.length === 0 ? void 0 : Object.fromEntries(names.map((level) => [level, resolve({ grants: [{
1236
+ permission: key,
1237
+ level
1238
+ }] })]))
1239
+ });
1240
+ }
1241
+ const includes = {};
1242
+ for (const role of roles) {
1243
+ const grants = resolve({ includes: [role] });
1244
+ if (grants.length > 0) includes[role] = grants;
1245
+ }
1246
+ return {
1247
+ permissions,
1248
+ includes
1249
+ };
1250
+ }
1251
+ /**
1252
+ * What the policy grants, as JSON a device turns into snapshots from its own
1253
+ * membership rows (`localSnapshot` in `permdock/react-native`). Write it at
1254
+ * build time; the policy itself never ships to the client.
1255
+ */
1256
+ function localSnapshotManifest(policy) {
1257
+ const roles = [...declaredRoleNames(policy)].toSorted();
1258
+ const custom = {};
1259
+ for (const scope of [...scopeList(policy.scopes).map((item) => item.name), "global"]) {
1260
+ const table = customTable(policy, scope, roles);
1261
+ if (table !== void 0) custom[scope] = table;
1262
+ }
1263
+ const scopes = snapshotScopes(policy);
1264
+ const { vocabulary } = buildSnapshot({
1265
+ subject: {
1266
+ principal: null,
1267
+ context: {}
1268
+ },
1269
+ roles: [],
1270
+ grants: [],
1271
+ vocabulary: policy.vocabulary
1272
+ });
1273
+ return freezeDeep(compact({
1274
+ v: 1,
1275
+ scopes,
1276
+ vocabulary,
1277
+ roles,
1278
+ rank: usesAssigns(policy) ? rankRoles(policy, roles) : void 0,
1279
+ grants: grantList(policy).map(localGrant),
1280
+ custom
1281
+ }));
1282
+ }
1283
+ //#endregion
1284
+ //#region src/app/define-app.ts
1285
+ function grantsOf(policy) {
1286
+ return [...policy.index.grantsByKey.values()].flat();
1287
+ }
1288
+ function assertProduction(policy, options) {
1289
+ const grants = grantsOf(policy);
1290
+ if (options.store === void 0 && grants.some((grant) => grant.approval !== void 0)) throw new Error("PermDock: profile 'prod' needs a store: a grant requires approval and approvals cannot complete without an ApprovalStore");
1291
+ if (options.limits === void 0 && grants.some((grant) => grant.limit !== void 0)) throw new Error("PermDock: profile 'prod' needs limits: a grant has a limit and every call would deny with limit-unavailable; pass limits: limits(store)");
1292
+ }
1293
+ /**
1294
+ * The in-process services `dev` fills in: one memory approval store that
1295
+ * every adapter of the app shares, and memory limits when a grant has a
1296
+ * `limit`. They live here, not in the adapters, so an adapter ships no store
1297
+ * and an app without `defineApp` ships neither.
1298
+ */
1299
+ function devDefaults(policy, options) {
1300
+ return {
1301
+ ...options,
1302
+ profile: "dev",
1303
+ ...options.store === void 0 ? { store: memoryApprovalStore() } : {},
1304
+ ...options.limits === void 0 && grantsOf(policy).some((grant) => grant.limit !== void 0) ? { limits: limits(memoryLimitStore()) } : {}
1305
+ };
1306
+ }
1307
+ /**
1308
+ * Binds the app's sources, features and services to `policy`. The result
1309
+ * is a policy: pass it wherever a policy goes (`createPermDock`, every
1310
+ * adapter, the CLI) and each picks up the app definition, with its own
1311
+ * options taking precedence. The profile defaults to `prod`.
1312
+ */
1313
+ function defineApp(policy, options = {}) {
1314
+ const profile = options.profile ?? "prod";
1315
+ const definition = profile === "dev" ? devDefaults(policy, options) : {
1316
+ ...options,
1317
+ profile
1318
+ };
1319
+ if (profile === "prod") assertProduction(policy, definition);
1320
+ const prototype = Object.getPrototypeOf(policy);
1321
+ const app = Object.create(prototype, Object.getOwnPropertyDescriptors(policy));
1322
+ Object.defineProperty(app, APP, { value: Object.freeze(definition) });
1323
+ return Object.freeze(app);
1324
+ }
1325
+ //#endregion
1326
+ //#region src/core/shadow.ts
1327
+ function legacyAnswer(legacy, permission, data, subject) {
1328
+ try {
1329
+ return legacy({
1330
+ permission,
1331
+ data,
1332
+ subject
1333
+ }) === true;
1334
+ } catch {
1335
+ return false;
1336
+ }
1337
+ }
1338
+ function legacyDecision(allowed, permission, subject) {
1339
+ return allowed ? freezeDeep({
1340
+ outcome: "granted",
1341
+ subject,
1342
+ matched: {
1343
+ role: "legacy",
1344
+ permission: permission.key
1345
+ },
1346
+ token: "pd1.legacy"
1347
+ }) : freezeDeep({
1348
+ outcome: "denied",
1349
+ permission: permission.key,
1350
+ denials: [{
1351
+ role: null,
1352
+ reason: "no-grant",
1353
+ detail: "legacy"
1354
+ }],
1355
+ alternatives: []
1356
+ });
1357
+ }
1358
+ /**
1359
+ * Runs PermDock beside the application's existing checks while adopting
1360
+ * it. Each `can`, `decide`, `decideEach`, `filter` and `assert` asks both;
1361
+ * the legacy answer is returned unless the permission is in `enforce`, and
1362
+ * every disagreement reaches `onMismatch`. Promote permissions one by one
1363
+ * as their mismatches are resolved, then remove the wrap. Pass it as an
1364
+ * adapter's `wrap` option, or call it on a core instance.
1365
+ */
1366
+ function shadowMode(options) {
1367
+ const enforced = (permission) => options.enforce === "all" || (options.enforce ?? []).some((item) => item.key === permission.key);
1368
+ const report = (mismatch) => {
1369
+ try {
1370
+ options.onMismatch?.(mismatch);
1371
+ } catch {}
1372
+ };
1373
+ return (permdock) => wrapPermDock(permdock, (inner) => {
1374
+ const decide = (permission, data, decideOptions) => {
1375
+ const ours = inner.decide(permission, data, decideOptions);
1376
+ const theirs = legacyAnswer(options.legacy, permission, data, inner.subject);
1377
+ const enforce = enforced(permission);
1378
+ if (theirs !== (ours.outcome === "granted")) report({
1379
+ permission: permission.key,
1380
+ principal: inner.subject.principal?.id ?? null,
1381
+ legacy: theirs,
1382
+ permdock: ours.outcome,
1383
+ enforced: enforce
1384
+ });
1385
+ if (enforce || theirs === (ours.outcome === "granted")) return ours;
1386
+ return legacyDecision(theirs, permission, inner.subject);
1387
+ };
1388
+ const can = (permission, data, decideOptions) => {
1389
+ try {
1390
+ return decide(permission, data, decideOptions).outcome === "granted";
1391
+ } catch {
1392
+ return false;
1393
+ }
1394
+ };
1395
+ return {
1396
+ decide,
1397
+ can,
1398
+ decideEach: (permission, rows, decideOptions) => rows.map((row) => decide(permission, row, decideOptions)),
1399
+ filter: (permission, rows, decideOptions) => rows.filter((row) => can(permission, row, decideOptions)),
1400
+ assert: ((permission, data, decideOptions) => {
1401
+ const decision = decide(permission, data, decideOptions);
1402
+ if (decision.outcome === "granted") return decision;
1403
+ if (decision.outcome === "approval-required") return inner.assert(permission, data, decideOptions);
1404
+ throw new PermDockDeniedError({
1405
+ decision,
1406
+ permission: permission.key,
1407
+ scope: permission.scope,
1408
+ resource: { type: permission.resource },
1409
+ subject: inner.subject,
1410
+ message: `PermDock: ${permission.key} denied`
1411
+ });
1412
+ })
1413
+ };
1414
+ });
1415
+ }
1416
+ //#endregion
1417
+ //#region src/core/may-access.ts
1418
+ function policyPlans(policy) {
1419
+ const names = new Set(listPlans(policy.vocabulary?.plans).map((p) => p.key));
1420
+ for (const grant of grantList(policy)) for (const item of flattenGrantee(grant.to)) if (item.kind === "plan") names.add(item.plan);
1421
+ return [...names];
1422
+ }
1423
+ function heldRoleNames(principal) {
1424
+ return [...principal.roles ?? [], ...(principal.memberships ?? []).flatMap((item) => item.roles)];
1425
+ }
1426
+ /**
1427
+ * An optimistic routing hint for a proxy or middleware, never a decision.
1428
+ * `false` only when the subject's declared roles provably lack `permission`;
1429
+ * `true` whenever custom roles, plans, memberships the claims do not carry or
1430
+ * row conditions could still grant it. Synchronous, no network, never throws.
1431
+ * Pages, Server Actions and RLS remain the enforcement points.
1432
+ */
1433
+ function mayAccess(policy, user, permission, options = {}) {
1434
+ try {
1435
+ const resolved = resolveSubject(policy, user, compact({ tenant: options.tenant }), []);
1436
+ if (isThenable$1(resolved)) return true;
1437
+ const principal = resolved.principal;
1438
+ const relevant = policy.index.grantsByKey.get(permission.key) ?? [];
1439
+ if (principal !== null) {
1440
+ const declared = declaredRoleNames(policy);
1441
+ if (heldRoleNames(principal).some((name) => !declared.has(name))) return true;
1442
+ if ((principal.memberships ?? []).length === 0 && relevant.some((grant) => grant.scope !== "global")) return true;
1443
+ }
1444
+ const tenant = options.tenant;
1445
+ const subject = principal === null ? resolved : {
1446
+ ...resolved,
1447
+ principal: {
1448
+ ...principal,
1449
+ plans: policyPlans(policy),
1450
+ memberships: (principal.memberships ?? []).filter((item) => {
1451
+ const owner = tenantOf(item, scopeList(policy.scopes));
1452
+ return tenant === void 0 || owner === void 0 || owner === tenant;
1453
+ })
1454
+ }
1455
+ };
1456
+ const matched = collectSnapshotGrants(policy, subject, []).filter((item) => item.grant.permission.key === permission.key);
1457
+ if (matched.some((item) => item.grant.effect === "deny" && item.grant.where === void 0 && item.grant.check === void 0 && item.grant.portable)) return false;
1458
+ return matched.some((item) => item.grant.effect === "allow");
1459
+ } catch {
1460
+ return true;
1461
+ }
1462
+ }
1463
+ //#endregion
1464
+ //#region src/core/custom-role-source.ts
1465
+ function ofTenant(tenant, roles) {
1466
+ return Array.isArray(roles) ? roles.filter((role) => role !== null && typeof role === "object" && Reflect.get(role, "tenant") === tenant) : [];
1467
+ }
1468
+ /**
1469
+ * A `CustomRoleSource` over a reader that returns every custom role of a tenant.
1470
+ * It keeps only the roles of the requested tenant. With `read: 'held'` it
1471
+ * skips a tenant's read, and `globalRoles` and `sharedRoles`, when the
1472
+ * subject holds only declared roles there.
1473
+ */
1474
+ function customRoleSource(reader, options = {}) {
1475
+ const declared = options.read === "held" ? declaredRoleNames(options.policy) : void 0;
1476
+ return Object.freeze({
1477
+ rolesFor(tenant, context) {
1478
+ if (declared !== void 0 && context?.held.every((name) => declared.has(name)) === true) return [];
1479
+ const roles = reader.rolesFor(tenant);
1480
+ return isThenable$1(roles) ? roles.then((list) => ofTenant(tenant, list)) : ofTenant(tenant, roles);
1481
+ },
1482
+ ...reader.assignable === void 0 ? {} : { assignable: (tenant) => reader.assignable?.(tenant) ?? [] },
1483
+ ...reader.globalRoles === void 0 ? {} : { globalRoles: (context) => declared !== void 0 && context?.held.every((name) => declared.has(name)) === true ? [] : reader.globalRoles?.() ?? [] },
1484
+ ...reader.sharedRoles === void 0 ? {} : { sharedRoles: (context) => declared !== void 0 && context?.held.every((name) => declared.has(name)) === true ? [] : reader.sharedRoles?.() ?? [] }
1485
+ });
1486
+ }
1487
+ //#endregion
1488
+ //#region src/core/snapshot-for.ts
1489
+ function withPlans(subject, plans) {
1490
+ if (plans === void 0 || subject.principal === null) return subject;
1491
+ return freezeDeep(compact({
1492
+ ...subject,
1493
+ principal: compact({
1494
+ ...subject.principal,
1495
+ plans: [...plans]
1496
+ })
1497
+ }));
1498
+ }
1499
+ /**
1500
+ * Builds the serializable access snapshot for a subject without a request,
1501
+ * a network call or a cache directive: call it inside the app's own
1502
+ * `'use cache: private'` function. Synchronous; the policy's `subject` and
1503
+ * `context` mappers must be synchronous too.
1504
+ */
1505
+ function snapshotFor(policy, user, options = {}) {
1506
+ const auth = [];
1507
+ const memberships = options.memberships;
1508
+ const resolved = resolveSubject(policy, user, compact({
1509
+ tenant: options.tenant,
1510
+ memberships: memberships === void 0 ? void 0 : { membershipsFor: () => [...memberships] }
1511
+ }), auth);
1512
+ if (isThenable$1(resolved)) throw new TypeError("PermDock: snapshotFor() needs synchronous subject and context mappers. Resolve async data first and pass it as a Subject, or use (await getPermDock(...)).snapshot().");
1513
+ const subject = withPlans(resolved, options.plans);
1514
+ const tenants = new Set(tenantsOf(subject.principal, scopeList(policy.scopes)));
1515
+ const customRoles = (options.customRoles ?? []).filter((item) => item.scope === "global" || item.shared === true && tenants.size > 0 || item.tenant !== void 0 && tenants.has(item.tenant));
1516
+ const names = options.assignable;
1517
+ const assignable = names === void 0 ? void 0 : new Map([...tenants].map((tenant) => [tenant, Object.hasOwn(names, tenant) ? names[tenant] ?? [] : []]));
1518
+ return snapshotOf(policy, subject, compact({
1519
+ customRoles,
1520
+ assignable,
1521
+ include: options.include,
1522
+ tenants: options.tenants,
1523
+ now: options.now === void 0 ? void 0 : nowSeconds(options.now)
1524
+ }));
1525
+ }
1526
+ //#endregion
1527
+ //#region src/core/presets.ts
1528
+ const CRUD_ACTIONS = {
1529
+ read: { readOnly: true },
1530
+ update: {},
1531
+ delete: { destructive: true }
1532
+ };
1533
+ const CRUD_COLLECTION = {
1534
+ create: {},
1535
+ list: { readOnly: true }
1536
+ };
1537
+ const READABLE_ACTIONS = { read: { readOnly: true } };
1538
+ const READABLE_COLLECTION = { list: { readOnly: true } };
1539
+ const WRITABLE_ACTIONS = {
1540
+ read: { readOnly: true },
1541
+ update: {}
1542
+ };
1543
+ const WRITABLE_COLLECTION = {};
1544
+ function isNameList(list) {
1545
+ return Array.isArray(list);
1546
+ }
1547
+ function toRecord(list) {
1548
+ if (list === void 0) return {};
1549
+ if (isNameList(list)) {
1550
+ const out = {};
1551
+ for (const name of list) out[name] = {};
1552
+ return out;
1553
+ }
1554
+ return { ...list };
1555
+ }
1556
+ function mergeMeta(base, extra) {
1557
+ return compact({
1558
+ title: extra.title ?? base.title,
1559
+ description: extra.description ?? base.description,
1560
+ tags: extra.tags ?? base.tags,
1561
+ readOnly: extra.readOnly ?? base.readOnly,
1562
+ destructive: extra.destructive ?? base.destructive,
1563
+ idempotent: extra.idempotent ?? base.idempotent
1564
+ });
1565
+ }
1566
+ function mergeActionLists(base, extra) {
1567
+ const extraRecord = toRecord(extra);
1568
+ const out = {};
1569
+ for (const [name, baseMeta] of Object.entries(base)) {
1570
+ const extraMeta = extraRecord[name];
1571
+ out[name] = extraMeta === void 0 ? baseMeta : mergeMeta(baseMeta, extraMeta);
1572
+ }
1573
+ for (const [name, extraMeta] of Object.entries(extraRecord)) {
1574
+ if (Object.hasOwn(out, name)) continue;
1575
+ out[name] = extraMeta;
1576
+ }
1577
+ return freezeDeep(out);
1578
+ }
1579
+ function finishPreset(baseActions, baseCollection, options) {
1580
+ const actions = mergeActionLists(baseActions, options?.actions);
1581
+ const collection = mergeActionLists(baseCollection, options?.collection);
1582
+ return compact({
1583
+ id: options?.id,
1584
+ parent: options?.parent,
1585
+ relations: options?.relations,
1586
+ restricted: options?.restricted,
1587
+ disclosure: options?.disclosure,
1588
+ actions,
1589
+ collection: Object.keys(collection).length === 0 ? void 0 : collection
1590
+ });
1591
+ }
1592
+ function crud(options) {
1593
+ return finishPreset(CRUD_ACTIONS, CRUD_COLLECTION, options);
1594
+ }
1595
+ function readable(options) {
1596
+ return finishPreset(READABLE_ACTIONS, READABLE_COLLECTION, options);
1597
+ }
1598
+ function writable(options) {
1599
+ return finishPreset(WRITABLE_ACTIONS, WRITABLE_COLLECTION, options);
1600
+ }
1601
+ //#endregion
1602
+ //#region src/core/ownership.ts
1603
+ function coversInstance(membership, scopes, scope, id, within) {
1604
+ if (membership.scope === void 0 || membership.id === void 0) return false;
1605
+ if (membership.scope === scope) return sameId(membership.id, id);
1606
+ if (!scopeChain(scopes, scope).slice(1).includes(membership.scope)) return false;
1607
+ const wanted = within === void 0 ? void 0 : Object.entries(within).find(([key]) => resolveScope(scopes, key) === membership.scope)?.[1] ?? void 0;
1608
+ return wanted !== void 0 && scopeIdOf(membership, membership.scope) === wanted;
1609
+ }
1610
+ /** Roles the principal holds at the instance, at an ancestor named in `within`, or globally. */
1611
+ function rolesAtInstance(policy, principal, scopes, scope, id, within, now) {
1612
+ const declared = declaredRoleNames(policy);
1613
+ const names = new Set((principal.roles ?? []).filter((name) => declared.has(name)));
1614
+ for (const membership of principal.memberships ?? []) if (!isMembershipExpired(membership, now) && coversInstance(membership, scopes, scope, id, within)) for (const name of membership.roles) names.add(name);
1615
+ return rankRoles(policy, [...names]);
1616
+ }
1617
+ /** Whether the principal holds `role` on a live membership of exactly this instance. */
1618
+ function holdsAt(principal, role, scope, id, now) {
1619
+ return (principal.memberships ?? []).some((membership) => membership.scope === scope && sameId(membership.id, id) && !isMembershipExpired(membership, now) && membership.roles.includes(role));
1620
+ }
1621
+ function includedRoles(role) {
1622
+ return isReadonlyArray(role.includes) ? role.includes.filter((name) => typeof name === "string") : [];
1623
+ }
1624
+ /**
1625
+ * The membership kinds a custom role may be held through: those every
1626
+ * included declared role with `for` allows. `undefined` when none restricts.
1627
+ */
1628
+ function customForKinds(policy, role) {
1629
+ let kinds;
1630
+ for (const name of includedRoles(role)) {
1631
+ const listed = bindingOf(policy, name)?.for;
1632
+ if (listed !== void 0) kinds = kinds === void 0 ? listed : kinds.filter((kind) => listed.includes(kind));
1633
+ }
1634
+ return kinds;
1635
+ }
1636
+ function conflictsWith(policy, role) {
1637
+ const out = new Set(bindingOf(policy, role)?.exclusiveWith ?? []);
1638
+ for (const binding of policy.roles) if (binding.exclusiveWith?.includes(role) === true) out.add(binding.name);
1639
+ return out;
1640
+ }
1641
+ /** What the change does to the instance's holder count. */
1642
+ function countRules(binding, role, holders, delta, deny) {
1643
+ if (binding === void 0 || delta === 0) return;
1644
+ const min = binding.min ?? 0;
1645
+ if (!(min > 0 || binding.max !== void 0 || binding.transferOnly === true)) return;
1646
+ if (!(holders !== void 0 && Number.isInteger(holders) && holders >= 0)) {
1647
+ deny(delta < 0 && min > 0 ? "last-holder" : delta > 0 && binding.max !== void 0 ? "max-holders" : "transfer-only", {
1648
+ role,
1649
+ holders: null
1650
+ });
1651
+ return;
1652
+ }
1653
+ const after = holders + delta;
1654
+ if (delta < 0 && min > 0 && after < min) deny("last-holder", {
1655
+ role,
1656
+ min,
1657
+ holders
1658
+ });
1659
+ if (delta > 0 && binding.max !== void 0 && after > binding.max) deny("max-holders", {
1660
+ role,
1661
+ max: binding.max,
1662
+ holders
1663
+ });
1664
+ if (binding.transferOnly === true && holders > 0 && after > 0) deny("transfer-only", {
1665
+ role,
1666
+ holders
1667
+ });
1668
+ }
1669
+ /**
1670
+ * A live membership of the principal on the instance or on an instance under
1671
+ * it: the one in-band fact that ties a nested instance to a tenant.
1672
+ */
1673
+ function heldAnchor(principal, scopes, scope, id, now) {
1674
+ return (principal.memberships ?? []).find((membership) => !isMembershipExpired(membership, now) && membership.scope !== void 0 && scopeChain(scopes, membership.scope).includes(scope) && scopeIdOf(membership, scope) === id && tenantOf(membership, scopes) !== void 0);
1675
+ }
1676
+ /**
1677
+ * The one rule check behind `permdock.decideRoleChange`. The actor is always
1678
+ * the instance's own principal; nothing in `change` can stand in for it.
1679
+ */
1680
+ /**
1681
+ * Whether the subject of `permdock` may assign, revoke or transfer a role
1682
+ * in one scope instance: `assigns`, the ceiling, `for`, `exclusiveWith`,
1683
+ * `min`, `max` and `transferOnly`. It never writes; the application does,
1684
+ * and generated RLS triggers re-check the holder counts at commit. A nested
1685
+ * instance's tenant comes from a live membership the subject holds on it,
1686
+ * or from `change.within` only with `{ trusted: true }`; otherwise
1687
+ * `no-membership`. An instance built from a snapshot denies with
1688
+ * `unsupported`.
1689
+ */
1690
+ function decideRoleChange(permdock, change, options = {}) {
1691
+ const internals = internalsOf(permdock);
1692
+ if (internals === void 0) return freezeDeep({
1693
+ outcome: "denied",
1694
+ change,
1695
+ denials: [{
1696
+ role: null,
1697
+ reason: "unsupported"
1698
+ }]
1699
+ });
1700
+ const { policy, subject } = internals;
1701
+ return decideRoleChangeWith(policy, subject.principal, scopeList(policy.scopes), change, internals.env.customRoles, (tenant) => {
1702
+ const found = internals.assignable(tenant);
1703
+ return {
1704
+ assignable: new Set(found.roles.map((leaf) => leaf.key)),
1705
+ manage: found.manage,
1706
+ inert: new Set(found.inert)
1707
+ };
1708
+ }, internals.now(), options);
1709
+ }
1710
+ function decideRoleChangeWith(policy, principal, scopes, change, customRoles, authority, now, options = {}) {
1711
+ const name = typeof change?.role === "string" ? change.role : change?.role?.key;
1712
+ const denials = [];
1713
+ const deny = (reason, detail) => {
1714
+ denials.push(compact({
1715
+ role: name ?? null,
1716
+ reason,
1717
+ detail
1718
+ }));
1719
+ };
1720
+ const done = (role) => freezeDeep(denials.length === 0 ? {
1721
+ outcome: "granted",
1722
+ change,
1723
+ role
1724
+ } : {
1725
+ outcome: "denied",
1726
+ change,
1727
+ denials
1728
+ });
1729
+ if (principal === null) {
1730
+ deny("anonymous");
1731
+ return done(null);
1732
+ }
1733
+ const kind = change?.kind;
1734
+ const target = change?.target;
1735
+ const global = change?.scope === "global";
1736
+ if (typeof name !== "string" || kind !== "assign" && kind !== "revoke" && kind !== "transfer" || (global ? change.id !== void 0 : typeof change.id !== "string" || change.id === "") || target === null || typeof target !== "object" || typeof target.id !== "string" || target.id === "") {
1737
+ deny("validation");
1738
+ return done(null);
1739
+ }
1740
+ const id = change.id ?? "";
1741
+ const binding = bindingOf(policy, name);
1742
+ const declared = declaredRoleNames(policy).has(name);
1743
+ const named = declared || global ? [] : tenantCustomRoles(policy, customRoles).filter((role) => role.name === name);
1744
+ if (!declared && named.length === 0) {
1745
+ deny("unknown-role");
1746
+ return done(null);
1747
+ }
1748
+ const scope = global ? "global" : resolveScope(scopes, change.scope);
1749
+ const customAt = named.map((role) => customRoleScope(role, scopes));
1750
+ const on = declared ? binding?.on ?? findRole(policy.vocabulary?.roles, name)?.on : customAt.includes(scope) ? scope : customAt[0];
1751
+ const heldAt = typeof on === "string" ? resolveScope(scopes, on) : global ? "global" : void 0;
1752
+ if (scope === void 0 || heldAt === void 0 || heldAt !== scope) {
1753
+ deny("scope", { expected: heldAt ?? null });
1754
+ return done(null);
1755
+ }
1756
+ let tenant;
1757
+ let within = change.within;
1758
+ let custom;
1759
+ if (!global) {
1760
+ const root = scopes[0]?.name;
1761
+ const supplied = change.within === void 0 ? void 0 : Object.entries(change.within).find(([key]) => resolveScope(scopes, key) === root)?.[1];
1762
+ if (scope === root) tenant = id;
1763
+ else {
1764
+ const anchor = heldAnchor(principal, scopes, scope, id, now);
1765
+ const held = anchor === void 0 ? void 0 : tenantOf(anchor, scopes);
1766
+ if (held !== void 0) {
1767
+ tenant = supplied === void 0 || supplied === held ? held : void 0;
1768
+ within = anchor?.within;
1769
+ } else if (options.trusted === true) tenant = supplied;
1770
+ }
1771
+ if (tenant === void 0) {
1772
+ deny("no-membership", {
1773
+ scope,
1774
+ id
1775
+ });
1776
+ return done(null);
1777
+ }
1778
+ const found = tenant;
1779
+ custom = named.find((role) => customRoleOf(role, found) && customRoleScope(role, scopes) === scope && sameId(customRoleId(role) ?? id, id));
1780
+ }
1781
+ if (!declared && custom === void 0) {
1782
+ deny("unknown-role");
1783
+ return done(null);
1784
+ }
1785
+ if (target.managedBy === "idp") {
1786
+ deny("externally-managed");
1787
+ return done(null);
1788
+ }
1789
+ const self = target.id === principal.id;
1790
+ const targetRoles = isReadonlyArray(target.roles) ? target.roles : [];
1791
+ const already = targetRoles.includes(name);
1792
+ let by = null;
1793
+ if (kind === "transfer") {
1794
+ if (self) deny("self-demotion");
1795
+ if (global ? (principal.roles ?? []).includes(name) : holdsAt(principal, name, scope, id, now)) by = name;
1796
+ else deny("not-assignable-by", { holds: false });
1797
+ } else {
1798
+ if (self) deny(kind === "revoke" ? "self-demotion" : "not-assignable-by", { self: true });
1799
+ const allowed = authority(tenant);
1800
+ const revocable = kind === "revoke" && custom !== void 0 && allowed.inert?.has(name);
1801
+ if (!allowed.assignable.has(name) && revocable !== true) deny("not-assignable-by");
1802
+ else if (custom === void 0 && usesAssigns(policy) && !allowed.manage) {
1803
+ const held = global ? rankRoles(policy, (principal.roles ?? []).filter((role) => declaredRoleNames(policy).has(role))) : rolesAtInstance(policy, principal, scopes, scope, id, within, now);
1804
+ by = held.find((role) => bindingOf(policy, role)?.assigns?.includes(name) === true) ?? null;
1805
+ if (by === null) deny("not-assignable-by", { held });
1806
+ }
1807
+ }
1808
+ if (kind !== "revoke" && !already) {
1809
+ const kinds = custom === void 0 ? binding?.for : customForKinds(policy, custom);
1810
+ if (kinds !== void 0 && (target.via === void 0 || !kinds.includes(target.via))) deny("not-allowed-for-membership", {
1811
+ via: target.via ?? null,
1812
+ for: kinds
1813
+ });
1814
+ const conflicts = custom === void 0 ? conflictsWith(policy, name) : new Set(includedRoles(custom).flatMap((include) => Array.from(conflictsWith(policy, include))));
1815
+ const clash = targetRoles.filter((role) => conflicts.has(role));
1816
+ if (clash.length > 0) deny("conflicting-role", { with: clash });
1817
+ }
1818
+ const delta = kind === "assign" ? already ? 0 : 1 : kind === "revoke" ? targetRoles.length > 0 && !already ? 0 : -1 : already ? -1 : 0;
1819
+ countRules(binding, name, change.holders, delta, deny);
1820
+ return done(by);
1821
+ }
1822
+ //#endregion
1823
+ //#region src/core/csv.ts
1824
+ /** The CSV export columns, in order; the header row of every CSV file. */
1825
+ const CSV_COLUMNS = Object.freeze([
1826
+ "time",
1827
+ "principal",
1828
+ "actor",
1829
+ "tenant",
1830
+ "permission",
1831
+ "outcome",
1832
+ "matched.role",
1833
+ "via",
1834
+ "denials.reason",
1835
+ "token"
1836
+ ]);
1837
+ function field(value) {
1838
+ const text = value ?? "";
1839
+ return /[",\r\n]/u.test(text) ? `"${text.replaceAll("\"", "\"\"")}"` : text;
1840
+ }
1841
+ /**
1842
+ * One RFC 4180 row for a decision or approval event, without a line
1843
+ * terminator; join rows with CRLF under a `CSV_COLUMNS` header.
1844
+ */
1845
+ function toCsvRow(event) {
1846
+ return [
1847
+ event.at,
1848
+ event.subject.principal?.id,
1849
+ event.subject.actor?.id,
1850
+ event.tenant,
1851
+ event.permission,
1852
+ event.outcome,
1853
+ event.matched?.role,
1854
+ event.via,
1855
+ event.denials?.map((denial) => denial.reason).join(";"),
1856
+ event.token
1857
+ ].map(field).join(",");
1858
+ }
1859
+ //#endregion
1860
+ export { memorySnapshotSource as A, validateApprovalPolicy as C, memoryEntitlementSource as D, memoryCustomRoleSource as E, memoryMembershipSource as O, memoryApprovalPolicySource as S, isOperationEffect as T, limits as _, readable as a, approvalPolicies as b, customRoleSource as c, defineApp as d, localSnapshotManifest as f, memoryRelationSource as g, signPolicyDocument as h, crud as i, sqlFunction as j, memorySettingsSource as k, mayAccess as l, simulateArazzo as m, toCsvRow as n, writable as o, arazzoFindings as p, decideRoleChange as r, snapshotFor as s, CSV_COLUMNS as t, shadowMode as u, memoryLimitStore as v, defineOperations as w, approvalPoliciesFor as x, stripeEntitlementSource as y };