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,2252 @@
1
+ import { f as Permission, m as PermissionTree, p as PermissionKind, y as ResourceNode } from "./permissions-DttnqqxC.js";
2
+ import { a as RoleTree, i as RoleMeta, n as PlanTree, r as Role, t as Plan } from "./vocabulary-DA8a8zif.js";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+ //#region src/conditions/ast.d.ts
5
+ type ConditionRef = {
6
+ readonly ref: string;
7
+ };
8
+ type ConditionDate = {
9
+ readonly date: string;
10
+ };
11
+ type ConditionValue = string | number | boolean | null | readonly ConditionValue[] | ConditionRef | ConditionDate;
12
+ type ComparisonOp = "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains";
13
+ type ComparisonCondition = {
14
+ readonly op: ComparisonOp;
15
+ readonly field: string;
16
+ readonly value: ConditionValue;
17
+ };
18
+ type InCondition = {
19
+ readonly op: "in" | "notIn";
20
+ readonly field: string;
21
+ readonly value: readonly ConditionValue[] | ConditionRef;
22
+ };
23
+ type IsNullCondition = {
24
+ readonly op: "isNull";
25
+ readonly field: string;
26
+ readonly value: boolean;
27
+ };
28
+ type AndCondition = {
29
+ readonly op: "and";
30
+ readonly conditions: readonly Condition[];
31
+ };
32
+ type OrCondition = {
33
+ readonly op: "or";
34
+ readonly conditions: readonly Condition[];
35
+ };
36
+ type NotCondition = {
37
+ readonly op: "not";
38
+ readonly condition: Condition;
39
+ };
40
+ type MemberOfCondition = {
41
+ readonly op: "memberOf";
42
+ /** A declared scope name (or the `tenant` / `team` alias), or `'resource'`. */
43
+ readonly scope: string;
44
+ readonly field: string;
45
+ readonly roles: readonly string[];
46
+ readonly resource?: string;
47
+ readonly parents?: readonly MemberOfParent[];
48
+ };
49
+ /**
50
+ * A row field holding an ancestor's id. The keyed form matches only a
51
+ * membership on that resource; a bare field name matches a membership on any
52
+ * resource whose id equals the field.
53
+ */
54
+ type MemberOfParent = string | {
55
+ readonly field: string;
56
+ readonly resource: string;
57
+ };
58
+ /**
59
+ * The subject holds `relation` on the `resource` instance whose id the row's
60
+ * `field` holds, or on one of its ancestors within `depth` parent hops.
61
+ * Evaluated through a `RelationSource` in process, the closure table in RLS,
62
+ * and, given relation mappings, a subquery in the `toWhere` compilers.
63
+ */
64
+ type RelatedCondition = {
65
+ readonly op: "related";
66
+ readonly resource: string;
67
+ readonly relation: string;
68
+ /** The row's own id field, or (with `parent` or `hops`) the field holding the next instance's id. */
69
+ readonly field: string;
70
+ /** Parent hops walked above the first `resource` instance; `0` reads only that instance. */
71
+ readonly depth: number;
72
+ /** The row is a child of `resource`, reached through `field`. */
73
+ readonly parent?: true;
74
+ /**
75
+ * To-one links from the row to `resource`: `field` points at the first
76
+ * hop's resource, each later hop follows `link` on the resource before it,
77
+ * and the last hop's resource is `resource`.
78
+ */
79
+ readonly hops?: readonly RelatedHop[];
80
+ /**
81
+ * The `resource` instances the subject holds a resource role on; replaces
82
+ * the `relation` lookup (`relation` is then empty).
83
+ */
84
+ readonly ids?: readonly string[];
85
+ readonly permission?: string;
86
+ /**
87
+ * The row's boolean column that keeps ancestor grants out: with `parent` or
88
+ * `hops`, a restricted row matches nothing; without, the walk stops at the row.
89
+ */
90
+ readonly restricted?: string;
91
+ readonly restrictedAncestors?: RestrictedAncestors;
92
+ readonly passRestricted?: true;
93
+ };
94
+ type RestrictedAncestors = {
95
+ readonly resource: string;
96
+ readonly id: string;
97
+ readonly parent: string;
98
+ readonly depth: number;
99
+ readonly field: string;
100
+ };
101
+ type RelatedHop = {
102
+ readonly link: string;
103
+ readonly resource: string;
104
+ };
105
+ type OpaqueCondition = {
106
+ readonly op: "opaque";
107
+ readonly sql: string;
108
+ readonly fingerprint: string;
109
+ };
110
+ type SqlFunctionField = {
111
+ readonly field: string;
112
+ };
113
+ type SqlFunctionArg = ConditionValue | SqlFunctionField;
114
+ type SqlFunctionCondition = {
115
+ readonly op: "sqlFunction";
116
+ readonly name: string;
117
+ readonly args: readonly SqlFunctionArg[];
118
+ readonly twin: Condition;
119
+ };
120
+ /**
121
+ * The request's session was checked against the Auth server while the
122
+ * subject was resolved (`liveSession: true`), not only verified from the
123
+ * token: a revoked session still verifies until `exp`. Written
124
+ * `{ subject: { session: { live: true } } }`.
125
+ */
126
+ type LiveSessionCondition = {
127
+ readonly op: "liveSession";
128
+ };
129
+ type Condition = ComparisonCondition | InCondition | IsNullCondition | AndCondition | OrCondition | NotCondition | MemberOfCondition | RelatedCondition | OpaqueCondition | SqlFunctionCondition | LiveSessionCondition;
130
+ declare function isConditionRef(value: unknown): value is ConditionRef;
131
+ declare function isConditionDate(value: unknown): value is ConditionDate;
132
+ declare function isCondition(value: unknown): value is Condition;
133
+ declare function isSqlFunctionField(value: unknown): value is SqlFunctionField;
134
+ declare function hasConditionOp(condition: Condition | undefined, op: Condition["op"]): boolean;
135
+ //#endregion
136
+ //#region src/core/subject.d.ts
137
+ type JsonWebKeyLike = {
138
+ readonly kty?: string;
139
+ readonly [key: string]: unknown;
140
+ };
141
+ type Binding = {
142
+ readonly jkt?: string;
143
+ readonly "x5t#S256"?: string;
144
+ readonly jwk?: JsonWebKeyLike;
145
+ readonly kid?: string;
146
+ };
147
+ /**
148
+ * One OpenID Connect for Identity Assurance `verified_claims` entry, kept as
149
+ * the issuer sent it: opaque, frozen evidence for conditions and audit.
150
+ */
151
+ type VerifiedClaims = {
152
+ readonly verification: Readonly<Record<string, unknown>> & {
153
+ readonly trust_framework: string;
154
+ };
155
+ readonly claims: Readonly<Record<string, unknown>>;
156
+ };
157
+ type Assurance = {
158
+ readonly acr?: string;
159
+ readonly amr?: readonly string[];
160
+ readonly authTime?: number;
161
+ readonly verified?: readonly VerifiedClaims[];
162
+ };
163
+ /**
164
+ * Roles held in one scope instance (`scope` + `id`, with the id of every
165
+ * ancestor scope in `within`) or on one resource (`on`). Evaluation only sees
166
+ * the canonical form; `tenant` / `team` are accepted as input for the first
167
+ * and second declared scope and normalised away.
168
+ */
169
+ type Membership = {
170
+ readonly scope?: string;
171
+ readonly id?: string;
172
+ readonly within?: Readonly<Record<string, string>>;
173
+ readonly on?: {
174
+ readonly resource: string;
175
+ readonly id: string;
176
+ };
177
+ readonly roles: readonly string[];
178
+ /** Roles the holder may activate here but does not hold; `permdock.activate` writes an elevated membership. */
179
+ readonly eligible?: readonly string[];
180
+ readonly via?: string;
181
+ readonly expiresAt?: number;
182
+ /** The principal id that wrote this membership: who elevated, consented to or granted the access. */
183
+ readonly grantedBy?: string;
184
+ /** Free text recording why the membership was written: the activation or consent justification. */
185
+ readonly reason?: string;
186
+ /** A subgroup the holder belongs to inside the instance (`vendor-support`); a `fromJunction` group column fills it. */
187
+ readonly member?: {
188
+ readonly group: string;
189
+ };
190
+ /** `idp`: the identity provider (SCIM) owns this membership; the application must not edit it. */
191
+ readonly managedBy?: "idp";
192
+ /** Seats this membership holds (`dev-mode`, `editor`); `plan()` grantees match them inside the active tenant. */
193
+ readonly entitlements?: readonly string[];
194
+ /**
195
+ * Set when the instance or an ancestor instance is suspended: the
196
+ * permission keys the membership still grants (`suspension.scopes.<scope>.keep`).
197
+ * Every other grant, allow or deny, ignores it, and so do role listings.
198
+ */
199
+ readonly keep?: readonly string[];
200
+ /** Input only: an instance of the first scope. */
201
+ readonly tenant?: string;
202
+ /** Input only: an instance of the second scope, inside `tenant`. */
203
+ readonly team?: string;
204
+ };
205
+ /**
206
+ * One permission a custom role adds or removes. It names a declared
207
+ * permission key and carries no condition, approval or limit of its own.
208
+ */
209
+ type CustomRoleGrant = {
210
+ readonly permission: string;
211
+ readonly effect?: "allow" | "deny";
212
+ /** A level the permission's resource declares (`resource(…, { levels })`); allows only. */
213
+ readonly level?: string;
214
+ };
215
+ type CustomRoleBody = {
216
+ readonly name: string;
217
+ readonly includes?: readonly string[];
218
+ readonly grants?: readonly CustomRoleGrant[];
219
+ readonly meta?: Readonly<Record<string, unknown>>;
220
+ };
221
+ /** A role a tenant defines, held on memberships inside that tenant. */
222
+ type TenantCustomRole = CustomRoleBody & {
223
+ /** The instance of the first scope that owns the role. */
224
+ readonly tenant: string;
225
+ /** The scope the role is held at; defaults to the first scope. Its ceiling is that scope's assignable roles. */
226
+ readonly scope?: string;
227
+ /** Pins the role to one instance of `scope`. */
228
+ readonly id?: string;
229
+ /** Input only: `scope` = the second scope, `id` = this team. */
230
+ readonly team?: string;
231
+ };
232
+ /**
233
+ * A role the platform defines, held through `principal.roles` like a declared
234
+ * global role. Its ceiling is the allows of the declared global roles marked
235
+ * `assignable`.
236
+ */
237
+ type GlobalCustomRole = CustomRoleBody & {
238
+ readonly scope: "global";
239
+ readonly tenant?: undefined;
240
+ readonly id?: undefined;
241
+ readonly team?: undefined;
242
+ };
243
+ type CustomRole = TenantCustomRole | GlobalCustomRole;
244
+ type Principal = {
245
+ readonly id: string;
246
+ readonly issuer?: string;
247
+ readonly kind?: "user" | "service" | "workload" | "link";
248
+ readonly roles?: readonly string[];
249
+ readonly plans?: readonly string[];
250
+ readonly memberships?: readonly Membership[];
251
+ /** The token dropped memberships to stay under its size budget; a `claimsFirst` source reads the rest. */
252
+ readonly membershipsTruncated?: boolean;
253
+ /** The authorization version the token was minted at (`authz_ver`). */
254
+ readonly authzVersion?: number;
255
+ readonly tenant?: string;
256
+ readonly assurance?: Assurance;
257
+ readonly binding?: Binding;
258
+ readonly [key: string]: unknown;
259
+ };
260
+ type Actor = {
261
+ readonly id: string;
262
+ readonly kind: string;
263
+ readonly binding?: Binding;
264
+ /** `true` narrows every policy delegation to this actor to its read-only permissions (`readOnlyHint`). */
265
+ readonly readOnly?: boolean;
266
+ /** The stable name the application gives this OAuth client (`ClientNames`), set by the subject resolver from the verified client id; policy delegations match it with `to: { kind, client }`. */
267
+ readonly client?: string;
268
+ readonly [key: string]: unknown;
269
+ };
270
+ type AuthorizationDetail = {
271
+ readonly type: string;
272
+ readonly actions?: readonly string[];
273
+ readonly [key: string]: unknown;
274
+ };
275
+ type GnapAccess = string | Readonly<Record<string, unknown>>;
276
+ type Delegation = {
277
+ readonly scopes?: readonly string[];
278
+ readonly authorizationDetails?: readonly AuthorizationDetail[];
279
+ readonly access?: readonly GnapAccess[];
280
+ readonly chain?: unknown;
281
+ };
282
+ type Subject<TPrincipal extends Principal = Principal> = {
283
+ readonly principal: TPrincipal | null;
284
+ readonly actor?: Actor;
285
+ readonly delegation?: Delegation;
286
+ readonly context: Readonly<Record<string, unknown>>;
287
+ readonly session?: string;
288
+ readonly expiresAt?: number;
289
+ /** The token's memberships are behind the source's authorization version: `fresh` permissions deny. */
290
+ readonly stale?: true;
291
+ /**
292
+ * The resolver checked the session against the Auth server for this request
293
+ * (`liveSession: true`), so `{ subject: { session: { live: true } } }` holds.
294
+ * Never read from claims.
295
+ */
296
+ readonly liveSession?: true;
297
+ };
298
+ //#endregion
299
+ //#region src/core/scopes.d.ts
300
+ /** One entry of `definePolicy({ scopes })`: the row field holding the scope id, and its parent scope. */
301
+ type ScopeDeclaration = {
302
+ readonly key: string;
303
+ readonly within?: string;
304
+ };
305
+ type PolicyScopesInput = Readonly<Record<string, ScopeDeclaration>>;
306
+ /**
307
+ * A declared scope, in declaration order. `key` is absent only on the
308
+ * implicit `tenant` / `team` pair of a policy that declares no scopes.
309
+ */
310
+ type Scope = {
311
+ readonly name: string;
312
+ readonly key?: string;
313
+ readonly within?: string;
314
+ };
315
+ /** The names `role(..., { on })`, `memberOf` and memberships may use: declared names plus the aliases. */
316
+ type ScopeNames<S> = [S] extends [PolicyScopesInput] ? string extends keyof S ? string : (keyof S & string) | "tenant" | "team" : string;
317
+ //#endregion
318
+ //#region src/core/grantee.d.ts
319
+ type RoleGrantee = {
320
+ readonly kind: "role";
321
+ readonly role: string;
322
+ /** `'global'`, a scope name, or one resource. */
323
+ readonly scope: string | {
324
+ readonly resource: string;
325
+ };
326
+ };
327
+ type AnyoneGrantee = {
328
+ readonly kind: "anyone";
329
+ };
330
+ type AuthenticatedGrantee = {
331
+ readonly kind: "authenticated";
332
+ };
333
+ type RelationGrantee = {
334
+ readonly kind: "relation";
335
+ readonly resource: string;
336
+ readonly relation: string;
337
+ /**
338
+ * `'parent'`: follow the row's `parent` chain upward to `resource`, then its
339
+ * own parents. A list of link names: follow those to-one links from the row
340
+ * to `resource`, then walk its parents only when `depth` is set.
341
+ */
342
+ readonly through?: "parent" | readonly string[];
343
+ /** Parent hops walked above the first `resource` instance; absent means `DEFAULT_RELATION_DEPTH` for `'parent'` and `0` for links. */
344
+ readonly depth?: number;
345
+ };
346
+ type PlanGrantee = {
347
+ readonly kind: "plan";
348
+ readonly plan: string;
349
+ };
350
+ type ActorGrantee = {
351
+ readonly kind: "actor";
352
+ readonly actor: string;
353
+ };
354
+ type AssuranceGrantee = {
355
+ readonly kind: "assurance";
356
+ readonly acr?: readonly string[];
357
+ readonly amr?: readonly string[];
358
+ readonly maxAge?: number;
359
+ };
360
+ type InheritGrantee = {
361
+ readonly kind: "inherit";
362
+ readonly permission: string;
363
+ readonly resource: string;
364
+ readonly through: "parent" | readonly string[];
365
+ };
366
+ type Grantee = RoleGrantee | InheritGrantee | AnyoneGrantee | AuthenticatedGrantee | RelationGrantee | PlanGrantee | ActorGrantee | AssuranceGrantee;
367
+ type GranteeInput = Grantee | Role | Plan | string | readonly GranteeInput[];
368
+ declare function anyone(): AnyoneGrantee;
369
+ declare function authenticated(): AuthenticatedGrantee;
370
+ declare function relation(resource: Permission | PermissionTree, name: string, options?: {
371
+ readonly through?: "parent" | readonly string[];
372
+ readonly depth?: number;
373
+ }): RelationGrantee;
374
+ declare function inherit(permission: Permission, options: {
375
+ readonly through: "parent" | readonly string[];
376
+ }): InheritGrantee;
377
+ declare function plan(name: Plan | string): PlanGrantee;
378
+ declare function actor(kind: string): ActorGrantee;
379
+ declare function assurance(options: {
380
+ readonly acr?: string | readonly string[];
381
+ readonly amr?: string | readonly string[];
382
+ readonly maxAge?: number;
383
+ }): AssuranceGrantee;
384
+ //#endregion
385
+ //#region src/core/decision.d.ts
386
+ type DenialReason = "no-grant" | "condition" | "deny" | "inactive-grant" | "closure-error" | "opaque-condition" | "server-only" | "anonymous" | "not-delegated" | "no-delegation" | "insufficient-user-authentication" | "not-entitled" | "purpose" | "reason-required" | "actor-required" | "limit" | "limit-unavailable" | "relation-depth" | "relation-unavailable" | "validation" | "tenant-mismatch" | "no-membership" | "scope" | "expired-membership" | "stale-credentials" | "unknown-role" | "last-holder" | "max-holders" | "transfer-only" | "not-assignable-by" | "self-demotion" | "externally-managed" | "not-allowed-for-membership" | "conflicting-role" | "approval" | "stale-approval" | "pdp-denied" | "pdp-unavailable" | "pdp-invalid-response" | "undocumented" | "unsupported" | "exceeds-creator" | "credential-policy";
387
+ type Denial = {
388
+ readonly role: string | null;
389
+ readonly reason: DenialReason;
390
+ readonly detail?: unknown;
391
+ readonly to?: Grantee | readonly Grantee[];
392
+ };
393
+ type MatchedGrant = {
394
+ readonly role: string | null;
395
+ readonly permission: string;
396
+ /** The grant's declared `name`, when it has one. */
397
+ readonly name?: string;
398
+ readonly to?: Grantee | readonly Grantee[];
399
+ readonly where?: Grant["where"];
400
+ readonly check?: Grant["check"];
401
+ readonly approval?: "human" | ApprovalRequirement;
402
+ readonly provider?: string;
403
+ /** The hosted policy document fingerprint and grant id, when a hosted grant matched. */
404
+ readonly hosted?: HostedGrantRef;
405
+ /** A break-glass grant overrode a matching deny. */
406
+ readonly breakGlass?: true;
407
+ };
408
+ /**
409
+ * Something the caller owes alongside a granted action. `over-limit`: a soft
410
+ * `limit` was past its count; `near-limit`: usage reached `alertAt`.
411
+ * `notify` / `review`: a break-glass grant's declared follow-ups.
412
+ * `justify`: the break-glass reason, carried so audit records why.
413
+ */
414
+ type Obligation = {
415
+ readonly kind: "over-limit" | "near-limit" | "notify" | "review";
416
+ } | {
417
+ readonly kind: "justify";
418
+ readonly reason: string;
419
+ };
420
+ /** What is left of the `limit` that applied; `resetsAt` is Unix seconds. */
421
+ type Quota = {
422
+ readonly remaining: number;
423
+ readonly resetsAt: number;
424
+ };
425
+ /**
426
+ * The `detail` of a `limit` denial: the grant's `count`, its window in
427
+ * seconds and when the window resets (Unix seconds).
428
+ */
429
+ type LimitDetail = {
430
+ readonly count: number;
431
+ readonly window: number;
432
+ readonly resetsAt: number;
433
+ };
434
+ /**
435
+ * Why a candidate grant for the permission was passed over before its
436
+ * condition ran: `via-only` (the subject holds no membership of its kind),
437
+ * `purpose` (no asserted purpose it lists), `field` (its `fields` do not
438
+ * cover the requested field), `grantee` (its `to` did not match and added no
439
+ * denial), `role` (a role it names is not held), `validity` (a deny outside
440
+ * its `validFrom` / `validUntil`; an inactive allow adds an `inactive-grant`
441
+ * denial instead), `break-glass-inactive` (a break-glass grant with no
442
+ * asserted purpose).
443
+ */
444
+ type TraceSkipReason = "via-only" | "purpose" | "field" | "grantee" | "role" | "validity" | "break-glass-inactive";
445
+ type TraceSkip = {
446
+ readonly role: string | null;
447
+ readonly permission: string;
448
+ readonly effect: "allow" | "deny";
449
+ readonly why: TraceSkipReason;
450
+ };
451
+ /**
452
+ * What `explain` saw: how many candidate grants it examined before the
453
+ * outcome, which allows matched (including the ones a deny overrode), which
454
+ * denies matched, and which grants it passed over. `denies[0]` is the deny
455
+ * that produced a `deny` outcome, or the deny a break-glass grant lifted.
456
+ * Pure local computation; never on a decision event.
457
+ */
458
+ type Trace = {
459
+ readonly evaluated: number;
460
+ readonly allows: readonly MatchedGrant[];
461
+ readonly denies: readonly MatchedGrant[];
462
+ readonly skipped: readonly TraceSkip[];
463
+ };
464
+ type GrantedDecision = {
465
+ readonly outcome: "granted";
466
+ readonly subject: Subject;
467
+ readonly matched: MatchedGrant;
468
+ readonly token: string;
469
+ readonly obligations?: readonly Obligation[];
470
+ readonly quota?: Quota;
471
+ /**
472
+ * The membership `permdock.activate` produced for the app to write: an
473
+ * elevated, time-bound, attributed row. Set only by `activate`; a plain
474
+ * `decide` never writes memberships.
475
+ */
476
+ readonly elevation?: Membership;
477
+ /** Present only with `explain: true`. */
478
+ readonly trace?: Trace;
479
+ };
480
+ type DeniedDecision = {
481
+ readonly outcome: "denied";
482
+ readonly denials: readonly Denial[];
483
+ readonly alternatives: readonly Permission[];
484
+ /** Present only with `explain: true`. */
485
+ readonly trace?: Trace;
486
+ };
487
+ type ApprovalRequiredDecision = {
488
+ readonly outcome: "approval-required";
489
+ readonly grant: MatchedGrant;
490
+ readonly reason: "human";
491
+ readonly token: string;
492
+ /** Present only with `explain: true`. */
493
+ readonly trace?: Trace;
494
+ };
495
+ /** A decision from `explain`: the same union, with the trace always present. */
496
+ type ExplainedDecision = Decision & {
497
+ readonly trace: Trace;
498
+ };
499
+ type Decision = GrantedDecision | DeniedDecision | ApprovalRequiredDecision;
500
+ //#endregion
501
+ //#region src/core/approval-policies.d.ts
502
+ /**
503
+ * One approval requirement kept as data, for a tenant or the whole platform.
504
+ * It adds to what the code requires and never removes a requirement.
505
+ */
506
+ type ApprovalPolicy = {
507
+ /** The permission key; a former key from `renamed` resolves. */
508
+ readonly permission: string;
509
+ /** Absent: every tenant. */
510
+ readonly tenant?: string;
511
+ /** Actor kinds it applies to (`['agent']`); absent: every call. A call without an actor never matches a list. */
512
+ readonly actors?: readonly string[];
513
+ /** A portable condition over the row; instance permissions only, since a collection action has no row. */
514
+ readonly where?: Condition;
515
+ /** A portable condition over the call's input (the proposed row). */
516
+ readonly check?: Condition;
517
+ /**
518
+ * The same shape as `allow(..., { approval })`. An `escalation` here widens
519
+ * only this entry's stages, never the code's.
520
+ */
521
+ readonly approval: ApprovalOption;
522
+ };
523
+ /**
524
+ * Data-driven approval requirements, a subject input like `RoleSource`:
525
+ * read once per instance for the subject's tenants (entries without a
526
+ * tenant always apply). A throw, a rejected promise or an invalid entry
527
+ * denies every call an allow would otherwise permit.
528
+ */
529
+ type ApprovalPolicySource = {
530
+ approvalPoliciesFor(query: {
531
+ readonly tenants: readonly string[];
532
+ }): readonly ApprovalPolicy[] | Promise<readonly ApprovalPolicy[]>;
533
+ };
534
+ /** The denial detail when an `ApprovalPolicySource` fails: every call an allow would grant denies with reason `approval`. */
535
+ declare const APPROVAL_POLICY_UNAVAILABLE = "approval-policy-unavailable";
536
+ declare function memoryApprovalPolicies(policies: readonly ApprovalPolicy[]): ApprovalPolicySource;
537
+ /**
538
+ * Why an `ApprovalPolicy` entry does not load. `unknown-permission`: the
539
+ * policy declares no such key (the entry applies to nothing). `invalid`: a
540
+ * field has the wrong shape or the approval option does not normalise.
541
+ * `where-on-collection`: `where` reads a row, which a collection action
542
+ * never has, so the entry could never match; use `check` over the input.
543
+ * `stale-on-without-version`: `staleOn` needs an instance permission whose
544
+ * resource declares `version`.
545
+ */
546
+ type ApprovalPolicyProblem = "unknown-permission" | "invalid" | "where-on-collection" | "stale-on-without-version";
547
+ type ApprovalPolicyValidation = {
548
+ readonly ok: true;
549
+ } | {
550
+ readonly ok: false;
551
+ readonly problem: ApprovalPolicyProblem;
552
+ };
553
+ /**
554
+ * Checks one entry against the policy the way `approvalPoliciesFor` loads
555
+ * it, for an application to refuse a bad entry when it is saved instead of
556
+ * finding every call denied. Never throws.
557
+ */
558
+ declare function validateApprovalPolicy(policy: Policy, entry: unknown): ApprovalPolicyValidation;
559
+ //#endregion
560
+ //#region src/core/arazzo.d.ts
561
+ type ArazzoSimulateInput = {
562
+ readonly arazzo: unknown;
563
+ readonly openapi: unknown;
564
+ readonly workflowId?: string;
565
+ readonly permissions?: PermissionTree;
566
+ readonly inputs?: Readonly<Record<string, unknown>>;
567
+ };
568
+ type ArazzoStepResult = {
569
+ readonly stepId: string;
570
+ /** The nested workflow that owns the step, when it is not the plan's workflow. */
571
+ readonly workflowId?: string;
572
+ readonly operationId?: string;
573
+ readonly permissions: readonly Permission[];
574
+ readonly decision: Decision;
575
+ readonly provisional?: true;
576
+ };
577
+ type ArazzoPlan = {
578
+ readonly workflowId: string;
579
+ readonly outcome: Decision["outcome"];
580
+ readonly steps: readonly ArazzoStepResult[];
581
+ };
582
+ type ArazzoFinding = {
583
+ readonly stepId: string;
584
+ readonly workflowId: string;
585
+ readonly reason: "undocumented" | "unsupported" | "validation" | "unknown-key";
586
+ readonly detail: string;
587
+ };
588
+ declare function arazzoFindings(input: ArazzoSimulateInput, tree: PermissionTree | undefined): readonly ArazzoFinding[];
589
+ declare function simulateArazzo(input: ArazzoSimulateInput, tree: PermissionTree | undefined, decide: (permission: Permission, data: unknown) => Decision): ArazzoPlan;
590
+ //#endregion
591
+ //#region src/core/elevated.d.ts
592
+ /**
593
+ * The only deny override: a break-glass grant overrides deny grants whose
594
+ * `name` it lists, and nothing else. It is an allow that stays non-portable
595
+ * (RLS never compiles it) and grants only once its `requires` are met.
596
+ */
597
+ declare function breakGlass<T>(permission: Permission<string, T> | readonly Permission<string, T>[], options?: BreakGlassOptions): Omit<Grant, "role" | "scope"> | Omit<Grant, "role" | "scope">[];
598
+ /**
599
+ * Support access with tenant consent: a role a vendor holds only through a
600
+ * consented, time-bound `via: 'support'` membership. `actorRequired` denies
601
+ * every decision under it without an `act`; `forbid` compiles to deny grants
602
+ * scoped to `via: 'support'`.
603
+ */
604
+ declare function supportAccess<const S extends string>(options: SupportAccessOptions<S> & {
605
+ readonly on: S;
606
+ }): RoleBinding<S>;
607
+ /** Support access held in the `tenant` scope. */
608
+ declare function supportAccess(options: SupportAccessOptions<never>): RoleBinding<"tenant">;
609
+ type ActivateInput = {
610
+ readonly role: string | Role;
611
+ /** The scope the activation applies in (a declared name or the `tenant` / `team` alias). */
612
+ readonly scope: string;
613
+ readonly id: string;
614
+ /** Ancestor scope ids, keyed by scope name, for a nested-scope activation. */
615
+ readonly within?: Readonly<Record<string, string>>;
616
+ /** How long the elevation lasts; capped at the role's `maxDuration`. */
617
+ readonly duration?: string;
618
+ readonly reason?: string;
619
+ };
620
+ //#endregion
621
+ //#region src/core/ownership.d.ts
622
+ /** Who a role change is about: their principal id and their membership in the scope instance. */
623
+ type RoleChangeTarget = {
624
+ readonly id: string;
625
+ /** The kind of the target's membership in the instance (`staff`, `contact`, ...). */
626
+ readonly via?: string;
627
+ /** The roles the target holds in the instance now. */
628
+ readonly roles?: readonly string[];
629
+ /** `idp` when the identity provider owns the target's membership: the application cannot change it. */
630
+ readonly managedBy?: "idp";
631
+ };
632
+ type RoleChange = {
633
+ readonly kind: "assign" | "revoke" | "transfer";
634
+ readonly role: string | Role;
635
+ /** The scope the role is held at (a declared name or alias). */
636
+ readonly scope: string;
637
+ /** The scope instance. */
638
+ readonly id: string;
639
+ /** Ids of the instance's ancestor scopes; a holder there may assign here. */
640
+ readonly within?: Readonly<Record<string, string>>;
641
+ readonly target: RoleChangeTarget;
642
+ /**
643
+ * How many principals hold `role` in the instance now, from the
644
+ * application's store. Without it a role with `min`, `max` or
645
+ * `transferOnly` is denied.
646
+ */
647
+ readonly holders?: number;
648
+ };
649
+ /**
650
+ * `granted` names the role that authorised the change (`null` when a
651
+ * `meta.manageRoles` holder or the declared-role ceiling did); `denied` lists
652
+ * every rule the change breaks.
653
+ */
654
+ type RoleChangeDecision = {
655
+ readonly outcome: "granted";
656
+ readonly change: RoleChange;
657
+ readonly role: string | null;
658
+ } | {
659
+ readonly outcome: "denied";
660
+ readonly change: RoleChange;
661
+ readonly denials: readonly Denial[];
662
+ };
663
+ type RoleChangeOptions = {
664
+ /**
665
+ * `true` when the application loaded `change.within` from its own store
666
+ * (the instance's stored parent), not from the request. Without it, a
667
+ * nested instance's tenant comes only from a live membership the actor
668
+ * holds on that instance or under it.
669
+ */
670
+ readonly trusted?: boolean;
671
+ };
672
+ //#endregion
673
+ //#region src/core/validation.d.ts
674
+ type Boundary = "http-body" | "mcp-args" | "tool-args" | "decision-endpoint" | "manual";
675
+ //#endregion
676
+ //#region src/core/who-can.d.ts
677
+ /** One way a principal holds a permission on an object. */
678
+ type HoldingVia = {
679
+ readonly kind: "role";
680
+ readonly role: string;
681
+ readonly membership: Membership;
682
+ } | {
683
+ readonly kind: "relation";
684
+ readonly resource: string;
685
+ readonly relation: string;
686
+ /** The instance the relation is held on: the object or one of its ancestors. */
687
+ readonly id: string;
688
+ } | {
689
+ readonly kind: "share";
690
+ readonly resource: string;
691
+ readonly relation: string;
692
+ readonly id: string;
693
+ readonly expiresAt?: number;
694
+ /** The group the share names, when the principal holds it as one of its members. */
695
+ readonly group?: RelationGroup;
696
+ };
697
+ type Holder = {
698
+ readonly principal: {
699
+ readonly id: string;
700
+ };
701
+ readonly via: readonly HoldingVia[];
702
+ };
703
+ /**
704
+ * Who holds a permission on one object, for share dialogs and access
705
+ * reviews. It lists and never grants. `complete: false` means some grantee
706
+ * could not be enumerated (a global role, a plan, a source without `list`,
707
+ * an unavailable relation): holders may be missing, so check with `decide`.
708
+ */
709
+ type WhoCan = {
710
+ readonly permission: string;
711
+ readonly holders: readonly Holder[];
712
+ readonly complete: boolean;
713
+ };
714
+ //#endregion
715
+ //#region src/core/hosted.d.ts
716
+ /** One grant authored in PermDock Cloud; its grantee is a declared role, plan or relation. */
717
+ type HostedGrant = {
718
+ readonly id: string;
719
+ readonly permission: string;
720
+ readonly effect?: "allow" | "deny";
721
+ readonly to: Grantee | readonly Grantee[];
722
+ readonly where?: Condition;
723
+ readonly check?: Condition;
724
+ readonly approval?: "human" | ApprovalRequirement;
725
+ readonly fields?: readonly string[];
726
+ };
727
+ /** PolicyDocument v1: the payload of a `permdock-policy+jwt` under the `policy` claim. */
728
+ type PolicyDocument = {
729
+ readonly v: 1;
730
+ readonly id: string;
731
+ readonly fingerprint: string;
732
+ /** The catalog fingerprint the document was authored against. */
733
+ readonly catalog: string;
734
+ readonly issuedAt: number;
735
+ readonly grants: readonly HostedGrant[];
736
+ };
737
+ /**
738
+ * The channel for hosted grants. `createPermDock` reads `current()` once;
739
+ * the application calls `refresh()` on its own schedule, never a check.
740
+ */
741
+ type PolicySource = {
742
+ current(): PolicyDocument | null;
743
+ refresh(): Promise<void>;
744
+ };
745
+ type HostedGrantDropReason = "not-hostable" | "unknown-permission" | "unknown-grantee" | "non-portable" | "weaker-approval" | "invalid";
746
+ /** Reported through `on('error')` when a hosted grant is not merged; never thrown. */
747
+ type HostedGrantDropped = {
748
+ readonly kind: "hosted-grant-dropped";
749
+ readonly document: string;
750
+ readonly grant: string;
751
+ readonly reason: HostedGrantDropReason;
752
+ };
753
+ declare function memoryPolicySource(document?: PolicyDocument | null): PolicySource;
754
+ /** Validates the document envelope; per-grant checks happen at merge time. */
755
+ declare function parsePolicyDocument(json: unknown): PolicyDocument;
756
+ /** True for the portable subset only: no `opaque`, no `sqlFunction`, no unknown op. */
757
+ declare function isPortableCondition(value: unknown): value is Condition;
758
+ /**
759
+ * The code policy plus the hosted grants that pass every rule. Hosted
760
+ * allows OR with code allows and any deny still wins, so a hosted grant can
761
+ * never override a code deny; one that fails a rule is dropped, not thrown.
762
+ */
763
+ declare function mergeHostedGrants(policy: Policy, document: PolicyDocument | null): {
764
+ readonly policy: Policy;
765
+ readonly dropped: readonly HostedGrantDropped[];
766
+ };
767
+ //#endregion
768
+ //#region src/core/permdock.d.ts
769
+ type DecideOptions = {
770
+ /** `true` skips schema validation for a row the server loaded itself. Otherwise `data` is validated against the resource schema first (`validate: 'boundary'`), and a failure denies with reason `validation`. */
771
+ readonly trusted?: boolean;
772
+ /** Where untrusted data came from, reported on validation errors. Defaults to `'manual'`. */
773
+ readonly boundary?: Boundary;
774
+ /** Decision clock in Unix seconds, for expiries and limits. Defaults to the current time. */
775
+ readonly now?: number;
776
+ /** The call that produced the decision, reported on the decision event. Defaults to `'decide'`. */
777
+ readonly source?: DecisionEvent["source"];
778
+ /** The adapter that made the call, reported on the decision event. */
779
+ readonly adapter?: string;
780
+ /** Per-call unauthorized handler for `assert`; runs before instance and policy handlers. */
781
+ readonly onDenied?: (decision: Decision) => never | void;
782
+ /** The field being read or written; only grants whose `fields` cover it match. */
783
+ readonly field?: string;
784
+ /** `true` attaches a `trace` to the decision: the grants evaluated, matched and skipped. Off by default and free when off. */
785
+ readonly explain?: boolean;
786
+ /**
787
+ * A declared scope name: only memberships of that scope answer the check.
788
+ * Naming the first scope keeps nested memberships out of a tenant-level
789
+ * guard on a collection action. Global roles still apply; resource roles
790
+ * and memberships of other scopes are skipped with reason `scope`.
791
+ */
792
+ readonly scope?: string;
793
+ };
794
+ type SimulateOptions = {
795
+ /** Decision clock in Unix seconds for the whole batch: grant validity, membership expiry and limits are read as of this instant. Defaults to the current time. */
796
+ readonly now?: number;
797
+ };
798
+ type RowPair<T> = {
799
+ readonly current: T;
800
+ readonly next: T;
801
+ };
802
+ type WhereResult = {
803
+ readonly condition: Condition | {
804
+ readonly op: "or";
805
+ readonly conditions: readonly [];
806
+ };
807
+ readonly partial: boolean;
808
+ /**
809
+ * The subject `where()` was built for. `toWhere` reads its memberships for
810
+ * `memberOf` when no `subject` option is passed. Not enumerable, so it never
811
+ * serialises with the result.
812
+ */
813
+ readonly subject?: Subject;
814
+ /** The policy's scopes, for `memberOf`; not enumerable either. */
815
+ readonly scopes?: readonly Scope[];
816
+ /** The policy's resource graph, for `related`; not enumerable either. */
817
+ readonly resources?: ReadonlyMap<string, ResourceNode>;
818
+ };
819
+ type SnapshotOptions = {
820
+ readonly include?: readonly (Permission | {
821
+ readonly [key: string]: unknown;
822
+ })[];
823
+ readonly tenants?: "all";
824
+ readonly signer?: TokenSigner;
825
+ readonly audience?: string | readonly string[];
826
+ };
827
+ type PermDock<V extends PolicyVocabulary = PolicyVocabulary> = {
828
+ readonly can: {
829
+ (permission: Permission<string, unknown, "instance">, data: unknown, options?: DecideOptions): boolean;
830
+ (permission: Permission<string, unknown, "collection">, data?: unknown, options?: DecideOptions): boolean;
831
+ /**
832
+ * A permission held as `Permission` at run time (from a list, a catalog
833
+ * or `findPermission`), whose kind the type does not say: pass `data`,
834
+ * or `undefined` for a check without a row.
835
+ */
836
+ (permission: Permission, data: unknown, options?: DecideOptions): boolean;
837
+ };
838
+ readonly decide: {
839
+ (permission: Permission<string, unknown, "instance">, data: unknown, options?: DecideOptions): Decision;
840
+ (permission: Permission<string, unknown, "collection">, data?: unknown, options?: DecideOptions): Decision;
841
+ /**
842
+ * A permission held as `Permission` at run time (from a list, a catalog
843
+ * or `findPermission`), whose kind the type does not say: pass `data`,
844
+ * or `undefined` for a check without a row.
845
+ */
846
+ (permission: Permission, data: unknown, options?: DecideOptions): Decision;
847
+ };
848
+ readonly assert: {
849
+ (permission: Permission<string, unknown, "instance">, data: unknown, options?: DecideOptions): Extract<Decision, {
850
+ readonly outcome: "granted";
851
+ }>;
852
+ (permission: Permission<string, unknown, "collection">, data?: unknown, options?: DecideOptions): Extract<Decision, {
853
+ readonly outcome: "granted";
854
+ }>;
855
+ /**
856
+ * A permission held as `Permission` at run time (from a list, a catalog
857
+ * or `findPermission`), whose kind the type does not say: pass `data`,
858
+ * or `undefined` for a check without a row.
859
+ */
860
+ (permission: Permission, data: unknown, options?: DecideOptions): Extract<Decision, {
861
+ readonly outcome: "granted";
862
+ }>;
863
+ };
864
+ /**
865
+ * `decide` with `explain: true`: the same decision, with a `trace` that
866
+ * names the grants evaluated, the allows and denies that matched (so a
867
+ * `denied` says which deny won) and the grants passed over. Local
868
+ * computation only; the trace never reaches a `DecisionSink`.
869
+ */
870
+ readonly explain: {
871
+ (permission: Permission<string, unknown, "instance">, data: unknown, options?: Omit<DecideOptions, "explain">): ExplainedDecision;
872
+ (permission: Permission<string, unknown, "collection">, data?: unknown, options?: Omit<DecideOptions, "explain">): ExplainedDecision;
873
+ (permission: Permission, data: unknown, options?: Omit<DecideOptions, "explain">): ExplainedDecision;
874
+ };
875
+ readonly filter: <T>(permission: Permission<string, T, "instance">, rows: readonly T[], options?: DecideOptions) => T[];
876
+ readonly pick: <T>(permission: Permission<string, T, "instance">, row: T, options?: DecideOptions) => Partial<T>;
877
+ readonly where: (permission: Permission) => WhereResult;
878
+ readonly actions: (resource: Permission | {
879
+ readonly [key: string]: unknown;
880
+ }, data: unknown, options?: DecideOptions) => Permission[];
881
+ readonly simulate: {
882
+ (checks: readonly (readonly [Permission, unknown?])[], options?: SimulateOptions): Decision[];
883
+ (preview: {
884
+ readonly roles?: readonly (string | Role)[];
885
+ readonly memberships?: readonly Membership[];
886
+ readonly tenant?: string;
887
+ }): PermDock<V>;
888
+ (plan: ArazzoSimulateInput): ArazzoPlan;
889
+ };
890
+ readonly snapshot: {
891
+ (options?: SnapshotOptions & {
892
+ readonly signer?: undefined;
893
+ }): Snapshot;
894
+ (options: SnapshotOptions & {
895
+ readonly signer: TokenSigner;
896
+ }): Promise<string>;
897
+ (options?: SnapshotOptions): Snapshot | Promise<string>;
898
+ };
899
+ readonly on: (event: "decision" | "denied" | "approval" | "auth" | "error", handler: (payload: unknown) => void) => () => void;
900
+ readonly tenant: (id: string) => PermDock<V>;
901
+ readonly team: (id: string) => PermDock<V>;
902
+ readonly memberships: () => readonly Membership[];
903
+ readonly tenants: () => readonly string[];
904
+ /**
905
+ * Roles held in a tenant (the active one by default), or only on the
906
+ * memberships of one `scope` (and instance `id`). Ordered by rank: a role
907
+ * comes before the roles its `assigns` lists.
908
+ */
909
+ readonly heldRoles: (options?: {
910
+ readonly tenant?: string;
911
+ readonly scope?: string;
912
+ readonly id?: string;
913
+ }) => readonly Role[];
914
+ /** The distinct `meta.audience` values of the roles held in the active tenant, in rank order. */
915
+ readonly audiences: () => readonly string[];
916
+ readonly assignableRoles: (options?: {
917
+ readonly tenant?: string;
918
+ }) => readonly Role[];
919
+ /**
920
+ * The custom-role ceiling the subject may hand out: in a tenant (empty
921
+ * without one), or with `scope: 'global'` for platform custom roles, the
922
+ * allows of assignable global roles the subject holds. A snapshot answers
923
+ * only the tenant form.
924
+ */
925
+ readonly assignablePermissions: (options?: {
926
+ readonly tenant?: string;
927
+ readonly scope?: "global";
928
+ }) => readonly Permission[];
929
+ /**
930
+ * The levels of `permission` (`resource(…, { levels })`) the subject may
931
+ * hand out in a custom role: those it holds, or every level with
932
+ * `meta.manageRoles`. Empty when the permission is not assignable.
933
+ */
934
+ readonly assignableLevels: (permission: Permission, options?: {
935
+ readonly tenant?: string;
936
+ readonly scope?: "global";
937
+ }) => readonly string[];
938
+ /**
939
+ * Whether the subject may assign, revoke or transfer a role in one scope
940
+ * instance: `assigns`, the ceiling, `for`, `exclusiveWith`, `min`, `max`
941
+ * and `transferOnly`. It never writes; the application does, and generated
942
+ * RLS triggers re-check the holder counts at commit. A nested instance's
943
+ * tenant comes from a live membership the subject holds on it, or from
944
+ * `change.within` only with `{ trusted: true }`; otherwise `no-membership`.
945
+ */
946
+ readonly decideRoleChange: (change: RoleChange, options?: RoleChangeOptions) => RoleChangeDecision;
947
+ /**
948
+ * Loads the relation facts `permission` needs for `rows` into this
949
+ * instance's cache, so `can`, `decide` and `filter` answer synchronously
950
+ * over an async `RelationSource`. It never grants; a failed load leaves
951
+ * the checks denied with `relation-unavailable`.
952
+ */
953
+ readonly loadRelations: (permission: Permission, rows: readonly unknown[]) => Promise<void>;
954
+ /**
955
+ * Who holds `permission` on `resource` and how (role, relation or share),
956
+ * from `MembershipSource.list` and `RelationSource.related`. It lists and
957
+ * never grants; `complete: false` means some holders could not be listed.
958
+ */
959
+ readonly whoCan: (permission: Permission<string, unknown, "instance">, resource: unknown) => Promise<WhoCan>;
960
+ /**
961
+ * Requests a just-in-time activation of an eligible role. It never writes:
962
+ * a granted decision carries the elevated membership under `elevation` for
963
+ * the app to write, and `approval-required` comes back first when the
964
+ * role's `activation` sets `approval`.
965
+ */
966
+ readonly activate: (input: ActivateInput) => Decision;
967
+ readonly roles: V["roles"] extends RoleTree ? V["roles"] : RoleTree;
968
+ readonly plans: V["plans"] extends PlanTree ? V["plans"] : PlanTree;
969
+ readonly permissions: V["permissions"] extends Policy["permissions"] ? V["permissions"] : Policy["permissions"];
970
+ readonly subject: Subject;
971
+ /**
972
+ * The same subject, tenant, team, actor, delegation, sink and limits with
973
+ * other sources: `customRoles`, `approvalPolicies` or `relations`. The
974
+ * sources it names are read again for the subject's tenants; the others
975
+ * keep what this instance loaded. Returns a promise when a source it names
976
+ * answers asynchronously.
977
+ */
978
+ readonly derive: (options: DeriveOptions) => PermDock<V> | Promise<PermDock<V>>;
979
+ };
980
+ /** What `permdock.derive` may replace: the sources read after the subject is resolved. */
981
+ type DeriveOptions = Pick<PermDockOptions, "customRoles" | "approvalPolicies" | "relations">;
982
+ type PermDockOptions = {
983
+ readonly tenant?: string;
984
+ /** One source, or several composed with `composeMemberships`. */
985
+ readonly memberships?: MembershipSource | readonly MembershipSource[];
986
+ readonly customRoles?: RoleSource | RoleSourceFactory;
987
+ /** Plans and seats from billing, merged into `principal.plans` for the active tenant. */
988
+ readonly entitlements?: EntitlementSource;
989
+ readonly actor?: Actor;
990
+ readonly delegation?: Delegation;
991
+ readonly sink?: DecisionSink;
992
+ readonly limits?: LimitStore;
993
+ readonly session?: string;
994
+ readonly expiresAt?: number;
995
+ /** Hosted grants; `current()` is read once, when the instance is created. */
996
+ readonly policies?: PolicySource;
997
+ /** The object graph for `through` and edge-table relations; without it they deny with `relation-unavailable`. */
998
+ readonly relations?: RelationSource;
999
+ /** Approval requirements kept as data; they add to the code's and never remove one. A throw denies. */
1000
+ readonly approvalPolicies?: ApprovalPolicySource;
1001
+ };
1002
+ declare function createPermDock<TUser, TPrincipal extends Principal = Principal, V extends PolicyVocabulary = PolicyVocabulary>(policy: Policy<TUser, TPrincipal, V>, user: TUser | Subject | null, options?: PermDockOptions): PermDock<V> | Promise<PermDock<V>>;
1003
+ //#endregion
1004
+ //#region src/core/credential.d.ts
1005
+ type CredentialKind = "user" | "service";
1006
+ /** One permission (a key) a credential may use: on every instance, or only on `ids`. */
1007
+ type CredentialPermission = {
1008
+ readonly permission: string;
1009
+ readonly ids?: readonly string[];
1010
+ };
1011
+ /**
1012
+ * Credential v1: what a verified API key stands for, never the secret. A
1013
+ * `user` credential acts as its owner (`principal`) narrowed to
1014
+ * `permissions`, and to the memberships inside `tenant` when it names one;
1015
+ * a `service` credential is its own `service` principal holding `roles` in
1016
+ * `tenant`, narrowed the same way.
1017
+ */
1018
+ type Credential = {
1019
+ readonly v: 1;
1020
+ readonly id: string;
1021
+ readonly kind: CredentialKind;
1022
+ /** The owner of a `user` credential, or the id of the service principal. */
1023
+ readonly principal: string;
1024
+ /**
1025
+ * The instance of the first scope the key is held to. Required on a
1026
+ * service credential, where its roles are held; optional on a user
1027
+ * credential, where it keeps only the owner's memberships inside it.
1028
+ */
1029
+ readonly tenant?: string;
1030
+ /** Service only: the roles it holds in `tenant`. */
1031
+ readonly roles?: readonly string[];
1032
+ readonly permissions: readonly CredentialPermission[];
1033
+ readonly createdBy: string;
1034
+ /** Seconds since the epoch. */
1035
+ readonly createdAt: number;
1036
+ /** Seconds since the epoch; absent only where a credential policy allows it. */
1037
+ readonly expiresAt?: number;
1038
+ readonly name?: string;
1039
+ };
1040
+ type CredentialPrincipal = Principal & {
1041
+ readonly credential: Credential;
1042
+ };
1043
+ /**
1044
+ * What one scope instance allows for API keys created in it. Every rule only
1045
+ * tightens; several policies must all hold.
1046
+ */
1047
+ type CredentialPolicy = {
1048
+ /** Longest a key may live, in seconds from `createdAt`. */
1049
+ readonly maxTtl?: number;
1050
+ /** Kinds that may be created. */
1051
+ readonly kinds?: readonly CredentialKind[];
1052
+ /** Creating a key is `approval-required`. */
1053
+ readonly approval?: boolean;
1054
+ /** A key may omit `expiresAt`; without it every key must expire. */
1055
+ readonly allowNoExpiry?: boolean;
1056
+ };
1057
+ type CredentialPolicyViolation = "kind" | "no-expiry" | "ttl";
1058
+ type CredentialPermissionInput = Permission | {
1059
+ readonly permission: Permission;
1060
+ readonly ids: readonly string[];
1061
+ };
1062
+ type CredentialRequestBase = {
1063
+ readonly id: string;
1064
+ readonly permissions: readonly CredentialPermissionInput[];
1065
+ readonly expiresAt?: number;
1066
+ readonly name?: string;
1067
+ };
1068
+ type CredentialRequest = (CredentialRequestBase & {
1069
+ readonly kind: "user";
1070
+ /** Holds the key to the creator's memberships inside this tenant. */
1071
+ readonly tenant?: string;
1072
+ }) | (CredentialRequestBase & {
1073
+ readonly kind: "service";
1074
+ /** The service principal's id; defaults to the credential id. */
1075
+ readonly principal?: string;
1076
+ readonly tenant: string;
1077
+ readonly roles: readonly string[];
1078
+ });
1079
+ type CredentialDecision = {
1080
+ readonly outcome: "granted";
1081
+ readonly credential: Credential;
1082
+ } | {
1083
+ readonly outcome: "approval-required";
1084
+ readonly credential: Credential;
1085
+ /** Bound to the credential's content and its creator; pass it as `approved` to resume. */
1086
+ readonly token: string;
1087
+ } | {
1088
+ readonly outcome: "denied";
1089
+ readonly denials: readonly Denial[];
1090
+ };
1091
+ type DecideCredentialOptions = {
1092
+ /** Where the tenant's `credentials` policy comes from. Without it, only the no-expiry rule applies. */
1093
+ readonly settings?: SettingsSource;
1094
+ /** The `token` of an approval the application consumed for this request. */
1095
+ readonly approved?: string;
1096
+ /** Seconds since the epoch. */
1097
+ readonly now?: number;
1098
+ };
1099
+ /**
1100
+ * The first rule of `policy` the credential breaks, or `undefined`. A key
1101
+ * without `expiresAt` passes only when some policy sets `allowNoExpiry` and
1102
+ * none sets `maxTtl`; an empty list therefore refuses it.
1103
+ */
1104
+ declare function credentialPolicyViolation(credential: Credential, policy: CredentialPolicy | readonly CredentialPolicy[]): CredentialPolicyViolation | undefined;
1105
+ /**
1106
+ * Validates an untrusted credential record and returns a frozen copy with
1107
+ * only the v1 fields, or `undefined`. Unknown fields are dropped; a wrong
1108
+ * type in a known field, a service credential without `tenant` and `roles`,
1109
+ * or a user credential with `roles`, rejects the whole record.
1110
+ */
1111
+ declare function parseCredential(input: unknown): Credential | undefined;
1112
+ /**
1113
+ * The delegation a credential narrows its principal to: OAuth scopes for
1114
+ * permissions on every instance, one RFC 9396 entry per id otherwise. A key
1115
+ * the definitions no longer declare is dropped, so a credential whose every
1116
+ * key is gone delegates nothing and every check is denied.
1117
+ */
1118
+ declare function credentialDelegation(credential: Credential, permissions: PermissionTree): Delegation;
1119
+ /**
1120
+ * The subject a verified credential acts as. A `user` credential is its
1121
+ * owner, passed live as `owner` (roles and memberships as of this request),
1122
+ * with the credential's delegation: every check is the owner's rights
1123
+ * intersected with the key's. One that names a `tenant` makes it the active
1124
+ * tenant, and `createPermDock` then keeps only the owner's memberships
1125
+ * inside it and no global role. A `service` credential is a `service`
1126
+ * principal whose only membership is `roles` in `tenant`. An owner whose id
1127
+ * is not the credential's `principal`, or who is not a user, is anonymous.
1128
+ */
1129
+ declare function credentialSubject(credential: Credential, options: {
1130
+ readonly permissions: PermissionTree;
1131
+ readonly owner?: Principal;
1132
+ }): Subject<CredentialPrincipal> | Subject;
1133
+ /**
1134
+ * Decides whether the subject of `permdock` may create the credential in
1135
+ * `request`. The creator must be a signed-in user or service that is not
1136
+ * itself a link or a credential; a delegated creator hands out only what its
1137
+ * delegation covers. A key's tenant must be one the creator is a member of;
1138
+ * a service key's roles among the creator's `assignableRoles` there and its
1139
+ * permissions within `assignablePermissions` there (`exceeds-creator`). The
1140
+ * `credentials` policy of the key's tenant (its own, or for a user key
1141
+ * without one the creator's active tenant) then applies (`credential-policy`; a
1142
+ * settings source that throws denies with `rule: 'unavailable'`), and
1143
+ * `approval` makes the result `approval-required` until `approved` carries
1144
+ * its token. PermDock never stores the credential; the application does,
1145
+ * after a `granted` result.
1146
+ */
1147
+ declare function decideCredential(permdock: PermDock, request: CredentialRequest, options?: DecideCredentialOptions): Promise<CredentialDecision>;
1148
+ //#endregion
1149
+ //#region src/core/wire-denial.d.ts
1150
+ /**
1151
+ * A denial as it leaves the process: in a decision event, a Problem Details
1152
+ * body, an MCP or WebMCP refusal and the decision endpoint. `detail` is a
1153
+ * JSON value (a string, or `LimitDetail` on `limit`); what a closure threw
1154
+ * and a validation error stay in process.
1155
+ */
1156
+ type WireDenial = {
1157
+ readonly role: string | null;
1158
+ readonly reason: DenialReason;
1159
+ readonly to?: Grantee | readonly Grantee[];
1160
+ readonly detail?: unknown;
1161
+ };
1162
+ /** A `Decision` whose denials are `WireDenial`s, as the decision endpoint sends it. */
1163
+ type WireDecision = GrantedDecision | ApprovalRequiredDecision | (Omit<DeniedDecision, "denials"> & {
1164
+ readonly denials: readonly WireDenial[];
1165
+ });
1166
+ //#endregion
1167
+ //#region src/core/interfaces.d.ts
1168
+ type DecisionProvider = {
1169
+ readonly name: string;
1170
+ handles(permission: Permission): boolean;
1171
+ decide(request: {
1172
+ readonly permission: Permission;
1173
+ readonly data?: unknown;
1174
+ readonly subject: Subject;
1175
+ readonly local: Decision;
1176
+ }): Promise<Decision>;
1177
+ /**
1178
+ * Ids of the resources of `permission.resource` the subject may act on.
1179
+ * `null` means the provider could not answer and every row is denied;
1180
+ * `undefined` means it cannot list, and each row is decided on its own.
1181
+ */
1182
+ permitted?(request: {
1183
+ readonly permission: Permission;
1184
+ readonly subject: Subject;
1185
+ }): Promise<readonly string[] | null | undefined>;
1186
+ };
1187
+ type RoleSource = {
1188
+ /**
1189
+ * The custom roles of one tenant. `createPermDock` passes `held`, the role
1190
+ * names the subject's live memberships hold there, declared or not, so a
1191
+ * source can skip its read when none of them is a custom role.
1192
+ */
1193
+ rolesFor(tenant: string, context?: {
1194
+ readonly held: readonly string[];
1195
+ }): CustomRole[] | Promise<CustomRole[]>;
1196
+ assignable?(tenant: string): string[] | Promise<string[]>;
1197
+ /**
1198
+ * Platform custom roles (`scope: 'global'`), read once per signed-in
1199
+ * subject, with `held`, the global role names the subject holds. A role
1200
+ * here with a tenant is ignored.
1201
+ */
1202
+ globalRoles?(context?: {
1203
+ readonly held: readonly string[];
1204
+ }): CustomRole[] | Promise<CustomRole[]>;
1205
+ };
1206
+ /**
1207
+ * A `RoleSource` built for the subject the instance serves, for an adapter
1208
+ * option shared by every request: it gets the resolved subject (principal,
1209
+ * actor and delegation) and returns that subject's source, or `undefined`
1210
+ * for none. A throw reads no custom roles and reports `source-threw`.
1211
+ */
1212
+ type RoleSourceFactory = (subject: Subject) => RoleSource | undefined;
1213
+ /** One member of a scope instance, as `MembershipSource.list` returns it. */
1214
+ type MemberEntry = {
1215
+ readonly principal: {
1216
+ readonly id: string;
1217
+ };
1218
+ readonly membership: Membership;
1219
+ };
1220
+ type MembershipSource = {
1221
+ membershipsFor(principal: {
1222
+ readonly id: string;
1223
+ readonly kind?: string;
1224
+ }, options: {
1225
+ readonly tenant?: string;
1226
+ }): Membership[] | Promise<Membership[]>;
1227
+ /** Every membership held in one scope instance, for member lists and access reviews. */
1228
+ list?(query: {
1229
+ readonly scope: string;
1230
+ readonly id: string;
1231
+ }): MemberEntry[] | Promise<MemberEntry[]>;
1232
+ /**
1233
+ * The principal's current authorization version, bumped on every membership
1234
+ * change. A token whose `authzVersion` is behind it is stale for the
1235
+ * policy's `fresh` permissions. `roles` and `memberships` are what the
1236
+ * token claims, so a source can read more than the version in the same
1237
+ * call when the claims show it will be needed.
1238
+ */
1239
+ version?(principal: {
1240
+ readonly id: string;
1241
+ readonly roles?: readonly string[];
1242
+ readonly memberships?: readonly Membership[];
1243
+ }): number | undefined | Promise<number | undefined>;
1244
+ /**
1245
+ * Keep the memberships the verified token carries and read this source only
1246
+ * when the token says they were truncated (`claimsFirst`).
1247
+ */
1248
+ readonly claimsFirst?: boolean;
1249
+ readonly onStale?: "deny" | "reread";
1250
+ };
1251
+ /** An object's parent chain, as `RelationSource.ancestors` returns it. */
1252
+ type RelationChain = {
1253
+ /** Whether the object itself is restricted: nothing above it reaches it. */
1254
+ readonly restricted?: boolean;
1255
+ /** Ancestors nearest first, at most `depth`; a restricted one ends the walk after itself. */
1256
+ readonly ancestors: readonly {
1257
+ readonly id: string;
1258
+ readonly restricted?: boolean;
1259
+ }[];
1260
+ /** The chain goes on above the last entry. */
1261
+ readonly truncated?: boolean;
1262
+ };
1263
+ type HolderPeriod = {
1264
+ /** Seconds since the epoch; before it the relation does not hold yet. */
1265
+ readonly startsAt?: number;
1266
+ /** Seconds since the epoch; from it on the relation no longer holds. */
1267
+ readonly expiresAt?: number;
1268
+ };
1269
+ /** A group holding a relation on an object: whoever holds `relation` on the group's instance holds it too. */
1270
+ type RelationGroup = {
1271
+ readonly resource: string;
1272
+ readonly id: string;
1273
+ readonly relation: string;
1274
+ };
1275
+ /**
1276
+ * One holder of a relation on an object, as `RelationSource.related` returns
1277
+ * it: a principal, or a group (an edge row whose `groups` column names one).
1278
+ */
1279
+ type RelationHolder = HolderPeriod & ({
1280
+ readonly principal: {
1281
+ readonly id: string;
1282
+ };
1283
+ } | {
1284
+ readonly group: RelationGroup;
1285
+ });
1286
+ /**
1287
+ * The object graph: parent chains, links and who holds a relation on an
1288
+ * object. A source answers facts and never decides; a thrown or rejected
1289
+ * call, or a Promise the instance has not loaded, denies with
1290
+ * `relation-unavailable`.
1291
+ */
1292
+ type RelationSource = {
1293
+ /**
1294
+ * With `through: 'parent'`, the parent chain; with a link name, the one
1295
+ * instance that link points to (`depth` is then 1).
1296
+ */
1297
+ ancestors(query: {
1298
+ readonly resource: string;
1299
+ readonly id: string;
1300
+ readonly through: string;
1301
+ readonly depth: number;
1302
+ }): RelationChain | Promise<RelationChain>;
1303
+ related(query: {
1304
+ readonly resource: string;
1305
+ readonly id: string;
1306
+ readonly relation: string;
1307
+ }): RelationHolder[] | Promise<RelationHolder[]>;
1308
+ row?(query: {
1309
+ readonly resource: string;
1310
+ readonly id: string;
1311
+ }): Readonly<Record<string, unknown>> | null | undefined | Promise<Readonly<Record<string, unknown>> | null | undefined>;
1312
+ };
1313
+ /** Plan and seat names a principal holds in a tenant, from billing (Stripe Entitlements, a table). */
1314
+ type EntitlementSource = {
1315
+ entitlementsFor(principal: {
1316
+ readonly id: string;
1317
+ }, options: {
1318
+ readonly tenant?: string;
1319
+ }): string[] | Promise<string[]>;
1320
+ };
1321
+ declare function memoryEntitlementSource(entries: Readonly<Record<string, readonly string[]>>): EntitlementSource;
1322
+ type JwtClaims = {
1323
+ readonly iss?: string;
1324
+ readonly sub?: string;
1325
+ readonly aud?: string | readonly string[];
1326
+ readonly exp?: number;
1327
+ readonly nbf?: number;
1328
+ readonly iat?: number;
1329
+ readonly [key: string]: unknown;
1330
+ };
1331
+ type TokenFailureCause = "invalid-signature" | "expired" | "not-yet-valid" | "wrong-audience" | "wrong-issuer" | "wrong-token-type" | "alg-not-allowed" | "alg-none" | "unknown-kid" | "malformed" | "encrypted-token" | "dpop-proof-invalid" | "mtls-binding-mismatch" | "sender-constraint-required" | "token-in-query" | "invalid-claims" | "invalid-chain" | "jwks-unavailable" | "discovery-unavailable" | "discovery-mismatch";
1332
+ type VerifiedToken<TClaims extends JwtClaims = JwtClaims> = {
1333
+ readonly ok: true;
1334
+ readonly claims: TClaims;
1335
+ readonly header: {
1336
+ readonly alg: string;
1337
+ readonly kid?: string;
1338
+ readonly typ?: string;
1339
+ };
1340
+ };
1341
+ type VerificationFailure = {
1342
+ readonly ok: false;
1343
+ readonly reason: "invalid-token";
1344
+ readonly cause: TokenFailureCause;
1345
+ };
1346
+ type TokenVerifier<TClaims extends JwtClaims = JwtClaims> = {
1347
+ verify(token: string, expectations: {
1348
+ readonly typ?: string | readonly string[];
1349
+ readonly audience?: string | readonly string[];
1350
+ readonly issuer?: string;
1351
+ readonly clockTolerance?: number;
1352
+ }): Promise<VerifiedToken<TClaims> | VerificationFailure>;
1353
+ };
1354
+ type TokenSigner = {
1355
+ sign(payload: Readonly<Record<string, unknown>>, options: {
1356
+ readonly typ: "permdock-snapshot+jwt" | "permdock-approval+jwt" | "permdock-decisions+jwt" | "permdock-policy+jwt" | "permdock-capability+jwt";
1357
+ readonly audience?: string | readonly string[];
1358
+ readonly expiresAt?: number;
1359
+ }): Promise<string>;
1360
+ readonly kid?: string;
1361
+ jwks?(): Promise<{
1362
+ readonly keys: readonly JsonWebKeyLike[];
1363
+ }>;
1364
+ };
1365
+ type SubjectResolver<TInput, TPrincipal extends Principal = Principal> = (input: TInput, options?: {
1366
+ readonly tenant?: string;
1367
+ }) => Subject<TPrincipal> | Promise<Subject<TPrincipal>>;
1368
+ type Snapshot = {
1369
+ readonly v: 1;
1370
+ readonly issuedAt: number;
1371
+ readonly subject: {
1372
+ readonly principal: {
1373
+ readonly id: string;
1374
+ readonly roles: readonly string[];
1375
+ readonly plans?: readonly string[];
1376
+ readonly tenant?: string;
1377
+ readonly memberships?: readonly Membership[];
1378
+ } | null;
1379
+ readonly delegation?: Subject["delegation"];
1380
+ readonly context: Readonly<Record<string, unknown>>;
1381
+ };
1382
+ /** Roles held in the active tenant, in rank order. */
1383
+ readonly roles: readonly string[];
1384
+ /** The distinct `meta.audience` values of `roles`, in rank order; absent when none has one. */
1385
+ readonly audiences?: readonly string[];
1386
+ readonly grants: readonly SnapshotGrant[];
1387
+ readonly tenants: readonly string[];
1388
+ readonly include?: readonly string[];
1389
+ readonly simulated?: true;
1390
+ readonly expiresAt?: number;
1391
+ readonly vocabulary?: {
1392
+ readonly roles?: Readonly<Record<string, Role>>;
1393
+ readonly plans?: Readonly<Record<string, Plan>>;
1394
+ };
1395
+ /** The policy's scopes in order, so a client checks the row against each membership's instance. */
1396
+ readonly scopes?: readonly SnapshotScope[];
1397
+ /** One entry per tenant in `tenants`: what the subject may hand out there. Absent without tenants. */
1398
+ readonly assignable?: readonly SnapshotAssignable[];
1399
+ /**
1400
+ * Allow grants of held roles that only a plan the subject lacks keeps
1401
+ * from applying; they grant nothing and name the plan a denial asks for.
1402
+ */
1403
+ readonly notEntitled?: readonly SnapshotNotEntitled[];
1404
+ /**
1405
+ * The row id field per resource whose `id` option is not `id`, for the
1406
+ * grants in `grants`. Absent when every one reads `id`.
1407
+ */
1408
+ readonly ids?: Readonly<Record<string, string>>;
1409
+ /**
1410
+ * The permission keys the policy's delegations let the actor use for the
1411
+ * principal, sorted; present only when one applies. Outside it a check is
1412
+ * `not-delegated`; inside it a token delegation, when there is one, must
1413
+ * still cover.
1414
+ */
1415
+ readonly delegated?: readonly string[];
1416
+ };
1417
+ /** A grant the subject would hold on another plan: its permission, role and `to`. */
1418
+ type SnapshotNotEntitled = {
1419
+ readonly permission: string;
1420
+ readonly role: string | null;
1421
+ readonly to: Grantee | readonly Grantee[];
1422
+ };
1423
+ /** One declared scope as a snapshot carries it. */
1424
+ type SnapshotScope = {
1425
+ readonly name: string;
1426
+ readonly key: string;
1427
+ readonly within?: string;
1428
+ /** Resources whose rows this scope's key partitions, from their `memberOf` relations. */
1429
+ readonly resources?: readonly string[];
1430
+ /** Resource name to the field holding this scope's id, for a resource whose field is not `key` (its own `id`). */
1431
+ readonly fields?: Readonly<Record<string, string>>;
1432
+ };
1433
+ /** The declared roles and the custom-role ceiling the subject may assign in one tenant. */
1434
+ type SnapshotAssignable = {
1435
+ readonly tenant: string;
1436
+ readonly roles: readonly string[];
1437
+ readonly permissions: readonly Permission[];
1438
+ /** Permission key to the levels the subject may hand out; only permissions whose resource declares levels. */
1439
+ readonly levels?: Readonly<Record<string, readonly string[]>>;
1440
+ };
1441
+ type SnapshotGrant = {
1442
+ readonly permission: string;
1443
+ readonly effect: "allow" | "deny";
1444
+ readonly role: string | null;
1445
+ readonly to: Grantee | readonly Grantee[];
1446
+ readonly where?: Condition;
1447
+ readonly check?: Condition;
1448
+ readonly approval?: "human" | ApprovalRequirement;
1449
+ /** A scope name or one resource; absent for a global grant. */
1450
+ readonly scope?: string | {
1451
+ readonly resource: string;
1452
+ };
1453
+ readonly membership?: Membership;
1454
+ readonly portable?: false;
1455
+ readonly fields?: readonly string[];
1456
+ /** When the grant applies (Unix seconds, `from` inclusive, `until` exclusive); absent means always. */
1457
+ readonly validity?: GrantValidity;
1458
+ };
1459
+ /**
1460
+ * What a policy grants, as JSON a client builds snapshots from without the
1461
+ * policy: `localSnapshotManifest(policy)` writes it, `localSnapshot` in
1462
+ * `permdock/react-native` reads it.
1463
+ */
1464
+ type LocalSnapshotManifest = {
1465
+ readonly v: 1;
1466
+ readonly scopes?: readonly SnapshotScope[];
1467
+ readonly vocabulary?: Snapshot["vocabulary"];
1468
+ /** Declared role names; a custom role cannot take one. */
1469
+ readonly roles: readonly string[];
1470
+ /** Declared role names in rank order, when an `assigns` graph ranks them. */
1471
+ readonly rank?: readonly string[];
1472
+ /** Every declared grant, without a membership. */
1473
+ readonly grants: readonly SnapshotGrant[];
1474
+ /** Per custom-role scope (`global` for platform roles): the grants each entry resolves to. */
1475
+ readonly custom: Readonly<Record<string, LocalCustomRoleTable>>;
1476
+ };
1477
+ /** Grants a custom role entry resolves to, held by a placeholder role the client renames. */
1478
+ type LocalCustomRoleTable = {
1479
+ /** `{ permission }` per permission key, and `{ permission, level }` per declared level. */
1480
+ readonly permissions: Readonly<Record<string, {
1481
+ readonly all: readonly SnapshotGrant[];
1482
+ readonly levels?: Readonly<Record<string, readonly SnapshotGrant[]>>;
1483
+ }>>;
1484
+ /** `includes: [role]` per declared role. */
1485
+ readonly includes: Readonly<Record<string, readonly SnapshotGrant[]>>;
1486
+ };
1487
+ type SnapshotSource = {
1488
+ get(): Promise<Snapshot | string> | Snapshot | string;
1489
+ subscribe?(listener: () => void): () => void;
1490
+ };
1491
+ type WhereCompiler<TTarget, TOptions = unknown> = (condition: Condition, target: TTarget, options?: TOptions) => unknown;
1492
+ type LimitConsumeInput = {
1493
+ readonly key: string;
1494
+ readonly subjectId: string;
1495
+ readonly count: number;
1496
+ readonly per: string;
1497
+ readonly now?: number;
1498
+ /** The active tenant; a quota counts per subject and tenant. */
1499
+ readonly tenant?: string;
1500
+ };
1501
+ type LimitRemaining = {
1502
+ readonly remaining: number;
1503
+ };
1504
+ type LimitStore = {
1505
+ consume(input: LimitConsumeInput): Promise<LimitRemaining> | LimitRemaining;
1506
+ remaining(input: LimitConsumeInput): LimitRemaining | undefined;
1507
+ };
1508
+ type DecisionSink = {
1509
+ write(events: readonly SinkEvent[]): Promise<void> | void;
1510
+ flush?(): Promise<void>;
1511
+ };
1512
+ type DirectoryEvent = {
1513
+ readonly type: "directory";
1514
+ readonly at: string;
1515
+ readonly source: "scim";
1516
+ readonly operation: "create" | "replace" | "patch" | "delete";
1517
+ readonly tenant: string;
1518
+ readonly resource: {
1519
+ readonly type: "User" | "Group";
1520
+ readonly id: string;
1521
+ };
1522
+ readonly credential: {
1523
+ readonly kind: "token";
1524
+ } | {
1525
+ readonly kind: "jwt";
1526
+ readonly iss?: string;
1527
+ };
1528
+ readonly active?: boolean;
1529
+ };
1530
+ type MembershipEvent = {
1531
+ readonly type: "membership";
1532
+ readonly at: string;
1533
+ readonly source: string;
1534
+ readonly operation: "added" | "removed" | "changed";
1535
+ readonly principal: {
1536
+ readonly id: string;
1537
+ };
1538
+ /** A declared scope name, or the `tenant` / `team` alias; absent for a global role change. */
1539
+ readonly scope?: string;
1540
+ /** The scope instance; present exactly when `scope` is. */
1541
+ readonly id?: string;
1542
+ /** The id of every ancestor scope, keyed by scope name. */
1543
+ readonly within?: Readonly<Record<string, string>>;
1544
+ readonly via?: string;
1545
+ /** When the membership lapses, in seconds since the epoch. */
1546
+ readonly expiresAt?: number;
1547
+ readonly roles: {
1548
+ readonly added: readonly string[];
1549
+ readonly removed: readonly string[];
1550
+ };
1551
+ readonly by?: {
1552
+ readonly id: string;
1553
+ readonly kind: string;
1554
+ };
1555
+ };
1556
+ /**
1557
+ * An API key's lifecycle: `created`, `rotated` and `revoked` from the
1558
+ * application or a credential store, `used` from `subjectFromApiKey`. A
1559
+ * `used` event carries `sample`, the fraction of uses reported.
1560
+ */
1561
+ type CredentialEvent = {
1562
+ readonly type: "credential";
1563
+ readonly at: string;
1564
+ readonly source: string;
1565
+ readonly operation: "created" | "used" | "rotated" | "revoked";
1566
+ readonly credential: {
1567
+ readonly id: string;
1568
+ readonly kind: CredentialKind;
1569
+ };
1570
+ readonly principal: {
1571
+ readonly id: string;
1572
+ };
1573
+ readonly tenant?: string;
1574
+ readonly expiresAt?: number;
1575
+ readonly by?: {
1576
+ readonly id: string;
1577
+ readonly kind: string;
1578
+ };
1579
+ readonly sample?: number;
1580
+ };
1581
+ type SinkEvent = DecisionEvent | DirectoryEvent | MembershipEvent | CredentialEvent | AccessEvent;
1582
+ /**
1583
+ * A support-access session lifecycle event: a tenant consented to vendor
1584
+ * support (`started`), the session lapsed (`ended`), or the tenant pulled
1585
+ * consent early (`revoked`). It never decides; it records what happened for
1586
+ * audit and revocation.
1587
+ */
1588
+ type AccessEvent = {
1589
+ readonly type: "access";
1590
+ readonly at: string;
1591
+ readonly source: string;
1592
+ readonly operation: "started" | "ended" | "revoked";
1593
+ readonly tenant: string;
1594
+ readonly principal: {
1595
+ readonly id: string;
1596
+ };
1597
+ /** The membership kind the session runs under (`support`). */
1598
+ readonly via: string;
1599
+ readonly roles: readonly string[];
1600
+ readonly member?: {
1601
+ readonly group: string;
1602
+ };
1603
+ readonly expiresAt?: number;
1604
+ /** The tenant principal that consented. */
1605
+ readonly grantedBy?: string;
1606
+ readonly reason?: string;
1607
+ readonly actor?: {
1608
+ readonly id: string;
1609
+ readonly kind: string;
1610
+ };
1611
+ };
1612
+ /**
1613
+ * Looks up the credential an API key stands for. `null` for a key that is
1614
+ * malformed, unknown, revoked or whose secret does not match; never throws
1615
+ * for bad input. Verification is the application's (or `apiKeyVerifier`'s),
1616
+ * never core's.
1617
+ */
1618
+ type CredentialVerifier = {
1619
+ verify(secret: string): Credential | null | Promise<Credential | null>;
1620
+ /**
1621
+ * Records a successful use at `at` (Unix seconds), for a `lastUsedAt`
1622
+ * column. Called after a key resolved and not awaited; a throw or a
1623
+ * rejection is ignored, so it never changes the subject.
1624
+ */
1625
+ touch?(id: string, at: number): void | Promise<void>;
1626
+ };
1627
+ type DecisionEvent = {
1628
+ readonly type: "decision";
1629
+ readonly at: string;
1630
+ readonly outcome: "granted" | "denied" | "approval-required";
1631
+ readonly permission: string;
1632
+ readonly scope: string;
1633
+ readonly resource: {
1634
+ readonly type: string;
1635
+ readonly id?: string;
1636
+ };
1637
+ readonly subject: {
1638
+ readonly principal: {
1639
+ readonly id: string;
1640
+ readonly roles: readonly string[];
1641
+ readonly tenant?: string;
1642
+ } | null;
1643
+ readonly actor?: {
1644
+ readonly id: string;
1645
+ readonly kind: string;
1646
+ };
1647
+ readonly delegation?: {
1648
+ readonly scopes?: readonly string[];
1649
+ readonly authorizationDetails?: readonly unknown[];
1650
+ };
1651
+ /** The API key the subject came from. */
1652
+ readonly credential?: {
1653
+ readonly id: string;
1654
+ readonly kind: CredentialKind;
1655
+ };
1656
+ };
1657
+ readonly tenant?: string;
1658
+ readonly membership?: Membership;
1659
+ readonly via?: string | null;
1660
+ readonly matched?: {
1661
+ readonly role: string | null;
1662
+ readonly permission: string;
1663
+ readonly to?: Grantee | readonly Grantee[];
1664
+ readonly hosted?: HostedGrantRef;
1665
+ readonly breakGlass?: true;
1666
+ };
1667
+ /** Purposes of use the caller asserted (`context.purpose`); present when any was. */
1668
+ readonly purpose?: readonly string[];
1669
+ /** The justification the caller supplied (`context.reason`); present when set. */
1670
+ readonly reason?: string;
1671
+ readonly denials?: readonly WireDenial[];
1672
+ readonly alternatives?: readonly string[];
1673
+ readonly token?: string;
1674
+ readonly trusted: boolean;
1675
+ readonly source: "can" | "decide" | "assert" | "filter" | "endpoint" | "adapter" | "approval" | "simulate" | "explain";
1676
+ readonly adapter?: string;
1677
+ readonly phase?: "requested" | "resolved";
1678
+ readonly counts?: {
1679
+ readonly granted: number;
1680
+ readonly denied: number;
1681
+ readonly approvalRequired: number;
1682
+ };
1683
+ };
1684
+ type AuthEvent = {
1685
+ readonly reason: "invalid-token" | "schema" | "unknown-role" | "groups-overflow" | "source-threw";
1686
+ readonly cause?: string;
1687
+ readonly source: string;
1688
+ readonly kid?: string;
1689
+ readonly alg?: string;
1690
+ readonly typ?: string;
1691
+ readonly issuer?: string;
1692
+ readonly requestId?: string;
1693
+ };
1694
+ /** What one tenant configures for itself. Every field only tightens. */
1695
+ type TenantSettings = {
1696
+ /** Rules for API keys created in, or used against, this tenant. */
1697
+ readonly credentials?: CredentialPolicy;
1698
+ };
1699
+ /**
1700
+ * Per-tenant settings, a subject input like `RoleSource`: they tighten what
1701
+ * a key may be and never grant. A throw denies.
1702
+ */
1703
+ type SettingsSource = {
1704
+ settingsFor(tenant: string): TenantSettings | undefined | Promise<TenantSettings | undefined>;
1705
+ };
1706
+ declare function memorySettings(settings: Readonly<Record<string, TenantSettings>>): SettingsSource;
1707
+ /** Memberships keyed by principal id; `tenant` is not a filter, as for a database source. */
1708
+ declare function memoryMembershipSource(entries: Readonly<Record<string, readonly Membership[]>>): MembershipSource;
1709
+ /** A snapshot held in memory; `set` replaces it and notifies every subscriber. */
1710
+ declare function memorySnapshotSource(initial: Snapshot | string): SnapshotSource & {
1711
+ set(snapshot: Snapshot | string): void;
1712
+ };
1713
+ declare function memoryRoleSource(customRoles: readonly CustomRole[]): RoleSource;
1714
+ //#endregion
1715
+ //#region src/conditions/normalize.d.ts
1716
+ type FieldOperator = {
1717
+ readonly eq?: unknown;
1718
+ readonly ne?: unknown;
1719
+ readonly gt?: unknown;
1720
+ readonly gte?: unknown;
1721
+ readonly lt?: unknown;
1722
+ readonly lte?: unknown;
1723
+ readonly contains?: unknown;
1724
+ readonly in?: unknown;
1725
+ readonly notIn?: unknown;
1726
+ readonly isNull?: boolean;
1727
+ };
1728
+ type WhereShorthand<T = Record<string, unknown>> = {
1729
+ readonly and?: readonly WhereShorthand<T>[];
1730
+ readonly or?: readonly WhereShorthand<T>[];
1731
+ readonly not?: WhereShorthand<T>;
1732
+ } & ("subject" extends keyof T ? { readonly [K in keyof T as Exclude<K, "subject">]?: FieldWhere<T[K]>; } & {
1733
+ readonly subject?: SubjectWhere | FieldWhere<T["subject"]>;
1734
+ } : { readonly [K in keyof T]?: FieldWhere<T[K]>; } & {
1735
+ /** Holds only when the resolver checked the session live (`liveSession: true`). */
1736
+ readonly subject?: SubjectWhere;
1737
+ });
1738
+ type SubjectWhere = {
1739
+ readonly session: {
1740
+ readonly live: true;
1741
+ };
1742
+ };
1743
+ type FieldWhere<V> = V | FieldOperator | {
1744
+ readonly ref: string;
1745
+ };
1746
+ //#endregion
1747
+ //#region src/core/approvers.d.ts
1748
+ /** One named approver, by principal id. */
1749
+ type UserApprover = {
1750
+ readonly kind: "user";
1751
+ readonly id: string;
1752
+ };
1753
+ /**
1754
+ * Whoever holds `permission` in the request's tenant, through any role,
1755
+ * custom roles included. Checked only through verdict facts
1756
+ * (`ApprovalVerdict.permissions`) that the handler computes from the
1757
+ * approver's own instance.
1758
+ */
1759
+ type PermissionApprover = {
1760
+ readonly kind: "permission";
1761
+ readonly permission: string;
1762
+ };
1763
+ /** An approver who matches at least one item; an item that is a list matches when every entry does. */
1764
+ type AnyOfApprover = {
1765
+ readonly kind: "any-of";
1766
+ readonly of: readonly (Approver | readonly Approver[])[];
1767
+ };
1768
+ /**
1769
+ * Who may approve: a subject-only grantee, a `relation()` the approver holds
1770
+ * on the requested row (checked when the verdict is given), `user(id)`,
1771
+ * `holder(permission)`, or `anyOf(...)`. A list (or `allOf(...)`) matches an
1772
+ * approver who satisfies every item.
1773
+ */
1774
+ type Approver = Grantee | UserApprover | PermissionApprover | AnyOfApprover;
1775
+ type ApproverInput = GranteeInput | UserApprover | PermissionApprover | {
1776
+ readonly kind: "any-of";
1777
+ readonly of: readonly ApproverInput[];
1778
+ } | readonly ApproverInput[];
1779
+ /** Approves when the approver holds `permission` in the request's tenant (any role, custom roles included). */
1780
+ declare function holder(permission: Permission): PermissionApprover;
1781
+ /** Approves when the approver matches any one of `items`. */
1782
+ declare function anyOf(...items: readonly ApproverInput[]): {
1783
+ readonly kind: "any-of";
1784
+ readonly of: readonly ApproverInput[];
1785
+ };
1786
+ /** Approves when the approver matches every one of `items`; the same as a list. */
1787
+ declare function allOf(...items: readonly ApproverInput[]): readonly ApproverInput[];
1788
+ /** A named approver for `approval.by`, matched on the approver's principal id. */
1789
+ declare function user(id: string): UserApprover;
1790
+ //#endregion
1791
+ //#region src/core/policy.d.ts
1792
+ type ClosureContext = {
1793
+ readonly subject: {
1794
+ readonly principal: Principal | null;
1795
+ readonly actor?: unknown;
1796
+ readonly delegation?: unknown;
1797
+ readonly context: Readonly<Record<string, unknown>>;
1798
+ };
1799
+ readonly actor?: unknown;
1800
+ readonly delegation?: unknown;
1801
+ readonly context: Readonly<Record<string, unknown>>;
1802
+ };
1803
+ type ClosureGrantFn<T = unknown> = (data: T, ctx: ClosureContext) => boolean;
1804
+ /** Who else may approve once a request has waited `after`. */
1805
+ type ApprovalEscalation = {
1806
+ /** A duration (`'4h'`) from the request's creation. */
1807
+ readonly after: string;
1808
+ readonly to: Approver | readonly Approver[];
1809
+ };
1810
+ /** One group of approvers; `quorum` distinct approvers of `by` complete it. */
1811
+ type ApprovalStage = {
1812
+ readonly by: Approver | readonly Approver[];
1813
+ /** Absent means 1. */
1814
+ readonly quorum?: number;
1815
+ /** After `after`, `to` may approve this stage as well as `by`; other stages are unaffected. */
1816
+ readonly escalation?: ApprovalEscalation;
1817
+ };
1818
+ /**
1819
+ * `'any'`: `quorum` approvers from `by`. `'all'`: every stage completes, in
1820
+ * any order. `'sequential'`: stages complete in order; an approver signs
1821
+ * only the first incomplete stage. An approver signs once per request.
1822
+ */
1823
+ type ApprovalMode = "any" | "all" | "sequential";
1824
+ type ApprovalRequirement = {
1825
+ /** Set when `mode` is `'any'` (the default); absent under `stages`. */
1826
+ readonly by?: Approver | readonly Approver[];
1827
+ /** Absent means `'any'`. */
1828
+ readonly mode?: ApprovalMode;
1829
+ /** Set when `mode` is `'all'` or `'sequential'`. */
1830
+ readonly stages?: readonly ApprovalStage[];
1831
+ /** `false` lets the request's principal approve it; absent means `true`. */
1832
+ readonly distinct?: boolean;
1833
+ /** `'resource-change'` binds the approval to the row's `version` field. */
1834
+ readonly staleOn?: "resource-change";
1835
+ /** Distinct approvers a request needs before it is approved under `by`; absent means 1. */
1836
+ readonly quorum?: number;
1837
+ /** How long a request stays open (`'30m'`); the store's default when absent, and never longer than it. */
1838
+ readonly ttl?: string;
1839
+ readonly escalation?: ApprovalEscalation;
1840
+ };
1841
+ type ApprovalOption = "human" | {
1842
+ readonly by?: ApproverInput;
1843
+ /** `'all'` or `'sequential'` with `stages`; absent means `'any'` with `by`. */
1844
+ readonly mode?: ApprovalMode;
1845
+ readonly stages?: readonly {
1846
+ readonly by: ApproverInput;
1847
+ readonly quorum?: number;
1848
+ /** After `after`, `to` may approve this stage as well as `by`. */
1849
+ readonly escalation?: {
1850
+ readonly after: string;
1851
+ readonly to: ApproverInput;
1852
+ };
1853
+ }[];
1854
+ /** `false` lets the request's principal approve it; absent means `true`. */
1855
+ readonly distinct?: boolean;
1856
+ /**
1857
+ * `'resource-change'`: the approval covers the row as it was when it was
1858
+ * requested. The resource must declare `version`; once that field
1859
+ * changes, resuming denies with `stale-approval`.
1860
+ */
1861
+ readonly staleOn?: "resource-change";
1862
+ /** Distinct approvers needed (an integer of at least 1); the same approver counts once. Absent means 1. */
1863
+ readonly quorum?: number;
1864
+ /** How long the request stays open (`'30m'`, `'2d'`); caps the approval store's default. */
1865
+ readonly ttl?: string;
1866
+ /** After `after` (`'4h'`), `to` may approve as well as `by`, at any open stage; same kinds as `by`. */
1867
+ readonly escalation?: {
1868
+ readonly after: string;
1869
+ readonly to: ApproverInput;
1870
+ };
1871
+ };
1872
+ /**
1873
+ * A quota on a grant. `hard` (the default) denies past `count`; `soft` grants
1874
+ * with an `over-limit` obligation. `alertAt` (a fraction of `count`, above 0
1875
+ * and at most 1) adds a `near-limit` obligation once usage reaches it.
1876
+ */
1877
+ type GrantLimit = {
1878
+ readonly count: number;
1879
+ readonly per: string;
1880
+ readonly mode?: "hard" | "soft";
1881
+ readonly alertAt?: number;
1882
+ };
1883
+ /** How fresh the subject's authentication must be for an elevated grant. */
1884
+ type AssuranceRequirement = {
1885
+ /** Seconds since the subject last authenticated (`assurance.authTime`). */
1886
+ readonly maxAge?: number;
1887
+ /** Authentication context class references, any of which satisfies it. */
1888
+ readonly acr?: readonly string[];
1889
+ /** Authentication methods, all of which must be present. */
1890
+ readonly amr?: readonly string[];
1891
+ };
1892
+ /**
1893
+ * Time-boxed role activation. A role with `activation` is never held
1894
+ * directly: a membership lists it under `eligible`, and `permdock.activate`
1895
+ * mints the elevated membership to write.
1896
+ */
1897
+ type ActivationOption = {
1898
+ /** The longest an activation may last, as a duration (`'4h'`, `'30m'`). */
1899
+ readonly maxDuration?: string;
1900
+ /** `'required'` denies an activation without a reason. */
1901
+ readonly justification?: "required" | "optional";
1902
+ /** When set, `activate` returns `approval-required` before the membership can be written. */
1903
+ readonly approval?: ApprovalOption;
1904
+ /** How fresh the activator's authentication must be. */
1905
+ readonly assurance?: AssuranceRequirement;
1906
+ };
1907
+ type ActivationSpec = {
1908
+ readonly maxDuration?: string;
1909
+ readonly justification: "required" | "optional";
1910
+ readonly approval?: "human" | ApprovalRequirement;
1911
+ readonly assurance?: AssuranceRequirement;
1912
+ };
1913
+ /** What a break-glass grant demands before it overrides a deny. */
1914
+ type BreakGlassRequirements = {
1915
+ /** Purposes of use (`context.purpose`), any of which engages break-glass. */
1916
+ readonly purpose?: readonly string[];
1917
+ /** `true` denies unless the caller supplies `context.reason`. */
1918
+ readonly reason?: boolean;
1919
+ readonly assurance?: AssuranceRequirement;
1920
+ };
1921
+ type BreakGlassOptions = {
1922
+ /** Names of the deny grants this override lifts; every other deny still wins. */
1923
+ readonly overrides?: readonly string[];
1924
+ readonly requires?: BreakGlassRequirements;
1925
+ /** The longest a break-glass session may last, as a duration. */
1926
+ readonly maxDuration?: string;
1927
+ /** Follow-ups the grant owes: each becomes an obligation on the decision. */
1928
+ readonly obligations?: readonly ("notify" | "review")[];
1929
+ };
1930
+ /** The normalized break-glass spec carried on a grant. */
1931
+ type BreakGlassSpec = {
1932
+ readonly overrides: readonly string[];
1933
+ readonly purpose?: readonly string[];
1934
+ readonly reason: boolean;
1935
+ readonly assurance?: AssuranceRequirement;
1936
+ readonly maxDuration?: string;
1937
+ readonly obligations: readonly ("notify" | "review")[];
1938
+ };
1939
+ /** How a tenant consents to support access, and for how long. */
1940
+ type SupportConsent = {
1941
+ readonly by: GranteeInput;
1942
+ /** The durations a tenant owner may pick, as duration strings. */
1943
+ readonly durations: readonly string[];
1944
+ };
1945
+ type SupportAccessOptions<S extends string = string> = {
1946
+ /** The role a consented support membership holds. */
1947
+ readonly role: string;
1948
+ /** The scope the support membership sits in; defaults to `tenant`. */
1949
+ readonly on?: S;
1950
+ /** Every decision under the support membership denies with `actor-required` without an `act`. */
1951
+ readonly actorRequired?: boolean;
1952
+ readonly consent: SupportConsent;
1953
+ /** Permissions a support session never reaches, compiled to deny grants scoped to `via: 'support'`. */
1954
+ readonly forbid?: readonly (Permission | PermissionTree)[];
1955
+ /** The subgroup a consented membership records under `member.group`. */
1956
+ readonly group?: string;
1957
+ };
1958
+ type SupportSpec = {
1959
+ readonly role: string;
1960
+ readonly actorRequired: boolean;
1961
+ readonly consent: {
1962
+ readonly by: Grantee | readonly Grantee[];
1963
+ readonly durations: readonly string[];
1964
+ };
1965
+ readonly group: string;
1966
+ };
1967
+ type GrantOptions<T = Record<string, unknown>> = {
1968
+ readonly to?: GranteeInput;
1969
+ readonly where?: WhereShorthand<T> | Condition;
1970
+ readonly check?: WhereShorthand<T> | Condition;
1971
+ readonly approval?: ApprovalOption;
1972
+ readonly limit?: GrantLimit;
1973
+ readonly reason?: string;
1974
+ readonly fields?: readonly (keyof T & string)[];
1975
+ /** A name a `breakGlass` override may lift; only meaningful on a deny. */
1976
+ readonly name?: string;
1977
+ readonly group?: string;
1978
+ /** Purposes of use (`context.purpose`) that make the grant apply; non-portable. */
1979
+ readonly purpose?: readonly string[];
1980
+ /** The grant applies from this instant on (RFC 3339 string or Unix seconds); before it an allow denies with `inactive-grant` and a deny does not apply. */
1981
+ readonly validFrom?: string | number;
1982
+ /** The grant stops applying at this instant (exclusive; RFC 3339 string or Unix seconds). */
1983
+ readonly validUntil?: string | number;
1984
+ /**
1985
+ * An allow on an instance action counts only on rows whose scope instance
1986
+ * (or the whole app, globally) is one where the subject also holds this
1987
+ * permission through a role grant without a row condition.
1988
+ */
1989
+ readonly requires?: Permission | readonly Permission[];
1990
+ };
1991
+ /**
1992
+ * When a grant applies, in Unix seconds. `from` is inclusive, `until`
1993
+ * exclusive; either may be absent. Portable: `where()` drops an inactive
1994
+ * grant at the decision clock and generated RLS compares against `now()`.
1995
+ */
1996
+ type GrantValidity = {
1997
+ readonly from?: number;
1998
+ readonly until?: number;
1999
+ };
2000
+ /**
2001
+ * The actor a policy delegation is for: an actor kind, narrowed to one id
2002
+ * when `id` is set, or to one named client when `client` is set (the name
2003
+ * the subject resolver gives a verified client id through `clients`).
2004
+ */
2005
+ type DelegationTarget = {
2006
+ readonly kind: string;
2007
+ readonly id?: string;
2008
+ readonly client?: string;
2009
+ };
2010
+ /**
2011
+ * A normalised policy delegation: holders of `from` let actors matching `to`
2012
+ * use `permissions` (keys) on their behalf while `validity` holds, without a
2013
+ * token saying so. Attenuation only: the principal's grants still decide.
2014
+ */
2015
+ type PolicyDelegation = {
2016
+ readonly from: Grantee | readonly Grantee[];
2017
+ readonly to: DelegationTarget;
2018
+ readonly permissions: readonly string[];
2019
+ /** The keys of `permissions` whose `readOnlyHint` is true: all a `readOnly` actor may use. */
2020
+ readonly readOnly: readonly string[];
2021
+ readonly validity?: GrantValidity;
2022
+ };
2023
+ type DelegationInput = {
2024
+ /** Who hands over: the same subject-only selectors as `approval.by` (a role, `authenticated()`, a plan, `assurance()`); not `relation()`. */
2025
+ readonly from: GranteeInput;
2026
+ /** Which actor may act: `actor('eve')`, an actor kind, `{ kind, id }` for one agent, or `{ kind, client }` for one named OAuth client. */
2027
+ readonly to: ActorGrantee | string | DelegationTarget;
2028
+ /** The leaves or subtrees the actor may use; a deny grant still applies. */
2029
+ readonly permissions: readonly (Permission | PermissionTree)[];
2030
+ readonly validFrom?: string | number;
2031
+ readonly validUntil?: string | number;
2032
+ };
2033
+ /** A declared scope name (or the `tenant` / `team` alias), or the resource a role is held on. */
2034
+ type RoleScope<S extends string = string> = S | Permission | PermissionTree | readonly (Permission | PermissionTree)[];
2035
+ type RoleOptions<S extends string = string> = {
2036
+ readonly on?: RoleScope<S>;
2037
+ readonly assignable?: boolean;
2038
+ /** Roles nobody may hold together with this one in the same scope instance. */
2039
+ readonly exclusiveWith?: readonly string[];
2040
+ /** Fewest holders a scope instance keeps (checked at commit); default 0. Needs a named-scope `on`. */
2041
+ readonly min?: number;
2042
+ /** Most holders a scope instance may have. Needs a named-scope `on`. */
2043
+ readonly max?: number;
2044
+ /** The holder count of a scope instance never changes: the role only moves by transfer. */
2045
+ readonly transferOnly?: boolean;
2046
+ /**
2047
+ * Roles a holder may assign and revoke. Once any role declares `assigns`,
2048
+ * a role nobody lists is assigned only by `meta.manageRoles` holders.
2049
+ */
2050
+ readonly assigns?: readonly string[];
2051
+ /** Membership kinds (`via`) that may hold the role; others hold it for nothing. */
2052
+ readonly for?: readonly string[];
2053
+ readonly meta?: RoleMeta;
2054
+ /** Time-boxed activation: the role becomes eligible-only and `activate` mints its membership. */
2055
+ readonly activation?: ActivationOption;
2056
+ /** Reserved for restricted credentials; setting it throws until it ships. */
2057
+ readonly restricted?: never;
2058
+ };
2059
+ /** Where a grant applies: `'global'`, a declared scope name, or one resource. */
2060
+ type GrantScope = string | {
2061
+ readonly resource: string;
2062
+ };
2063
+ type Grant = {
2064
+ readonly permission: Permission;
2065
+ readonly effect: "allow" | "deny";
2066
+ readonly to: Grantee | readonly Grantee[];
2067
+ readonly role: string | null;
2068
+ readonly where?: Condition;
2069
+ readonly check?: Condition;
2070
+ readonly approval?: "human" | ApprovalRequirement;
2071
+ readonly portable: boolean;
2072
+ /** Set when `portable` is false only because the grant reads the relation graph. */
2073
+ readonly graph?: true;
2074
+ readonly closure?: ClosureGrantFn;
2075
+ readonly limit?: GrantLimit;
2076
+ readonly fields?: readonly string[];
2077
+ readonly scope: GrantScope;
2078
+ /** A name a `breakGlass` override may lift; only meaningful on a deny. */
2079
+ readonly name?: string;
2080
+ readonly group?: string;
2081
+ /** Purposes of use that make the grant apply (`context.purpose`); non-portable. */
2082
+ readonly purpose?: readonly string[];
2083
+ /** Set on a break-glass allow: it overrides named denies and carries obligations. */
2084
+ readonly breakGlass?: BreakGlassSpec;
2085
+ /** The membership kind (`via`) this grant applies under; others never match it. */
2086
+ readonly viaOnly?: string;
2087
+ /** Set only on a grant merged from a hosted policy document. */
2088
+ readonly hosted?: HostedGrantRef;
2089
+ /** When the grant applies; absent means always. */
2090
+ readonly validity?: GrantValidity;
2091
+ /** Set on a custom-role grant narrowed by a resource level (`CustomRoleGrant.level`). */
2092
+ readonly level?: string;
2093
+ /** The permission key the subject must also hold, through a role, on the row's scope instance or globally. */
2094
+ readonly requires?: readonly string[];
2095
+ };
2096
+ /** Which hosted policy document and grant a merged grant came from. */
2097
+ type HostedGrantRef = {
2098
+ readonly document: string;
2099
+ readonly grant: string;
2100
+ };
2101
+ type RoleBinding<S extends string = string> = {
2102
+ readonly name: string;
2103
+ readonly grants: readonly Grant[];
2104
+ readonly on?: RoleScope<S>;
2105
+ readonly assignable: boolean;
2106
+ readonly exclusiveWith?: readonly string[];
2107
+ readonly min?: number;
2108
+ readonly max?: number;
2109
+ readonly transferOnly?: boolean;
2110
+ readonly assigns?: readonly string[];
2111
+ readonly for?: readonly string[];
2112
+ readonly meta?: RoleMeta;
2113
+ /** Time-boxed activation: the role is eligible-only, and `activate` mints its membership. */
2114
+ readonly activation?: ActivationSpec;
2115
+ /** Support access: consent and `actorRequired` for a vendor-support membership. */
2116
+ readonly support?: SupportSpec;
2117
+ };
2118
+ type ValidateMode = "boundary" | "always" | "never";
2119
+ /** The declared scopes, in declaration order; empty when the policy declares none. */
2120
+ type PolicyScopes = readonly Scope[];
2121
+ type PolicyVocabulary = {
2122
+ readonly permissions: PermissionTree;
2123
+ readonly roles?: RoleTree;
2124
+ readonly plans?: PlanTree;
2125
+ };
2126
+ type VocabularyFromInput<Input> = Input extends PolicyVocabulary ? Input : {
2127
+ readonly permissions: Input & PermissionTree;
2128
+ readonly roles?: RoleTree;
2129
+ readonly plans?: PlanTree;
2130
+ };
2131
+ type Policy<TUser = unknown, TPrincipal extends Principal = Principal, V extends PolicyVocabulary = PolicyVocabulary> = {
2132
+ readonly permissions: V["permissions"];
2133
+ readonly roles: readonly RoleBinding[];
2134
+ readonly rolesByName: ReadonlyMap<string, RoleBinding>;
2135
+ readonly grants: readonly Grant[];
2136
+ readonly vocabulary: V;
2137
+ readonly scopes: PolicyScopes;
2138
+ principal(user: TUser): TPrincipal | null;
2139
+ subject(user: TUser): TPrincipal | null;
2140
+ context?(user: TUser): Readonly<Record<string, unknown>> | Promise<Readonly<Record<string, unknown>>>;
2141
+ readonly validate: ValidateMode;
2142
+ readonly onDenied?: (decision: unknown) => never | void;
2143
+ readonly fingerprint: string;
2144
+ readonly resources: ReadonlyMap<string, ResourceNode>;
2145
+ readonly providers?: readonly DecisionProvider[];
2146
+ /** Permission keys a hosted policy document may grant or deny; empty by default. */
2147
+ readonly hostable: readonly string[];
2148
+ /** Permission keys that deny with `stale-credentials` when the subject's token is behind the source. */
2149
+ readonly fresh?: readonly string[];
2150
+ /** Policy delegations in declaration order; absent or empty when the policy declares none. */
2151
+ readonly delegations?: readonly PolicyDelegation[];
2152
+ /** Grant levels by resource (`resource(…, { levels })`), normalised; absent when none are declared. */
2153
+ readonly levels?: PolicyLevels;
2154
+ /** Coarse OAuth scopes in declaration order; absent when the policy declares none. */
2155
+ readonly oauthScopes?: readonly PolicyOAuthScope[];
2156
+ readonly index: PolicyIndex;
2157
+ };
2158
+ /**
2159
+ * A coarse OAuth scope an authorization server issues (`mcp:read`) and the
2160
+ * permission keys it covers, with their own scopes (`task:read`).
2161
+ */
2162
+ type PolicyOAuthScope = {
2163
+ readonly scope: string;
2164
+ readonly permissions: readonly string[];
2165
+ readonly scopes: readonly string[];
2166
+ };
2167
+ /** Lookups built once per policy, so a decision does not rescan every role and grant. */
2168
+ type PolicyIndex = {
2169
+ readonly declaredRoles: ReadonlySet<string>;
2170
+ readonly supports: readonly SupportSpec[];
2171
+ /** The grants `grantList` returns, by permission key, in the same order. */
2172
+ readonly grantsByKey: ReadonlyMap<string, readonly Grant[]>;
2173
+ };
2174
+ declare function normalizeApproval(approval: ApprovalOption | undefined, permission?: string): Grant["approval"];
2175
+ type GrantCondition<T, K extends PermissionKind> = K extends "collection" ? Omit<GrantOptions<T>, "where" | "fields"> | ClosureGrantFn<T> : GrantOptions<T> | ClosureGrantFn<T>;
2176
+ declare function allow<T, K extends PermissionKind = PermissionKind>(permission: Permission<string, T, K> | readonly Permission<string, T, K>[], condition?: GrantCondition<T, K>): Omit<Grant, "role" | "scope"> | Omit<Grant, "role" | "scope">[];
2177
+ declare function deny<T, K extends PermissionKind = PermissionKind>(permission: Permission<string, T, K> | readonly Permission<string, T, K>[], condition?: GrantCondition<T, K>): Omit<Grant, "role" | "scope"> | Omit<Grant, "role" | "scope">[];
2178
+ type RoleGrants = readonly (Omit<Grant, "role" | "scope"> | readonly Omit<Grant, "role" | "scope">[])[];
2179
+ /** A role held at a named scope: `on` is checked against `definePolicy({ scopes })`. */
2180
+ declare function role<const S extends string>(name: string | Role, grants: RoleGrants, options: RoleOptions<S> & {
2181
+ readonly on: S;
2182
+ }): RoleBinding<S>;
2183
+ /** A global role, or one held on a resource. */
2184
+ declare function role(name: string | Role, grants: RoleGrants, options?: RoleOptions<never>): RoleBinding<never>;
2185
+ /** Options built at runtime: the scope name is only checked by `definePolicy`. */
2186
+ declare function role(name: string | Role, grants: RoleGrants, options?: RoleOptions): RoleBinding;
2187
+ declare function normalizeAssurance(input: AssuranceRequirement | undefined): AssuranceRequirement | undefined;
2188
+ /** Resource name to level name to its normalised condition. */
2189
+ type PolicyLevels = Readonly<Record<string, Readonly<Record<string, Condition>>>>;
2190
+ type DefinePolicyOptions<TUser, TPrincipal extends Principal, S extends PolicyScopesInput = PolicyScopesInput> = {
2191
+ readonly roles?: readonly RoleBinding<ScopeNames<S>>[];
2192
+ readonly grants?: readonly (Omit<Grant, "role" | "scope"> | readonly Omit<Grant, "role" | "scope">[] | Grant)[];
2193
+ /**
2194
+ * Named scopes in order, each with the row field holding its id and an
2195
+ * optional parent (`within`, an earlier scope). `tenant` and `team` alias
2196
+ * the first and second scope.
2197
+ */
2198
+ readonly scopes?: S;
2199
+ readonly principal?: (user: TUser) => TPrincipal | null;
2200
+ readonly subject?: (user: TUser) => TPrincipal | null;
2201
+ readonly context?: (user: TUser) => Readonly<Record<string, unknown>> | Promise<Readonly<Record<string, unknown>>>;
2202
+ readonly validate?: ValidateMode;
2203
+ readonly onDenied?: (decision: unknown) => never | void;
2204
+ readonly providers?: readonly DecisionProvider[];
2205
+ /**
2206
+ * Leaves or subtrees a hosted policy document (`PolicySource`) may touch.
2207
+ * The default is none, so a policy without it ignores every hosted grant.
2208
+ */
2209
+ readonly hostable?: readonly (Permission | PermissionTree)[];
2210
+ /**
2211
+ * Sensitive permissions that need an up-to-date token: when the subject's
2212
+ * memberships come from a token behind the `MembershipSource` version, they
2213
+ * deny with `stale-credentials`.
2214
+ */
2215
+ readonly fresh?: readonly (Permission | PermissionTree)[];
2216
+ /**
2217
+ * Standing delegations: holders of `from` let actors matching `to` use
2218
+ * `permissions` for them without a token saying so. A token delegation on
2219
+ * the call still applies as well; both must cover.
2220
+ */
2221
+ readonly delegations?: readonly DelegationInput[];
2222
+ /**
2223
+ * Coarse OAuth scopes the authorization server issues, each covering
2224
+ * permissions: a token holding `mcp:read` is delegated every permission
2225
+ * listed under it, as if it held each permission's own scope. Scope
2226
+ * challenges name the first coarse scope that covers the permission.
2227
+ */
2228
+ readonly oauthScopes?: Readonly<Record<string, readonly (Permission | PermissionTree)[]>>;
2229
+ };
2230
+ declare function definePolicy<TUser, TPrincipal extends Principal, const Input extends PermissionTree | PolicyVocabulary, const S extends PolicyScopesInput = PolicyScopesInput>(permissions: Input, options: DefinePolicyOptions<TUser, TPrincipal, S>): Policy<TUser, TPrincipal, VocabularyFromInput<Input>>;
2231
+ type MembershipFixture = {
2232
+ readonly principal?: string;
2233
+ readonly tenant?: string;
2234
+ readonly roles: readonly string[];
2235
+ };
2236
+ type SeparationConflict = {
2237
+ readonly principal: string;
2238
+ readonly tenant?: string;
2239
+ readonly roles: readonly [string, string];
2240
+ };
2241
+ declare function separationConflicts(policy: Policy, memberships: readonly MembershipFixture[]): readonly SeparationConflict[];
2242
+ type PrincipalOf<P> = P extends Policy<unknown, infer TPrincipal> ? TPrincipal : Principal;
2243
+ type SubjectOf<P> = {
2244
+ readonly principal: PrincipalOf<P> | null;
2245
+ readonly actor?: Actor;
2246
+ readonly delegation?: Delegation;
2247
+ readonly context: Readonly<Record<string, unknown>>;
2248
+ readonly session?: string;
2249
+ readonly expiresAt?: number;
2250
+ };
2251
+ //#endregion
2252
+ export { AccessEvent as $, ExplainedDecision as $n, CredentialPrincipal as $t, RoleOptions as A, RoleChangeOptions as An, GnapAccess as Ar, SnapshotSource as At, normalizeApproval as B, simulateArazzo as Bn, MemberOfParent as Br, memoryMembershipSource as Bt, Policy as C, mergeHostedGrants as Cn, Actor as Cr, SettingsSource as Ct, PolicyVocabulary as D, WhoCan as Dn, CustomRole as Dr, SnapshotGrant as Dt, PolicyScopes as E, HoldingVia as En, Binding as Er, SnapshotAssignable as Et, SupportConsent as F, ArazzoFinding as Fn, VerifiedClaims as Fr, TokenVerifier as Ft, Approver as G, ApprovalPolicyValidation as Gn, SqlFunctionArg as Gr, WireDenial as Gt, role as H, ApprovalPolicy as Hn, RelatedCondition as Hr, memorySettings as Ht, ValidateMode as I, ArazzoPlan as In, Condition as Ir, VerificationFailure as It, UserApprover as J, ApprovalRequiredDecision as Jn, isCondition as Jr, CredentialKind as Jt, ApproverInput as K, memoryApprovalPolicies as Kn, SqlFunctionCondition as Kr, Credential as Kt, allow as L, ArazzoSimulateInput as Ln, ConditionRef as Lr, VerifiedToken as Lt, SeparationConflict as M, ActivateInput as Mn, Membership as Mr, TenantSettings as Mt, SubjectOf as N, breakGlass as Nn, Principal as Nr, TokenFailureCause as Nt, PrincipalOf as O, RoleChange as On, CustomRoleGrant as Or, SnapshotNotEntitled as Ot, SupportAccessOptions as P, supportAccess as Pn, Subject as Pr, TokenSigner as Pt, user as Q, DeniedDecision as Qn, CredentialPolicyViolation as Qt, definePolicy as R, ArazzoStepResult as Rn, ConditionValue as Rr, WhereCompiler as Rt, MembershipFixture as S, memoryPolicySource as Sn, ScopeNames as Sr, RoleSourceFactory as St, PolicyOAuthScope as T, Holder as Tn, AuthorizationDetail as Tr, Snapshot as Tt, separationConflicts as U, ApprovalPolicyProblem as Un, RelatedHop as Ur, memorySnapshotSource as Ut, normalizeAssurance as V, APPROVAL_POLICY_UNAVAILABLE as Vn, OpaqueCondition as Vr, memoryRoleSource as Vt, AnyOfApprover as W, ApprovalPolicySource as Wn, RestrictedAncestors as Wr, WireDecision as Wt, anyOf as X, Denial as Xn, isConditionRef as Xr, CredentialPermissionInput as Xt, allOf as Y, Decision as Yn, isConditionDate as Yr, CredentialPermission as Yt, holder as Z, DenialReason as Zn, isSqlFunctionField as Zr, CredentialPolicy as Zt, GrantLimit as _, HostedGrantDropReason as _n, plan as _r, RelationChain as _t, ApprovalRequirement as a, decideCredential as an, Trace as ar, DecisionSink as at, GrantValidity as b, PolicySource as bn, Scope as br, RelationSource as bt, BreakGlassOptions as c, DeriveOptions as cn, Grantee as cr, JwtClaims as ct, ClosureContext as d, RowPair as dn, RelationGrantee as dr, LimitStore as dt, CredentialRequest as en, GrantedDecision as er, AuthEvent as et, ClosureGrantFn as f, SimulateOptions as fn, actor as fr, LocalCustomRoleTable as ft, GrantCondition as g, HostedGrant as gn, inherit as gr, MembershipSource as gt, Grant as h, createPermDock as hn, authenticated as hr, MembershipEvent as ht, ApprovalOption as i, credentialSubject as in, Quota as ir, DecisionProvider as it, RoleScope as j, RoleChangeTarget as jn, JsonWebKeyLike as jr, SubjectResolver as jt, RoleBinding as k, RoleChangeDecision as kn, Delegation as kr, SnapshotScope as kt, BreakGlassRequirements as l, PermDock as ln, GranteeInput as lr, LimitConsumeInput as lt, DelegationTarget as m, WhereResult as mn, assurance as mr, MemberEntry as mt, ApprovalEscalation as n, credentialDelegation as nn, MatchedGrant as nr, CredentialVerifier as nt, ApprovalStage as o, parseCredential as on, TraceSkip as or, DirectoryEvent as ot, DelegationInput as p, SnapshotOptions as pn, anyone as pr, LocalSnapshotManifest as pt, PermissionApprover as q, validateApprovalPolicy as qn, hasConditionOp as qr, CredentialDecision as qt, ApprovalMode as r, credentialPolicyViolation as rn, Obligation as rr, DecisionEvent as rt, AssuranceRequirement as s, DecideOptions as sn, TraceSkipReason as sr, EntitlementSource as st, ActivationOption as t, DecideCredentialOptions as tn, LimitDetail as tr, CredentialEvent as tt, BreakGlassSpec as u, PermDockOptions as un, InheritGrantee as ur, LimitRemaining as ut, GrantOptions as v, HostedGrantDropped as vn, relation as vr, RelationGroup as vt, PolicyDelegation as w, parsePolicyDocument as wn, Assurance as wr, SinkEvent as wt, HostedGrantRef as x, isPortableCondition as xn, ScopeDeclaration as xr, RoleSource as xt, GrantScope as y, PolicyDocument as yn, PolicyScopesInput as yr, RelationHolder as yt, deny as z, arazzoFindings as zn, MemberOfCondition as zr, memoryEntitlementSource as zt };