permdock 0.0.0 → 0.1.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 (290) hide show
  1. package/README.md +268 -1
  2. package/dist/a2a/index.d.ts +178 -0
  3. package/dist/a2a/index.js +271 -0
  4. package/dist/ai-sdk/index.d.ts +74 -0
  5. package/dist/ai-sdk/index.js +137 -0
  6. package/dist/approval-required-TzNB9oQA.js +6 -0
  7. package/dist/approvals/index.d.ts +3 -0
  8. package/dist/approvals/index.js +4 -0
  9. package/dist/approvals-DaxY-Bdg.js +218 -0
  10. package/dist/approvers-aH0PJkmf.js +20 -0
  11. package/dist/arazzo-CTeVuXr5.js +70 -0
  12. package/dist/arazzo-aoTkqYsJ.js +54 -0
  13. package/dist/authzen/index.d.ts +48 -0
  14. package/dist/authzen/index.js +336 -0
  15. package/dist/better-auth/index.d.ts +92 -0
  16. package/dist/better-auth/index.js +324 -0
  17. package/dist/budget-JqcRqyhK.d.ts +11 -0
  18. package/dist/budget-NbEtbJC_.js +11 -0
  19. package/dist/capability-B68OFnZx.js +171 -0
  20. package/dist/capability-BDG_nkxt.d.ts +99 -0
  21. package/dist/catalog/index.d.ts +12 -0
  22. package/dist/catalog/index.js +2 -0
  23. package/dist/catalog-B0E6bggc.js +48 -0
  24. package/dist/catalog-H-vFGwWK.js +55 -0
  25. package/dist/catalog-doc-BSo_Q_-6.js +298 -0
  26. package/dist/catalog-idsHc0vo.js +2 -0
  27. package/dist/catalog-path-CnI0XTFK.js +12 -0
  28. package/dist/claude-agent/index.d.ts +81 -0
  29. package/dist/claude-agent/index.js +83 -0
  30. package/dist/clerk/index.d.ts +56 -0
  31. package/dist/clerk/index.js +280 -0
  32. package/dist/cli/bin.d.ts +1 -0
  33. package/dist/cli/bin.js +20 -0
  34. package/dist/cli/index.d.ts +46 -0
  35. package/dist/cli/index.js +5 -0
  36. package/dist/cloud/index.d.ts +91 -0
  37. package/dist/cloud/index.js +390 -0
  38. package/dist/cloud-BNQTrmrr.js +50 -0
  39. package/dist/cloud-Cuxr6Czw.js +117 -0
  40. package/dist/collect-B7_TIfmg.js +49 -0
  41. package/dist/collect-O-tOtbnk.js +350 -0
  42. package/dist/collect-fRPAQIWb.js +2 -0
  43. package/dist/commands-BMh_Etm2.js +93 -0
  44. package/dist/compact-y6vfu2_f.js +19 -0
  45. package/dist/compare-pfyVnBjE.js +12 -0
  46. package/dist/compile-CQbvyIBr.d.ts +30 -0
  47. package/dist/compile-D22iwvuV.js +558 -0
  48. package/dist/config-BPYmjTOp.js +26 -0
  49. package/dist/connection-JvqwHODC.js +194 -0
  50. package/dist/context-CKEAabd7.js +73 -0
  51. package/dist/context-gtAwAILx.js +6 -0
  52. package/dist/convex/index.d.ts +40 -0
  53. package/dist/convex/index.js +55 -0
  54. package/dist/create-BKF3dgFk.d.ts +162 -0
  55. package/dist/create-CSkhDU9T.js +222 -0
  56. package/dist/credential-B_rkUNlY.js +326 -0
  57. package/dist/credentials-BgRX3WEg.js +268 -0
  58. package/dist/describe-Bt1YD5uS.js +99 -0
  59. package/dist/describe-DernyItf.d.ts +37 -0
  60. package/dist/diff-BUzf5Poi.js +48 -0
  61. package/dist/diff-x5Il8LVa.js +418 -0
  62. package/dist/digest-B3kc_PgQ.d.ts +19 -0
  63. package/dist/digest-BI-6aa6d.js +27 -0
  64. package/dist/doctor-BGle8Gqi.js +1314 -0
  65. package/dist/doctor-Bqo6FwUa.js +53 -0
  66. package/dist/drizzle/index.d.ts +72 -0
  67. package/dist/drizzle/index.js +160 -0
  68. package/dist/duration-xK2jGFVc.js +25 -0
  69. package/dist/elysia/index.d.ts +71 -0
  70. package/dist/elysia/index.js +103 -0
  71. package/dist/errors-DSMnAVNa.js +43 -0
  72. package/dist/errors-DbZ1YOnb.d.ts +138 -0
  73. package/dist/errors-Iy71s7Oj.js +177 -0
  74. package/dist/errors-m3u9TmDu.js +27 -0
  75. package/dist/evaluations-DsAU9ppl.js +479 -0
  76. package/dist/eve/index.d.ts +95 -0
  77. package/dist/eve/index.js +181 -0
  78. package/dist/express/index.d.ts +46 -0
  79. package/dist/express/index.js +108 -0
  80. package/dist/fastify/index.d.ts +56 -0
  81. package/dist/fastify/index.js +141 -0
  82. package/dist/files-B_wAGYmt.js +121 -0
  83. package/dist/fixtures-Cvaw0gDG.js +64 -0
  84. package/dist/freeze-y1_jQL4v.js +31 -0
  85. package/dist/from-snapshot-BMGnhmgv.js +552 -0
  86. package/dist/generate-CH7ThJ14.js +173 -0
  87. package/dist/grantee-Bv04_Vzf.js +521 -0
  88. package/dist/headers-B5RRv3Xm.js +6 -0
  89. package/dist/headers-C8SHQccD.d.ts +6 -0
  90. package/dist/helpers-DnSOrhB9.js +682 -0
  91. package/dist/hono/index.d.ts +70 -0
  92. package/dist/hono/index.js +131 -0
  93. package/dist/hosted-BwKQ1BTA.js +265 -0
  94. package/dist/http-DPuDaChb.d.ts +13 -0
  95. package/dist/http-GgVApX1k.js +111 -0
  96. package/dist/index-CltcQ4Bf.d.ts +138 -0
  97. package/dist/index-LF_hS-yn.d.ts +177 -0
  98. package/dist/index-fG6NSXlc.d.ts +9 -0
  99. package/dist/index-xIxJLwOQ.d.ts +415 -0
  100. package/dist/index.d.ts +11 -0
  101. package/dist/index.js +21 -0
  102. package/dist/jwt/index.d.ts +87 -0
  103. package/dist/jwt/index.js +571 -0
  104. package/dist/kernel-YOGCWNLf.js +211 -0
  105. package/dist/kysely/index.d.ts +77 -0
  106. package/dist/kysely/index.js +129 -0
  107. package/dist/load-BZ24CpZP.js +69 -0
  108. package/dist/load-QOOm1z70.js +2 -0
  109. package/dist/load-jose-BL6LH4bL.js +11 -0
  110. package/dist/lru-8q4WZjBV.js +28 -0
  111. package/dist/manifest-DDQbC6K0.d.ts +118 -0
  112. package/dist/map-DowSO96j.js +158 -0
  113. package/dist/map-claims-B_6I1Rn-.js +360 -0
  114. package/dist/map-error-RJ3ZsUyA.js +16 -0
  115. package/dist/markers-B0hYLvMD.js +60 -0
  116. package/dist/may-use-CnFEjVEp.js +37 -0
  117. package/dist/mcp/index.d.ts +127 -0
  118. package/dist/mcp/index.js +563 -0
  119. package/dist/nest/index.d.ts +80 -0
  120. package/dist/nest/index.js +270 -0
  121. package/dist/next/client.d.ts +24 -0
  122. package/dist/next/client.js +31 -0
  123. package/dist/next/index.d.ts +110 -0
  124. package/dist/next/index.js +195 -0
  125. package/dist/next/plugin.d.ts +14 -0
  126. package/dist/next/plugin.js +2 -0
  127. package/dist/node/index.d.ts +43 -0
  128. package/dist/node/index.js +66 -0
  129. package/dist/openai/index.d.ts +71 -0
  130. package/dist/openai/index.js +105 -0
  131. package/dist/openapi/index.d.ts +93 -0
  132. package/dist/openapi/index.js +3 -0
  133. package/dist/openapi-CwePaF7C.js +164 -0
  134. package/dist/openapi-DWD0Uc_4.js +250 -0
  135. package/dist/openapi-DcqM8nU7.js +306 -0
  136. package/dist/openapi-import-BWRUNNeW.js +5959 -0
  137. package/dist/openapi-schema-D8j_T9tO.js +6902 -0
  138. package/dist/orpc/index.d.ts +64 -0
  139. package/dist/orpc/index.js +188 -0
  140. package/dist/otel/index.d.ts +13 -0
  141. package/dist/otel/index.js +202 -0
  142. package/dist/package-root-zGkxO3oN.js +30 -0
  143. package/dist/parse-DPfIvFMU.js +135 -0
  144. package/dist/pdp/index.d.ts +22 -0
  145. package/dist/pdp/index.js +795 -0
  146. package/dist/peer-BOr_kJE1.js +31 -0
  147. package/dist/permdock-yoZ7EjxX.js +2956 -0
  148. package/dist/permissions-B4apnahQ.d.ts +185 -0
  149. package/dist/permissions-B8vCg_bI.d.ts +52 -0
  150. package/dist/permissions-CofRqesP.js +142 -0
  151. package/dist/permissions-DC7GROPA.js +600 -0
  152. package/dist/pg-4GJWDUxG.js +953 -0
  153. package/dist/pins-CqE1jZuF.js +12 -0
  154. package/dist/plugin-4gr7IxFJ.js +65 -0
  155. package/dist/policy-ANp36PnI.js +971 -0
  156. package/dist/policy-CInmNGkM.d.ts +1959 -0
  157. package/dist/policy-Cq2fB8Q5.d.ts +20 -0
  158. package/dist/prisma/index.d.ts +135 -0
  159. package/dist/prisma/index.js +430 -0
  160. package/dist/problem-Cgp9-KZA.js +226 -0
  161. package/dist/prompt-CXYhLfsS.js +32 -0
  162. package/dist/protected-B4K3BKoX.js +138 -0
  163. package/dist/protected-BuPAycJT.d.ts +26 -0
  164. package/dist/protected-wY7nXhY9.d.ts +23 -0
  165. package/dist/provider-_wx46HpB.js +48 -0
  166. package/dist/provider-wTAUda2v.d.ts +6 -0
  167. package/dist/react/index.d.ts +6 -0
  168. package/dist/react/index.js +6 -0
  169. package/dist/react/provider-client.d.ts +2 -0
  170. package/dist/react/provider-client.js +3 -0
  171. package/dist/react-native/index.d.ts +42 -0
  172. package/dist/react-native/index.js +174 -0
  173. package/dist/refs-ChLSxbST.js +90 -0
  174. package/dist/relations-r4soIFZB.js +426 -0
  175. package/dist/revocations-Cy06JNx2.d.ts +21 -0
  176. package/dist/rls-BOFU3chG.js +233 -0
  177. package/dist/rls-CJVja9Ww.js +2119 -0
  178. package/dist/rls-graph-DxQ39PJj.js +371 -0
  179. package/dist/rls-helpers-BxRuif0l.js +1346 -0
  180. package/dist/rls-import-CXV6LBlS.js +942 -0
  181. package/dist/rls-migrate-DrFPbf8p.js +366 -0
  182. package/dist/row-check-BajTgQZ-.d.ts +43 -0
  183. package/dist/run-CJ6UvS3a.js +155 -0
  184. package/dist/runtime-DP9ttFh1.js +27 -0
  185. package/dist/saas-BRrZzJkM.js +1193 -0
  186. package/dist/schema-P8yoma__.js +296 -0
  187. package/dist/scim/index.d.ts +2 -0
  188. package/dist/scim/index.js +2 -0
  189. package/dist/scim-9NFa0XVZ.js +1445 -0
  190. package/dist/scopes-cKVp_WTw.js +212 -0
  191. package/dist/server/index.d.ts +123 -0
  192. package/dist/server/index.js +8 -0
  193. package/dist/sha256-BO0swRXL.js +150 -0
  194. package/dist/sink-Bd9PSyfq.js +141 -0
  195. package/dist/sink-Cfr9-7YC.d.ts +104 -0
  196. package/dist/skills-C_lpV4Jx.js +50 -0
  197. package/dist/skills-Dx3QLnMY.js +110 -0
  198. package/dist/snapshot-DE8dE_hz.js +1051 -0
  199. package/dist/solid/index.d.ts +63 -0
  200. package/dist/solid/index.js +197 -0
  201. package/dist/source-DoBBYJi2.js +6 -0
  202. package/dist/sources-DOpW5Ila.d.ts +347 -0
  203. package/dist/sources-DVHM3Mwq.js +284 -0
  204. package/dist/sql-Bll1d7y0.js +22 -0
  205. package/dist/src-CTNT-PBW.js +430 -0
  206. package/dist/ssf/index.d.ts +3 -0
  207. package/dist/ssf/index.js +622 -0
  208. package/dist/store-Bq90395i.d.ts +27 -0
  209. package/dist/store-C6hFW6ta.js +508 -0
  210. package/dist/stores-CkG2HrSg.js +140 -0
  211. package/dist/stores-CvOnu_2T.d.ts +41 -0
  212. package/dist/stream-BhMfZOwr.d.ts +12 -0
  213. package/dist/stream-Q_xlB6Ko.js +52 -0
  214. package/dist/style-CTm1AXDT.js +22 -0
  215. package/dist/subject-C6dLxqHU.js +24 -0
  216. package/dist/subject-settings-xt7V845g.js +82 -0
  217. package/dist/supabase/index.d.ts +67 -0
  218. package/dist/supabase/index.js +4 -0
  219. package/dist/supabase/middleware.d.ts +77 -0
  220. package/dist/supabase/middleware.js +68 -0
  221. package/dist/supabase-D8UlBA7Z.js +83 -0
  222. package/dist/supabase-DTxGtYdi.js +796 -0
  223. package/dist/supabase-hook-DW-xP4hU.js +2 -0
  224. package/dist/supabase-hook-D_OqGb_V.js +1528 -0
  225. package/dist/svelte/Protected.svelte +34 -0
  226. package/dist/svelte/index.d.ts +10 -0
  227. package/dist/svelte/index.js +53 -0
  228. package/dist/svelte/runtime.d.ts +6 -0
  229. package/dist/svelte/runtime.js +3 -0
  230. package/dist/svelte/source.d.ts +10 -0
  231. package/dist/svelte/source.js +8 -0
  232. package/dist/terminal/index.d.ts +171 -0
  233. package/dist/terminal/index.js +821 -0
  234. package/dist/testing/index.d.ts +656 -0
  235. package/dist/testing/index.js +3208 -0
  236. package/dist/testing/saas/index.d.ts +194 -0
  237. package/dist/testing/saas/index.js +3 -0
  238. package/dist/testing/saas/permissions.d.ts +2 -0
  239. package/dist/testing/saas/permissions.js +2 -0
  240. package/dist/text-diff-BdkkYSbi.js +15 -0
  241. package/dist/thenable-okc2xDsj.js +10 -0
  242. package/dist/timeout-D51niuQP.js +8 -0
  243. package/dist/trpc/index.d.ts +80 -0
  244. package/dist/trpc/index.js +205 -0
  245. package/dist/types-B8w5PFtS.d.ts +141 -0
  246. package/dist/types-B9dmiiab.d.ts +66 -0
  247. package/dist/types-BBK-exvJ.d.ts +177 -0
  248. package/dist/types-BvBk1wgn.d.ts +118 -0
  249. package/dist/types-CxquUByI.d.ts +9 -0
  250. package/dist/types-D6Z6-rKJ.d.ts +312 -0
  251. package/dist/types-DbWdEfcm.d.ts +87 -0
  252. package/dist/types-bva3i4Gf.d.ts +98 -0
  253. package/dist/types-i4BAOvdb.d.ts +97 -0
  254. package/dist/unplugin/index.d.ts +7 -0
  255. package/dist/unplugin/index.js +30 -0
  256. package/dist/usage-1ozMubLY.js +42 -0
  257. package/dist/usage-CUnK6Ou9.js +530 -0
  258. package/dist/usage-PyEor6GA.js +2 -0
  259. package/dist/validity-D0uRmJKJ.js +224 -0
  260. package/dist/verifier-B90agnhl.js +461 -0
  261. package/dist/version-CnSh33Fj.js +16 -0
  262. package/dist/vocabulary-Dk0fs-Jk.d.ts +56 -0
  263. package/dist/vue/index.d.ts +57 -0
  264. package/dist/vue/index.js +203 -0
  265. package/dist/webmcp/index.d.ts +75 -0
  266. package/dist/webmcp/index.js +313 -0
  267. package/package.json +423 -4
  268. package/rulesets/permdock.yaml +29 -0
  269. package/schemas/catalog-v1.json +507 -0
  270. package/schemas/openapi/oas-3.1.json +1298 -0
  271. package/schemas/openapi/oas-3.2.json +1516 -0
  272. package/schemas/openapi/overlay-1.1.json +79 -0
  273. package/schemas/supabase-claims-v1.json +139 -0
  274. package/schemas/supabase-manifest-v1.json +217 -0
  275. package/skills/permdock/SKILL.md +66 -0
  276. package/skills/permdock-agents/SKILL.md +77 -0
  277. package/skills/permdock-agents/references/runtimes.md +211 -0
  278. package/skills/permdock-approvals/SKILL.md +80 -0
  279. package/skills/permdock-approvals/references/stores-and-resume.md +83 -0
  280. package/skills/permdock-audit/SKILL.md +67 -0
  281. package/skills/permdock-credentials/SKILL.md +55 -0
  282. package/skills/permdock-credentials/references/tokens-keys-links.md +127 -0
  283. package/skills/permdock-data/SKILL.md +57 -0
  284. package/skills/permdock-data/references/queries-and-rls.md +54 -0
  285. package/skills/permdock-data/references/relationships.md +65 -0
  286. package/skills/permdock-tenancy/SKILL.md +77 -0
  287. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +83 -0
  288. package/skills/permdock-wire/SKILL.md +116 -0
  289. package/skills/permdock-wire/references/adapters.md +480 -0
  290. package/skills/permdock-wire/references/policy-options.md +43 -0
