permdock 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/README.md +327 -1
  2. package/dist/a2a/index.d.ts +169 -0
  3. package/dist/a2a/index.js +232 -0
  4. package/dist/adapter-context-mlWsVGGg.js +23 -0
  5. package/dist/ai-sdk/index.d.ts +95 -0
  6. package/dist/ai-sdk/index.js +154 -0
  7. package/dist/approval-required-TzNB9oQA.js +6 -0
  8. package/dist/approvals/index.d.ts +3 -0
  9. package/dist/approvals/index.js +5 -0
  10. package/dist/approvals-DbYAuNkG.js +224 -0
  11. package/dist/approvers-DT4AVyIg.js +52 -0
  12. package/dist/arazzo-BAgw9ap6.js +70 -0
  13. package/dist/arazzo-cmvX2jDe.js +54 -0
  14. package/dist/authzen/index.d.ts +39 -0
  15. package/dist/authzen/index.js +302 -0
  16. package/dist/better-auth/index.d.ts +109 -0
  17. package/dist/better-auth/index.js +344 -0
  18. package/dist/better-supabase/index.d.ts +206 -0
  19. package/dist/better-supabase/index.js +620 -0
  20. package/dist/bind-CVy3Espv.d.ts +25 -0
  21. package/dist/bind-VnYn2HKq.js +97 -0
  22. package/dist/boundary-BM8a_P6E.js +13 -0
  23. package/dist/boundary-BmHxVH1J.d.ts +15 -0
  24. package/dist/budget-JqcRqyhK.d.ts +11 -0
  25. package/dist/budget-NbEtbJC_.js +11 -0
  26. package/dist/canonical-json-DemiK4Vp.js +26 -0
  27. package/dist/capability-4qPdO9gk.js +173 -0
  28. package/dist/capability-Dq43tT1u.d.ts +99 -0
  29. package/dist/catalog/index.d.ts +12 -0
  30. package/dist/catalog/index.js +2 -0
  31. package/dist/catalog-BjZSovXQ.js +2 -0
  32. package/dist/catalog-doc-Dsc9y7sd.js +309 -0
  33. package/dist/catalog-h2tlKFkq.js +48 -0
  34. package/dist/catalog-path-CnI0XTFK.js +12 -0
  35. package/dist/catalog-z8q6bi_r.js +55 -0
  36. package/dist/claude-agent/index.d.ts +72 -0
  37. package/dist/claude-agent/index.js +77 -0
  38. package/dist/clerk/index.d.ts +65 -0
  39. package/dist/clerk/index.js +301 -0
  40. package/dist/cli/bin.d.ts +1 -0
  41. package/dist/cli/bin.js +20 -0
  42. package/dist/cli/index.d.ts +46 -0
  43. package/dist/cli/index.js +5 -0
  44. package/dist/clients-C7zLFuWT.d.ts +12 -0
  45. package/dist/clients-DjU5ABMy.js +23 -0
  46. package/dist/cloud/index.d.ts +90 -0
  47. package/dist/cloud/index.js +404 -0
  48. package/dist/cloud-BGhHS-lY.js +50 -0
  49. package/dist/cloud-Bo3e9Ak3.js +118 -0
  50. package/dist/collect-DDDv_ESs.js +502 -0
  51. package/dist/collect-DLlujdHC.js +83 -0
  52. package/dist/collect-rG2IQ3t0.js +2 -0
  53. package/dist/commands-DWOrSQic.js +97 -0
  54. package/dist/compact-y6vfu2_f.js +19 -0
  55. package/dist/compare-pfyVnBjE.js +12 -0
  56. package/dist/compile/index.d.ts +3 -0
  57. package/dist/compile/index.js +2 -0
  58. package/dist/compile-Ba4blROR.js +613 -0
  59. package/dist/compile-CNnl6uIt.d.ts +94 -0
  60. package/dist/config-BJiM-xAm.js +157 -0
  61. package/dist/config-Bn00Z3ks.js +36 -0
  62. package/dist/config-report-Dw_JcUqT.js +44 -0
  63. package/dist/connection-CU8MQxRi.js +194 -0
  64. package/dist/context-Ttp0ekMT.js +82 -0
  65. package/dist/convex/index.d.ts +45 -0
  66. package/dist/convex/index.js +65 -0
  67. package/dist/create-BWyx3jua.d.ts +245 -0
  68. package/dist/create-CPhDL6qx.js +253 -0
  69. package/dist/credential-8P81ff4u.js +306 -0
  70. package/dist/delegation-D8pUEuce.js +103 -0
  71. package/dist/describe-B_gVZEVi.js +94 -0
  72. package/dist/describe-PdoqESvg.d.ts +36 -0
  73. package/dist/diff-B8Tunc3o.js +451 -0
  74. package/dist/diff-CzqLxZ77.js +48 -0
  75. package/dist/digest-B3kc_PgQ.d.ts +19 -0
  76. package/dist/digest-BI-6aa6d.js +27 -0
  77. package/dist/doctor-WpvG6p4k.js +1194 -0
  78. package/dist/doctor-collect-ByfYlNv1.js +664 -0
  79. package/dist/doctor-rOr-4ZfS.js +53 -0
  80. package/dist/drizzle/index.d.ts +73 -0
  81. package/dist/drizzle/index.js +160 -0
  82. package/dist/duration-xK2jGFVc.js +25 -0
  83. package/dist/elysia/index.d.ts +49 -0
  84. package/dist/elysia/index.js +59 -0
  85. package/dist/errors-CWfoNg9N.js +47 -0
  86. package/dist/errors-Cz5zn0mW.js +123 -0
  87. package/dist/errors-DAqevpNk.d.ts +125 -0
  88. package/dist/errors-DRnGZHzF.js +30 -0
  89. package/dist/evaluation-items-CfCCejQd.js +40 -0
  90. package/dist/evaluations-tz6D9A2G.js +461 -0
  91. package/dist/eve/index.d.ts +86 -0
  92. package/dist/eve/index.js +176 -0
  93. package/dist/expiry-BoBJ8Tvc.js +7 -0
  94. package/dist/express/index.d.ts +23 -0
  95. package/dist/express/index.js +78 -0
  96. package/dist/fastify/index.d.ts +33 -0
  97. package/dist/fastify/index.js +92 -0
  98. package/dist/fields-BMl1RxoX.js +26 -0
  99. package/dist/files-DWUN9PzI.js +125 -0
  100. package/dist/fixtures-ht28Cplr.js +67 -0
  101. package/dist/freeze-CrU8nQeX.js +60 -0
  102. package/dist/from-snapshot-C3sHpZNS.js +569 -0
  103. package/dist/generate-CH7ThJ14.js +173 -0
  104. package/dist/grantee-Cv5Sogfv.js +602 -0
  105. package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
  106. package/dist/headers-BZSDieNT.js +6 -0
  107. package/dist/headers-Cf-zWvsO.d.ts +6 -0
  108. package/dist/helpers-H_KARDVC.js +421 -0
  109. package/dist/hono/index.d.ts +48 -0
  110. package/dist/hono/index.js +99 -0
  111. package/dist/hosted-DJQw46hn.js +266 -0
  112. package/dist/http-BIhmLfCc.js +95 -0
  113. package/dist/http-DPuDaChb.d.ts +13 -0
  114. package/dist/http-SO7qGttf.js +44 -0
  115. package/dist/ids-DC4V4CFu.js +18 -0
  116. package/dist/index-A0YNL8jZ.d.ts +177 -0
  117. package/dist/index-CtE07CBF.d.ts +6 -0
  118. package/dist/index-D3vbkoSI.d.ts +483 -0
  119. package/dist/index-D6_cSa1z.d.ts +201 -0
  120. package/dist/index.d.ts +16 -0
  121. package/dist/index.js +26 -0
  122. package/dist/instance-options-BK_rNOSC.d.ts +11 -0
  123. package/dist/instance-options-Dhhcnm3y.js +22 -0
  124. package/dist/json-schema-BsAflUGW.js +106 -0
  125. package/dist/jwt/index.d.ts +91 -0
  126. package/dist/jwt/index.js +590 -0
  127. package/dist/kernel-GSQnMz3O.js +208 -0
  128. package/dist/kysely/index.d.ts +78 -0
  129. package/dist/kysely/index.js +129 -0
  130. package/dist/live-options-H2eG8dfJ.js +60 -0
  131. package/dist/load-DhWEB9P1.js +75 -0
  132. package/dist/load-DwJUafYN.js +2 -0
  133. package/dist/load-jose-BL6LH4bL.js +11 -0
  134. package/dist/lru-8q4WZjBV.js +28 -0
  135. package/dist/manifest-iaoBXHKc.js +783 -0
  136. package/dist/manifest-uDS9y5de.d.ts +206 -0
  137. package/dist/map-AcxK9o_D.js +147 -0
  138. package/dist/map-claims-Z4QZOiFF.js +369 -0
  139. package/dist/map-error-pgUWNNtG.js +23 -0
  140. package/dist/markers-B0hYLvMD.js +60 -0
  141. package/dist/may-use-DndQ5tQ-.js +77 -0
  142. package/dist/mcp/index.d.ts +159 -0
  143. package/dist/mcp/index.js +603 -0
  144. package/dist/nest/index.d.ts +75 -0
  145. package/dist/nest/index.js +261 -0
  146. package/dist/next/client.d.ts +23 -0
  147. package/dist/next/client.js +33 -0
  148. package/dist/next/index.d.ts +93 -0
  149. package/dist/next/index.js +180 -0
  150. package/dist/next/plugin.d.ts +14 -0
  151. package/dist/next/plugin.js +33 -0
  152. package/dist/node/index.d.ts +24 -0
  153. package/dist/node/index.js +34 -0
  154. package/dist/openai/index.d.ts +62 -0
  155. package/dist/openai/index.js +92 -0
  156. package/dist/openapi/index.d.ts +176 -0
  157. package/dist/openapi/index.js +3 -0
  158. package/dist/openapi-Bbg4wGVL.js +164 -0
  159. package/dist/openapi-BqRBvAng.js +538 -0
  160. package/dist/openapi-CqqEbHsL.js +250 -0
  161. package/dist/openapi-import-cmwetbzw.js +5959 -0
  162. package/dist/openapi-schema--ARjyfQr.js +6902 -0
  163. package/dist/orpc/index.d.ts +51 -0
  164. package/dist/orpc/index.js +145 -0
  165. package/dist/otel/index.d.ts +13 -0
  166. package/dist/otel/index.js +202 -0
  167. package/dist/package-root-zGkxO3oN.js +30 -0
  168. package/dist/parse-BuyjxhZV.js +53 -0
  169. package/dist/parse-local-manifest-BkGQNzAh.d.ts +10 -0
  170. package/dist/parse-local-manifest-BrMozJCo.js +36 -0
  171. package/dist/pdp/index.d.ts +22 -0
  172. package/dist/pdp/index.js +682 -0
  173. package/dist/peer-BOr_kJE1.js +31 -0
  174. package/dist/permdock-CzqXjCpU.js +3471 -0
  175. package/dist/permissions-CDgvKG5L.d.ts +52 -0
  176. package/dist/permissions-CpZrivYv.js +142 -0
  177. package/dist/permissions-DVoF6dMt.js +662 -0
  178. package/dist/permissions-DttnqqxC.d.ts +214 -0
  179. package/dist/pins-8ILTftC9.js +12 -0
  180. package/dist/policy-CFZAr_Al.d.ts +2252 -0
  181. package/dist/policy-D8UFyERw.d.ts +20 -0
  182. package/dist/policy-xyWg7QdR.js +1122 -0
  183. package/dist/powersync-A8x_Yyvh.js +2 -0
  184. package/dist/powersync-C7kLglqX.js +540 -0
  185. package/dist/powersync-yW1UUFzp.js +62 -0
  186. package/dist/prisma/index.d.ts +136 -0
  187. package/dist/prisma/index.js +455 -0
  188. package/dist/problem-B43ztKIm.js +191 -0
  189. package/dist/problem-details-CkL50EEf.d.ts +7 -0
  190. package/dist/problem-details-_AMOYz-w.js +144 -0
  191. package/dist/prompt-CXYhLfsS.js +32 -0
  192. package/dist/protected-CNsMzrVd.d.ts +27 -0
  193. package/dist/protected-Cs6kTaHo.js +100 -0
  194. package/dist/protected-bZs6rbT1.d.ts +40 -0
  195. package/dist/provider-Cjr62YMV.d.ts +6 -0
  196. package/dist/provider-DLzpb2Xz.js +52 -0
  197. package/dist/provider-store-DNyC1y48.js +43 -0
  198. package/dist/react/index.d.ts +8 -0
  199. package/dist/react/index.js +7 -0
  200. package/dist/react/provider-client.d.ts +2 -0
  201. package/dist/react/provider-client.js +3 -0
  202. package/dist/react-native/index.d.ts +198 -0
  203. package/dist/react-native/index.js +696 -0
  204. package/dist/refs-KYb4ntaz.js +91 -0
  205. package/dist/relations-cjOL01hZ.js +505 -0
  206. package/dist/replay-BsOyTrdV.js +28 -0
  207. package/dist/replay-sqBGMnNs.d.ts +5 -0
  208. package/dist/resource-ref-CaS9yVPi.js +20 -0
  209. package/dist/revocations-Bhr0aMIC.js +27 -0
  210. package/dist/revocations-Cy06JNx2.d.ts +21 -0
  211. package/dist/rls-BMNydpHk.js +2521 -0
  212. package/dist/rls-CEvs64Kj.js +238 -0
  213. package/dist/rls-fields-BMasREhR.js +3502 -0
  214. package/dist/rls-graph-pc9fuXYm.js +435 -0
  215. package/dist/rls-import-D8F7j35Q.js +943 -0
  216. package/dist/rls-migrate-7wikfrVI.js +367 -0
  217. package/dist/rls-ownership-B5Lkq62W.js +843 -0
  218. package/dist/rls-shared-aOQ4hGTO.js +493 -0
  219. package/dist/rls-verify-D8B7dOTh.js +745 -0
  220. package/dist/row-check-Dt35czLy.d.ts +40 -0
  221. package/dist/rpc-DOK54_CS.js +89 -0
  222. package/dist/run-YXCJDNYk.js +174 -0
  223. package/dist/runtime-CB8gQFvS.js +11 -0
  224. package/dist/saas-Bj_FFkjN.js +1203 -0
  225. package/dist/schema-D3MnDMxa.js +300 -0
  226. package/dist/scim/index.d.ts +2 -0
  227. package/dist/scim/index.js +2 -0
  228. package/dist/scim-BFGBBAqR.js +1445 -0
  229. package/dist/scopes-CVdPrWN-.js +239 -0
  230. package/dist/server/index.d.ts +134 -0
  231. package/dist/server/index.js +11 -0
  232. package/dist/server-DlZ28Oz5.js +268 -0
  233. package/dist/sha256-BO0swRXL.js +150 -0
  234. package/dist/shared-DRu8VFVM.js +123 -0
  235. package/dist/sink-Bd9PSyfq.js +141 -0
  236. package/dist/sink-Gs6TTVa-.d.ts +104 -0
  237. package/dist/skills-Biq5uup3.js +192 -0
  238. package/dist/skills-JaymNCdK.js +56 -0
  239. package/dist/snapshot-Enxd0n-s.js +975 -0
  240. package/dist/snapshot-cache-D6jLelln.js +44 -0
  241. package/dist/snapshot-cache-DwQH8ufx.d.ts +45 -0
  242. package/dist/solid/index.d.ts +93 -0
  243. package/dist/solid/index.js +188 -0
  244. package/dist/sources-B0UvrJ21.js +534 -0
  245. package/dist/sources-BcJgw0lt.d.ts +192 -0
  246. package/dist/sql-xdg5f4Fi.js +27 -0
  247. package/dist/src-CSbUiozF.js +568 -0
  248. package/dist/ssf/index.d.ts +4 -0
  249. package/dist/ssf/index.js +596 -0
  250. package/dist/store-DMAWwAJV.js +371 -0
  251. package/dist/store-D_pjn91-.d.ts +36 -0
  252. package/dist/store-options-yO0V6gRn.js +716 -0
  253. package/dist/stores-4_sqiOA1.js +87 -0
  254. package/dist/stores-DVR5NHLE.d.ts +52 -0
  255. package/dist/stream-DDpvynSB.js +66 -0
  256. package/dist/stream-DlvG2hs-.d.ts +12 -0
  257. package/dist/style-CTm1AXDT.js +22 -0
  258. package/dist/subject-C6dLxqHU.js +24 -0
  259. package/dist/subject-settings-BwBmCdTR.js +128 -0
  260. package/dist/supabase/index.d.ts +183 -0
  261. package/dist/supabase/index.js +5 -0
  262. package/dist/supabase/middleware.d.ts +82 -0
  263. package/dist/supabase/middleware.js +102 -0
  264. package/dist/supabase-CwafwxxF.js +83 -0
  265. package/dist/supabase-DTBaC20O.js +774 -0
  266. package/dist/supabase-config-Bs44dare.js +472 -0
  267. package/dist/supabase-hook-BuxLQLpU.js +1814 -0
  268. package/dist/supabase-hook-D5qVd_D8.js +2 -0
  269. package/dist/supautils-DYZnzRWV.js +91 -0
  270. package/dist/svelte/PermissionBoundary.svelte +37 -0
  271. package/dist/svelte/Protected.svelte +40 -0
  272. package/dist/svelte/index.d.ts +13 -0
  273. package/dist/svelte/index.js +107 -0
  274. package/dist/svelte/runtime.d.ts +7 -0
  275. package/dist/svelte/runtime.js +4 -0
  276. package/dist/svelte/source.d.ts +13 -0
  277. package/dist/svelte/source.js +11 -0
  278. package/dist/terminal/index.d.ts +163 -0
  279. package/dist/terminal/index.js +833 -0
  280. package/dist/testing/index.d.ts +745 -0
  281. package/dist/testing/index.js +3672 -0
  282. package/dist/testing/saas/index.d.ts +194 -0
  283. package/dist/testing/saas/index.js +3 -0
  284. package/dist/testing/saas/permissions.d.ts +2 -0
  285. package/dist/testing/saas/permissions.js +2 -0
  286. package/dist/text-diff-BdkkYSbi.js +15 -0
  287. package/dist/thenable-okc2xDsj.js +10 -0
  288. package/dist/timeout-D51niuQP.js +8 -0
  289. package/dist/token-CIWxJOCh.js +50 -0
  290. package/dist/trpc/index.d.ts +61 -0
  291. package/dist/trpc/index.js +122 -0
  292. package/dist/types-9AWO9EGt.d.ts +197 -0
  293. package/dist/types-BPxgszlT.d.ts +550 -0
  294. package/dist/types-BVyImy5I.d.ts +120 -0
  295. package/dist/types-Bvc4oWT6.d.ts +9 -0
  296. package/dist/types-C3s9xVJG.d.ts +48 -0
  297. package/dist/types-Dnemwd77.d.ts +183 -0
  298. package/dist/types-kxznc7cn.d.ts +52 -0
  299. package/dist/types-vKyAMtcX.d.ts +157 -0
  300. package/dist/types-vNSDF7Dq.d.ts +66 -0
  301. package/dist/types-yF5LmQVD.d.ts +306 -0
  302. package/dist/unplugin/index.d.ts +7 -0
  303. package/dist/unplugin/index.js +31 -0
  304. package/dist/usage-D07N9QJ3.js +42 -0
  305. package/dist/usage-D82l1CwK.js +2 -0
  306. package/dist/usage-DG1oeCca.js +693 -0
  307. package/dist/validation-error-CnjZ4t92.js +33 -0
  308. package/dist/validation-error-CtF23SrC.d.ts +26 -0
  309. package/dist/validity-uOp8UpYn.js +245 -0
  310. package/dist/verifier-BxBo6I44.js +466 -0
  311. package/dist/version-BvacVTZR.js +17 -0
  312. package/dist/views-Soe7bGSC.js +95 -0
  313. package/dist/vocabulary-DA8a8zif.d.ts +56 -0
  314. package/dist/vue/index.d.ts +79 -0
  315. package/dist/vue/index.js +196 -0
  316. package/dist/watch-Etoa_Mvr.js +2 -0
  317. package/dist/watch-UihESpsJ.js +128 -0
  318. package/dist/webmcp/index.d.ts +75 -0
  319. package/dist/webmcp/index.js +307 -0
  320. package/package.json +450 -5
  321. package/rulesets/permdock.yaml +29 -0
  322. package/schemas/approval-request-v1.json +175 -0
  323. package/schemas/catalog-v1.json +535 -0
  324. package/schemas/openapi/oas-3.1.json +1298 -0
  325. package/schemas/openapi/oas-3.2.json +1516 -0
  326. package/schemas/openapi/overlay-1.1.json +79 -0
  327. package/schemas/supabase-claims-v1.json +144 -0
  328. package/schemas/supabase-manifest-v1.json +361 -0
  329. package/skills/permdock/SKILL.md +66 -0
  330. package/skills/permdock-agents/SKILL.md +77 -0
  331. package/skills/permdock-agents/references/runtimes.md +213 -0
  332. package/skills/permdock-approvals/SKILL.md +80 -0
  333. package/skills/permdock-approvals/references/stores-and-resume.md +94 -0
  334. package/skills/permdock-audit/SKILL.md +67 -0
  335. package/skills/permdock-credentials/SKILL.md +55 -0
  336. package/skills/permdock-credentials/references/tokens-keys-links.md +132 -0
  337. package/skills/permdock-data/SKILL.md +57 -0
  338. package/skills/permdock-data/references/queries-and-rls.md +62 -0
  339. package/skills/permdock-data/references/relationships.md +67 -0
  340. package/skills/permdock-tenancy/SKILL.md +80 -0
  341. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +89 -0
  342. package/skills/permdock-wire/SKILL.md +116 -0
  343. package/skills/permdock-wire/references/adapters.md +492 -0
  344. package/skills/permdock-wire/references/policy-options.md +45 -0
