agent-passport-system 7.0.0 → 7.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 (198) hide show
  1. package/SECURITY.md +11 -0
  2. package/dist/src/core/tool-integrity.d.ts +13 -0
  3. package/dist/src/core/tool-integrity.d.ts.map +1 -1
  4. package/dist/src/core/tool-integrity.js +1 -1
  5. package/dist/src/core/tool-integrity.js.map +1 -1
  6. package/dist/src/index.d.ts +52 -2
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +282 -1
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/v2/activation/canonical.d.ts +40 -0
  11. package/dist/src/v2/activation/canonical.d.ts.map +1 -0
  12. package/dist/src/v2/activation/canonical.js +64 -0
  13. package/dist/src/v2/activation/canonical.js.map +1 -0
  14. package/dist/src/v2/activation/index.d.ts +4 -0
  15. package/dist/src/v2/activation/index.d.ts.map +1 -0
  16. package/dist/src/v2/activation/index.js +11 -0
  17. package/dist/src/v2/activation/index.js.map +1 -0
  18. package/dist/src/v2/activation/types.d.ts +268 -0
  19. package/dist/src/v2/activation/types.d.ts.map +1 -0
  20. package/dist/src/v2/activation/types.js +198 -0
  21. package/dist/src/v2/activation/types.js.map +1 -0
  22. package/dist/src/v2/activation/verify.d.ts +132 -0
  23. package/dist/src/v2/activation/verify.d.ts.map +1 -0
  24. package/dist/src/v2/activation/verify.js +406 -0
  25. package/dist/src/v2/activation/verify.js.map +1 -0
  26. package/dist/src/v2/authority-revocation/canonical.d.ts +46 -0
  27. package/dist/src/v2/authority-revocation/canonical.d.ts.map +1 -0
  28. package/dist/src/v2/authority-revocation/canonical.js +68 -0
  29. package/dist/src/v2/authority-revocation/canonical.js.map +1 -0
  30. package/dist/src/v2/authority-revocation/index.d.ts +9 -0
  31. package/dist/src/v2/authority-revocation/index.d.ts.map +1 -0
  32. package/dist/src/v2/authority-revocation/index.js +11 -0
  33. package/dist/src/v2/authority-revocation/index.js.map +1 -0
  34. package/dist/src/v2/authority-revocation/issue.d.ts +54 -0
  35. package/dist/src/v2/authority-revocation/issue.d.ts.map +1 -0
  36. package/dist/src/v2/authority-revocation/issue.js +111 -0
  37. package/dist/src/v2/authority-revocation/issue.js.map +1 -0
  38. package/dist/src/v2/authority-revocation/record.d.ts +69 -0
  39. package/dist/src/v2/authority-revocation/record.d.ts.map +1 -0
  40. package/dist/src/v2/authority-revocation/record.js +51 -0
  41. package/dist/src/v2/authority-revocation/record.js.map +1 -0
  42. package/dist/src/v2/authority-revocation/resolver.d.ts +30 -0
  43. package/dist/src/v2/authority-revocation/resolver.d.ts.map +1 -0
  44. package/dist/src/v2/authority-revocation/resolver.js +52 -0
  45. package/dist/src/v2/authority-revocation/resolver.js.map +1 -0
  46. package/dist/src/v2/authority-revocation/schema.d.ts +15 -0
  47. package/dist/src/v2/authority-revocation/schema.d.ts.map +1 -0
  48. package/dist/src/v2/authority-revocation/schema.js +107 -0
  49. package/dist/src/v2/authority-revocation/schema.js.map +1 -0
  50. package/dist/src/v2/authority-revocation/store.d.ts +55 -0
  51. package/dist/src/v2/authority-revocation/store.d.ts.map +1 -0
  52. package/dist/src/v2/authority-revocation/store.js +69 -0
  53. package/dist/src/v2/authority-revocation/store.js.map +1 -0
  54. package/dist/src/v2/authority-revocation/types.d.ts +136 -0
  55. package/dist/src/v2/authority-revocation/types.d.ts.map +1 -0
  56. package/dist/src/v2/authority-revocation/types.js +11 -0
  57. package/dist/src/v2/authority-revocation/types.js.map +1 -0
  58. package/dist/src/v2/authority-revocation/verify.d.ts +38 -0
  59. package/dist/src/v2/authority-revocation/verify.d.ts.map +1 -0
  60. package/dist/src/v2/authority-revocation/verify.js +139 -0
  61. package/dist/src/v2/authority-revocation/verify.js.map +1 -0
  62. package/dist/src/v2/authority-state/fencing.d.ts +49 -0
  63. package/dist/src/v2/authority-state/fencing.d.ts.map +1 -0
  64. package/dist/src/v2/authority-state/fencing.js +92 -0
  65. package/dist/src/v2/authority-state/fencing.js.map +1 -0
  66. package/dist/src/v2/authority-state/index.d.ts +7 -0
  67. package/dist/src/v2/authority-state/index.d.ts.map +1 -0
  68. package/dist/src/v2/authority-state/index.js +14 -0
  69. package/dist/src/v2/authority-state/index.js.map +1 -0
  70. package/dist/src/v2/authority-state/marker.d.ts +70 -0
  71. package/dist/src/v2/authority-state/marker.d.ts.map +1 -0
  72. package/dist/src/v2/authority-state/marker.js +122 -0
  73. package/dist/src/v2/authority-state/marker.js.map +1 -0
  74. package/dist/src/v2/authority-state/report.d.ts +55 -0
  75. package/dist/src/v2/authority-state/report.d.ts.map +1 -0
  76. package/dist/src/v2/authority-state/report.js +51 -0
  77. package/dist/src/v2/authority-state/report.js.map +1 -0
  78. package/dist/src/v2/authority-state/retained.d.ts +82 -0
  79. package/dist/src/v2/authority-state/retained.d.ts.map +1 -0
  80. package/dist/src/v2/authority-state/retained.js +93 -0
  81. package/dist/src/v2/authority-state/retained.js.map +1 -0
  82. package/dist/src/v2/authority-state/types.d.ts +198 -0
  83. package/dist/src/v2/authority-state/types.d.ts.map +1 -0
  84. package/dist/src/v2/authority-state/types.js +103 -0
  85. package/dist/src/v2/authority-state/types.js.map +1 -0
  86. package/dist/src/v2/authority-state/withdrawal.d.ts +80 -0
  87. package/dist/src/v2/authority-state/withdrawal.d.ts.map +1 -0
  88. package/dist/src/v2/authority-state/withdrawal.js +199 -0
  89. package/dist/src/v2/authority-state/withdrawal.js.map +1 -0
  90. package/dist/src/v2/bounds/canonical.d.ts +30 -0
  91. package/dist/src/v2/bounds/canonical.d.ts.map +1 -0
  92. package/dist/src/v2/bounds/canonical.js +69 -0
  93. package/dist/src/v2/bounds/canonical.js.map +1 -0
  94. package/dist/src/v2/bounds/evaluate.d.ts +107 -0
  95. package/dist/src/v2/bounds/evaluate.d.ts.map +1 -0
  96. package/dist/src/v2/bounds/evaluate.js +315 -0
  97. package/dist/src/v2/bounds/evaluate.js.map +1 -0
  98. package/dist/src/v2/bounds/index.d.ts +6 -0
  99. package/dist/src/v2/bounds/index.d.ts.map +1 -0
  100. package/dist/src/v2/bounds/index.js +13 -0
  101. package/dist/src/v2/bounds/index.js.map +1 -0
  102. package/dist/src/v2/bounds/purpose.d.ts +2 -0
  103. package/dist/src/v2/bounds/purpose.d.ts.map +1 -0
  104. package/dist/src/v2/bounds/purpose.js +23 -0
  105. package/dist/src/v2/bounds/purpose.js.map +1 -0
  106. package/dist/src/v2/bounds/record.d.ts +78 -0
  107. package/dist/src/v2/bounds/record.d.ts.map +1 -0
  108. package/dist/src/v2/bounds/record.js +170 -0
  109. package/dist/src/v2/bounds/record.js.map +1 -0
  110. package/dist/src/v2/bounds/types.d.ts +275 -0
  111. package/dist/src/v2/bounds/types.d.ts.map +1 -0
  112. package/dist/src/v2/bounds/types.js +124 -0
  113. package/dist/src/v2/bounds/types.js.map +1 -0
  114. package/dist/src/v2/capability-binding/binding.d.ts +67 -0
  115. package/dist/src/v2/capability-binding/binding.d.ts.map +1 -0
  116. package/dist/src/v2/capability-binding/binding.js +267 -0
  117. package/dist/src/v2/capability-binding/binding.js.map +1 -0
  118. package/dist/src/v2/capability-binding/digest.d.ts +33 -0
  119. package/dist/src/v2/capability-binding/digest.d.ts.map +1 -0
  120. package/dist/src/v2/capability-binding/digest.js +55 -0
  121. package/dist/src/v2/capability-binding/digest.js.map +1 -0
  122. package/dist/src/v2/capability-binding/identifier.d.ts +103 -0
  123. package/dist/src/v2/capability-binding/identifier.d.ts.map +1 -0
  124. package/dist/src/v2/capability-binding/identifier.js +281 -0
  125. package/dist/src/v2/capability-binding/identifier.js.map +1 -0
  126. package/dist/src/v2/capability-binding/index.d.ts +6 -0
  127. package/dist/src/v2/capability-binding/index.d.ts.map +1 -0
  128. package/dist/src/v2/capability-binding/index.js +13 -0
  129. package/dist/src/v2/capability-binding/index.js.map +1 -0
  130. package/dist/src/v2/capability-binding/pins.d.ts +30 -0
  131. package/dist/src/v2/capability-binding/pins.d.ts.map +1 -0
  132. package/dist/src/v2/capability-binding/pins.js +109 -0
  133. package/dist/src/v2/capability-binding/pins.js.map +1 -0
  134. package/dist/src/v2/capability-binding/types.d.ts +213 -0
  135. package/dist/src/v2/capability-binding/types.d.ts.map +1 -0
  136. package/dist/src/v2/capability-binding/types.js +150 -0
  137. package/dist/src/v2/capability-binding/types.js.map +1 -0
  138. package/dist/src/v2/chain-selection/index.d.ts +4 -0
  139. package/dist/src/v2/chain-selection/index.d.ts.map +1 -0
  140. package/dist/src/v2/chain-selection/index.js +11 -0
  141. package/dist/src/v2/chain-selection/index.js.map +1 -0
  142. package/dist/src/v2/chain-selection/select.d.ts +62 -0
  143. package/dist/src/v2/chain-selection/select.d.ts.map +1 -0
  144. package/dist/src/v2/chain-selection/select.js +390 -0
  145. package/dist/src/v2/chain-selection/select.js.map +1 -0
  146. package/dist/src/v2/chain-selection/types.d.ts +189 -0
  147. package/dist/src/v2/chain-selection/types.d.ts.map +1 -0
  148. package/dist/src/v2/chain-selection/types.js +81 -0
  149. package/dist/src/v2/chain-selection/types.js.map +1 -0
  150. package/dist/src/v2/lifecycle-state/index.d.ts +4 -0
  151. package/dist/src/v2/lifecycle-state/index.d.ts.map +1 -0
  152. package/dist/src/v2/lifecycle-state/index.js +10 -0
  153. package/dist/src/v2/lifecycle-state/index.js.map +1 -0
  154. package/dist/src/v2/lifecycle-state/map.d.ts +52 -0
  155. package/dist/src/v2/lifecycle-state/map.d.ts.map +1 -0
  156. package/dist/src/v2/lifecycle-state/map.js +122 -0
  157. package/dist/src/v2/lifecycle-state/map.js.map +1 -0
  158. package/dist/src/v2/lifecycle-state/state.d.ts +60 -0
  159. package/dist/src/v2/lifecycle-state/state.d.ts.map +1 -0
  160. package/dist/src/v2/lifecycle-state/state.js +157 -0
  161. package/dist/src/v2/lifecycle-state/state.js.map +1 -0
  162. package/dist/src/v2/lifecycle-state/types.d.ts +163 -0
  163. package/dist/src/v2/lifecycle-state/types.d.ts.map +1 -0
  164. package/dist/src/v2/lifecycle-state/types.js +121 -0
  165. package/dist/src/v2/lifecycle-state/types.js.map +1 -0
  166. package/dist/src/v2/receipt-core/composite.d.ts +69 -3
  167. package/dist/src/v2/receipt-core/composite.d.ts.map +1 -1
  168. package/dist/src/v2/receipt-core/composite.js +75 -9
  169. package/dist/src/v2/receipt-core/composite.js.map +1 -1
  170. package/dist/src/v2/receipt-core/predecessor.d.ts +95 -0
  171. package/dist/src/v2/receipt-core/predecessor.d.ts.map +1 -0
  172. package/dist/src/v2/receipt-core/predecessor.js +115 -0
  173. package/dist/src/v2/receipt-core/predecessor.js.map +1 -0
  174. package/dist/src/v2/status-coverage/decide.d.ts +52 -0
  175. package/dist/src/v2/status-coverage/decide.d.ts.map +1 -0
  176. package/dist/src/v2/status-coverage/decide.js +398 -0
  177. package/dist/src/v2/status-coverage/decide.js.map +1 -0
  178. package/dist/src/v2/status-coverage/index.d.ts +3 -0
  179. package/dist/src/v2/status-coverage/index.d.ts.map +1 -0
  180. package/dist/src/v2/status-coverage/index.js +10 -0
  181. package/dist/src/v2/status-coverage/index.js.map +1 -0
  182. package/dist/src/v2/status-coverage/types.d.ts +258 -0
  183. package/dist/src/v2/status-coverage/types.d.ts.map +1 -0
  184. package/dist/src/v2/status-coverage/types.js +127 -0
  185. package/dist/src/v2/status-coverage/types.js.map +1 -0
  186. package/dist/src/v2/suspension/evaluate.d.ts +88 -0
  187. package/dist/src/v2/suspension/evaluate.d.ts.map +1 -0
  188. package/dist/src/v2/suspension/evaluate.js +404 -0
  189. package/dist/src/v2/suspension/evaluate.js.map +1 -0
  190. package/dist/src/v2/suspension/index.d.ts +3 -0
  191. package/dist/src/v2/suspension/index.d.ts.map +1 -0
  192. package/dist/src/v2/suspension/index.js +10 -0
  193. package/dist/src/v2/suspension/index.js.map +1 -0
  194. package/dist/src/v2/suspension/types.d.ts +243 -0
  195. package/dist/src/v2/suspension/types.d.ts.map +1 -0
  196. package/dist/src/v2/suspension/types.js +135 -0
  197. package/dist/src/v2/suspension/types.js.map +1 -0
  198. package/package.json +10 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/issue.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAY7E,OAAO,KAAK,EAA6B,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAElF,mFAAmF;AACnF,MAAM,WAAW,6BAA6B;IAC5C;;;;;yDAKqD;IACrD,GAAG,EAAE,MAAM,CAAA;IACX,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAA;IACf;;uFAEmF;IACnF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;IACnB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,qBAAqB,EACjC,KAAK,EAAE,6BAA6B,EACpC,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAmEvB"}