@@ -0,0 +1,224 @@
1
+ import { n as freezeDeep } from "./freeze-y1_jQL4v.js";
2
+ import { C as ownGet, S as isForbiddenKey, d as isFieldRelation, w as ownKeys } from "./permissions-DC7GROPA.js";
3
+ import { a as resolveScope, c as scopeChain, f as tenantOf, l as scopeIdOf, r as findScope, s as rootScope, t as activeFor } from "./scopes-cKVp_WTw.js";
4
+ //#region src/core/fields.ts
5
+ function sanitizeFields(fields) {
6
+ if (fields === void 0) return;
7
+ return fields.filter((field) => field.length > 0 && !isForbiddenKey(field));
8
+ }
9
+ function grantCoversField(fields, field, effect) {
10
+ if (fields === void 0) return true;
11
+ if (fields.length === 0) return false;
12
+ if (field === void 0) return effect === "allow";
13
+ return fields.includes(field);
14
+ }
15
+ function pickVisible(row, canField) {
16
+ const out = {};
17
+ for (const key of ownKeys(row)) if (canField(key)) out[key] = ownGet(row, key);
18
+ return freezeDeep(out);
19
+ }
20
+ function sanitizeContext(value) {
21
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
22
+ const out = {};
23
+ for (const key of ownKeys(value)) out[key] = ownGet(value, key);
24
+ return out;
25
+ }
26
+ //#endregion
27
+ //#region src/core/tenancy.ts
28
+ function nowSeconds(now) {
29
+ return now ?? Date.now() / 1e3;
30
+ }
31
+ function isMembershipExpired(membership, now) {
32
+ return membership.expiresAt !== void 0 && membership.expiresAt <= (now ?? nowSeconds());
33
+ }
34
+ /** The instances of the first scope the subject holds a live membership in. */
35
+ function tenantsOf(principal, scopes, now) {
36
+ if (principal === null) return [];
37
+ const tenants = /* @__PURE__ */ new Set();
38
+ for (const membership of principal.memberships ?? []) {
39
+ if (isMembershipExpired(membership, now)) continue;
40
+ const tenant = tenantOf(membership, scopes);
41
+ if (tenant !== void 0) tenants.add(tenant);
42
+ }
43
+ return [...tenants];
44
+ }
45
+ /** `requested` when a live membership sits in that instance of the first scope; never a default. */
46
+ function resolveActiveTenant(principal, requested, scopes, now) {
47
+ if (requested === void 0) return principal.tenant;
48
+ return (principal.memberships ?? []).some((membership) => !isMembershipExpired(membership, now) && tenantOf(membership, scopes) === requested) ? requested : void 0;
49
+ }
50
+ /** `permdock.team(id)`: only memberships inside that instance of the second scope. */
51
+ function inTeam(membership, scopes, team) {
52
+ if (team === void 0) return true;
53
+ const second = scopes[1]?.name;
54
+ return second !== void 0 && scopeIdOf(membership, second) === team;
55
+ }
56
+ /**
57
+ * Whether `resource` declares a `memberOf` relation to `scope` on `field`:
58
+ * its rows are partitioned by that scope, so a row without the field matches
59
+ * no membership.
60
+ */
61
+ function relatesTo(resource, field, scope, scopes) {
62
+ if (resource === void 0) return false;
63
+ return Object.values(resource.relations).some((relation) => isFieldRelation(relation) && relation.field === field && relation.memberOf !== void 0 && resolveScope(scopes, relation.memberOf) === scope);
64
+ }
65
+ /** The scopes whose key partitions `resource`, from its `memberOf` relations. */
66
+ function partitionsOf(resource, scopes) {
67
+ return scopes.filter((scope) => scope.key !== void 0 && relatesTo(resource, scope.key, scope.name, scopes)).map((scope) => scope.name);
68
+ }
69
+ /**
70
+ * Whether `row` lies inside a named membership's instance: for the scope and
71
+ * each ancestor, outermost first, a row that carries the scope's key (or whose
72
+ * resource declares it) must hold the membership's id for it. There is no
73
+ * cascade: the membership's own scope is checked, never a scope below it.
74
+ */
75
+ function rowInScope(membership, scopes, row, partitioned) {
76
+ if (membership.scope === void 0 || row === null || typeof row !== "object") return { ok: true };
77
+ const root = rootScope(scopes);
78
+ const chain = scopeChain(scopes, membership.scope).toReversed();
79
+ for (const name of chain) {
80
+ const key = findScope(scopes, name)?.key;
81
+ if (key === void 0) continue;
82
+ const value = Object.hasOwn(row, key) ? row[key] : void 0;
83
+ if ((value !== void 0 || partitioned(name, key)) && value !== scopeIdOf(membership, name)) return {
84
+ ok: false,
85
+ reason: name === root ? "tenant-mismatch" : "scope"
86
+ };
87
+ }
88
+ return { ok: true };
89
+ }
90
+ function matchScopedMembership(subject, scope, roleName, row, scopes, resource, resources, now, rolesOf = (membership) => membership.roles, team, walk) {
91
+ if (scope === "global") return { ok: true };
92
+ const principal = subject.principal;
93
+ if (principal === null) return {
94
+ ok: false,
95
+ reason: "no-membership"
96
+ };
97
+ const memberships = principal.memberships ?? [];
98
+ const root = rootScope(scopes);
99
+ let sawExpired = false;
100
+ let sawWrongScope = false;
101
+ let sawTenantMismatch = false;
102
+ let sawGraph;
103
+ for (const membership of memberships) {
104
+ if (!rolesOf(membership).includes(roleName)) continue;
105
+ if (isMembershipExpired(membership, now)) {
106
+ sawExpired = true;
107
+ continue;
108
+ }
109
+ if (typeof scope === "string") {
110
+ if (findScope(scopes, scope) === void 0 || membership.scope !== scope || !inTeam(membership, scopes, team) || !activeFor(membership, scopes, principal.tenant)) continue;
111
+ const inside = rowInScope(membership, scopes, row, (name, key) => relatesTo(resource, key, name, scopes));
112
+ if (!inside.ok) {
113
+ if (inside.reason === "tenant-mismatch") sawTenantMismatch = true;
114
+ else sawWrongScope = true;
115
+ continue;
116
+ }
117
+ return {
118
+ ok: true,
119
+ membership
120
+ };
121
+ }
122
+ if (membership.on === void 0) continue;
123
+ if (matchResourceMembership(membership, scope.resource, row, resource, resources)) return {
124
+ ok: true,
125
+ membership
126
+ };
127
+ const walked = walk !== void 0 && (membership.on.resource === scope.resource || membershipField(resources.get(scope.resource), membership.on.resource, resources) !== void 0) ? walk(membership, row) : false;
128
+ if (walked === true) return {
129
+ ok: true,
130
+ membership
131
+ };
132
+ if (walked !== false) sawGraph ??= walked;
133
+ sawWrongScope = true;
134
+ }
135
+ if (sawGraph !== void 0) return {
136
+ ok: false,
137
+ reason: sawGraph
138
+ };
139
+ if (scope === root && principal.tenant !== void 0 && !memberships.some((membership) => tenantOf(membership, scopes) === principal.tenant && !isMembershipExpired(membership, now))) return {
140
+ ok: false,
141
+ reason: "no-membership"
142
+ };
143
+ if (sawTenantMismatch) return {
144
+ ok: false,
145
+ reason: "tenant-mismatch"
146
+ };
147
+ if (sawExpired && !sawWrongScope) return {
148
+ ok: false,
149
+ reason: "expired-membership"
150
+ };
151
+ if (sawWrongScope) return {
152
+ ok: false,
153
+ reason: "scope"
154
+ };
155
+ return {
156
+ ok: false,
157
+ reason: "no-membership"
158
+ };
159
+ }
160
+ function matchResourceMembership(membership, roleResource, row, resource, resources) {
161
+ const on = membership.on;
162
+ if (on === void 0)
163
+ /* v8 ignore next */
164
+ return false;
165
+ if (row === null || typeof row !== "object") return false;
166
+ if (on.resource !== roleResource && membershipField(resources.get(roleResource), on.resource, resources) === void 0) return false;
167
+ const field = membershipField(resource, on.resource, resources);
168
+ return field !== void 0 && row[field] === on.id;
169
+ }
170
+ /**
171
+ * The row field that holds the id of a `membershipResource` membership: the
172
+ * row's own id field when the row is of that resource, the declared parent
173
+ * field of the matching ancestor otherwise (the row carries it, never a
174
+ * walk-up query), `undefined` when the resource is not on the row's chain.
175
+ */
176
+ function membershipField(resource, membershipResource, resources) {
177
+ if (resource === void 0) return;
178
+ if (resource.name === membershipResource) return resource.id ?? "id";
179
+ let current = resource;
180
+ const seen = /* @__PURE__ */ new Set();
181
+ while (current?.parent !== void 0 && !seen.has(current.name)) {
182
+ seen.add(current.name);
183
+ if (current.parent.resource === membershipResource) return current.parent.field;
184
+ current = resources.get(current.parent.resource);
185
+ }
186
+ }
187
+ //#endregion
188
+ //#region src/core/validity.ts
189
+ /**
190
+ * An instant as Unix seconds: a finite number is taken as seconds already, a
191
+ * string must parse as RFC 3339. Anything else is `undefined`, and the caller
192
+ * decides whether that is "absent" or an error.
193
+ */
194
+ function instantOf(input) {
195
+ if (typeof input === "number") return Number.isFinite(input) ? Math.floor(input) : void 0;
196
+ if (typeof input !== "string" || input.trim() === "") return;
197
+ const millis = Date.parse(input);
198
+ return Number.isFinite(millis) ? Math.floor(millis / 1e3) : void 0;
199
+ }
200
+ /**
201
+ * The normalised validity of a grant, or `undefined` when neither bound is
202
+ * set. Fail-closed at definition time: a bound that does not parse, or a
203
+ * window that ends before it starts, throws so a typo never widens a grant.
204
+ */
205
+ function normalizeValidity(options, permissionKey) {
206
+ const from = options.validFrom === void 0 ? void 0 : instantOf(options.validFrom);
207
+ const until = options.validUntil === void 0 ? void 0 : instantOf(options.validUntil);
208
+ if (options.validFrom !== void 0 && from === void 0) throw new Error(`PermDock: validFrom on '${permissionKey}' must be an RFC 3339 string or Unix seconds`);
209
+ if (options.validUntil !== void 0 && until === void 0) throw new Error(`PermDock: validUntil on '${permissionKey}' must be an RFC 3339 string or Unix seconds`);
210
+ if (from !== void 0 && until !== void 0 && until <= from) throw new Error(`PermDock: validUntil on '${permissionKey}' must be after validFrom`);
211
+ if (from === void 0 && until === void 0) return;
212
+ return Object.freeze({
213
+ ...from === void 0 ? {} : { from },
214
+ ...until === void 0 ? {} : { until }
215
+ });
216
+ }
217
+ /** Whether a grant with this validity applies at `now` (Unix seconds); no validity always applies. */
218
+ function isActive(validity, now) {
219
+ if (validity === void 0) return true;
220
+ if (validity.from !== void 0 && now < validity.from) return false;
221
+ return validity.until === void 0 || now < validity.until;
222
+ }
223
+ //#endregion
224
+ export { matchScopedMembership as a, partitionsOf as c, rowInScope as d, tenantsOf as f, sanitizeFields as g, sanitizeContext as h, isMembershipExpired as i, relatesTo as l, pickVisible as m, normalizeValidity as n, membershipField as o, grantCoversField as p, inTeam as r, nowSeconds as s, isActive as t, resolveActiveTenant as u };
@@ -0,0 +1,461 @@
1
+ import { n as isReadonlyArray, t as compact } from "./compact-y6vfu2_f.js";
2
+ import { E as splitPath, S as isForbiddenKey } from "./permissions-DC7GROPA.js";
3
+ import { t as loadJose } from "./load-jose-BL6LH4bL.js";
4
+ //#region src/jwt/header.ts
5
+ function compactParts(token) {
6
+ return token.split(".");
7
+ }
8
+ function isJwe(token) {
9
+ return compactParts(token).length === 5;
10
+ }
11
+ function decodeHeader(token) {
12
+ const [encoded] = compactParts(token);
13
+ if (encoded === void 0 || encoded.length === 0) return;
14
+ try {
15
+ const padded = encoded.replaceAll("-", "+").replaceAll("_", "/");
16
+ const pad = padded.length % 4 === 0 ? "" : "=".repeat(4 - padded.length % 4);
17
+ const json = atob(`${padded}${pad}`);
18
+ const value = JSON.parse(json);
19
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return;
20
+ return value;
21
+ } catch {
22
+ return;
23
+ }
24
+ }
25
+ function unknownCrit(header) {
26
+ const crit = header.crit;
27
+ if (crit === void 0) return false;
28
+ if (!isReadonlyArray(crit)) return true;
29
+ const understood = /* @__PURE__ */ new Set([
30
+ "alg",
31
+ "kid",
32
+ "typ",
33
+ "cty",
34
+ "enc"
35
+ ]);
36
+ return crit.some((name) => typeof name !== "string" || !understood.has(name));
37
+ }
38
+ function normalizeTyp(typ) {
39
+ if (typ === void 0) return;
40
+ const lower = typ.toLowerCase();
41
+ return lower.startsWith("application/") ? lower.slice(12) : lower;
42
+ }
43
+ //#endregion
44
+ //#region src/jwt/config.ts
45
+ const DEFAULT_ALGORITHMS = [
46
+ "ES256",
47
+ "PS256",
48
+ "Ed25519",
49
+ "RS256"
50
+ ];
51
+ const FAPI2_ALGORITHMS = [
52
+ "ES256",
53
+ "PS256",
54
+ "Ed25519"
55
+ ];
56
+ const DEFAULT_DECRYPTION_ALGS = [
57
+ "RSA-OAEP-256",
58
+ "ECDH-ES",
59
+ "ECDH-ES+A256KW",
60
+ "dir"
61
+ ];
62
+ const DEFAULT_CLOCK_TOLERANCE = 5;
63
+ const FAPI2_CLOCK_TOLERANCE = 5;
64
+ function fail(cause) {
65
+ return {
66
+ ok: false,
67
+ reason: "invalid-token",
68
+ cause
69
+ };
70
+ }
71
+ function isSecretJwks(jwks) {
72
+ return typeof jwks === "object" && jwks !== null && !(jwks instanceof URL) && "secret" in jwks;
73
+ }
74
+ function issuerFromDiscovery(discovery) {
75
+ return typeof discovery === "string" ? discovery : discovery.issuer;
76
+ }
77
+ function resolveAlgorithms(options) {
78
+ if (options.algorithms !== void 0) return options.algorithms;
79
+ return options.profile === "fapi2" ? FAPI2_ALGORITHMS : DEFAULT_ALGORITHMS;
80
+ }
81
+ function resolveClockTolerance(options, override) {
82
+ const configured = override ?? options.clockTolerance ?? DEFAULT_CLOCK_TOLERANCE;
83
+ if (options.profile === "fapi2") return Math.min(configured, FAPI2_CLOCK_TOLERANCE);
84
+ return configured;
85
+ }
86
+ function assertSafeClaimPaths(claims) {
87
+ if (claims === void 0) return;
88
+ const paths = [
89
+ claims.id,
90
+ claims.roles,
91
+ claims.groups,
92
+ claims.entitlements,
93
+ claims.tenant,
94
+ claims.memberships,
95
+ claims.session
96
+ ].filter((path) => path !== void 0);
97
+ if (typeof claims.assurance === "string") paths.push(claims.assurance);
98
+ else if (claims.assurance !== void 0) paths.push(...[
99
+ claims.assurance.acr,
100
+ claims.assurance.amr,
101
+ claims.assurance.authTime,
102
+ claims.assurance.verified
103
+ ].filter((path) => path !== void 0));
104
+ if (claims.kind !== void 0 && claims.kind !== "workload" && claims.kind !== "user" && claims.kind !== "service") paths.push(claims.kind);
105
+ for (const path of paths) for (const segment of splitPath(path)) if (isForbiddenKey(segment)) throw new Error(`PermDock: forbidden claim path '${path}'.`);
106
+ }
107
+ function assertVerifierConfig(options) {
108
+ if (options.discovery !== void 0 && options.jwks !== void 0) throw new Error("PermDock: discovery and jwks are mutually exclusive.");
109
+ if (options.discovery === void 0 && options.jwks === void 0) throw new Error("PermDock: joseTokenVerifier requires jwks or discovery.");
110
+ if (typeof options.jwks === "string" && !URL.canParse(options.jwks)) throw new Error("PermDock: jwks must be an absolute URL.");
111
+ if (options.discovery !== void 0) {
112
+ const issuer = issuerFromDiscovery(options.discovery);
113
+ let url;
114
+ try {
115
+ url = new URL(issuer);
116
+ } catch {
117
+ throw new Error("PermDock: discovery issuer must be an absolute URL.");
118
+ }
119
+ if (url.protocol !== "https:") throw new Error("PermDock: discovery issuer must use https.");
120
+ if (options.issuer !== void 0 && options.issuer !== issuer) throw new Error("PermDock: issuer must match discovery or be omitted.");
121
+ const jwksUri = typeof options.discovery === "string" ? void 0 : options.discovery.metadata?.jwks_uri;
122
+ if (jwksUri !== void 0 && URL.parse(jwksUri)?.protocol !== "https:") throw new Error("PermDock: discovery jwks_uri must use https.");
123
+ }
124
+ if (options.jwks !== void 0 && isSecretJwks(options.jwks)) {
125
+ if (secretBits(options.jwks.secret) < 256) throw new Error("PermDock: HMAC secret must be at least 256 bits.");
126
+ }
127
+ if (resolveAlgorithms(options).includes("none")) throw new Error("PermDock: alg none is never accepted.");
128
+ }
129
+ function assertSubjectConfig(options) {
130
+ if (options.verifier === void 0) {
131
+ assertVerifierConfig(options);
132
+ if (options.jwks !== void 0 && !isSecretJwks(options.jwks) && options.issuer === void 0) throw new Error("PermDock: issuer is required with jwks.");
133
+ }
134
+ assertSafeClaimPaths(options.claims);
135
+ if (options.profile === "fapi2" && options.sender === "none") throw new Error("PermDock: profile 'fapi2' requires a sender constraint.");
136
+ }
137
+ function secretBits(secret) {
138
+ if (typeof secret === "string") return secret.length * 8;
139
+ return secret.byteLength * 8;
140
+ }
141
+ function secretBytes(secret) {
142
+ if (typeof secret === "string") return new TextEncoder().encode(secret);
143
+ return secret;
144
+ }
145
+ //#endregion
146
+ //#region src/jwt/cache.ts
147
+ function clampTtl(seconds, minTtl, maxTtl) {
148
+ return Math.min(maxTtl, Math.max(minTtl, seconds));
149
+ }
150
+ function cacheControlMaxAge(header) {
151
+ if (header === null) return;
152
+ const match = /max-age=(\d+)/iu.exec(header);
153
+ if (match?.[1] === void 0) return;
154
+ return Math.trunc(Number(match[1]));
155
+ }
156
+ function isHttpsUrl(value) {
157
+ return typeof value === "string" && URL.parse(value)?.protocol === "https:";
158
+ }
159
+ function discoveryUrls(issuer) {
160
+ const url = new URL(issuer);
161
+ const oidc = new URL("/.well-known/openid-configuration", url.origin);
162
+ if (url.pathname !== "/" && url.pathname !== "") oidc.pathname = `${url.pathname.replace(/\/$/u, "")}/.well-known/openid-configuration`;
163
+ const rfc8414 = new URL(url.href);
164
+ rfc8414.pathname = `/.well-known/oauth-authorization-server${url.pathname === "/" ? "" : url.pathname.replace(/\/$/u, "")}`;
165
+ return [oidc.href, rfc8414.href];
166
+ }
167
+ function createKeyCache(options) {
168
+ const minTtl = options.jwksCache?.minTtl ?? 60;
169
+ const maxTtl = options.jwksCache?.maxTtl ?? 3600;
170
+ const cooldown = options.jwksCache?.cooldown ?? 60;
171
+ const timeout = options.jwksCache?.timeout ?? 5e3;
172
+ const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
173
+ const jwksInFlight = /* @__PURE__ */ new Map();
174
+ let discoveryInFlight;
175
+ let discoveryCache;
176
+ let jwksCache;
177
+ let cooldownUntil = 0;
178
+ let discoveryCause;
179
+ const readDiscovery = async (href, issuer, now) => {
180
+ try {
181
+ const response = await fetchImpl(href, {
182
+ headers: { accept: "application/json" },
183
+ signal: AbortSignal.timeout(timeout)
184
+ });
185
+ if (!response.ok) return;
186
+ const body = await response.json();
187
+ if (body.issuer !== issuer) {
188
+ discoveryCause = "discovery-mismatch";
189
+ return {
190
+ ok: false,
191
+ cause: "discovery-mismatch"
192
+ };
193
+ }
194
+ if (!isHttpsUrl(body.jwks_uri)) return;
195
+ const ttl = clampTtl(cacheControlMaxAge(response.headers.get("cache-control")) ?? maxTtl, minTtl, maxTtl);
196
+ discoveryCache = {
197
+ value: {
198
+ issuer: body.issuer,
199
+ jwks_uri: body.jwks_uri
200
+ },
201
+ expiresAt: now + ttl
202
+ };
203
+ discoveryCause = void 0;
204
+ return {
205
+ ok: true,
206
+ ...discoveryCache.value
207
+ };
208
+ } catch {
209
+ return;
210
+ }
211
+ };
212
+ const loadDiscovery = (discovery, now) => {
213
+ if (typeof discovery !== "string" && discovery.metadata?.jwks_uri !== void 0) {
214
+ const issuer = issuerFromDiscovery(discovery);
215
+ if (discovery.metadata.issuer !== void 0 && discovery.metadata.issuer !== issuer) {
216
+ discoveryCause = "discovery-mismatch";
217
+ return Promise.resolve({
218
+ ok: false,
219
+ cause: "discovery-mismatch"
220
+ });
221
+ }
222
+ return Promise.resolve({
223
+ ok: true,
224
+ issuer,
225
+ jwks_uri: discovery.metadata.jwks_uri
226
+ });
227
+ }
228
+ if (discoveryCache !== void 0 && discoveryCache.expiresAt > now) return Promise.resolve({
229
+ ok: true,
230
+ ...discoveryCache.value
231
+ });
232
+ discoveryInFlight ??= fetchDiscovery(discovery, now).finally(() => {
233
+ discoveryInFlight = void 0;
234
+ });
235
+ return discoveryInFlight;
236
+ };
237
+ const fetchDiscovery = async (discovery, now) => {
238
+ const issuer = issuerFromDiscovery(discovery);
239
+ const [oidc, rfc8414] = discoveryUrls(issuer);
240
+ const fromOidc = oidc === void 0 ? void 0 : await readDiscovery(oidc, issuer, now);
241
+ if (fromOidc !== void 0) return fromOidc;
242
+ const fromRfc8414 = rfc8414 === void 0 ? void 0 : await readDiscovery(rfc8414, issuer, now);
243
+ if (fromRfc8414 !== void 0) return fromRfc8414;
244
+ if (discoveryCache !== void 0) return {
245
+ ok: true,
246
+ ...discoveryCache.value
247
+ };
248
+ return {
249
+ ok: false,
250
+ cause: discoveryCause ?? "discovery-unavailable"
251
+ };
252
+ };
253
+ const loadJwks = (href, now, force) => {
254
+ if (!force && jwksCache !== void 0 && jwksCache.expiresAt > now) return Promise.resolve({
255
+ ok: true,
256
+ jwks: jwksCache.value
257
+ });
258
+ const pending = jwksInFlight.get(href);
259
+ if (pending !== void 0) return pending;
260
+ const fetched = fetchJwks(href, now).finally(() => {
261
+ jwksInFlight.delete(href);
262
+ });
263
+ jwksInFlight.set(href, fetched);
264
+ return fetched;
265
+ };
266
+ const fetchJwks = async (href, now) => {
267
+ try {
268
+ const response = await fetchImpl(href, {
269
+ headers: { accept: "application/jwk-set+json, application/json" },
270
+ signal: AbortSignal.timeout(timeout)
271
+ });
272
+ if (!response.ok) throw new Error("jwks fetch failed");
273
+ const body = await response.json();
274
+ if (!Array.isArray(body.keys) || body.keys.length === 0) throw new Error("empty jwks");
275
+ jwksCache = {
276
+ value: body,
277
+ expiresAt: now + clampTtl(cacheControlMaxAge(response.headers.get("cache-control")) ?? maxTtl, minTtl, maxTtl)
278
+ };
279
+ return {
280
+ ok: true,
281
+ jwks: body
282
+ };
283
+ } catch {
284
+ if (jwksCache !== void 0 && jwksCache.expiresAt > now) return {
285
+ ok: true,
286
+ jwks: jwksCache.value
287
+ };
288
+ return {
289
+ ok: false,
290
+ cause: "jwks-unavailable"
291
+ };
292
+ }
293
+ };
294
+ const resolve = async (force, nowInput) => {
295
+ const now = nowInput ?? Math.floor(Date.now() / 1e3);
296
+ if (options.jwks instanceof URL) return loadJwks(options.jwks.href, now, force);
297
+ if (typeof options.jwks === "string") return loadJwks(options.jwks, now, force);
298
+ if (options.jwks !== void 0 && typeof options.jwks === "object" && "keys" in options.jwks) return {
299
+ ok: true,
300
+ jwks: options.jwks
301
+ };
302
+ if (options.discovery === void 0) return {
303
+ ok: false,
304
+ cause: "jwks-unavailable"
305
+ };
306
+ const discovered = await loadDiscovery(options.discovery, now);
307
+ if (!discovered.ok) return discovered;
308
+ return loadJwks(discovered.jwks_uri, now, force);
309
+ };
310
+ return {
311
+ resolveJwks(now) {
312
+ return resolve(false, now);
313
+ },
314
+ refetchJwks(now) {
315
+ const current = now ?? Math.floor(Date.now() / 1e3);
316
+ if (current < cooldownUntil) return resolve(false, current);
317
+ cooldownUntil = current + cooldown;
318
+ return resolve(true, current);
319
+ }
320
+ };
321
+ }
322
+ //#endregion
323
+ //#region src/jwt/verifier.ts
324
+ const ACCESS_TYPS = /* @__PURE__ */ new Set(["at+jwt", "jwt"]);
325
+ const FAPI2_TYPS = /* @__PURE__ */ new Set(["at+jwt"]);
326
+ function algorithmAllowed(alg, allowed, key) {
327
+ if (alg === "none") return false;
328
+ if (alg === "EdDSA") return allowed.includes("Ed25519") && key?.["kty"] === "OKP" && key["crv"] === "Ed25519";
329
+ return allowed.includes(alg);
330
+ }
331
+ function findKey(keys, kid, profile) {
332
+ const usable = keys.filter((key) => !skipUndersized(key, profile));
333
+ if (kid === void 0) return usable.length === 1 ? usable[0] : void 0;
334
+ return usable.find((key) => key["kid"] === kid);
335
+ }
336
+ function skipUndersized(key, profile) {
337
+ if (profile !== "fapi2") return false;
338
+ if (key["kty"] === "RSA" && typeof key["n"] === "string") return Math.floor(key["n"].length * 6 / 8) * 8 < 2048;
339
+ if (key["kty"] === "EC" && key["crv"] === "P-192") return true;
340
+ return false;
341
+ }
342
+ function typAccepted(headerTyp, expected, profile) {
343
+ const seen = normalizeTyp(headerTyp);
344
+ if (expected !== void 0) return (typeof expected === "string" ? [expected] : expected).some((item) => normalizeTyp(item) === seen);
345
+ if (profile === "fapi2") return seen !== void 0 && FAPI2_TYPS.has(seen.toLowerCase());
346
+ if (seen === void 0) return true;
347
+ return ACCESS_TYPS.has(seen.toLowerCase());
348
+ }
349
+ function mapJoseCause(error) {
350
+ if (typeof error !== "object" || error === null || !("code" in error)) return "invalid-signature";
351
+ const code = String(error.code);
352
+ if (code === "ERR_JWT_EXPIRED") return "expired";
353
+ if (code === "ERR_JWKS_NO_MATCHING_KEY") return "unknown-kid";
354
+ if (code === "ERR_JOSE_ALG_NOT_ALLOWED" || code === "ERR_JWS_ALG_NOT_ALLOWED") return "alg-not-allowed";
355
+ if (code === "ERR_JWE_INVALID" || code === "ERR_JWE_NOT_SUPPORTED") return "encrypted-token";
356
+ if (code === "ERR_JWT_CLAIM_VALIDATION_FAILED") {
357
+ const claim = error.claim;
358
+ if (claim === "aud") return "wrong-audience";
359
+ if (claim === "iss") return "wrong-issuer";
360
+ if (claim === "nbf" || claim === "iat") return "not-yet-valid";
361
+ if (claim === "typ") return "wrong-token-type";
362
+ return "malformed";
363
+ }
364
+ if (code === "ERR_JWS_INVALID" || code === "ERR_JWT_INVALID") return "malformed";
365
+ return "invalid-signature";
366
+ }
367
+ function joseTokenVerifier(options) {
368
+ assertVerifierConfig(options);
369
+ const algorithms = resolveAlgorithms(options);
370
+ const cache = options.jwks !== void 0 && isSecretJwks(options.jwks) ? void 0 : createKeyCache(options);
371
+ const issuer = options.issuer ?? (options.discovery === void 0 ? void 0 : issuerFromDiscovery(options.discovery));
372
+ const verifyInner = async (token, expectations, keys, header) => {
373
+ const jose = await loadJose();
374
+ const alg = header?.alg ?? "";
375
+ const key = keys instanceof Uint8Array ? void 0 : findKey(keys, header?.kid, options.profile);
376
+ if (!(keys instanceof Uint8Array) && key === void 0) return fail("unknown-kid");
377
+ if (!algorithmAllowed(alg, algorithms, key)) return fail(alg === "none" ? "alg-none" : "alg-not-allowed");
378
+ const expectedTyp = expectations.typ ?? options.typ;
379
+ if (!typAccepted(header?.typ, expectedTyp, options.profile)) return fail("wrong-token-type");
380
+ const securityEvent = normalizeTyp(header?.typ) === "secevent+jwt";
381
+ const verifyAlgs = algorithms.includes("Ed25519") ? [...algorithms, "EdDSA"] : [...algorithms];
382
+ try {
383
+ const getKey = keys instanceof Uint8Array ? keys : jose.createLocalJWKSet({ keys });
384
+ const result = await jose.jwtVerify(token, getKey, compact({
385
+ algorithms: verifyAlgs,
386
+ issuer: expectations.issuer ?? issuer,
387
+ audience: expectations.audience ?? options.audience,
388
+ clockTolerance: resolveClockTolerance(options, expectations.clockTolerance),
389
+ requiredClaims: securityEvent ? ["iat"] : ["exp"]
390
+ }));
391
+ const claims = result.payload;
392
+ if (!securityEvent && typeof claims.exp !== "number") return fail("expired");
393
+ return {
394
+ ok: true,
395
+ claims,
396
+ header: compact({
397
+ alg: String(result.protectedHeader.alg ?? alg),
398
+ kid: typeof result.protectedHeader.kid === "string" ? result.protectedHeader.kid : header?.kid,
399
+ typ: typeof result.protectedHeader.typ === "string" ? result.protectedHeader.typ : header?.typ
400
+ })
401
+ };
402
+ } catch (error) {
403
+ return fail(mapJoseCause(error));
404
+ }
405
+ };
406
+ const decryptNested = async (token) => {
407
+ if (options.decryptionKeys === void 0) return fail("encrypted-token");
408
+ const header = decodeHeader(token);
409
+ if (header?.zip !== void 0 || header?.alg === "RSA1_5" || header?.cty === void 0 || normalizeTyp(header.cty) !== "jwt") return fail("encrypted-token");
410
+ const jose = await loadJose();
411
+ try {
412
+ const listed = options.decryptionKeys;
413
+ const first = ("keys" in listed && Array.isArray(listed.keys) ? listed.keys : [listed])[0];
414
+ if (first === void 0 || first["kty"] !== "oct" || typeof first["k"] !== "string") return fail("encrypted-token");
415
+ const { plaintext } = await jose.compactDecrypt(token, jose.base64url.decode(first["k"]), { keyManagementAlgorithms: [...options.decryptionAlgorithms ?? DEFAULT_DECRYPTION_ALGS].filter((alg) => alg !== "RSA1_5") });
416
+ return {
417
+ ok: true,
418
+ jwt: new TextDecoder().decode(plaintext)
419
+ };
420
+ } catch {
421
+ return fail("encrypted-token");
422
+ }
423
+ };
424
+ return { verify(token, expectations = {}) {
425
+ return verifyToken(token, expectations);
426
+ } };
427
+ async function verifyToken(token, expectations) {
428
+ try {
429
+ if (typeof token !== "string" || token.length === 0) return fail("malformed");
430
+ let jwt = token;
431
+ if (isJwe(token)) {
432
+ const decrypted = await decryptNested(token);
433
+ if (!decrypted.ok) return decrypted;
434
+ jwt = decrypted.jwt;
435
+ }
436
+ const header = decodeHeader(jwt);
437
+ if (header === void 0) return fail("malformed");
438
+ if (header.alg === "none") return fail("alg-none");
439
+ if (unknownCrit(header)) return fail("malformed");
440
+ if (options.jwks !== void 0 && isSecretJwks(options.jwks)) {
441
+ if (!algorithms.includes("HS256") || header.alg !== "HS256") return fail(header.alg === "none" ? "alg-none" : "alg-not-allowed");
442
+ return await verifyInner(jwt, expectations, secretBytes(options.jwks.secret), header);
443
+ }
444
+ if (cache === void 0) return fail("jwks-unavailable");
445
+ let resolved = await cache.resolveJwks();
446
+ if (!resolved.ok) return fail(resolved.cause);
447
+ let key = findKey(resolved.jwks.keys, header.kid, options.profile);
448
+ if (key === void 0 && header.kid !== void 0) {
449
+ resolved = await cache.refetchJwks();
450
+ if (!resolved.ok) return fail(resolved.cause);
451
+ key = findKey(resolved.jwks.keys, header.kid, options.profile);
452
+ }
453
+ if (key === void 0) return fail("unknown-kid");
454
+ return await verifyInner(jwt, expectations, resolved.jwks.keys, header);
455
+ } catch {
456
+ return fail("malformed");
457
+ }
458
+ }
459
+ }
460
+ //#endregion
461
+ export { decodeHeader as a, issuerFromDiscovery as i, assertSubjectConfig as n, normalizeTyp as o, fail as r, joseTokenVerifier as t };