@@ -0,0 +1,67 @@
1
+ import { a as loadModule, o as pickNamed } from "./load-DhWEB9P1.js";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ //#region src/cli/fixtures.ts
5
+ function isRecord(value) {
6
+ return value !== null && typeof value === "object" && !Array.isArray(value);
7
+ }
8
+ function asFixtures(value) {
9
+ const list = Array.isArray(value) ? value : isRecord(value) && Array.isArray(value["fixtures"]) ? value["fixtures"] : void 0;
10
+ if (list === void 0) throw new Error("PermDock CLI: fixtures must be an array or { fixtures }");
11
+ return list.map((item, index) => {
12
+ if (!isRecord(item) || !isRecord(item["subject"]) || item["row"] === void 0) throw new Error(`PermDock CLI: fixture ${index} needs subject and row`);
13
+ if (typeof item["action"] !== "string") throw new TypeError(`PermDock CLI: fixture ${index} needs action`);
14
+ if (typeof item["subject"]["id"] !== "string") throw new TypeError(`PermDock CLI: fixture ${index} subject needs id`);
15
+ const memberships = item["subject"]["memberships"];
16
+ if (memberships !== void 0 && !Array.isArray(memberships)) throw new Error(`PermDock CLI: fixture ${index} subject.memberships must be an array`);
17
+ const tenant = item["subject"]["tenant"];
18
+ if (tenant !== void 0 && typeof tenant !== "string") throw new Error(`PermDock CLI: fixture ${index} subject.tenant must be a string`);
19
+ const claims = item["subject"]["claims"];
20
+ if (claims !== void 0 && !isRecord(claims)) throw new Error(`PermDock CLI: fixture ${index} subject.claims must be an object`);
21
+ return item;
22
+ });
23
+ }
24
+ function asCustomRoles(value) {
25
+ if (!isRecord(value) || value["customRoles"] === void 0) return [];
26
+ if (!Array.isArray(value["customRoles"])) throw new TypeError("PermDock CLI: fixtures customRoles must be an array");
27
+ return value["customRoles"];
28
+ }
29
+ /** A `.json` file or a module exporting `fixtures` (or default) and optionally `customRoles`. */
30
+ async function loadFixtures(cwd, path) {
31
+ const abs = resolve(cwd, path);
32
+ if (!existsSync(abs)) throw new Error(`PermDock CLI: fixtures not found: ${path}`);
33
+ if (abs.endsWith(".json")) {
34
+ const parsed = JSON.parse(readFileSync(abs, "utf8"));
35
+ return {
36
+ fixtures: asFixtures(parsed),
37
+ customRoles: asCustomRoles(parsed)
38
+ };
39
+ }
40
+ const mod = await loadModule(abs);
41
+ return {
42
+ fixtures: asFixtures(pickNamed(mod, ["fixtures", "default"])),
43
+ customRoles: asCustomRoles(mod)
44
+ };
45
+ }
46
+ /** The fixture subject as a `Subject`: a principal with no actor and an empty context. */
47
+ function fixtureSubject(fixture) {
48
+ return {
49
+ principal: {
50
+ id: fixture.id,
51
+ roles: fixture.roles ?? [],
52
+ ...fixture.tenant === void 0 ? {} : { tenant: fixture.tenant },
53
+ memberships: fixture.memberships ?? [],
54
+ ...fixture.claims === void 0 ? {} : { claims: fixture.claims }
55
+ },
56
+ context: {}
57
+ };
58
+ }
59
+ /** The row `can` receives: `{ current, next }` for an instance action with a `newRow`. */
60
+ function fixtureRow(fixture, kind) {
61
+ return fixture.newRow === void 0 || kind === "collection" ? fixture.row : {
62
+ current: fixture.row,
63
+ next: fixture.newRow
64
+ };
65
+ }
66
+ //#endregion
67
+ export { fixtureSubject as n, loadFixtures as r, fixtureRow as t };
@@ -0,0 +1,60 @@
1
+ //#region src/core/freeze.ts
2
+ function refuse() {
3
+ throw new TypeError("PermDock: this collection is frozen");
4
+ }
5
+ const LOCKED = {
6
+ value: refuse,
7
+ writable: false,
8
+ enumerable: false
9
+ };
10
+ /**
11
+ * `Object.freeze` leaves a `Map` or `Set` writable through `set`, `add`,
12
+ * `delete` and `clear`, so those are shadowed on the instance with a method
13
+ * that throws. Identity and `instanceof` stay as they were.
14
+ */
15
+ function freezeCollection(value) {
16
+ Object.defineProperties(value, value instanceof Map ? {
17
+ set: LOCKED,
18
+ delete: LOCKED,
19
+ clear: LOCKED
20
+ } : {
21
+ add: LOCKED,
22
+ delete: LOCKED,
23
+ clear: LOCKED
24
+ });
25
+ Object.freeze(value);
26
+ for (const [key, item] of value.entries()) {
27
+ freezeDeep(key);
28
+ freezeDeep(item);
29
+ }
30
+ }
31
+ function freezeDeep(value) {
32
+ if (value === null || typeof value !== "object") return value;
33
+ if (Object.isFrozen(value)) return value;
34
+ if (value instanceof Map || value instanceof Set) {
35
+ freezeCollection(value);
36
+ return value;
37
+ }
38
+ Object.freeze(value);
39
+ if (Array.isArray(value)) {
40
+ for (const item of value) freezeDeep(item);
41
+ return value;
42
+ }
43
+ for (const key of Object.getOwnPropertyNames(value)) freezeDeep(value[key]);
44
+ return value;
45
+ }
46
+ function isPlain(value) {
47
+ const proto = Object.getPrototypeOf(value);
48
+ return proto === Object.prototype || proto === null;
49
+ }
50
+ /** A deeply frozen copy of the plain objects and arrays in `value`; the caller's own objects stay writable. */
51
+ function freezeCopy(value) {
52
+ if (value === null || typeof value !== "object") return value;
53
+ if (Array.isArray(value)) return Object.freeze(value.map((item) => freezeCopy(item)));
54
+ if (!isPlain(value)) return value;
55
+ const copy = {};
56
+ for (const key of Object.keys(value)) copy[key] = freezeCopy(value[key]);
57
+ return Object.freeze(copy);
58
+ }
59
+ //#endregion
60
+ export { freezeDeep as n, freezeCopy as t };
@@ -0,0 +1,569 @@
1
+ import { t as compact } from "./compact-y6vfu2_f.js";
2
+ import { n as freezeDeep } from "./freeze-CrU8nQeX.js";
3
+ import { _ as listPermissions } from "./permissions-DVoF6dMt.js";
4
+ import { a as deniedMessage, i as approvalMessage, n as PermDockDeniedError, t as PermDockApprovalRequiredError } from "./errors-Cz5zn0mW.js";
5
+ import { n as sameId } from "./ids-DC4V4CFu.js";
6
+ import { a as normalizeMemberships, d as scopeList, m as tenantOf, o as resolveScope, t as activeFor } from "./scopes-CVdPrWN-.js";
7
+ import { a as whereFromGrants, c as rowIdOf, d as isArazzoSimulateInput, f as simulateArazzo, i as signSnapshot, l as rowValues, p as evaluateCondition } from "./snapshot-Enxd0n-s.js";
8
+ import { D as synthesiseRole, E as listRoles, S as findRole, d as matchGrantee } from "./grantee-Cv5Sogfv.js";
9
+ import { n as pickVisible, t as grantCoversField } from "./fields-BMl1RxoX.js";
10
+ import { a as isMembershipExpired, i as inTeam, l as nestedAppliesWithoutRow, m as rowInScope, p as resolveActiveTenant, t as isActive, u as nowSeconds } from "./validity-uOp8UpYn.js";
11
+ import { t as requiresApproval } from "./approval-required-TzNB9oQA.js";
12
+ import { t as coveredByDelegation } from "./delegation-D8pUEuce.js";
13
+ import { t as resourceIdOf } from "./resource-ref-CaS9yVPi.js";
14
+ import { n as payloadDigest, t as decisionToken } from "./token-CIWxJOCh.js";
15
+ //#region src/core/snapshot-evaluate.ts
16
+ function coveredByInclude(snapshot, permission) {
17
+ const include = snapshot.include;
18
+ if (include === void 0 || include.length === 0) return true;
19
+ return include.some((prefix) => permission.key === prefix || permission.key.startsWith(`${prefix}.`) || permission.resource === prefix);
20
+ }
21
+ /** The field of `resource` that holds scope `name`'s id in a snapshot: its `fields` entry, else the scope's key. */
22
+ function snapshotField(snapshot, name, resource) {
23
+ const entry = snapshot.scopes?.find((item) => item.name === name);
24
+ return entry?.fields?.[resource] ?? entry?.key;
25
+ }
26
+ function scopeOk(snapshot, grant, permission, subject, data, team, now, only) {
27
+ const scope = grant.scope;
28
+ if (scope === void 0) return { ok: true };
29
+ if (only !== void 0 && scope !== only) return {
30
+ ok: false,
31
+ reason: "scope"
32
+ };
33
+ const principal = subject.principal;
34
+ const membership = grant.membership;
35
+ if (principal === null || membership === void 0) return {
36
+ ok: false,
37
+ reason: "no-membership"
38
+ };
39
+ if (isMembershipExpired(membership, now)) return {
40
+ ok: false,
41
+ reason: "expired-membership"
42
+ };
43
+ if (typeof scope === "string") {
44
+ const scopes = scopeList(snapshot.scopes);
45
+ if (membership.scope !== scope || !scopes.some((entry) => entry.name === scope)) return {
46
+ ok: false,
47
+ reason: "scope"
48
+ };
49
+ if (!activeFor(membership, scopes, principal.tenant)) return {
50
+ ok: false,
51
+ reason: principal.tenant === void 0 ? "no-membership" : "tenant-mismatch"
52
+ };
53
+ if (!inTeam(membership, scopes, team)) return {
54
+ ok: false,
55
+ reason: "scope"
56
+ };
57
+ if (data === null || typeof data !== "object") return permission.kind !== "instance" || nestedAppliesWithoutRow(membership, scopes, data, team) ? { ok: true } : {
58
+ ok: false,
59
+ reason: "scope"
60
+ };
61
+ const partitioned = (name) => snapshot.scopes?.find((entry) => entry.name === name)?.resources?.includes(permission.resource) === true;
62
+ return rowInScope(membership, scopes, data, partitioned, (name) => snapshotField(snapshot, name, permission.resource));
63
+ }
64
+ const on = membership.on;
65
+ if (on === void 0 || on.resource !== scope.resource || on.resource !== permission.resource) return {
66
+ ok: false,
67
+ reason: "scope"
68
+ };
69
+ if (on.id !== rowIdOf(data, snapshot.ids?.[permission.resource])) return {
70
+ ok: false,
71
+ reason: "scope"
72
+ };
73
+ return { ok: true };
74
+ }
75
+ function conditionOk(grant, permission, current, next, subject, now, scopes) {
76
+ let opaqueReached = false;
77
+ const onOpaque = () => {
78
+ opaqueReached = true;
79
+ };
80
+ if (grant.portable === false) return {
81
+ matched: false,
82
+ reason: "opaque-condition"
83
+ };
84
+ if (grant.where !== void 0) {
85
+ if (permission.kind === "collection" || current === void 0) return {
86
+ matched: false,
87
+ reason: "condition"
88
+ };
89
+ if (grant.where.op === "opaque" || grant.check?.op === "opaque") return {
90
+ matched: false,
91
+ reason: "opaque-condition"
92
+ };
93
+ const matched = evaluateCondition(grant.where, current, subject, now, scopes, void 0, onOpaque);
94
+ if (opaqueReached) return {
95
+ matched: false,
96
+ reason: "opaque-condition"
97
+ };
98
+ if (!matched) return {
99
+ matched: false,
100
+ reason: "condition"
101
+ };
102
+ }
103
+ const check = grant.check;
104
+ if (check !== void 0) {
105
+ if (check.op === "opaque") return {
106
+ matched: false,
107
+ reason: "opaque-condition"
108
+ };
109
+ if (next === void 0) return {
110
+ matched: false,
111
+ reason: "condition"
112
+ };
113
+ const matched = evaluateCondition(check, next, subject, now, scopes, void 0, onOpaque);
114
+ if (opaqueReached) return {
115
+ matched: false,
116
+ reason: "opaque-condition"
117
+ };
118
+ if (!matched) return {
119
+ matched: false,
120
+ reason: "condition"
121
+ };
122
+ }
123
+ return { matched: true };
124
+ }
125
+ function matchedOf(grant) {
126
+ return compact({
127
+ role: grant.role,
128
+ permission: grant.permission,
129
+ to: grant.to,
130
+ where: grant.where,
131
+ check: grant.check,
132
+ approval: grant.approval
133
+ });
134
+ }
135
+ function evaluateSnapshot(snapshot, subject, permission, data, team, options, outcomeOnly = false) {
136
+ let clock = options.now;
137
+ const now = () => clock ??= nowSeconds();
138
+ const tracer = options.explain === true ? {
139
+ evaluated: 0,
140
+ allows: [],
141
+ denies: [],
142
+ skipped: []
143
+ } : void 0;
144
+ const done = (decision) => outcomeOnly ? decision : freezeDeep(tracer === void 0 ? decision : {
145
+ ...decision,
146
+ trace: {
147
+ evaluated: tracer.evaluated,
148
+ allows: tracer.allows,
149
+ denies: tracer.denies,
150
+ skipped: tracer.skipped
151
+ }
152
+ });
153
+ const skip = (grant, why) => {
154
+ tracer?.skipped.push({
155
+ role: grant.role,
156
+ permission: grant.permission,
157
+ effect: grant.effect,
158
+ why
159
+ });
160
+ };
161
+ if (!coveredByInclude(snapshot, permission)) return done({
162
+ outcome: "denied",
163
+ denials: [{
164
+ role: null,
165
+ reason: "opaque-condition"
166
+ }],
167
+ alternatives: []
168
+ });
169
+ const { current, next } = rowValues(permission, data);
170
+ const scopes = scopeList(snapshot.scopes);
171
+ const denials = [];
172
+ const allows = [];
173
+ for (const grant of snapshot.grants) {
174
+ if (grant.permission !== permission.key) continue;
175
+ if (tracer !== void 0) tracer.evaluated += 1;
176
+ const match = matchGrantee(grant.to, subject, now(), void 0, scopes, void 0, grant.effect === "deny");
177
+ if (!match.matched) {
178
+ denials.push(compact({
179
+ role: grant.role,
180
+ reason: match.reason ?? "no-grant",
181
+ to: grant.to
182
+ }));
183
+ continue;
184
+ }
185
+ let scoped = scopeOk(snapshot, grant, permission, subject, permission.kind === "instance" ? current : next, team, now(), options.scope);
186
+ if (scoped.ok && permission.kind === "instance" && next !== current) scoped = scopeOk(snapshot, grant, permission, subject, next, team, now(), options.scope);
187
+ if (!scoped.ok) {
188
+ denials.push(compact({
189
+ role: grant.role,
190
+ reason: scoped.reason,
191
+ to: grant.to
192
+ }));
193
+ continue;
194
+ }
195
+ if (!isActive(grant.validity, now())) {
196
+ if (grant.effect === "allow") denials.push({
197
+ role: grant.role,
198
+ reason: "inactive-grant",
199
+ detail: grant.validity
200
+ });
201
+ else skip(grant, "validity");
202
+ continue;
203
+ }
204
+ if (grant.effect === "deny" && grant.portable === false) {
205
+ if (!grantCoversField(grant.fields, options.field, grant.effect)) {
206
+ skip(grant, "field");
207
+ continue;
208
+ }
209
+ tracer?.denies.push(matchedOf(grant));
210
+ return done({
211
+ outcome: "denied",
212
+ denials: [{
213
+ role: grant.role,
214
+ reason: "opaque-condition"
215
+ }],
216
+ alternatives: []
217
+ });
218
+ }
219
+ const condition = conditionOk(grant, permission, current, next, subject, now(), scopes);
220
+ if (!condition.matched && grant.effect === "deny" && condition.reason === "opaque-condition" && grantCoversField(grant.fields, options.field, grant.effect)) {
221
+ tracer?.denies.push(matchedOf(grant));
222
+ return done({
223
+ outcome: "denied",
224
+ denials: [{
225
+ role: grant.role,
226
+ reason: "opaque-condition"
227
+ }],
228
+ alternatives: []
229
+ });
230
+ }
231
+ if (!condition.matched) {
232
+ denials.push({
233
+ role: grant.role,
234
+ reason: condition.reason ?? "condition"
235
+ });
236
+ continue;
237
+ }
238
+ if (!grantCoversField(grant.fields, options.field, grant.effect)) {
239
+ skip(grant, "field");
240
+ continue;
241
+ }
242
+ if (grant.effect === "deny") {
243
+ tracer?.denies.push(matchedOf(grant));
244
+ return done({
245
+ outcome: "denied",
246
+ denials: [{
247
+ role: grant.role,
248
+ reason: "deny"
249
+ }],
250
+ alternatives: []
251
+ });
252
+ }
253
+ tracer?.allows.push(matchedOf(grant));
254
+ allows.push(grant);
255
+ }
256
+ const [matched] = allows;
257
+ if (matched === void 0) {
258
+ for (const entry of snapshot.notEntitled ?? []) if (entry.permission === permission.key) denials.push({
259
+ role: entry.role,
260
+ reason: "not-entitled",
261
+ to: entry.to
262
+ });
263
+ return done({
264
+ outcome: "denied",
265
+ denials: denials.length > 0 ? denials : [{
266
+ role: null,
267
+ reason: subject.principal === null ? "anonymous" : "no-grant"
268
+ }],
269
+ alternatives: []
270
+ });
271
+ }
272
+ if (snapshot.delegated !== void 0 && !snapshot.delegated.includes(permission.key)) return done({
273
+ outcome: "denied",
274
+ denials: [{
275
+ role: null,
276
+ reason: "not-delegated"
277
+ }],
278
+ alternatives: []
279
+ });
280
+ const miss = coveredByDelegation(permission, subject.delegation, resourceIdOf(current), subject.actor !== void 0 && snapshot.delegated === void 0);
281
+ if (miss !== void 0) return done({
282
+ outcome: "denied",
283
+ denials: [{
284
+ role: null,
285
+ reason: miss
286
+ }],
287
+ alternatives: []
288
+ });
289
+ const resourceId = permission.kind === "collection" ? "*" : rowIdOf(current, snapshot.ids?.[permission.resource]);
290
+ const token = outcomeOnly ? "" : decisionToken({
291
+ key: permission.key,
292
+ resourceId,
293
+ principal: subject.principal,
294
+ actor: subject.actor,
295
+ fingerprint: `snapshot:${String(snapshot.issuedAt)}`,
296
+ payload: resourceId === "*" && (next ?? current) !== void 0 ? payloadDigest(next ?? current) : void 0
297
+ });
298
+ const grant = matchedOf(matched);
299
+ if (requiresApproval(matched.approval)) return done({
300
+ outcome: "approval-required",
301
+ grant,
302
+ reason: "human",
303
+ token
304
+ });
305
+ return done({
306
+ outcome: "granted",
307
+ subject,
308
+ matched: grant,
309
+ token
310
+ });
311
+ }
312
+ function whereFromSnapshot(snapshot, subject, permission, team) {
313
+ return whereFromGrants(snapshot.grants.filter((grant) => grant.permission === permission.key), {
314
+ resource: permission.resource,
315
+ scopes: scopeList(snapshot.scopes),
316
+ partitioned: (name) => snapshot.scopes?.find((entry) => entry.name === name)?.resources?.includes(permission.resource) === true,
317
+ fieldOf: (name) => snapshotField(snapshot, name, permission.resource),
318
+ tenant: subject.principal?.tenant,
319
+ team,
320
+ now: nowSeconds(),
321
+ subject
322
+ });
323
+ }
324
+ //#endregion
325
+ //#region src/core/snapshot-subject.ts
326
+ function subjectFromSnapshot(snapshot, tenant) {
327
+ const principal = snapshot.subject.principal;
328
+ const nextTenant = principal === null ? void 0 : tenant === void 0 ? principal.tenant : resolveActiveTenant(compact({
329
+ ...principal,
330
+ memberships: principal.memberships ?? []
331
+ }), tenant, scopeList(snapshot.scopes));
332
+ return freezeDeep(compact({
333
+ principal: principal === null ? null : compact({
334
+ ...principal,
335
+ tenant: nextTenant
336
+ }),
337
+ delegation: snapshot.subject.delegation,
338
+ context: snapshot.subject.context,
339
+ expiresAt: snapshot.expiresAt
340
+ }));
341
+ }
342
+ /**
343
+ * Role names held in `tenant`, or only on memberships of one `scope` (and
344
+ * instance `id`), ordered like `rank` (the snapshot's ranked `roles`).
345
+ */
346
+ function heldRoleNames(subject, tenant, scopes, only, now) {
347
+ const scope = only?.scope === void 0 ? void 0 : resolveScope(scopes, only.scope);
348
+ if (only?.scope !== void 0 && scope === void 0) return [];
349
+ const names = new Set(scope === void 0 ? subject.principal?.roles ?? [] : []);
350
+ for (const membership of subject.principal?.memberships ?? []) {
351
+ if (isMembershipExpired(membership, now)) continue;
352
+ if (!(scope === void 0 ? tenantOf(membership, scopes) === tenant : membership.scope === scope && (only?.id === void 0 || sameId(membership.id, only.id)))) continue;
353
+ for (const role of membership.roles) names.add(role);
354
+ }
355
+ const rank = only?.rank ?? [];
356
+ const position = (name) => {
357
+ const index = rank.indexOf(name);
358
+ return index === -1 ? rank.length : index;
359
+ };
360
+ return [...names].toSorted((a, b) => position(a) - position(b));
361
+ }
362
+ //#endregion
363
+ //#region src/core/from-snapshot.ts
364
+ function resourceRef(snapshot, permission, data) {
365
+ const id = permission.kind === "collection" ? void 0 : rowIdOf(data, snapshot.ids?.[permission.resource]);
366
+ return id === void 0 || id === "*" ? { type: permission.resource } : {
367
+ type: permission.resource,
368
+ id
369
+ };
370
+ }
371
+ function assignableEntry(snapshot, tenant) {
372
+ if (tenant === void 0) return;
373
+ return snapshot.assignable?.find((entry) => entry.tenant === tenant);
374
+ }
375
+ function fromSnapshot(snapshot, options = {}) {
376
+ const subject = subjectFromSnapshot(snapshot, options.tenant);
377
+ const team = options.team;
378
+ const run = (permission, data, decideOptions = {}) => evaluateSnapshot(snapshot, subject, permission, data, team, decideOptions);
379
+ const decide = ((permission, data, decideOptions = {}) => run(permission, data, decideOptions));
380
+ const can = ((permission, data, decideOptions) => {
381
+ try {
382
+ return evaluateSnapshot(snapshot, subject, permission, data, team, decideOptions ?? {}, true).outcome === "granted";
383
+ } catch {
384
+ return false;
385
+ }
386
+ });
387
+ const assert = ((permission, data, decideOptions) => {
388
+ const decision = run(permission, data, decideOptions);
389
+ if (decision.outcome === "granted") return decision;
390
+ if (decision.outcome === "approval-required") throw new PermDockApprovalRequiredError({
391
+ decision,
392
+ permission: permission.key,
393
+ scope: permission.scope,
394
+ resource: resourceRef(snapshot, permission, data),
395
+ message: approvalMessage(permission.key, decision.reason, decision.token)
396
+ });
397
+ throw new PermDockDeniedError({
398
+ decision,
399
+ permission: permission.key,
400
+ scope: permission.scope,
401
+ resource: resourceRef(snapshot, permission, data),
402
+ subject,
403
+ message: deniedMessage(permission.key, subject.principal?.id, decision.denials, [])
404
+ });
405
+ });
406
+ const explain = ((permission, data, decideOptions) => run(permission, data, {
407
+ ...decideOptions,
408
+ source: decideOptions?.source ?? "explain",
409
+ explain: true
410
+ }));
411
+ const instance = {
412
+ can,
413
+ decide,
414
+ assert,
415
+ explain,
416
+ permissions: {},
417
+ roles: snapshot.vocabulary?.roles ?? {},
418
+ plans: snapshot.vocabulary?.plans ?? {},
419
+ filter(permission, rows, decideOptions) {
420
+ return rows.filter((row) => can(permission, row, decideOptions) === true);
421
+ },
422
+ pick(permission, row, decideOptions) {
423
+ if (row === null || typeof row !== "object") return {};
424
+ if (can(permission, row, decideOptions) !== true) return {};
425
+ return pickVisible(row, (field) => {
426
+ const next = compact({
427
+ ...decideOptions,
428
+ field
429
+ });
430
+ return can(permission, row, next) === true;
431
+ });
432
+ },
433
+ where(permission) {
434
+ return whereFromSnapshot(snapshot, subject, permission, team);
435
+ },
436
+ actions(resource, data, decideOptions) {
437
+ return listPermissions(resource).filter((item) => run(item, data, decideOptions).outcome === "granted");
438
+ },
439
+ simulate: ((input, simulateOptions) => {
440
+ if (Array.isArray(input)) return input.map(([permission, data]) => run(permission, data, compact({ now: simulateOptions?.now })));
441
+ if (isArazzoSimulateInput(input)) return simulateArazzo(input, input.permissions, (permission, data) => run(permission, data));
442
+ const preview = input;
443
+ const previewRoles = preview.roles?.map((item) => typeof item === "string" ? item : item.key);
444
+ return fromSnapshot(freezeDeep({
445
+ ...snapshot,
446
+ simulated: true,
447
+ subject: {
448
+ ...snapshot.subject,
449
+ principal: snapshot.subject.principal === null ? null : compact({
450
+ ...snapshot.subject.principal,
451
+ roles: previewRoles ?? snapshot.subject.principal.roles,
452
+ memberships: preview.memberships === void 0 ? snapshot.subject.principal.memberships : normalizeMemberships(preview.memberships, scopeList(snapshot.scopes)),
453
+ tenant: preview.tenant ?? snapshot.subject.principal.tenant
454
+ })
455
+ }
456
+ }), options);
457
+ }),
458
+ snapshot: ((signing) => signing?.signer === void 0 ? snapshot : signSnapshot(snapshot, signing.signer, signing.audience)),
459
+ on() {
460
+ return () => void 0;
461
+ },
462
+ tenant(id) {
463
+ return fromSnapshot(snapshot, compact({
464
+ tenant: id,
465
+ team
466
+ }));
467
+ },
468
+ team(id) {
469
+ return fromSnapshot(snapshot, compact({
470
+ tenant: options.tenant,
471
+ team: id
472
+ }));
473
+ },
474
+ memberships() {
475
+ return subject.principal?.memberships ?? [];
476
+ },
477
+ tenants() {
478
+ return snapshot.tenants;
479
+ },
480
+ heldRoles(query) {
481
+ const names = heldRoleNames(subject, query?.tenant ?? subject.principal?.tenant, scopeList(snapshot.scopes), compact({
482
+ scope: query?.scope,
483
+ id: query?.id,
484
+ rank: snapshot.roles
485
+ }));
486
+ const tree = snapshot.vocabulary?.roles;
487
+ return names.map((name) => findRole(tree, name) ?? synthesiseRole(name));
488
+ },
489
+ audiences() {
490
+ const tenant = subject.principal?.tenant;
491
+ if (tenant === snapshot.subject.principal?.tenant) return snapshot.audiences ?? [];
492
+ const tree = snapshot.vocabulary?.roles;
493
+ const out = [];
494
+ for (const name of heldRoleNames(subject, tenant, scopeList(snapshot.scopes), { rank: snapshot.roles })) {
495
+ const audience = findRole(tree, name)?.meta.audience;
496
+ if (typeof audience === "string" && !out.includes(audience)) out.push(audience);
497
+ }
498
+ return out;
499
+ },
500
+ loadRelations() {
501
+ return Promise.resolve();
502
+ },
503
+ whoCan(permission) {
504
+ return Promise.resolve(freezeDeep({
505
+ permission: permission.key,
506
+ holders: [],
507
+ complete: false
508
+ }));
509
+ },
510
+ decideRoleChange(change) {
511
+ return freezeDeep({
512
+ outcome: "denied",
513
+ change,
514
+ denials: [{
515
+ role: null,
516
+ reason: "unsupported"
517
+ }]
518
+ });
519
+ },
520
+ derive() {
521
+ return instance;
522
+ },
523
+ activate() {
524
+ return freezeDeep({
525
+ outcome: "denied",
526
+ denials: [{
527
+ role: null,
528
+ reason: "unsupported"
529
+ }],
530
+ alternatives: []
531
+ });
532
+ },
533
+ assignableRoles(query) {
534
+ const tenant = query?.tenant ?? subject.principal?.tenant;
535
+ const tree = snapshot.vocabulary?.roles;
536
+ if (snapshot.assignable !== void 0) return (assignableEntry(snapshot, tenant)?.roles ?? []).map((name) => findRole(tree, name) ?? synthesiseRole(name, { assignable: true }));
537
+ const names = new Set(heldRoleNames(subject, tenant, scopeList(snapshot.scopes)));
538
+ return listRoles(tree).filter((leaf) => leaf.assignable && names.has(leaf.key));
539
+ },
540
+ assignablePermissions(query) {
541
+ if (query?.scope === "global") return [];
542
+ return assignableEntry(snapshot, query?.tenant ?? subject.principal?.tenant)?.permissions ?? [];
543
+ },
544
+ assignableLevels(permission, query) {
545
+ if (query?.scope === "global") return [];
546
+ const levels = assignableEntry(snapshot, query?.tenant ?? subject.principal?.tenant)?.levels;
547
+ if (levels === void 0 || !Object.hasOwn(levels, permission.key)) return [];
548
+ const names = levels[permission.key];
549
+ return Array.isArray(names) ? names.filter((name) => typeof name === "string") : [];
550
+ },
551
+ subject
552
+ };
553
+ return Object.freeze(instance);
554
+ }
555
+ function emptySnapshot() {
556
+ return freezeDeep({
557
+ v: 1,
558
+ issuedAt: 0,
559
+ subject: {
560
+ principal: null,
561
+ context: {}
562
+ },
563
+ roles: [],
564
+ grants: [],
565
+ tenants: []
566
+ });
567
+ }
568
+ //#endregion
569
+ export { fromSnapshot as n, heldRoleNames as r, emptySnapshot as t };