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,745 @@
1
+ import { At as SnapshotSource, C as Policy, Ct as SettingsSource, Dr as CustomRole, Ft as TokenVerifier, Mr as Membership, Nr as Principal, Pr as Subject, Pt as TokenSigner, Rt as WhereCompiler, Tt as Snapshot, Wn as ApprovalPolicySource, at as DecisionSink, bn as PolicySource, bt as RelationSource, dt as LimitStore, gt as MembershipSource, jt as SubjectResolver, ln as PermDock, mn as WhereResult, nt as CredentialVerifier, st as EntitlementSource, un as PermDockOptions, xt as RoleSource } from "../policy-CFZAr_Al.js";
2
+ import { f as Permission, g as ResourceInit, u as InferPermissionTree } from "../permissions-DttnqqxC.js";
3
+ import { r as Role } from "../vocabulary-DA8a8zif.js";
4
+ import { f as ApprovalStore } from "../types-vKyAMtcX.js";
5
+ import { t as ToolMap } from "../types-Bvc4oWT6.js";
6
+ import { n as SupabaseHookManifest } from "../manifest-uDS9y5de.js";
7
+ import { t as supabaseMembershipsBudget } from "../budget-JqcRqyhK.js";
8
+ import { n as RevocationFeed } from "../revocations-Cy06JNx2.js";
9
+ import { g as ReplayStore } from "../types-9AWO9EGt.js";
10
+ import { v as DirectoryStore } from "../index-A0YNL8jZ.js";
11
+ import { a as SaasProject } from "../permissions-CDgvKG5L.js";
12
+ import { n as saasPolicy } from "../policy-D8UFyERw.js";
13
+ import { expectTypeOf } from "vitest";
14
+ //#region src/testing/describe-policy.d.ts
15
+ type MatrixOutcome = "granted" | "denied" | "approval-required";
16
+ type MatrixCell = MatrixOutcome | {
17
+ readonly outcome?: MatrixOutcome;
18
+ readonly denials?: readonly {
19
+ readonly role?: string | null;
20
+ readonly reason: string;
21
+ }[];
22
+ readonly alternatives?: readonly string[];
23
+ /** Obligation kinds a granted decision carries, in order; `[]` asserts none. */
24
+ readonly obligations?: readonly string[];
25
+ /** The `name` of the deny grant `explain` reports as the one that won. */
26
+ readonly deniedBy?: string;
27
+ };
28
+ type DescribePolicyConfig<TSubject> = {
29
+ readonly subjects: Record<string, TSubject>;
30
+ readonly fixtures?: Record<string, unknown>;
31
+ readonly matrix: Record<string, Record<string, MatrixCell | Record<string, MatrixCell>>>;
32
+ readonly exhaustive?: boolean;
33
+ readonly options?: PermDockOptions;
34
+ /**
35
+ * Also assert every granted or denied cell against `fromSnapshot(permdock.snapshot())`,
36
+ * the client a Server Component hands down. Closures cannot cross a snapshot and deny on the client.
37
+ */
38
+ readonly snapshot?: boolean;
39
+ };
40
+ export declare function describePolicy<TSubject>(policy: Policy, config: DescribePolicyConfig<TSubject>): void;
41
+ //#endregion
42
+ //#region src/testing/rls-parity.d.ts
43
+ type RlsDbOutcome = "allowed" | "filtered" | "rejected";
44
+ type RlsParitySubject = {
45
+ readonly id: string;
46
+ readonly roles?: readonly string[];
47
+ readonly tenant?: string;
48
+ readonly memberships?: readonly Membership[];
49
+ /**
50
+ * Extra token claims, read in memory as `principal.claims.*`. They join the
51
+ * JWT claims (`supabase`, `neon`); under `guc` each top-level claim is its
52
+ * own `<prefix>.<name>` setting, strings as is and anything else as JSON.
53
+ */
54
+ readonly claims?: Readonly<Record<string, unknown>>;
55
+ };
56
+ type RlsParityFixture = {
57
+ readonly name: string;
58
+ readonly subject: RlsParitySubject;
59
+ readonly permission: Permission;
60
+ readonly row: Readonly<Record<string, unknown>>;
61
+ readonly table: string;
62
+ };
63
+ type RlsQueryResult = {
64
+ readonly rows: readonly Record<string, unknown>[];
65
+ readonly rowCount?: number;
66
+ readonly code?: string;
67
+ };
68
+ type RlsQueryFn = (sql: string, values?: readonly unknown[]) => Promise<RlsQueryResult>;
69
+ type RlsParityOptions = {
70
+ readonly query: RlsQueryFn;
71
+ readonly fixtures: readonly RlsParityFixture[];
72
+ /**
73
+ * `supabase` and `neon` set `request.jwt.claims`; a test database stubs
74
+ * `auth.jwt()` / `auth.uid()` or `auth.session()` / `auth.user_id()` over it.
75
+ */
76
+ readonly dialect?: "supabase" | "neon" | "guc";
77
+ readonly gucPrefix?: string;
78
+ readonly tenantClaim?: string;
79
+ /** Claim (or `guc` setting) the RLS helpers read global roles from. Default `user_role`. */
80
+ readonly roleClaim?: string;
81
+ readonly role?: "authenticated" | "anon";
82
+ /**
83
+ * Tenant-defined roles the subjects' memberships may hold. `decide` resolves them through a
84
+ * `RoleSource`; each membership's claim carries them as the compact `grants` map, which the
85
+ * helpers read in `jwt` mode. Seeding the `database`-mode tables is the caller's job.
86
+ */
87
+ readonly customRoles?: readonly CustomRole[];
88
+ /** Also decide each case from the subject's serialized snapshot (`fromSnapshot`); it must agree. */
89
+ readonly snapshot?: boolean;
90
+ /**
91
+ * With `rls generate --fields views`: for each instance read, the row of
92
+ * `<table>_visible` must hold exactly the columns `pick` keeps (plus the key,
93
+ * which always passes through). A table with no view is read directly.
94
+ */
95
+ readonly fieldViews?: boolean;
96
+ };
97
+ /** Columns with a value in the view's row and in `pick`'s result, sorted. */
98
+ type RlsFieldsOutcome = {
99
+ readonly app: readonly string[];
100
+ readonly database: readonly string[] | string;
101
+ };
102
+ type RlsParityCase = {
103
+ readonly name: string;
104
+ readonly granted: boolean;
105
+ readonly database: RlsDbOutcome;
106
+ /** The snapshot's decision, with `snapshot: true`. */
107
+ readonly snapshot?: boolean;
108
+ /** The field view check, with `fieldViews: true`; `database` is an error code when the read failed. */
109
+ readonly fields?: RlsFieldsOutcome;
110
+ readonly ok: boolean;
111
+ };
112
+ type RlsParityReport = {
113
+ readonly ok: boolean;
114
+ readonly results: readonly RlsParityCase[];
115
+ };
116
+ export declare function rlsParity<TUser>(policy: Policy<TUser>, options: RlsParityOptions): Promise<RlsParityReport>;
117
+ //#endregion
118
+ //#region src/testing/orm-parity.d.ts
119
+ type OrmParityScenario<TUser = unknown> = {
120
+ readonly name: string;
121
+ /** What the policy's `subject` mapper receives, as in `createPermDock(policy, user)`. */
122
+ readonly user: TUser;
123
+ /** The active tenant and role sources, as in `createPermDock(policy, user, options)`. */
124
+ readonly options?: PermDockOptions;
125
+ /** An instance permission; its `where()` filters the table. */
126
+ readonly permission: Permission<string, unknown, "instance">;
127
+ /** Every row of the table, exactly as the database holds them. */
128
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
129
+ };
130
+ type OrmParityRunInput<TUser = unknown> = {
131
+ readonly scenario: OrmParityScenario<TUser>;
132
+ readonly where: WhereResult;
133
+ };
134
+ type OrmParityOptions<TUser = unknown> = {
135
+ /** Runs `toWhere(where)` against the database and returns the matching row ids. */
136
+ readonly run: (input: OrmParityRunInput<TUser>) => Promise<readonly unknown[]>;
137
+ /** The row id field; default `id`. */
138
+ readonly id?: string;
139
+ };
140
+ type OrmParityCase = {
141
+ readonly name: string;
142
+ readonly expected: readonly string[];
143
+ readonly actual: readonly string[];
144
+ /**
145
+ * `where()` left out a non-portable grant. `toWhere` refusing it is
146
+ * fail-closed and passes; rows it does return must be a subset.
147
+ */
148
+ readonly partial: boolean;
149
+ readonly error?: string;
150
+ readonly ok: boolean;
151
+ };
152
+ type OrmParityReport = {
153
+ readonly ok: boolean;
154
+ readonly results: readonly OrmParityCase[];
155
+ };
156
+ /**
157
+ * ORM parity: for each scenario, the rows `permdock.filter()` keeps in memory
158
+ * must be exactly the rows the database returns for `toWhere(permdock.where())`.
159
+ * With a `relations` option, the graph is loaded for the rows first, so the
160
+ * in-memory side walks the same graph the database query does.
161
+ * A partial `where()` (a closure grant it cannot compile) may be refused or
162
+ * return fewer rows, never more.
163
+ */
164
+ export declare function ormParity<TUser>(policy: Policy<TUser>, scenarios: readonly OrmParityScenario<TUser>[], options: OrmParityOptions<TUser>): Promise<OrmParityReport>;
165
+ //#endregion
166
+ //#region src/testing/client-parity.d.ts
167
+ type ClientParityCase = {
168
+ readonly name: string;
169
+ /** The value the policy's `subject` function receives. */
170
+ readonly user: unknown;
171
+ readonly tenant?: string | undefined;
172
+ readonly permission: Permission;
173
+ readonly row?: unknown;
174
+ /**
175
+ * `true` when the client may deny what the server grants, because the
176
+ * outcome depends on a closure, a quota or an approval the snapshot omits.
177
+ */
178
+ readonly stricter?: boolean;
179
+ };
180
+ type ClientParityOptions = {
181
+ readonly customRoles?: RoleSource;
182
+ };
183
+ /**
184
+ * Asserts that `fromSnapshot(permdock.snapshot())` never grants what the
185
+ * server denies, and matches it exactly unless a case is marked `stricter`.
186
+ */
187
+ export declare function testClientParity(policy: Policy, cases: readonly ClientParityCase[], options?: ClientParityOptions): void;
188
+ //#endregion
189
+ //#region src/testing/client-store.d.ts
190
+ type ClientStoreStatus = "ready" | "pending" | "stale" | "server-only";
191
+ /** The client surface every UI adapter hands to components. */
192
+ type ClientStorePermDock = PermDock & {
193
+ status(permission?: Permission, data?: unknown): ClientStoreStatus;
194
+ refresh(query?: {
195
+ readonly tenant?: string;
196
+ }): Promise<void>;
197
+ clear(): void;
198
+ subscribe(listener: () => void): () => void;
199
+ };
200
+ type ClientStoreHandle = {
201
+ get(): ClientStorePermDock;
202
+ /** Hydrate from a server-pushed snapshot (a Server Action result, a socket message). */
203
+ replace(value: unknown): void;
204
+ };
205
+ type ClientStoreFactoryOptions = {
206
+ readonly snapshot: Snapshot | string;
207
+ readonly snapshotUrl?: string;
208
+ readonly endpoint?: string;
209
+ readonly tenant?: string;
210
+ readonly fetch: typeof fetch;
211
+ readonly verifier?: TokenVerifier;
212
+ };
213
+ type ClientStoreFactory = (options: ClientStoreFactoryOptions) => ClientStoreHandle;
214
+ /**
215
+ * Race and cache scenarios for a client snapshot store: tenant switches,
216
+ * `replace` and `refresh`, logout and a second user during a refresh, stale
217
+ * and signed snapshots, and endpoint answers cached per tenant. Runs against
218
+ * the saas domain; `createStore` wraps the store an adapter ships.
219
+ */
220
+ export declare function testClientStore(name: string, createStore: ClientStoreFactory): void;
221
+ //#endregion
222
+ //#region src/testing/snapshot-fixture.d.ts
223
+ export declare function snapshotFixture(policy: Policy, subject: unknown, options?: {
224
+ readonly include?: readonly (Permission | {
225
+ readonly [key: string]: unknown;
226
+ })[];
227
+ readonly tenants?: "all";
228
+ readonly tenant?: string;
229
+ readonly simulated?: boolean;
230
+ }): Promise<Snapshot>;
231
+ //#endregion
232
+ //#region src/testing/http-adapter.d.ts
233
+ /**
234
+ * What a mount wires into its framework. Every value is server-side: the
235
+ * subject comes from a verified bearer token, memberships and plans from the
236
+ * seed, the tenant from the `:org` path segment.
237
+ */
238
+ type HttpScenarioDomain = {
239
+ readonly policy: typeof saasPolicy;
240
+ /**
241
+ * The verified principal for an `Authorization` header, with the plans of
242
+ * the org in the first segment of `path`. The path, not a route param, so
243
+ * the answer is the same in a global middleware that runs before routing.
244
+ */
245
+ readonly subject: (authorization: string | null | undefined, path: string) => Promise<Principal | null>;
246
+ /** `subject` as a full `Subject` whose `expiresAt` is the token's `exp`. */
247
+ readonly session: (authorization: string | null | undefined, path: string) => Promise<Subject | null>;
248
+ /** The feed stream mounts pass as `revocations`. */
249
+ readonly revocations: RevocationFeed;
250
+ /**
251
+ * The seed projects of an org, one every 20 ms, round and round until
252
+ * `signal` aborts: the source of the events stream.
253
+ */
254
+ readonly ticks: (org: string | undefined, signal: AbortSignal) => AsyncIterable<SaasProject>;
255
+ /** The `:org` segment of a path; mounts may read their route param instead. */
256
+ readonly org: (path: string) => string | undefined;
257
+ readonly customRoles: RoleSource;
258
+ readonly store: ApprovalStore;
259
+ readonly limits: LimitStore;
260
+ /** A project row by id, whatever its org: tenant checks belong to the policy. */
261
+ readonly project: (id: string | undefined) => SaasProject | null;
262
+ };
263
+ type HttpOp = {
264
+ readonly op: "project.get";
265
+ readonly org: string;
266
+ readonly id: string;
267
+ } | {
268
+ readonly op: "project.update";
269
+ readonly org: string;
270
+ readonly id: string;
271
+ } | {
272
+ readonly op: "project.create";
273
+ readonly org: string;
274
+ readonly body: unknown;
275
+ } | {
276
+ readonly op: "project.delete";
277
+ readonly org: string;
278
+ readonly id: string;
279
+ } | {
280
+ readonly op: "project.upload";
281
+ readonly org: string;
282
+ readonly id: string;
283
+ readonly file: {
284
+ readonly name: string;
285
+ readonly content: string;
286
+ };
287
+ } | {
288
+ readonly op: "analytics.read";
289
+ readonly org: string;
290
+ } | {
291
+ readonly op: "apiKey.create";
292
+ readonly org: string;
293
+ } | {
294
+ readonly op: "apiKey.revokeAll";
295
+ readonly org: string;
296
+ } | {
297
+ readonly op: "admin.members";
298
+ readonly org: string;
299
+ } | {
300
+ readonly op: "evaluations";
301
+ readonly org: string;
302
+ readonly body: unknown;
303
+ };
304
+ type HttpCall = HttpOp & {
305
+ /** `Bearer <token>` or `null` for an anonymous call. */
306
+ readonly authorization: string | null;
307
+ /** Sent as the `PermDock-Approval` header. */
308
+ readonly approval?: string;
309
+ };
310
+ type HttpResult = {
311
+ readonly status: number;
312
+ readonly body: unknown;
313
+ };
314
+ type HttpMounted = {
315
+ /**
316
+ * A fetch-shaped entry for REST adapters. It must serve:
317
+ *
318
+ * - `GET /:org/projects/:id`: `protect(project.read, row)`, 200 with the row
319
+ * - `PATCH /:org/projects/:id`: `protect(project.update, row)`, 200
320
+ * - `POST /:org/projects`: `protect(project.create, body, { trusted: false })`, 201 with the body
321
+ * - `DELETE /:org/projects/:id`: `protect(project.read, row)`, then the handler
322
+ * calls `permdock.assert(project.delete, row)`; 204
323
+ * - `POST /:org/projects/:id/files`: `protect(project.update, row)`, then the
324
+ * framework's own multipart parser reads field `file`; 201 `{ name, size }`
325
+ * - `GET /:org/analytics`: `protect(analytics.read)`, 200
326
+ * - `POST /:org/api-keys`: `protect(apiKey.create)`, 201
327
+ * - `POST /:org/api-keys/revoke-all`: `protect(apiKey.revokeAll)`, 204
328
+ * - `GET /:org/admin/members`: in a sub-app, router or group; `protect(member.list)`, 200
329
+ * - `POST /:org/permdock/access/v1/evaluations`: the adapter's decision endpoint
330
+ *
331
+ * A global `permdock()` middleware runs before every route.
332
+ *
333
+ * With `streams: true` it also serves `GET /:org/projects/:id/events`:
334
+ * `protect(project.read, row)` with the subject from `domain.session`,
335
+ * then a connection opened for `project.read` on the row with
336
+ * `revocations: domain.revocations`, streaming `domain.ticks(org)` as
337
+ * `text/event-stream` `data:` frames of JSON rows, dropping rows the
338
+ * subscriber cannot `project.update`, and ending with an
339
+ * `event: permdock` frame carrying the Problem Details when the connection aborts.
340
+ */
341
+ readonly fetch?: (request: Request) => Promise<Response>;
342
+ /** RPC adapters map a call to a procedure and its error to an HTTP status. */
343
+ readonly call?: (call: HttpCall) => Promise<HttpResult>;
344
+ readonly close?: () => Promise<void> | void;
345
+ };
346
+ type HttpScenarioName = "tenant" | "roles" | "custom-roles" | "plans" | "expired" | "limits" | "validation" | "assert" | "approval" | "stale-approval" | "evaluations" | "upload" | "sub-app" | "parallel" | "stream-revoked" | "stream-demoted" | "stream-filter" | "stream-expired";
347
+ type HttpAdapterOptions = {
348
+ readonly name: string;
349
+ readonly mount: (domain: HttpScenarioDomain) => HttpMounted | Promise<HttpMounted>;
350
+ /** Scenarios the transport cannot express (multipart over RPC), each with a reason. */
351
+ readonly skip?: Readonly<Partial<Record<HttpScenarioName, string>>>;
352
+ /** The mount serves the events stream; the `stream-*` scenarios run only then. */
353
+ readonly streams?: boolean;
354
+ };
355
+ /**
356
+ * Real-life HTTP scenarios over the shared SaaS domain. `mount` builds the
357
+ * application once with the adapter under test; every expectation below is
358
+ * written by hand, never computed with PermDock.
359
+ */
360
+ export declare function testHttpAdapter(options: HttpAdapterOptions): void;
361
+ //#endregion
362
+ //#region src/testing/agent-adapter.d.ts
363
+ /** The user whose subject resolver throws. */
364
+ export declare const AGENT_THROWING_USER = "throws";
365
+ /** The project id whose loader throws. */
366
+ export declare const AGENT_THROWING_ROW = "throws";
367
+ type AgentToolName = "project_read" | "api_keys_revoke_all";
368
+ /**
369
+ * What a mount wires into its adapter. The subject and the tenant come from
370
+ * the server-side context the mount builds for each call, never from the
371
+ * tool arguments.
372
+ */
373
+ type AgentScenarioDomain = {
374
+ readonly policy: typeof saasPolicy;
375
+ /**
376
+ * The principal for `user` with the plans of `org`, or `null` for an
377
+ * anonymous call. Throws for `AGENT_THROWING_USER`.
378
+ */
379
+ readonly subject: (user: string | null, org: string) => Principal | null;
380
+ /**
381
+ * `project_read` loads the row named by `args.id`: `null` for an unknown
382
+ * id, a throw for `AGENT_THROWING_ROW`. `api_keys_revoke_all` needs
383
+ * approval.
384
+ */
385
+ readonly tools: ToolMap & { readonly [K in AgentToolName]: ToolMap[K]; };
386
+ readonly customRoles: RoleSource;
387
+ readonly store: ApprovalStore;
388
+ };
389
+ type AgentCall = {
390
+ /** `null` for a call with no authenticated user. */
391
+ readonly user: string | null;
392
+ readonly org: string;
393
+ readonly tool: AgentToolName;
394
+ readonly args: {
395
+ readonly id?: string;
396
+ };
397
+ };
398
+ type AgentOutcome = "granted" | "denied" | "approval-required";
399
+ type AgentMounted = {
400
+ /** Runs one tool call through the adapter's own entry and reports its outcome. */
401
+ readonly call: (call: AgentCall) => Promise<AgentOutcome>;
402
+ readonly close?: () => Promise<void> | void;
403
+ };
404
+ type AgentScenarioName = "granted" | "denied" | "cross-tenant" | "anonymous" | "subject-throws" | "loader-throws" | "missing-row" | "approval-required";
405
+ type AgentAdapterOptions = {
406
+ readonly name: string;
407
+ readonly mount: (domain: AgentScenarioDomain) => AgentMounted | Promise<AgentMounted>;
408
+ /** Scenarios the adapter cannot express, each with a reason. */
409
+ readonly skip?: Readonly<Partial<Record<AgentScenarioName, string>>>;
410
+ };
411
+ /**
412
+ * Runs the same tool calls through an agent adapter: a grant, the denials an
413
+ * attacker or an outage produces, and an approval. Every failure denies.
414
+ */
415
+ export declare function testAgentAdapter(options: AgentAdapterOptions): void;
416
+ //#endregion
417
+ //#region src/testing/authzen.d.ts
418
+ type Entity = {
419
+ readonly type: string;
420
+ readonly id?: string;
421
+ readonly properties?: Readonly<Record<string, unknown>>;
422
+ };
423
+ type AuthZenEvaluationVector = {
424
+ readonly request: {
425
+ readonly subject: Entity;
426
+ readonly action: {
427
+ readonly name: string;
428
+ };
429
+ readonly resource: Entity;
430
+ readonly context?: Readonly<Record<string, unknown>>;
431
+ };
432
+ readonly expected: boolean;
433
+ };
434
+ type AuthZenEvaluationsVector = {
435
+ readonly request: {
436
+ readonly subject?: Entity;
437
+ readonly action?: {
438
+ readonly name: string;
439
+ };
440
+ readonly resource?: Entity;
441
+ readonly evaluations: readonly {
442
+ readonly subject?: Entity;
443
+ readonly action?: {
444
+ readonly name: string;
445
+ };
446
+ readonly resource?: Entity;
447
+ }[];
448
+ };
449
+ readonly expected: readonly {
450
+ readonly decision: boolean;
451
+ }[];
452
+ };
453
+ type AuthZenSearchVector = {
454
+ readonly request: Readonly<Record<string, unknown>>;
455
+ readonly expected: {
456
+ readonly results: readonly Readonly<Record<string, unknown>>[];
457
+ };
458
+ };
459
+ /**
460
+ * Vectors in the layout of the OpenID AuthZEN interop harness
461
+ * (`decisions-*.json` for Basic and Batch, `search/{subject,resource,action}`
462
+ * `results.json` for Search), so the official files load unchanged.
463
+ */
464
+ type AuthZenVectors = {
465
+ readonly evaluation?: readonly AuthZenEvaluationVector[];
466
+ readonly evaluations?: readonly AuthZenEvaluationsVector[];
467
+ readonly search?: {
468
+ readonly subject?: readonly AuthZenSearchVector[];
469
+ readonly resource?: readonly AuthZenSearchVector[];
470
+ readonly action?: readonly AuthZenSearchVector[];
471
+ };
472
+ };
473
+ type TestAuthZenOptions = {
474
+ readonly vectors: AuthZenVectors;
475
+ /** Origin the requests are addressed to; the discovery document must name it. */
476
+ readonly origin?: string;
477
+ readonly headers?: Readonly<Record<string, string>>;
478
+ /** Check `/.well-known/authzen-configuration`; on by default. */
479
+ readonly discovery?: boolean;
480
+ };
481
+ /** Runs AuthZEN 1.0 interop vectors against an Authorization API endpoint. */
482
+ export declare function testAuthZen(handle: (request: Request) => Promise<Response>, options: TestAuthZenOptions): void;
483
+ type TodoUser = {
484
+ readonly id: string;
485
+ readonly identity: string;
486
+ readonly roles: readonly ("admin" | "editor" | "viewer" | "evil_genius")[];
487
+ };
488
+ /** The AuthZEN interop Todo directory: each user is addressable by email or by identity. */
489
+ export declare const authzenTodoUsers: readonly TodoUser[];
490
+ type AuthzenTodoDefinition = {
491
+ readonly user: ResourceInit<unknown, readonly ["can_read_user"], readonly []>;
492
+ readonly todo: ResourceInit<unknown, readonly ["can_read_todos", "can_create_todo", "can_update_todo", "can_delete_todo"], readonly []>;
493
+ };
494
+ export declare const authzenTodoPermissions: InferPermissionTree<AuthzenTodoDefinition>;
495
+ /** The interop Todo rules: viewers read, editors write their own, admins delete and evil geniuses update anything. */
496
+ export declare const authzenTodoPolicy: Policy;
497
+ /** Rows for `resources.todo.list` and records for `subjects.list` in the Todo domain. */
498
+ export declare const authzenTodoData: {
499
+ readonly todos: readonly {
500
+ readonly id: string;
501
+ readonly ownerID: string;
502
+ }[];
503
+ readonly users: readonly {
504
+ readonly id: string;
505
+ }[];
506
+ };
507
+ /**
508
+ * PermDock's vectors over the interop Todo domain, in the interop layout:
509
+ * every user against every action on their own and on Rick's todo, one batch
510
+ * per user, and the three searches.
511
+ */
512
+ export declare function authzenTodoVectors(): AuthZenVectors;
513
+ //#endregion
514
+ //#region src/testing/conformance.d.ts
515
+ export declare function testSubjectResolver<TInput>(resolver: SubjectResolver<TInput>, options: {
516
+ readonly invalid: TInput;
517
+ }): void;
518
+ export declare function testMembershipSource(source: MembershipSource, options: {
519
+ readonly principals: readonly {
520
+ readonly id: string;
521
+ readonly kind?: string;
522
+ }[];
523
+ readonly expect?: Record<string, readonly Membership[]>;
524
+ /** With the policy, every membership must name one of its scopes and carry its parent ids. */
525
+ readonly policy?: Policy;
526
+ /** Passed to every `membershipsFor`; a source keyed by tenant answers nothing without one. */
527
+ readonly tenant?: string;
528
+ }): void;
529
+ /**
530
+ * A `RelationSource` answers facts only: well-formed chains nearest first and
531
+ * no longer than `depth`, holders with principal ids or group references and
532
+ * numeric instants, a `truncated` chain only when more ancestors exist, and
533
+ * empty answers (never a throw) for an object it does not know. `expect` pins
534
+ * the chains, holders and links for `objects`, keyed `resource:id`,
535
+ * `resource:id#relation` and `resource:id>link`; a group holder is written
536
+ * `resource:id#relation`.
537
+ */
538
+ export declare function testRelationSource(source: RelationSource, options: {
539
+ readonly objects: readonly {
540
+ readonly resource: string;
541
+ readonly id: string;
542
+ readonly relation?: string;
543
+ }[];
544
+ readonly expect?: {
545
+ readonly ancestors?: Readonly<Record<string, readonly string[]>>;
546
+ readonly holders?: Readonly<Record<string, readonly string[]>>;
547
+ /** Keyed `resource:id>link`, the id the link leads to. */
548
+ readonly links?: Readonly<Record<string, string>>;
549
+ };
550
+ }): void;
551
+ export declare function testEntitlementSource(source: EntitlementSource, options: {
552
+ readonly principal: {
553
+ readonly id: string;
554
+ };
555
+ readonly tenant: string;
556
+ readonly expect?: readonly string[];
557
+ }): void;
558
+ export declare function testRoleSource(source: RoleSource, options: {
559
+ readonly tenant: string;
560
+ readonly declared: readonly (string | Role)[];
561
+ /** When set, every custom role's `grants` must resolve inside the ceiling. */
562
+ readonly policy?: Policy;
563
+ /**
564
+ * Names of every custom role the tenant has. When set, `rolesFor` must
565
+ * return each of them with nothing held, as role management needs.
566
+ */
567
+ readonly every?: readonly string[];
568
+ }): void;
569
+ export declare function testLimitStore(store: LimitStore): void;
570
+ export declare function testDecisionSink(sink: DecisionSink): void;
571
+ export declare function testSnapshotSource(source: SnapshotSource): void;
572
+ export declare function testPolicySource(source: PolicySource, options?: {
573
+ readonly policy?: Policy;
574
+ }): void;
575
+ export declare function testReplayStore(store: ReplayStore): void;
576
+ export declare function testRevocationFeed(feed: RevocationFeed): void;
577
+ export declare function testDirectoryStore(store: DirectoryStore, options: {
578
+ readonly tenants: readonly [string, string];
579
+ }): void;
580
+ type ApprovalStoreOptions = {
581
+ /**
582
+ * Opens a second store over the same backing storage, as a restarted process
583
+ * would. Omit it for stores that do not persist (the resume-after-restart
584
+ * case is then skipped).
585
+ */
586
+ readonly reopen?: () => ApprovalStore | Promise<ApprovalStore>;
587
+ };
588
+ export declare function testApprovalStore(store: ApprovalStore, options?: ApprovalStoreOptions): void;
589
+ export declare function testTokenVerifier(verifier: TokenVerifier, options?: {
590
+ readonly audience?: string;
591
+ readonly issuer?: string;
592
+ }): void;
593
+ /** Settings for `tenant`, or `undefined`; a thrown source fails the runner. */
594
+ export declare function testSettingsSource(source: SettingsSource, options: {
595
+ readonly tenant: string;
596
+ readonly unknown?: string;
597
+ }): void;
598
+ /**
599
+ * Checks an `ApprovalPolicySource`: entries are plain JSON, belong to the
600
+ * queried tenant or to none, and every entry loads against `policy` (an
601
+ * entry that does not would deny every call).
602
+ */
603
+ export declare function testApprovalPolicySource(source: ApprovalPolicySource, options: {
604
+ readonly policy: Policy;
605
+ readonly tenant: string;
606
+ readonly unknown?: string;
607
+ }): void;
608
+ /**
609
+ * `key` is a live key the verifier knows, or a function issuing one (called
610
+ * once). `revoke`, when given, revokes it; the runner then expects the key
611
+ * to stop verifying.
612
+ */
613
+ export declare function testCredentialVerifier(verifier: CredentialVerifier, options: {
614
+ readonly key: string | (() => string | Promise<string>);
615
+ readonly revoke?: () => void | Promise<void>;
616
+ }): void;
617
+ export declare function testTokenSigner(signer: TokenSigner, options: {
618
+ readonly verifier: TokenVerifier;
619
+ }): void;
620
+ type WhereRow = Readonly<Record<string, unknown>>;
621
+ /**
622
+ * `matches` answers whether the compiled output selects `row`, for example
623
+ * by running it against a table holding only that row. With it, every case
624
+ * must select the rows the in-memory evaluator keeps, including rows whose
625
+ * fields are NULL.
626
+ */
627
+ export declare function testWhereCompiler<TTarget>(compiler: WhereCompiler<TTarget>, options: {
628
+ readonly target: TTarget;
629
+ readonly isFailClosed?: (compiled: unknown) => boolean;
630
+ readonly matches?: (compiled: unknown, row: WhereRow) => boolean | Promise<boolean>;
631
+ }): void;
632
+ //#endregion
633
+ //#region src/testing/jwt-fixtures.d.ts
634
+ export declare const jwtFixtureJwks: {
635
+ readonly keys: readonly [{
636
+ readonly crv: "Ed25519";
637
+ readonly x: "79ab4WR6Eb9LkefWpmh5ZlvjXg7wqVGNMwIEHQqduIQ";
638
+ readonly kty: "OKP";
639
+ readonly kid: "2026-09";
640
+ readonly alg: "Ed25519";
641
+ readonly use: "sig";
642
+ }];
643
+ };
644
+ export declare const jwtFixtureIssuer: "https://login.example.com";
645
+ export declare const jwtFixtureAudience: "https://api.example.com";
646
+ export declare const jwtFixtureTokens: {
647
+ readonly valid: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6ImF0K2p3dCJ9.eyJzdWIiOiJ1XzEiLCJjbGllbnRfaWQiOiJhcHAiLCJyb2xlcyI6WyJtZW1iZXIiXSwianRpIjoianRpLXZhbGlkIiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiaWF0IjoxNzAwMDAwMDAwLCJleHAiOjIwMDAwMDAwMDB9.ENFMmLSyVde-2s4Gdz4iP7srZvU0Xuy_ZLz-OJGHD_-W1lEayEBeSPTnab0L_TBdj8p5BmkFrT-7VE7o20GbAw";
648
+ readonly expired: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6ImF0K2p3dCJ9.eyJzdWIiOiJ1XzEiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJpYXQiOjEwMDAwMDAwMDAsImV4cCI6MTEwMDAwMDAwMH0.9X3d6kH3_2nmrbqMxuoxzFW-wsWJVCe-lR-aQ-MmsGGXlEUBMgQ-4MtAq1UR9lLE0h2b5JrE_GfjzuC04h5xCg";
649
+ readonly wrongAud: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6ImF0K2p3dCJ9.eyJzdWIiOiJ1XzEiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9vdGhlci5leGFtcGxlLmNvbSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoyMDAwMDAwMDAwfQ.PgWdzi56J31OwoMqH4ysHzVKSKUDhi-AtHFUp1ewFzi-qGE-tknzrNKnKhDOncVzj0okb_flyy3vQgfzJwG5AQ";
650
+ readonly wrongIss: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6ImF0K2p3dCJ9.eyJzdWIiOiJ1XzEiLCJpc3MiOiJodHRwczovL2V2aWwuZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoyMDAwMDAwMDAwfQ.tIcLHLa9JLtKz1gqjRGdr5DFbUzRDs5KsoPsJCxspvbBcsFfRFG2G0XJnd1h4QHyZ_5B4OhY3W_jIIsnOPD9Bg";
651
+ readonly unknownKid: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoibm9wZSIsInR5cCI6ImF0K2p3dCJ9.eyJzdWIiOiJ1XzEiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MjAwMDAwMDAwMH0.walgG5GvpCVBnkMtkdw-epi5c93JqfvAM_N4EWR9Tqhiw_cnzITnlQyoVfihECmV1fqtFrhwM1RCIRJvd38zAQ";
652
+ readonly none: "eyJhbGciOiJub25lIn0.eyJzdWIiOiJ1XzEiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJleHAiOjIwMDAwMDAwMDAsImlhdCI6MTcwMDAwMDAwMH0.";
653
+ readonly snapshot: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6InBlcm1kb2NrLXNuYXBzaG90K2p3dCJ9.eyJzbmFwc2hvdCI6eyJ2IjoyLCJpc3N1ZWRBdCI6MTcwMDAwMDAwMCwic3ViamVjdCI6eyJwcmluY2lwYWwiOnsiaWQiOiJ1XzEiLCJyb2xlcyI6WyJtZW1iZXIiXX0sImNvbnRleHQiOnt9fSwicm9sZXMiOlsibWVtYmVyIl0sImdyYW50cyI6W10sInRlbmFudHMiOltdfSwic3ViIjoidV8xIiwiaXNzIjoiaHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwczovL2FwcC5leGFtcGxlLmNvbSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoyMDAwMDAwMDAwLCJqdGkiOiJzbmFwX2ZpeHR1cmUifQ.4itaYctluoCwU-syytUxArtS_FRyNAti2SZxuSH-nKIMr7-Sb3h1Q3xugn_vPR1eupV4fVNIe6dH27_EiyDvCA";
654
+ readonly approval: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6InBlcm1kb2NrLWFwcHJvdmFsK2p3dCJ9.eyJhcHByb3ZhbCI6eyJ0b2tlbiI6InBkMS5hYmMiLCJwZXJtaXNzaW9uIjoicG9zdC5kZWxldGUiLCJyZXNvdXJjZSI6eyJ0eXBlIjoicG9zdCIsImlkIjoiNDIifSwic3RhdHVzIjoiYXBwcm92ZWQifSwic3ViIjoidV8xIiwiaXNzIjoiaHR0cHM6Ly9hcHAuZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwczovL2FwcC5leGFtcGxlLmNvbSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoyMDAwMDAwMDAwLCJqdGkiOiJhcHJfZml4dHVyZSJ9.UHsoSzQCo68G7ee-EFqdzMLvmqaKlFIMdQKFuqZEM4yUQnJsJJTXbld_aCXcyfN-IdjF9cj2F5EHzsV4nLKbBg";
655
+ readonly decisions: "eyJhbGciOiJFZDI1NTE5Iiwia2lkIjoiMjAyNi0wOSIsInR5cCI6InBlcm1kb2NrLWRlY2lzaW9ucytqd3QifQ.eyJldmVudHMiOltdLCJpc3MiOiJodHRwczovL2FwcC5leGFtcGxlLmNvbSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoyMDAwMDAwMDAwLCJqdGkiOiJkZWNfZml4dHVyZSJ9.UZhJd72yFGxHOdjYbzcGYUPgYjvLwOPCtHKxEbLu56SdKSKUDCREXmEBI9WaCPKWjlTBnnIKMYwjG8I8RATJCg";
656
+ };
657
+ //#endregion
658
+ //#region src/testing/supabase-fixtures.d.ts
659
+ /**
660
+ * Claim sets in the shape the Supabase custom access token hook produces (the RBAC guide's
661
+ * `user_role` claim, optionally mirrored into `app_metadata`, plus a `memberships` array for
662
+ * multi-org apps). `tenantPlans` has scoped memberships, `tenant_id` and per-tenant plans in
663
+ * `features`, read with `plans: 'features'`. `full` sets every field of the
664
+ * claim contract plus a `hook.claims` extra claim; `portalContact`, `oauthClient` and
665
+ * `actChain` cover a customer contact, a Supabase OAuth server token and an RFC 8693 chain.
666
+ * `supportSession`, `supportSessionReadOnly` and `impersonation` are the `act.kind` tokens
667
+ * of a support tool; `anonymousSignIn` is a `signInAnonymously()` token read with
668
+ * `anonymousSignIns: 'deny'`. Every fixture passes `supabaseClaims()` and
669
+ * `schemas/supabase-claims-v1.json`. Plain data: no Supabase types.
670
+ */
671
+ type SupabaseClaimFixture = {
672
+ readonly claims: Readonly<Record<string, unknown>>;
673
+ /** `subjectFromSupabase` options the case needs. */
674
+ readonly options?: {
675
+ readonly plans?: string;
676
+ readonly anonymousSignIns?: "deny";
677
+ };
678
+ readonly expect: {
679
+ readonly id: string | null;
680
+ readonly roles: readonly string[];
681
+ readonly memberships: readonly {
682
+ readonly tenant?: string;
683
+ readonly scope?: string;
684
+ readonly id?: string;
685
+ readonly within?: Readonly<Record<string, string>>;
686
+ readonly on?: {
687
+ readonly resource: string;
688
+ readonly id: string;
689
+ };
690
+ readonly roles: readonly string[];
691
+ readonly via?: string;
692
+ readonly expiresAt?: number;
693
+ readonly grantedBy?: string;
694
+ readonly reason?: string;
695
+ readonly managedBy?: "idp";
696
+ readonly entitlements?: readonly string[];
697
+ }[];
698
+ readonly tenant?: string;
699
+ readonly plans?: readonly string[];
700
+ /** `subject.actor`, absent when the token has neither `act` nor `client_id`. */
701
+ readonly actor?: {
702
+ readonly id: string;
703
+ readonly kind: "oauth-client" | "impersonation";
704
+ } | {
705
+ readonly id: string;
706
+ readonly kind: "support";
707
+ readonly sessionId: string;
708
+ readonly readOnly: boolean;
709
+ };
710
+ /** `subject.delegation`: the `scope` claim and the `act` chain of an `oauth-client` actor. */
711
+ readonly delegation?: {
712
+ readonly scopes?: readonly string[];
713
+ readonly chain?: Readonly<Record<string, unknown>>;
714
+ };
715
+ };
716
+ };
717
+ type SupabaseClaimFixtureName = "topLevelRole" | "appMetadataRole" | "nullTopLevelFallsBack" | "arrayRoles" | "missingRole" | "nullRole" | "userMetadataIgnored" | "multiOrg" | "tenantPlans" | "full" | "portalContact" | "oauthClient" | "actChain" | "supportSession" | "supportSessionReadOnly" | "impersonation" | "anonymousSignIn" | "anon" | "serviceRole";
718
+ export declare const supabaseClaimFixtures: Readonly<Record<SupabaseClaimFixtureName, SupabaseClaimFixture>>;
719
+ /**
720
+ * `supabaseClaimFixtures` as a `supabase/sdk` conformance vector file
721
+ * (`schema/conformance.schema.json`): each case's `input` is a verified
722
+ * `getClaims()` payload and the `subjectFromSupabase` options, `expected` the
723
+ * subject fields it maps to. `JSON.stringify` it for a port in another language.
724
+ */
725
+ type SupabaseClaimVectors = {
726
+ readonly feature: "auth.session.get_claims";
727
+ readonly cases: readonly {
728
+ readonly name: string;
729
+ readonly input: {
730
+ readonly claims: SupabaseClaimFixture["claims"];
731
+ readonly options?: SupabaseClaimFixture["options"];
732
+ };
733
+ readonly expected: SupabaseClaimFixture["expect"];
734
+ }[];
735
+ };
736
+ export declare const supabaseClaimVectors: SupabaseClaimVectors;
737
+ /**
738
+ * The `permdock supabase inspect --json` manifest for a policy with one
739
+ * `tenant` scope, the default `supabase.hook` and a `features` claim from
740
+ * `public.feature_claims`. A package that reads the manifest tests its
741
+ * parser against this value.
742
+ */
743
+ export declare const supabaseHookManifestFixture: SupabaseHookManifest;
744
+ //#endregion
745
+ export { type AgentAdapterOptions, type AgentCall, type AgentMounted, type AgentOutcome, type AgentScenarioDomain, type AgentScenarioName, type AgentToolName, type ApprovalStoreOptions, type AuthZenEvaluationVector, type AuthZenEvaluationsVector, type AuthZenSearchVector, type AuthZenVectors, type ClientParityCase, type ClientParityOptions, type ClientStoreFactory, type ClientStoreFactoryOptions, type ClientStoreHandle, type ClientStorePermDock, type ClientStoreStatus, type DescribePolicyConfig, type HttpAdapterOptions, type HttpCall, type HttpMounted, type HttpOp, type HttpResult, type HttpScenarioDomain, type HttpScenarioName, type MatrixCell, type MatrixOutcome, type OrmParityCase, type OrmParityOptions, type OrmParityReport, type OrmParityRunInput, type OrmParityScenario, type RlsDbOutcome, type RlsFieldsOutcome, type RlsParityCase, type RlsParityFixture, type RlsParityOptions, type RlsParityReport, type RlsParitySubject, type RlsQueryFn, type RlsQueryResult, type SupabaseClaimFixture, type SupabaseClaimFixtureName, type SupabaseClaimVectors, type TestAuthZenOptions, expectTypeOf, supabaseMembershipsBudget };