@@ -0,0 +1,111 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { authorityDelegationBody, computeAuthorityDelegationId, } from '../authority-delegation/canonical.js';
4
+ import { snapshotPlainData } from '../authority-delegation/plain-data.js';
5
+ import { isCanonicalTimestamp, validateAuthorityDelegationShape, } from '../authority-delegation/schema.js';
6
+ import { computeAuthorityRevocationCascadeTransactionIdForWrite, computeAuthorityRevocationIdForWrite, signAuthorityRevocation, } from './canonical.js';
7
+ import { validateAuthorityRevocationShape } from './schema.js';
8
+ import { AUTHORITY_REVOCATION_RECORD_TYPE, AUTHORITY_REVOCATION_VERSION, } from './types.js';
9
+ /**
10
+ * Mint a draft-03 section 3.5.1 direct revocation for one AuthorityDelegationV1.
11
+ *
12
+ * Section 3.5 line 634 states the only authorization rule this function applies: "Any
13
+ * delegation MAY be revoked by its issuer." The exact comparison is
14
+ * `input.revoker === delegation.issuer`, where `delegation` is the target record passed
15
+ * in by the caller and `issuer` is its own member. The record being minted is never
16
+ * consulted for its own authorization: a field a would-be revoker writes inside its own
17
+ * record cannot make that revoker the issuer of somebody else's delegation.
18
+ *
19
+ * The target's `delegation_id` is recomputed from its body before that comparison. A
20
+ * `delegation_id` sits outside the delegation's own identifier preimage, so a record
21
+ * whose claimed identifier does not match its body has an unauthenticated `issuer` too,
22
+ * and refusing there is what keeps the revoker check meaningful.
23
+ *
24
+ * What this function does NOT establish: that the holder of `privateKey` is in fact
25
+ * `input.revoker`, or that `input.verification_method` is one of that party's keys. An
26
+ * identifier-to-key binding is a resolver's answer, not a local one, and no string shape
27
+ * imposed on `verification_method` here could stand in for it. verifyAuthorityRevocation()
28
+ * makes that check, resolving the method under the TARGET delegation's `issuer` at
29
+ * `revoked_at`. Issuance can only refuse to mint a record that is already unverifiable; it
30
+ * cannot promise the record will verify.
31
+ *
32
+ * Nothing about a cascade over descendants is emitted here. This function produces one
33
+ * record about one delegation. Enforcement against descendants comes from chain
34
+ * verification, which rejects any chain containing a revoked ancestor.
35
+ *
36
+ * Throws on refusal; each message names its code in parentheses.
37
+ */
38
+ export function issueAuthorityRevocation(delegation, input, privateKey) {
39
+ // Each member is read exactly once, so a getter or Proxy trap cannot answer one way
40
+ // when a value is checked and another way when it is hashed and signed.
41
+ const read = (key) => {
42
+ try {
43
+ return input ? input[key] : undefined;
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ };
49
+ const now = read('now');
50
+ const revoker = read('revoker');
51
+ const verificationMethod = read('verification_method');
52
+ const reasonCode = read('reason_code');
53
+ const hasDetail = (() => {
54
+ try {
55
+ return !!input && Object.prototype.hasOwnProperty.call(input, 'detail');
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ })();
61
+ const detail = hasDetail ? read('detail') : undefined;
62
+ const nonce = read('nonce');
63
+ if (!isCanonicalTimestamp(now)) {
64
+ throw new Error('authority revocation now must be a canonical UTC-millisecond timestamp (NONCANONICAL_VALUE)');
65
+ }
66
+ const target = snapshotPlainData(delegation);
67
+ const targetFailures = validateAuthorityDelegationShape(target);
68
+ if (targetFailures.length > 0) {
69
+ throw new Error(`authority revocation target delegation invalid (${targetFailures[0].code})`);
70
+ }
71
+ if (computeAuthorityDelegationId(authorityDelegationBody(target)) !== target.delegation_id) {
72
+ throw new Error('authority revocation target content address does not match its body (TARGET_ID_MISMATCH)');
73
+ }
74
+ // Draft section 3.5: a delegation may be revoked by its issuer. The compared fields are
75
+ // the caller's claimed revoker and the TARGET delegation's own `issuer` member.
76
+ if (typeof revoker !== 'string' || revoker !== target.issuer) {
77
+ throw new Error('authority revocation revoker is not the target delegation issuer (REVOKER_NOT_ISSUER)');
78
+ }
79
+ const origin = {
80
+ record_type: AUTHORITY_REVOCATION_RECORD_TYPE,
81
+ version: AUTHORITY_REVOCATION_VERSION,
82
+ delegation_id: target.delegation_id,
83
+ revoker,
84
+ verification_method: verificationMethod,
85
+ revoked_at: now,
86
+ reason_code: reasonCode,
87
+ ...(hasDetail ? { detail: detail } : {}),
88
+ nonce: nonce,
89
+ };
90
+ const body = {
91
+ ...origin,
92
+ cascade_transaction_id: computeAuthorityRevocationCascadeTransactionIdForWrite(origin),
93
+ };
94
+ // Shape is judged on the finished record, so the probe carries placeholder values in
95
+ // exactly the two members that are not derivable yet. Both are replaced below.
96
+ const probe = {
97
+ ...body,
98
+ revocation_id: `sha256:${'0'.repeat(64)}`,
99
+ signature: '0'.repeat(128),
100
+ };
101
+ const failures = validateAuthorityRevocationShape(probe);
102
+ if (failures.length > 0) {
103
+ throw new Error(`authority revocation invalid: ${failures[0].message} (${failures[0].code})`);
104
+ }
105
+ const unsigned = {
106
+ ...body,
107
+ revocation_id: computeAuthorityRevocationIdForWrite(body),
108
+ };
109
+ return { ...unsigned, signature: signAuthorityRevocation(unsigned, privateKey) };
110
+ }
111
+ //# sourceMappingURL=issue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/issue.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AAEtC,OAAO,EACL,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AACzE,OAAO,EACL,oBAAoB,EACpB,gCAAgC,GACjC,MAAM,mCAAmC,CAAA;AAE1C,OAAO,EACL,sDAAsD,EACtD,oCAAoC,EACpC,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EACL,gCAAgC,EAChC,4BAA4B,GAC7B,MAAM,YAAY,CAAA;AAyBnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAAiC,EACjC,KAAoC,EACpC,UAAkB;IAElB,oFAAoF;IACpF,wEAAwE;IACxE,MAAM,IAAI,GAAG,CAAC,GAAwC,EAAW,EAAE;QACjE,IAAI,CAAC;YAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,SAAS,CAAA;QAAC,CAAC;IAC1E,CAAC,CAAA;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAA;IAC/B,MAAM,kBAAkB,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAA;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,CAAA;IACtC,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE;QACtB,IAAI,CAAC;YAAC,OAAO,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,KAAK,CAAA;QAAC,CAAC;IACxG,CAAC,CAAC,EAAE,CAAA;IACJ,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACrD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;IAE3B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6FAA6F,CAAC,CAAA;IAChH,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAA0B,CAAA;IACrE,MAAM,cAAc,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAA;IAC/D,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,mDAAmD,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,4BAA4B,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,aAAa,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CAAC,0FAA0F,CAAC,CAAA;IAC7G,CAAC;IAED,wFAAwF;IACxF,gFAAgF;IAChF,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAA;IAC1G,CAAC;IACD,MAAM,MAAM,GAAuC;QACjD,WAAW,EAAE,gCAAgC;QAC7C,OAAO,EAAE,4BAA4B;QACrC,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,OAAO;QACP,mBAAmB,EAAE,kBAA4B;QACjD,UAAU,EAAE,GAAG;QACf,WAAW,EAAE,UAAoB;QACjC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,KAAK,EAAE,KAAe;KACvB,CAAA;IACD,MAAM,IAAI,GAA8B;QACtC,GAAG,MAAM;QACT,sBAAsB,EAAE,sDAAsD,CAAC,MAAM,CAAC;KACvF,CAAA;IAED,qFAAqF;IACrF,+EAA+E;IAC/E,MAAM,KAAK,GAAG;QACZ,GAAG,IAAI;QACP,aAAa,EAAE,UAAU,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;QACzC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;KACF,CAAA;IAC1B,MAAM,QAAQ,GAAG,gCAAgC,CAAC,KAAK,CAAC,CAAA;IACxD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IAC/F,CAAC;IAED,MAAM,QAAQ,GAA6C;QACzD,GAAG,IAAI;QACP,aAAa,EAAE,oCAAoC,CAAC,IAAI,CAAC;KAC1D,CAAA;IACD,OAAO,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,uBAAuB,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAA;AAClF,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { AuthorityDelegationV1 } from '../authority-delegation/types.js';
2
+ import type { AuthorityRevocationVerificationOptions } from './verify.js';
3
+ import type { AuthorityRevocationStore, AuthorityRevocationV1, AuthorityRevocationVerificationResult } from './types.js';
4
+ /**
5
+ * What recordAuthorityRevocation() answers. Discriminated on `recorded`, so a caller
6
+ * cannot read `stored` without having decided which case it is in.
7
+ *
8
+ * - `recorded: true` — the candidate verified against its target. `stored` is what the
9
+ * store holds for that delegation now, and `inserted` says whether this call is the
10
+ * one that wrote it. `inserted: false` with `recorded: true` is the ordinary
11
+ * first-wins case: a valid revocation arrived second and the earlier record stands.
12
+ * - `recorded: false` — the candidate did not verify. `stored` is `undefined`, always,
13
+ * including when the store already holds a valid record for the same delegation. A
14
+ * rejected request is never handed somebody else's record as though it were its own
15
+ * result; `verification` carries the failures that rejected it.
16
+ *
17
+ * `verification` is the candidate's own result in both cases, never a result borrowed
18
+ * from a record already held.
19
+ */
20
+ export type AuthorityRevocationRecordResult = {
21
+ recorded: true;
22
+ inserted: boolean;
23
+ stored: AuthorityRevocationV1;
24
+ verification: AuthorityRevocationVerificationResult;
25
+ } | {
26
+ recorded: false;
27
+ inserted: false;
28
+ stored: undefined;
29
+ verification: AuthorityRevocationVerificationResult;
30
+ };
31
+ /**
32
+ * Verify one candidate revocation against the delegation it names and, only then, offer
33
+ * it to `store` for the delegation's first-wins slot. The one supported way a revocation
34
+ * enters a store.
35
+ *
36
+ * The defect this closes: a store's write primitive takes a record and a record alone,
37
+ * and a store can verify nothing, because verification needs the target delegation and a
38
+ * key resolver and a store holds neither. A write path reachable with an arbitrary object
39
+ * therefore lets any object take the first-wins slot for a delegation, and because that
40
+ * slot is irreversible (INV-5), the delegation can never afterwards record the valid
41
+ * revocation that would have revoked it. The resolver's own re-verification keeps such a
42
+ * record from ever reading as 'revoked', so the damage is not a false revocation; it is a
43
+ * permanently blocked real one. Verification belongs before the write, which is here.
44
+ *
45
+ * Order of operations:
46
+ *
47
+ * 1. snapshot the candidate as plain JSON data, once
48
+ * 2. verify that snapshot against `delegation` under `options`
49
+ * 3. on anything but `valid`, return `recorded: false` with that verification result and
50
+ * no record, having touched the store not at all
51
+ * 4. on `valid`, hand the SNAPSHOT to store.insertVerifiedRevocation() and report what
52
+ * the store says it now holds
53
+ *
54
+ * Step 1 and step 4 use the same snapshot, so the bytes the store keeps are exactly the
55
+ * bytes that were verified. Passing the caller's original value instead would let a
56
+ * getter or a Proxy trap answer one way for the verifier and another for the store.
57
+ *
58
+ * `options` is the same key resolution the resolver takes; the key is resolved under the
59
+ * TARGET delegation's issuer, at the revocation's own `revoked_at`. See
60
+ * verifyAuthorityRevocation().
61
+ *
62
+ * Does not throw on a bad candidate: an unusable candidate, an unusable target and an
63
+ * unusable resolver are all verification results, and verifyAuthorityRevocation() does
64
+ * not throw. An exception raised by `store` itself is not caught. A store that cannot
65
+ * complete a write has not produced a verification outcome, and reporting its failure as
66
+ * one would be a lie about the record rather than about the store.
67
+ */
68
+ export declare function recordAuthorityRevocation(store: AuthorityRevocationStore, delegation: AuthorityDelegationV1, candidate: unknown, options: AuthorityRevocationVerificationOptions): AuthorityRevocationRecordResult;
69
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/record.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAE7E,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,KAAK,EACV,wBAAwB,EACxB,qBAAqB,EACrB,qCAAqC,EACtC,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,+BAA+B,GACvC;IACE,QAAQ,EAAE,IAAI,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,YAAY,EAAE,qCAAqC,CAAA;CACpD,GACD;IACE,QAAQ,EAAE,KAAK,CAAA;IACf,QAAQ,EAAE,KAAK,CAAA;IACf,MAAM,EAAE,SAAS,CAAA;IACjB,YAAY,EAAE,qCAAqC,CAAA;CACpD,CAAA;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,wBAAwB,EAC/B,UAAU,EAAE,qBAAqB,EACjC,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,sCAAsC,GAC9C,+BAA+B,CAQjC"}
@@ -0,0 +1,51 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { snapshotPlainData } from '../authority-delegation/plain-data.js';
4
+ import { verifyAuthorityRevocation } from './verify.js';
5
+ /**
6
+ * Verify one candidate revocation against the delegation it names and, only then, offer
7
+ * it to `store` for the delegation's first-wins slot. The one supported way a revocation
8
+ * enters a store.
9
+ *
10
+ * The defect this closes: a store's write primitive takes a record and a record alone,
11
+ * and a store can verify nothing, because verification needs the target delegation and a
12
+ * key resolver and a store holds neither. A write path reachable with an arbitrary object
13
+ * therefore lets any object take the first-wins slot for a delegation, and because that
14
+ * slot is irreversible (INV-5), the delegation can never afterwards record the valid
15
+ * revocation that would have revoked it. The resolver's own re-verification keeps such a
16
+ * record from ever reading as 'revoked', so the damage is not a false revocation; it is a
17
+ * permanently blocked real one. Verification belongs before the write, which is here.
18
+ *
19
+ * Order of operations:
20
+ *
21
+ * 1. snapshot the candidate as plain JSON data, once
22
+ * 2. verify that snapshot against `delegation` under `options`
23
+ * 3. on anything but `valid`, return `recorded: false` with that verification result and
24
+ * no record, having touched the store not at all
25
+ * 4. on `valid`, hand the SNAPSHOT to store.insertVerifiedRevocation() and report what
26
+ * the store says it now holds
27
+ *
28
+ * Step 1 and step 4 use the same snapshot, so the bytes the store keeps are exactly the
29
+ * bytes that were verified. Passing the caller's original value instead would let a
30
+ * getter or a Proxy trap answer one way for the verifier and another for the store.
31
+ *
32
+ * `options` is the same key resolution the resolver takes; the key is resolved under the
33
+ * TARGET delegation's issuer, at the revocation's own `revoked_at`. See
34
+ * verifyAuthorityRevocation().
35
+ *
36
+ * Does not throw on a bad candidate: an unusable candidate, an unusable target and an
37
+ * unusable resolver are all verification results, and verifyAuthorityRevocation() does
38
+ * not throw. An exception raised by `store` itself is not caught. A store that cannot
39
+ * complete a write has not produced a verification outcome, and reporting its failure as
40
+ * one would be a lie about the record rather than about the store.
41
+ */
42
+ export function recordAuthorityRevocation(store, delegation, candidate, options) {
43
+ const snapshot = snapshotPlainData(candidate);
44
+ const verification = verifyAuthorityRevocation(snapshot, delegation, options);
45
+ if (!verification.valid) {
46
+ return { recorded: false, inserted: false, stored: undefined, verification };
47
+ }
48
+ const { inserted, stored } = store.insertVerifiedRevocation(snapshot);
49
+ return { recorded: true, inserted, stored, verification };
50
+ }
51
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/record.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAEzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAsCvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAA+B,EAC/B,UAAiC,EACjC,SAAkB,EAClB,OAA+C;IAE/C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA;IAC7C,MAAM,YAAY,GAAG,yBAAyB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IAC7E,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA;IAC9E,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAiC,CAAC,CAAA;IAC9F,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { AuthorityDelegationV1, RevocationResolution } from '../authority-delegation/types.js';
2
+ import type { AuthorityRevocationVerificationOptions } from './verify.js';
3
+ import type { AuthorityRevocationStore } from './types.js';
4
+ /**
5
+ * Adapt an AuthorityRevocationStore to the resolver verifyAuthorityDelegationChain and
6
+ * issueSubAuthorityDelegation already take.
7
+ *
8
+ * The three answers, and what each one costs to earn:
9
+ *
10
+ * - 'revoked' only when the store holds a record for this delegation AND that record
11
+ * verifies against this delegation under verifyAuthorityRevocation(). A stored record
12
+ * that does not verify yields 'unknown', not 'revoked' and not 'active': the store has
13
+ * an opinion this resolver cannot confirm, which is exactly indeterminate.
14
+ * - 'active' only when the store says it tracks this delegation and holds no revocation
15
+ * for it. Absence from a store is never 'active' on its own. A store that has never
16
+ * heard of a delegation has not said the delegation is unrevoked.
17
+ * - 'unknown' for everything else, including a store that throws and a delegation whose
18
+ * `delegation_id` does not recompute from its own body.
19
+ *
20
+ * The chain verifier treats 'unknown' as indeterminate (REVOCATION_UNKNOWN) and
21
+ * issueSubAuthorityDelegation refuses to mint under anything but 'active', so the
22
+ * fail-closed direction is already theirs; this resolver only has to avoid manufacturing
23
+ * an 'active' it cannot support.
24
+ *
25
+ * Never throws. A resolver that threw would be caught by both callers and read as
26
+ * 'unknown' anyway, so it returns 'unknown' in the open rather than through a catch in
27
+ * somebody else's code.
28
+ */
29
+ export declare function createAuthorityRevocationResolver(store: AuthorityRevocationStore, options: AuthorityRevocationVerificationOptions): (delegation: AuthorityDelegationV1) => RevocationResolution;
30
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/resolver.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,kCAAkC,CAAA;AAEzC,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,wBAAwB,EAC/B,OAAO,EAAE,sCAAsC,GAC9C,CAAC,UAAU,EAAE,qBAAqB,KAAK,oBAAoB,CAoB7D"}
@@ -0,0 +1,52 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { authorityDelegationBody, computeAuthorityDelegationId, } from '../authority-delegation/canonical.js';
4
+ import { verifyAuthorityRevocation } from './verify.js';
5
+ /**
6
+ * Adapt an AuthorityRevocationStore to the resolver verifyAuthorityDelegationChain and
7
+ * issueSubAuthorityDelegation already take.
8
+ *
9
+ * The three answers, and what each one costs to earn:
10
+ *
11
+ * - 'revoked' only when the store holds a record for this delegation AND that record
12
+ * verifies against this delegation under verifyAuthorityRevocation(). A stored record
13
+ * that does not verify yields 'unknown', not 'revoked' and not 'active': the store has
14
+ * an opinion this resolver cannot confirm, which is exactly indeterminate.
15
+ * - 'active' only when the store says it tracks this delegation and holds no revocation
16
+ * for it. Absence from a store is never 'active' on its own. A store that has never
17
+ * heard of a delegation has not said the delegation is unrevoked.
18
+ * - 'unknown' for everything else, including a store that throws and a delegation whose
19
+ * `delegation_id` does not recompute from its own body.
20
+ *
21
+ * The chain verifier treats 'unknown' as indeterminate (REVOCATION_UNKNOWN) and
22
+ * issueSubAuthorityDelegation refuses to mint under anything but 'active', so the
23
+ * fail-closed direction is already theirs; this resolver only has to avoid manufacturing
24
+ * an 'active' it cannot support.
25
+ *
26
+ * Never throws. A resolver that threw would be caught by both callers and read as
27
+ * 'unknown' anyway, so it returns 'unknown' in the open rather than through a catch in
28
+ * somebody else's code.
29
+ */
30
+ export function createAuthorityRevocationResolver(store, options) {
31
+ return (delegation) => {
32
+ try {
33
+ // A claimed delegation_id sits outside the delegation's own identifier preimage.
34
+ // Looking a revocation up by an unauthenticated label would let a caller ask about
35
+ // one delegation while presenting another.
36
+ const delegationId = computeAuthorityDelegationId(authorityDelegationBody(delegation));
37
+ if (delegationId !== delegation.delegation_id)
38
+ return 'unknown';
39
+ const record = store.get(delegationId);
40
+ if (record !== undefined) {
41
+ return verifyAuthorityRevocation(record, delegation, options).state === 'valid'
42
+ ? 'revoked'
43
+ : 'unknown';
44
+ }
45
+ return store.tracks(delegationId) ? 'active' : 'unknown';
46
+ }
47
+ catch {
48
+ return 'unknown';
49
+ }
50
+ };
51
+ }
52
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/resolver.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AAEtC,OAAO,EACL,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,sCAAsC,CAAA;AAK7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAIvD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,iCAAiC,CAC/C,KAA+B,EAC/B,OAA+C;IAE/C,OAAO,CAAC,UAAiC,EAAwB,EAAE;QACjE,IAAI,CAAC;YACH,iFAAiF;YACjF,mFAAmF;YACnF,2CAA2C;YAC3C,MAAM,YAAY,GAAG,4BAA4B,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,CAAA;YACtF,IAAI,YAAY,KAAK,UAAU,CAAC,aAAa;gBAAE,OAAO,SAAS,CAAA;YAE/D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,yBAAyB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,OAAO;oBAC7E,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,SAAS,CAAA;YACf,CAAC;YACD,OAAO,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { AuthorityRevocationFailure, AuthorityRevocationV1 } from './types.js';
2
+ /**
3
+ * Closed-schema and canonical-value validation for an in-memory decoded revocation.
4
+ *
5
+ * Snapshots `value` to plain JSON data first (see authority-delegation/plain-data.ts) and
6
+ * judges only that snapshot, so a getter or Proxy trap in the caller's argument is read
7
+ * at most once and cannot answer this function's checks differently from the value a
8
+ * caller goes on to hash.
9
+ *
10
+ * Returns every failure it finds rather than the first, matching
11
+ * validateAuthorityDelegationShape(). The caller decides which one it reports.
12
+ */
13
+ export declare function validateAuthorityRevocationShape(value: unknown): AuthorityRevocationFailure[];
14
+ export declare function isAuthorityRevocationV1(value: unknown): value is AuthorityRevocationV1;
15
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/schema.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,0BAA0B,EAE1B,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAqCnB;;;;;;;;;;GAUG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,EAAE,CA2D7F;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF"}
@@ -0,0 +1,107 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { snapshotPlainData } from '../authority-delegation/plain-data.js';
4
+ import { isCanonicalTimestamp } from '../authority-delegation/schema.js';
5
+ import { AUTHORITY_REVOCATION_RECORD_TYPE, AUTHORITY_REVOCATION_VERSION, } from './types.js';
6
+ const CONTENT_ADDRESS = /^sha256:[0-9a-f]{64}$/;
7
+ const HEX_32 = /^[0-9a-f]{32}$/;
8
+ const HEX_128 = /^[0-9a-f]{128}$/;
9
+ /** Every member a valid record may carry. A member outside this list is SCHEMA_INVALID:
10
+ * the schema is closed, so an unknown field cannot ride inside a signed preimage
11
+ * unnoticed. `detail` is the only OPTIONAL one. */
12
+ const REQUIRED_KEYS = [
13
+ 'record_type',
14
+ 'version',
15
+ 'revocation_id',
16
+ 'delegation_id',
17
+ 'revoker',
18
+ 'verification_method',
19
+ 'revoked_at',
20
+ 'reason_code',
21
+ 'cascade_transaction_id',
22
+ 'nonce',
23
+ 'signature',
24
+ ];
25
+ const OPTIONAL_KEYS = ['detail'];
26
+ function failure(code, message) {
27
+ return { code, message };
28
+ }
29
+ function record(value) {
30
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
31
+ ? value
32
+ : null;
33
+ }
34
+ /**
35
+ * Closed-schema and canonical-value validation for an in-memory decoded revocation.
36
+ *
37
+ * Snapshots `value` to plain JSON data first (see authority-delegation/plain-data.ts) and
38
+ * judges only that snapshot, so a getter or Proxy trap in the caller's argument is read
39
+ * at most once and cannot answer this function's checks differently from the value a
40
+ * caller goes on to hash.
41
+ *
42
+ * Returns every failure it finds rather than the first, matching
43
+ * validateAuthorityDelegationShape(). The caller decides which one it reports.
44
+ */
45
+ export function validateAuthorityRevocationShape(value) {
46
+ const failures = [];
47
+ const top = record(snapshotPlainData(value));
48
+ if (!top)
49
+ return [failure('SCHEMA_INVALID', 'revocation must be a JSON object')];
50
+ if (top.record_type !== AUTHORITY_REVOCATION_RECORD_TYPE) {
51
+ return [failure('UNSUPPORTED_RECORD_TYPE', `record_type must be ${AUTHORITY_REVOCATION_RECORD_TYPE}`)];
52
+ }
53
+ if (top.version !== AUTHORITY_REVOCATION_VERSION) {
54
+ return [failure('UNSUPPORTED_VERSION', `version must be ${AUTHORITY_REVOCATION_VERSION}`)];
55
+ }
56
+ for (const key of REQUIRED_KEYS) {
57
+ if (!Object.prototype.hasOwnProperty.call(top, key)) {
58
+ failures.push(failure('SCHEMA_INVALID', `${key} is required`));
59
+ }
60
+ }
61
+ const allowed = new Set([...REQUIRED_KEYS, ...OPTIONAL_KEYS]);
62
+ for (const key of Object.keys(top)) {
63
+ if (!allowed.has(key))
64
+ failures.push(failure('SCHEMA_INVALID', `unknown member ${key}`));
65
+ }
66
+ if (typeof top.revocation_id !== 'string' || !CONTENT_ADDRESS.test(top.revocation_id)) {
67
+ failures.push(failure('SCHEMA_INVALID', 'revocation_id must be sha256:<64 lowercase hex>'));
68
+ }
69
+ if (typeof top.delegation_id !== 'string' || !CONTENT_ADDRESS.test(top.delegation_id)) {
70
+ failures.push(failure('SCHEMA_INVALID', 'delegation_id must be sha256:<64 lowercase hex>'));
71
+ }
72
+ if (typeof top.cascade_transaction_id !== 'string' || !CONTENT_ADDRESS.test(top.cascade_transaction_id)) {
73
+ failures.push(failure('SCHEMA_INVALID', 'cascade_transaction_id must be sha256:<64 lowercase hex>'));
74
+ }
75
+ if (typeof top.revoker !== 'string' || top.revoker.length === 0) {
76
+ failures.push(failure('SCHEMA_INVALID', 'revoker must be a non-empty string'));
77
+ }
78
+ // Nothing here judges whether the method belongs to the revoker. That is decided only by
79
+ // key resolution against the target delegation's `issuer` at `revoked_at`, which
80
+ // verifyAuthorityRevocation() performs; a local string shape cannot establish it, and a
81
+ // method identifier need not be a fragment of the identifier that controls it.
82
+ if (typeof top.verification_method !== 'string' || top.verification_method.length === 0) {
83
+ failures.push(failure('SCHEMA_INVALID', 'verification_method must be a non-empty string'));
84
+ }
85
+ if (!isCanonicalTimestamp(top.revoked_at)) {
86
+ failures.push(failure('NONCANONICAL_VALUE', 'revoked_at must be a canonical UTC-millisecond timestamp'));
87
+ }
88
+ // The draft names a machine-readable reason code and fixes no grammar for one, so no
89
+ // grammar is invented here.
90
+ if (typeof top.reason_code !== 'string' || top.reason_code.length === 0) {
91
+ failures.push(failure('SCHEMA_INVALID', 'reason_code must be a non-empty string'));
92
+ }
93
+ if (Object.prototype.hasOwnProperty.call(top, 'detail') && typeof top.detail !== 'string') {
94
+ failures.push(failure('SCHEMA_INVALID', 'detail, when present, must be a string'));
95
+ }
96
+ if (typeof top.nonce !== 'string' || !HEX_32.test(top.nonce)) {
97
+ failures.push(failure('NONCANONICAL_VALUE', 'nonce must be 32 lowercase hex characters'));
98
+ }
99
+ if (typeof top.signature !== 'string' || !HEX_128.test(top.signature)) {
100
+ failures.push(failure('SCHEMA_INVALID', 'signature must be 128 lowercase hex characters'));
101
+ }
102
+ return failures;
103
+ }
104
+ export function isAuthorityRevocationV1(value) {
105
+ return validateAuthorityRevocationShape(value).length === 0;
106
+ }
107
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { AuthorityRevocationInsertion, AuthorityRevocationStore, AuthorityRevocationV1 } from './types.js';
2
+ /**
3
+ * Reference AuthorityRevocationStore holding every record in this process's heap.
4
+ *
5
+ * For tests, fixtures and local reference use. It is not a persistence layer and does not
6
+ * become one: the records live in two Maps and are gone when the process exits, when the
7
+ * object is garbage collected, or when a second process asks the same question. Draft
8
+ * section 3.5.1 makes cascade completion depend on a descendant's revocation being
9
+ * PERSISTENT, and nothing here can establish that, which is why this module emits no
10
+ * completion record.
11
+ *
12
+ * Behavior this class fixes, none of it settled by draft text:
13
+ *
14
+ * - First verified revocation for a delegation wins. INV-5 makes revocation
15
+ * irreversible, and a store that let a second record displace the first would make the
16
+ * recorded revocation time, reason and revoker mutable after the fact.
17
+ * - insertVerifiedRevocation() for a delegation that already has a record reports
18
+ * `inserted: false` and returns the record already held, and the caller's record is
19
+ * discarded. A repeated request is therefore idempotent in what the store reports, not
20
+ * in the bytes the caller minted: two calls with different nonces mint two different
21
+ * valid records, and the store keeps the first.
22
+ * - insertVerifiedRevocation() brings its target into the tracked view. Recording a
23
+ * revocation for a delegation is a statement that this store has an opinion about that
24
+ * delegation.
25
+ *
26
+ * insertVerifiedRevocation() is a persistence primitive and not an entry point. It does
27
+ * not verify, and a store cannot: verification needs the target delegation and a key
28
+ * resolver, neither of which is here. recordAuthorityRevocation() in record.ts is the
29
+ * one supported way in; it verifies against the target and calls this method only on a
30
+ * `valid` result. Nothing about that split relaxes the resolver, which still verifies on
31
+ * the way out, so a record that reached this store by some other route still cannot
32
+ * produce a 'revoked' answer.
33
+ */
34
+ export declare class InMemoryAuthorityRevocationStore implements AuthorityRevocationStore {
35
+ private readonly tracked;
36
+ private readonly records;
37
+ /** Bring `delegationId` into this store's view with no revocation recorded for it.
38
+ *
39
+ * Not part of AuthorityRevocationStore: how a store learns which delegations it covers
40
+ * is an implementation's own business, and a database-backed store would answer
41
+ * tracks() from its own rows rather than from a method like this one. */
42
+ track(delegationId: string): void;
43
+ tracks(delegationId: string): boolean;
44
+ get(delegationId: string): AuthorityRevocationV1 | undefined;
45
+ /** See AuthorityRevocationStore.insertVerifiedRevocation for the contract, including
46
+ * that `revocation` must already have been verified against its target delegation by
47
+ * recordAuthorityRevocation().
48
+ *
49
+ * The read of the existing record and the write are one synchronous statement sequence
50
+ * with no await and no callback between them, so on this single-threaded runtime no
51
+ * other caller can interleave and no second caller can observe `inserted: true` for a
52
+ * delegation whose slot is already taken. */
53
+ insertVerifiedRevocation(revocation: AuthorityRevocationV1): AuthorityRevocationInsertion;
54
+ }
55
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,gCAAiC,YAAW,wBAAwB;IAC/E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAEnE;;;;8EAI0E;IAC1E,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAEpC;IAED,GAAG,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAE3D;IAED;;;;;;;kDAO8C;IAC9C,wBAAwB,CAAC,UAAU,EAAE,qBAAqB,GAAG,4BAA4B,CAMxF;CACF"}
@@ -0,0 +1,69 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Reference AuthorityRevocationStore holding every record in this process's heap.
5
+ *
6
+ * For tests, fixtures and local reference use. It is not a persistence layer and does not
7
+ * become one: the records live in two Maps and are gone when the process exits, when the
8
+ * object is garbage collected, or when a second process asks the same question. Draft
9
+ * section 3.5.1 makes cascade completion depend on a descendant's revocation being
10
+ * PERSISTENT, and nothing here can establish that, which is why this module emits no
11
+ * completion record.
12
+ *
13
+ * Behavior this class fixes, none of it settled by draft text:
14
+ *
15
+ * - First verified revocation for a delegation wins. INV-5 makes revocation
16
+ * irreversible, and a store that let a second record displace the first would make the
17
+ * recorded revocation time, reason and revoker mutable after the fact.
18
+ * - insertVerifiedRevocation() for a delegation that already has a record reports
19
+ * `inserted: false` and returns the record already held, and the caller's record is
20
+ * discarded. A repeated request is therefore idempotent in what the store reports, not
21
+ * in the bytes the caller minted: two calls with different nonces mint two different
22
+ * valid records, and the store keeps the first.
23
+ * - insertVerifiedRevocation() brings its target into the tracked view. Recording a
24
+ * revocation for a delegation is a statement that this store has an opinion about that
25
+ * delegation.
26
+ *
27
+ * insertVerifiedRevocation() is a persistence primitive and not an entry point. It does
28
+ * not verify, and a store cannot: verification needs the target delegation and a key
29
+ * resolver, neither of which is here. recordAuthorityRevocation() in record.ts is the
30
+ * one supported way in; it verifies against the target and calls this method only on a
31
+ * `valid` result. Nothing about that split relaxes the resolver, which still verifies on
32
+ * the way out, so a record that reached this store by some other route still cannot
33
+ * produce a 'revoked' answer.
34
+ */
35
+ export class InMemoryAuthorityRevocationStore {
36
+ tracked = new Set();
37
+ records = new Map();
38
+ /** Bring `delegationId` into this store's view with no revocation recorded for it.
39
+ *
40
+ * Not part of AuthorityRevocationStore: how a store learns which delegations it covers
41
+ * is an implementation's own business, and a database-backed store would answer
42
+ * tracks() from its own rows rather than from a method like this one. */
43
+ track(delegationId) {
44
+ this.tracked.add(delegationId);
45
+ }
46
+ tracks(delegationId) {
47
+ return this.tracked.has(delegationId);
48
+ }
49
+ get(delegationId) {
50
+ return this.records.get(delegationId);
51
+ }
52
+ /** See AuthorityRevocationStore.insertVerifiedRevocation for the contract, including
53
+ * that `revocation` must already have been verified against its target delegation by
54
+ * recordAuthorityRevocation().
55
+ *
56
+ * The read of the existing record and the write are one synchronous statement sequence
57
+ * with no await and no callback between them, so on this single-threaded runtime no
58
+ * other caller can interleave and no second caller can observe `inserted: true` for a
59
+ * delegation whose slot is already taken. */
60
+ insertVerifiedRevocation(revocation) {
61
+ const existing = this.records.get(revocation.delegation_id);
62
+ if (existing)
63
+ return { inserted: false, stored: existing };
64
+ this.records.set(revocation.delegation_id, revocation);
65
+ this.tracked.add(revocation.delegation_id);
66
+ return { inserted: true, stored: revocation };
67
+ }
68
+ }
69
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/store.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AAQtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,OAAO,gCAAgC;IAC1B,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IAC3B,OAAO,GAAG,IAAI,GAAG,EAAiC,CAAA;IAEnE;;;;8EAI0E;IAC1E,KAAK,CAAC,YAAoB;QACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAChC,CAAC;IAED,MAAM,CAAC,YAAoB;QACzB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;IAED,GAAG,CAAC,YAAoB;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;IAED;;;;;;;kDAO8C;IAC9C,wBAAwB,CAAC,UAAiC;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;QAC3D,IAAI,QAAQ;YAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;QAC1D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;QACtD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;QAC1C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAC/C,CAAC;CACF"}