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,136 @@
1
+ import type { AuthorityDelegationV1 } from '../authority-delegation/types.js';
2
+ /** Draft-native direct revocation of an AuthorityDelegationV1, draft-03 section 3.5.1.
3
+ *
4
+ * Distinct from the pre-draft `RevocationRecord` in src/types/passport.ts, which carries
5
+ * a raw public key in `revokedBy`, a free-text `reason`, no cascade transaction identity,
6
+ * no nonce, no record_type and no domain-separated preimage. That record cannot represent
7
+ * section 3.5.1 evidence and is not reused here. The two models stay distinguishable. */
8
+ export declare const AUTHORITY_REVOCATION_RECORD_TYPE: 'aps:authority-revocation:v1';
9
+ export declare const AUTHORITY_REVOCATION_VERSION: '1.0';
10
+ /** The content over which `revocation_id` is computed: the record with `revocation_id`
11
+ * and `signature` absent. `revoked_at` is inside it, as section 3.5.1 requires of the
12
+ * revocation time. */
13
+ export interface AuthorityRevocationBodyV1 {
14
+ record_type: typeof AUTHORITY_REVOCATION_RECORD_TYPE;
15
+ version: typeof AUTHORITY_REVOCATION_VERSION;
16
+ /** Content address of the revoked delegation: `sha256:<64 lowercase hex>`. */
17
+ delegation_id: string;
18
+ /** The revoking authority. Section 3.5 names exactly one party for a direct
19
+ * revocation, the target delegation's issuer, so a valid record has
20
+ * `revoker === delegation.issuer` for the delegation it names. */
21
+ revoker: string;
22
+ /** Which key signed. A non-empty string, and nothing more is required of its shape: no
23
+ * local rule relates it to `revoker`. Whether the method belongs to the issuer is
24
+ * decided only by key resolution against the target delegation's `issuer` at
25
+ * `revoked_at`, which verifyAuthorityRevocation() performs. */
26
+ verification_method: string;
27
+ /** Canonical UTC-millisecond revocation time, supplied by the caller, never read from
28
+ * a clock inside issuance. */
29
+ revoked_at: string;
30
+ /** Machine-readable reason. A non-empty string; section 3.5.1 fixes no grammar for one
31
+ * and none is invented here. */
32
+ reason_code: string;
33
+ /** OPTIONAL free-text detail. Absent means the key is not present at all: JCS has no
34
+ * canonical form for undefined, so an absent detail is never serialized as null. */
35
+ detail?: string;
36
+ /** The transaction identity shared by every record one cascade produces. Deterministic
37
+ * and content-bound; see cascadeTransactionId() in canonical.ts. */
38
+ cascade_transaction_id: string;
39
+ /** 16 random bytes as 32 lowercase hexadecimal characters. */
40
+ nonce: string;
41
+ }
42
+ export interface AuthorityRevocationV1 extends AuthorityRevocationBodyV1 {
43
+ /** `sha256:<64 lowercase hex>` over the ID domain tag and JCS of the body. */
44
+ revocation_id: string;
45
+ /** Raw 64-byte Ed25519 signature as 128 lowercase hexadecimal characters. */
46
+ signature: string;
47
+ }
48
+ export type AuthorityRevocationFailureCode = 'SCHEMA_INVALID' | 'UNSUPPORTED_RECORD_TYPE' | 'UNSUPPORTED_VERSION' | 'NONCANONICAL_VALUE'
49
+ /** revocation_id does not recompute from the record's own body. */
50
+ | 'ID_MISMATCH'
51
+ /** cascade_transaction_id does not recompute from the record's own body. */
52
+ | 'CASCADE_TRANSACTION_MISMATCH'
53
+ /** The delegation handed in is not the one this record names. */
54
+ | 'TARGET_MISMATCH'
55
+ /** The delegation handed in does not recompute its own delegation_id, so its `issuer`
56
+ * is not an authenticated field and the revoker check cannot be made against it. */
57
+ | 'TARGET_ID_MISMATCH'
58
+ /** `revoker` is not the target delegation's `issuer`. */
59
+ | 'REVOKER_NOT_ISSUER' | 'KEY_RESOLUTION_FAILED' | 'KEY_SCHEME_UNSUPPORTED' | 'KEY_NOT_FOUND' | 'KEY_AMBIGUOUS' | 'KEY_UNREACHABLE' | 'KEY_MATERIAL_MALFORMED' | 'SIGNATURE_INVALID';
60
+ export interface AuthorityRevocationFailure {
61
+ code: AuthorityRevocationFailureCode;
62
+ message: string;
63
+ }
64
+ export interface AuthorityRevocationVerificationResult {
65
+ state: 'valid' | 'invalid' | 'indeterminate' | 'unsupported';
66
+ valid: boolean;
67
+ failures: AuthorityRevocationFailure[];
68
+ }
69
+ /** What a store's first-write primitive reports: whether this call was the write that
70
+ * took the first-wins slot, and what the store holds for the target now.
71
+ *
72
+ * `inserted` is the only way a caller learns which of the two happened. `stored` is the
73
+ * record passed in when `inserted` is true and the record already held when it is false,
74
+ * so a caller that must distinguish them reads `inserted` rather than comparing bytes. */
75
+ export interface AuthorityRevocationInsertion {
76
+ inserted: boolean;
77
+ stored: AuthorityRevocationV1;
78
+ }
79
+ /** The read and write boundary a revocation resolver needs.
80
+ *
81
+ * Nothing in this interface promises durability. An implementation backed by process
82
+ * memory, a file, or a replicated database all satisfy it; only the implementation says
83
+ * which. Section 3.5.1 makes the cascade-completion record depend on the last
84
+ * descendant's revocation being PERSISTENT, and no method here establishes persistence,
85
+ * which is one reason no completion record is issued in this module.
86
+ *
87
+ * This interface carries no method that takes an arbitrary, unverified record.
88
+ * `insertVerifiedRevocation` is a persistence primitive, not an entry point: the only
89
+ * supported way to move a candidate revocation into a store is
90
+ * recordAuthorityRevocation() in record.ts, which verifies first and calls the primitive
91
+ * only on a `valid` result. See that function for why the split exists. */
92
+ export interface AuthorityRevocationStore {
93
+ /** Whether `delegationId` is inside this store's view at all.
94
+ *
95
+ * This is what keeps absence from meaning "active". A store that has never heard of a
96
+ * delegation cannot say the delegation is unrevoked; it can only say it does not know.
97
+ * A store whose view covers the delegation and holds no revocation for it can. */
98
+ tracks(delegationId: string): boolean;
99
+ /** The revocation recorded for `delegationId`, or undefined when none is recorded. */
100
+ get(delegationId: string): AuthorityRevocationV1 | undefined;
101
+ /** Persistence primitive. Writes `revocation` only when this store holds no record for
102
+ * `revocation.delegation_id`, and reports what it holds for that target now.
103
+ *
104
+ * ACCEPTS ONLY A RECORD ALREADY VERIFIED AGAINST ITS TARGET DELEGATION by
105
+ * recordAuthorityRevocation(). It performs no verification, and none is possible here:
106
+ * verification needs the target delegation and a key resolver, neither of which a store
107
+ * has. An implementation is a write path, not a trust boundary, and a caller that
108
+ * reaches past recordAuthorityRevocation() to this method is the one asserting the
109
+ * record was verified.
110
+ *
111
+ * First verified revocation for a delegation wins. Revocation is irreversible (INV-5),
112
+ * so a later call naming a delegation that already has a record does not replace it:
113
+ * `inserted` is false and `stored` is the record already held, unchanged. The check for
114
+ * an existing record and the write MUST be one indivisible operation, so that two
115
+ * callers racing on the same delegation cannot both observe `inserted: true`.
116
+ *
117
+ * For a DURABLE implementation that means the first write MUST be an atomic conditional
118
+ * insert keyed by `delegation_id` — an insert the storage engine itself makes succeed
119
+ * for exactly one of two concurrent callers, such as a unique-constrained primary key,
120
+ * a compare-and-set, or an insert-if-absent. Reading the existing record and then
121
+ * writing does NOT satisfy this contract: under concurrency two callers can both read
122
+ * an empty slot before either writes, both report `inserted: true`, and the second
123
+ * write displaces the first, which makes the recorded revocation time, reason and
124
+ * revoker mutable after the fact and breaks first-wins and INV-5. The in-memory
125
+ * reference meets the contract only because its read and write are one synchronous
126
+ * statement sequence on a single-threaded runtime; that is a property of that runtime,
127
+ * not a pattern a durable store may copy.
128
+ *
129
+ * Brings its target into the tracked view: recording a revocation for a delegation is a
130
+ * statement that this store has an opinion about that delegation. */
131
+ insertVerifiedRevocation(revocation: AuthorityRevocationV1): AuthorityRevocationInsertion;
132
+ }
133
+ /** What a gateway eventually supplies to the chain verifier. Interface only; no gateway
134
+ * implementation lives in this repository. */
135
+ export type AuthorityRevocationLookup = (delegation: AuthorityDelegationV1) => AuthorityRevocationV1 | undefined;
136
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAE7E;;;;;0FAK0F;AAC1F,eAAO,MAAM,gCAAgC,EAAG,6BAAsC,CAAA;AACtF,eAAO,MAAM,4BAA4B,EAAG,KAAc,CAAA;AAE1D;;uBAEuB;AACvB,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,OAAO,gCAAgC,CAAA;IACpD,OAAO,EAAE,OAAO,4BAA4B,CAAA;IAC5C,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAA;IACrB;;uEAEmE;IACnE,OAAO,EAAE,MAAM,CAAA;IACf;;;oEAGgE;IAChE,mBAAmB,EAAE,MAAM,CAAA;IAC3B;mCAC+B;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB;qCACiC;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB;yFACqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;yEACqE;IACrE,sBAAsB,EAAE,MAAM,CAAA;IAC9B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,qBAAsB,SAAQ,yBAAyB;IACtE,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,MAAM,8BAA8B,GACtC,gBAAgB,GAChB,yBAAyB,GACzB,qBAAqB,GACrB,oBAAoB;AACtB,mEAAmE;GACjE,aAAa;AACf,4EAA4E;GAC1E,8BAA8B;AAChC,iEAAiE;GAC/D,iBAAiB;AACnB;qFACqF;GACnF,oBAAoB;AACtB,yDAAyD;GACvD,oBAAoB,GACpB,uBAAuB,GACvB,wBAAwB,GACxB,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,wBAAwB,GACxB,mBAAmB,CAAA;AAEvB,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,8BAA8B,CAAA;IACpC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,qCAAqC;IACpD,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,eAAe,GAAG,aAAa,CAAA;IAC5D,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,0BAA0B,EAAE,CAAA;CACvC;AAED;;;;;2FAK2F;AAC3F,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,qBAAqB,CAAA;CAC9B;AAED;;;;;;;;;;;;4EAY4E;AAC5E,MAAM,WAAW,wBAAwB;IACvC;;;;uFAImF;IACnF,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACrC,sFAAsF;IACtF,GAAG,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAAA;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0EA6BsE;IACtE,wBAAwB,CAAC,UAAU,EAAE,qBAAqB,GAAG,4BAA4B,CAAA;CAC1F;AAED;+CAC+C;AAC/C,MAAM,MAAM,yBAAyB,GAAG,CACtC,UAAU,EAAE,qBAAqB,KAC9B,qBAAqB,GAAG,SAAS,CAAA"}
@@ -0,0 +1,11 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /** Draft-native direct revocation of an AuthorityDelegationV1, draft-03 section 3.5.1.
4
+ *
5
+ * Distinct from the pre-draft `RevocationRecord` in src/types/passport.ts, which carries
6
+ * a raw public key in `revokedBy`, a free-text `reason`, no cascade transaction identity,
7
+ * no nonce, no record_type and no domain-separated preimage. That record cannot represent
8
+ * section 3.5.1 evidence and is not reused here. The two models stay distinguishable. */
9
+ export const AUTHORITY_REVOCATION_RECORD_TYPE = 'aps:authority-revocation:v1';
10
+ export const AUTHORITY_REVOCATION_VERSION = '1.0';
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/types.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AAItC;;;;;0FAK0F;AAC1F,MAAM,CAAC,MAAM,gCAAgC,GAAG,6BAAsC,CAAA;AACtF,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAc,CAAA"}
@@ -0,0 +1,38 @@
1
+ import type { VerificationKeyResolver } from '../authority-delegation/types.js';
2
+ import type { AuthorityRevocationVerificationResult } from './types.js';
3
+ export interface AuthorityRevocationVerificationOptions {
4
+ /** Resolves the key that signed the revocation, selected at the revocation's own
5
+ * `revoked_at`, per draft section 2.4: the key current at verification time is not
6
+ * necessarily the one that signed this record. */
7
+ resolveVerificationKey: VerificationKeyResolver;
8
+ }
9
+ /**
10
+ * Verify one draft-03 section 3.5.1 direct revocation against the delegation it names.
11
+ *
12
+ * A revocation is never judged alone. Whether a record is a revocation of THIS delegation
13
+ * and whether its signer was allowed to revoke are both questions about the target, so the
14
+ * target is a required argument and every authorization fact is read from it.
15
+ *
16
+ * Checks, in order, returning at the first that fails:
17
+ *
18
+ * 1. closed schema and canonical values on the revocation
19
+ * 2. `cascade_transaction_id` recomputes from the record's own origin content
20
+ * 3. `revocation_id` recomputes from the record's own body
21
+ * 4. closed schema and canonical values on the target delegation
22
+ * 5. the target's `delegation_id` recomputes from the target's own body
23
+ * 6. the revocation's `delegation_id` equals the target's
24
+ * 7. the revocation's `revoker` equals the TARGET's `issuer` (draft section 3.5)
25
+ * 8. the revoker's key resolves, at the revocation's `revoked_at`
26
+ * 9. the Ed25519 signature verifies over the domain-tagged preimage
27
+ *
28
+ * Step 8 hands the resolver `target.issuer`, read from the target delegation, not the
29
+ * `revoker` the record carries. The two are equal by step 7, and reading the target's
30
+ * member is what makes the authorization external to the record: no field inside a
31
+ * revocation selects the key that authorizes it.
32
+ *
33
+ * Fails closed. Anything unrecognized, any resolver that throws, any shape this schema
34
+ * does not claim, produces invalid, indeterminate or unsupported, never valid. This
35
+ * function does not throw.
36
+ */
37
+ export declare function verifyAuthorityRevocation(candidate: unknown, delegation: unknown, options: AuthorityRevocationVerificationOptions): AuthorityRevocationVerificationResult;
38
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/verify.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAGV,uBAAuB,EACxB,MAAM,kCAAkC,CAAA;AASzC,OAAO,KAAK,EAIV,qCAAqC,EACtC,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,sCAAsC;IACrD;;uDAEmD;IACnD,sBAAsB,EAAE,uBAAuB,CAAA;CAChD;AA6DD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,OAAO,EACnB,OAAO,EAAE,sCAAsC,GAC9C,qCAAqC,CA0DvC"}
@@ -0,0 +1,139 @@
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 { validateAuthorityDelegationShape } from '../authority-delegation/schema.js';
6
+ import { authorityRevocationBody, authorityRevocationCascadeOrigin, computeAuthorityRevocationCascadeTransactionId, computeAuthorityRevocationId, verifyAuthorityRevocationSignature, } from './canonical.js';
7
+ import { validateAuthorityRevocationShape } from './schema.js';
8
+ const KEY_MATERIAL = /^[0-9a-fA-F]{64}$/;
9
+ const UNSUPPORTED_CODES = new Set([
10
+ 'UNSUPPORTED_RECORD_TYPE',
11
+ 'UNSUPPORTED_VERSION',
12
+ ]);
13
+ function result(state, failures) {
14
+ return { state, valid: state === 'valid', failures };
15
+ }
16
+ function invalid(code, message) {
17
+ return result('invalid', [{ code, message }]);
18
+ }
19
+ function indeterminate(code, message) {
20
+ return result('indeterminate', [{ code, message }]);
21
+ }
22
+ /** Map a resolver's answer onto the draft's section 2.5 outcomes, or null when it
23
+ * resolved usable key material. An unsupported identifier scheme is unsupported;
24
+ * everything else that is not a usable key is indeterminate, never SIGNATURE_INVALID,
25
+ * because in those branches no signature was checked at all. */
26
+ function keyResolutionFailure(resolved) {
27
+ if (typeof resolved === 'string') {
28
+ return KEY_MATERIAL.test(resolved)
29
+ ? null
30
+ : indeterminate('KEY_MATERIAL_MALFORMED', 'resolved key material is not a 32-byte Ed25519 public key');
31
+ }
32
+ if (resolved && typeof resolved === 'object' && typeof resolved.outcome === 'string') {
33
+ switch (resolved.outcome) {
34
+ case 'unsupported_scheme':
35
+ return result('unsupported', [{ code: 'KEY_SCHEME_UNSUPPORTED', message: 'identifier scheme is not supported by the resolver' }]);
36
+ case 'not_found':
37
+ return indeterminate('KEY_NOT_FOUND', 'revoker or key was not found');
38
+ case 'ambiguous':
39
+ return indeterminate('KEY_AMBIGUOUS', 'key resolution was ambiguous');
40
+ case 'unreachable':
41
+ return indeterminate('KEY_UNREACHABLE', 'key material was unreachable');
42
+ case 'malformed':
43
+ return indeterminate('KEY_MATERIAL_MALFORMED', 'resolved key material is structurally malformed');
44
+ default:
45
+ break;
46
+ }
47
+ }
48
+ return indeterminate('KEY_RESOLUTION_FAILED', 'revoker verification key could not be resolved');
49
+ }
50
+ /**
51
+ * Verify one draft-03 section 3.5.1 direct revocation against the delegation it names.
52
+ *
53
+ * A revocation is never judged alone. Whether a record is a revocation of THIS delegation
54
+ * and whether its signer was allowed to revoke are both questions about the target, so the
55
+ * target is a required argument and every authorization fact is read from it.
56
+ *
57
+ * Checks, in order, returning at the first that fails:
58
+ *
59
+ * 1. closed schema and canonical values on the revocation
60
+ * 2. `cascade_transaction_id` recomputes from the record's own origin content
61
+ * 3. `revocation_id` recomputes from the record's own body
62
+ * 4. closed schema and canonical values on the target delegation
63
+ * 5. the target's `delegation_id` recomputes from the target's own body
64
+ * 6. the revocation's `delegation_id` equals the target's
65
+ * 7. the revocation's `revoker` equals the TARGET's `issuer` (draft section 3.5)
66
+ * 8. the revoker's key resolves, at the revocation's `revoked_at`
67
+ * 9. the Ed25519 signature verifies over the domain-tagged preimage
68
+ *
69
+ * Step 8 hands the resolver `target.issuer`, read from the target delegation, not the
70
+ * `revoker` the record carries. The two are equal by step 7, and reading the target's
71
+ * member is what makes the authorization external to the record: no field inside a
72
+ * revocation selects the key that authorizes it.
73
+ *
74
+ * Fails closed. Anything unrecognized, any resolver that throws, any shape this schema
75
+ * does not claim, produces invalid, indeterminate or unsupported, never valid. This
76
+ * function does not throw.
77
+ */
78
+ export function verifyAuthorityRevocation(candidate, delegation, options) {
79
+ const read = (key) => {
80
+ try {
81
+ return options ? options[key] : undefined;
82
+ }
83
+ catch {
84
+ return undefined;
85
+ }
86
+ };
87
+ const resolveVerificationKey = read('resolveVerificationKey');
88
+ const snapshot = snapshotPlainData(candidate);
89
+ const shapeFailures = validateAuthorityRevocationShape(snapshot);
90
+ if (shapeFailures.length > 0) {
91
+ const unsupported = shapeFailures.every(item => UNSUPPORTED_CODES.has(item.code));
92
+ return result(unsupported ? 'unsupported' : 'invalid', shapeFailures);
93
+ }
94
+ const revocation = snapshot;
95
+ const body = authorityRevocationBody(revocation);
96
+ const origin = authorityRevocationCascadeOrigin(body);
97
+ if (computeAuthorityRevocationCascadeTransactionId(origin) !== revocation.cascade_transaction_id) {
98
+ return invalid('CASCADE_TRANSACTION_MISMATCH', 'cascade_transaction_id does not recompute from the record');
99
+ }
100
+ if (computeAuthorityRevocationId(body) !== revocation.revocation_id) {
101
+ return invalid('ID_MISMATCH', 'revocation content address does not match its body');
102
+ }
103
+ const target = snapshotPlainData(delegation);
104
+ const targetFailures = validateAuthorityDelegationShape(target);
105
+ if (targetFailures.length > 0) {
106
+ return invalid('SCHEMA_INVALID', `target delegation invalid (${targetFailures[0].code})`);
107
+ }
108
+ if (computeAuthorityDelegationId(authorityDelegationBody(target)) !== target.delegation_id) {
109
+ return invalid('TARGET_ID_MISMATCH', 'target delegation content address does not match its body');
110
+ }
111
+ if (revocation.delegation_id !== target.delegation_id) {
112
+ return invalid('TARGET_MISMATCH', 'revocation does not name this delegation');
113
+ }
114
+ // Draft section 3.5: a delegation may be revoked by its issuer, and by nobody else this
115
+ // document names.
116
+ if (revocation.revoker !== target.issuer) {
117
+ return invalid('REVOKER_NOT_ISSUER', 'revoker is not the target delegation issuer');
118
+ }
119
+ if (typeof resolveVerificationKey !== 'function') {
120
+ return indeterminate('KEY_RESOLUTION_FAILED', 'no verification key resolver was supplied');
121
+ }
122
+ let resolved = null;
123
+ try {
124
+ // target.issuer, not revocation.revoker: the authorizing identity comes from the
125
+ // record being revoked.
126
+ resolved = resolveVerificationKey(target.issuer, revocation.verification_method, revocation.revoked_at);
127
+ }
128
+ catch {
129
+ resolved = null;
130
+ }
131
+ const keyFailure = keyResolutionFailure(resolved);
132
+ if (keyFailure)
133
+ return keyFailure;
134
+ if (!verifyAuthorityRevocationSignature(revocation, resolved)) {
135
+ return invalid('SIGNATURE_INVALID', 'Ed25519 signature is invalid');
136
+ }
137
+ return result('valid', []);
138
+ }
139
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../../src/v2/authority-revocation/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { FencedWrite, FencedWriteOutcome, StateMarker } from './types.js';
2
+ /**
3
+ * An authority-state publication log with a fencing gate on every write.
4
+ *
5
+ * Generic in the payload on purpose: this class orders writes and stores nothing about
6
+ * authority itself. The payload is whatever the deployment publishes as a state view, a
7
+ * store handle, a snapshot identifier or a record set. The SDK has no opinion about it.
8
+ *
9
+ * The gate, in one line each:
10
+ *
11
+ * - a token BELOW the highest already accepted is refused, `stale_fencing_token`
12
+ * - a token EQUAL to it is accepted, because equal has not gone backwards: the same holder
13
+ * is retrying, and the retry is idempotent
14
+ * - a token ABOVE it is accepted, and so is a token the log has never seen before, as long
15
+ * as it does not go backwards. The gate fences state that is behind, not state that
16
+ * merely differs
17
+ * - a token counted in a DIFFERENT SCOPE from the log's is refused,
18
+ * `fencing_scope_mismatch`, and an absent or malformed token is refused
19
+ * `fencing_token_unreadable`. Two markers from different scopes order nothing, and a
20
+ * write path that cannot order a token is not fenced. Neither refusal is in any source;
21
+ * both are this module's choice, and they are kept apart because an unreadable token is
22
+ * a different finding from a backwards one
23
+ *
24
+ * A refused write changes nothing: not the published payload, not the highest token. That
25
+ * is the property the whole class exists for, and a caller reads `accepted` to learn which
26
+ * of the two happened rather than comparing payloads.
27
+ *
28
+ * NOT DURABLE, NOT CONCURRENT, NOT A LOCK SERVICE. This holds one token and one payload in
29
+ * this process's heap. It acquires no lock, contacts no lock service, and its check-then-set
30
+ * is one synchronous statement sequence, which is safe on this runtime and is a property of
31
+ * the runtime rather than a pattern a durable store may copy. The same warning
32
+ * `InMemoryAuthorityRevocationStore` carries applies here for the same reason.
33
+ */
34
+ export declare class FencedAuthorityStateLog<T> {
35
+ private highest;
36
+ private payload;
37
+ private written;
38
+ /** The highest token accepted so far, or `null` when nothing has been published. */
39
+ highestToken(): StateMarker | null;
40
+ /** What is published now. `undefined` when no write has landed, which a caller must tell
41
+ * apart from a write that landed carrying `undefined`; `hasPublished()` is how. */
42
+ published(): T | undefined;
43
+ hasPublished(): boolean;
44
+ /** Submit a write. See the class doc for the four outcomes. Never throws for a malformed
45
+ * token: an unreadable token is one that cannot be shown to have moved forward, so it is
46
+ * refused. */
47
+ write(write: FencedWrite<T>): FencedWriteOutcome<T>;
48
+ }
49
+ //# sourceMappingURL=fencing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fencing.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-state/fencing.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,uBAAuB,CAAC,CAAC;IACpC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAAQ;IAEvB,oFAAoF;IACpF,YAAY,IAAI,WAAW,GAAG,IAAI,CAEjC;IAED;wFACoF;IACpF,SAAS,IAAI,CAAC,GAAG,SAAS,CAEzB;IAED,YAAY,IAAI,OAAO,CAEtB;IAED;;mBAEe;IACf,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAmBlD;CACF"}
@@ -0,0 +1,92 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // PROPOSED, OPT-IN. Fencing on the authority-state WRITE path.
5
+ // See ./types.ts for the specification position. Proposed.
6
+ //
7
+ // WHY THIS IS A SEPARATE AXIS FROM THE READ PATH. A read-side high-water mark protects one
8
+ // verifier that has already seen the newer state. It does nothing for a verifier that has
9
+ // seen nothing, reading a published view that a stale writer republished underneath it. A
10
+ // partition that resolves the wrong way rolls authority back with no restore involved, and
11
+ // the read path never sees a regression because the published state simply IS the old
12
+ // state. So the check has to exist where the write lands.
13
+ //
14
+ // The rule implemented here is the one Kleppmann's "How to do distributed locking" states:
15
+ // the storage server takes an active role in checking tokens and rejects any write on which
16
+ // the token has gone backwards. `OPEN-QUESTIONS.md` names authority rollback as open and
17
+ // names an append-only revocation log a restore must replay as the other candidate
18
+ // mechanism in the same sentence. That one is NOT modelled here. Neither is specified.
19
+ import { compareStateMarker, sameScope } from './marker.js';
20
+ /**
21
+ * An authority-state publication log with a fencing gate on every write.
22
+ *
23
+ * Generic in the payload on purpose: this class orders writes and stores nothing about
24
+ * authority itself. The payload is whatever the deployment publishes as a state view, a
25
+ * store handle, a snapshot identifier or a record set. The SDK has no opinion about it.
26
+ *
27
+ * The gate, in one line each:
28
+ *
29
+ * - a token BELOW the highest already accepted is refused, `stale_fencing_token`
30
+ * - a token EQUAL to it is accepted, because equal has not gone backwards: the same holder
31
+ * is retrying, and the retry is idempotent
32
+ * - a token ABOVE it is accepted, and so is a token the log has never seen before, as long
33
+ * as it does not go backwards. The gate fences state that is behind, not state that
34
+ * merely differs
35
+ * - a token counted in a DIFFERENT SCOPE from the log's is refused,
36
+ * `fencing_scope_mismatch`, and an absent or malformed token is refused
37
+ * `fencing_token_unreadable`. Two markers from different scopes order nothing, and a
38
+ * write path that cannot order a token is not fenced. Neither refusal is in any source;
39
+ * both are this module's choice, and they are kept apart because an unreadable token is
40
+ * a different finding from a backwards one
41
+ *
42
+ * A refused write changes nothing: not the published payload, not the highest token. That
43
+ * is the property the whole class exists for, and a caller reads `accepted` to learn which
44
+ * of the two happened rather than comparing payloads.
45
+ *
46
+ * NOT DURABLE, NOT CONCURRENT, NOT A LOCK SERVICE. This holds one token and one payload in
47
+ * this process's heap. It acquires no lock, contacts no lock service, and its check-then-set
48
+ * is one synchronous statement sequence, which is safe on this runtime and is a property of
49
+ * the runtime rather than a pattern a durable store may copy. The same warning
50
+ * `InMemoryAuthorityRevocationStore` carries applies here for the same reason.
51
+ */
52
+ export class FencedAuthorityStateLog {
53
+ highest = null;
54
+ payload = undefined;
55
+ written = false;
56
+ /** The highest token accepted so far, or `null` when nothing has been published. */
57
+ highestToken() {
58
+ return this.highest;
59
+ }
60
+ /** What is published now. `undefined` when no write has landed, which a caller must tell
61
+ * apart from a write that landed carrying `undefined`; `hasPublished()` is how. */
62
+ published() {
63
+ return this.payload;
64
+ }
65
+ hasPublished() {
66
+ return this.written;
67
+ }
68
+ /** Submit a write. See the class doc for the four outcomes. Never throws for a malformed
69
+ * token: an unreadable token is one that cannot be shown to have moved forward, so it is
70
+ * refused. */
71
+ write(write) {
72
+ const token = write?.token;
73
+ // Read the token on its own first. An unreadable token is a different finding from a
74
+ // stale one, and collapsing them would report a backwards move that never happened.
75
+ if (compareStateMarker(token, token) !== 'forward') {
76
+ return { accepted: false, code: 'fencing_token_unreadable', published: this.highest };
77
+ }
78
+ if (this.highest !== null) {
79
+ if (!sameScope(this.highest, token)) {
80
+ return { accepted: false, code: 'fencing_scope_mismatch', published: this.highest };
81
+ }
82
+ if (compareStateMarker(this.highest, token) !== 'forward') {
83
+ return { accepted: false, code: 'stale_fencing_token', published: this.highest };
84
+ }
85
+ }
86
+ this.highest = token;
87
+ this.payload = write.payload;
88
+ this.written = true;
89
+ return { accepted: true, published: token, payload: write.payload };
90
+ }
91
+ }
92
+ //# sourceMappingURL=fencing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fencing.js","sourceRoot":"","sources":["../../../../src/v2/authority-state/fencing.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,+DAA+D;AAC/D,2DAA2D;AAC3D,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,0FAA0F;AAC1F,2FAA2F;AAC3F,sFAAsF;AACtF,0DAA0D;AAC1D,EAAE;AACF,2FAA2F;AAC3F,4FAA4F;AAC5F,yFAAyF;AACzF,mFAAmF;AACnF,uFAAuF;AAEvF,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAG3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,OAAO,uBAAuB;IAC1B,OAAO,GAAuB,IAAI,CAAA;IAClC,OAAO,GAAkB,SAAS,CAAA;IAClC,OAAO,GAAG,KAAK,CAAA;IAEvB,oFAAoF;IACpF,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED;wFACoF;IACpF,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED;;mBAEe;IACf,KAAK,CAAC,KAAqB;QACzB,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,CAAA;QAC1B,qFAAqF;QACrF,oFAAoF;QACpF,IAAI,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,0BAA0B,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;QACvF,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;gBACpC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,wBAAwB,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;YACrF,CAAC;YACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;YAClF,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;IACrE,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './marker.js';
3
+ export * from './retained.js';
4
+ export * from './fencing.js';
5
+ export * from './withdrawal.js';
6
+ export * from './report.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-state/index.ts"],"names":[],"mappings":"AAQA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,14 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // PROPOSED, OPT-IN authority state markers, write fencing and revocation withdrawal.
5
+ // Nothing here is required by draft-pidlisnyi-aps-03 and nothing here changes any existing
6
+ // exported behaviour. Concept source: aeoess/agent-authority-lifecycle, invariant candidates
7
+ // CAND-08 and CAND-02.
8
+ export * from './types.js';
9
+ export * from './marker.js';
10
+ export * from './retained.js';
11
+ export * from './fencing.js';
12
+ export * from './withdrawal.js';
13
+ export * from './report.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/v2/authority-state/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,qFAAqF;AACrF,2FAA2F;AAC3F,6FAA6F;AAC7F,uBAAuB;AAEvB,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,70 @@
1
+ import { type MonotonicityOutcome, type StateMarker, type StateMarkerScope, type UnplaceableDisposition } from './types.js';
2
+ /** Thrown when a caller asks for a marker the vocabulary does not allow. A shape rule
3
+ * broken at construction is a programming error, not a verdict. Mirrors
4
+ * `LifecycleStateError` in src/v2/lifecycle-state/. */
5
+ export declare class AuthorityStateError extends Error {
6
+ readonly code: string;
7
+ constructor(code: string, message: string);
8
+ }
9
+ export declare function isStateMarkerScope(value: unknown): value is StateMarkerScope;
10
+ export declare function isMonotonicityOutcome(value: unknown): value is MonotonicityOutcome;
11
+ export declare function isUnplaceableDisposition(value: unknown): value is UnplaceableDisposition;
12
+ export interface StateMarkerInput {
13
+ readonly value: string;
14
+ readonly scope: StateMarkerScope;
15
+ readonly scope_ref?: string;
16
+ }
17
+ /**
18
+ * Build a `StateMarker`, enforcing its shape rules.
19
+ *
20
+ * 1. `value` is a canonical unsigned decimal integer, as a string. A number would lose
21
+ * exactness past 2^53 - 1 and would admit `1.0`, `1e3` and `-1`, none of which orders
22
+ * the way a generation counter has to.
23
+ * 2. `scope` is one of the four. There is no fifth and there is no default: which thing a
24
+ * generation is counted within is the choice the proposed text does not make, so it has
25
+ * to be stated rather than assumed.
26
+ * 3. `scope_ref` is present and non-empty exactly when `scope` is not `global`. A
27
+ * per-delegation marker that does not say which delegation cannot be compared against
28
+ * anything.
29
+ *
30
+ * Proposed. Concept source: aeoess/agent-authority-lifecycle, `Authority epoch`.
31
+ */
32
+ export declare function stateMarker(input: StateMarkerInput): StateMarker;
33
+ /** Whether two markers are counted in the same thing and can therefore be ordered. */
34
+ export declare function sameScope(a: StateMarker, b: StateMarker): boolean;
35
+ /**
36
+ * Place a presented marker against what a verifier has established.
37
+ *
38
+ * | established | presented | outcome |
39
+ * |-------------|--------------------|---------------|
40
+ * | `null` | any | `unplaceable` |
41
+ * | any | `null` | `unplaceable` |
42
+ * | any | a different scope | `unplaceable` |
43
+ * | m | >= m | `forward` |
44
+ * | m | < m | `regressed` |
45
+ *
46
+ * Equal is `forward`, not a third thing: a view that has not moved has not gone backwards.
47
+ *
48
+ * `unplaceable` is where the honesty of the whole module sits. It is returned for a first
49
+ * read and for a cross-scope comparison, it is NOT a verdict, and nothing downstream turns
50
+ * it into one on its own. The proposed text gives a verifier with no prior observation
51
+ * nothing to compare against and does not say whether such a read is trusted or refused.
52
+ *
53
+ * Comparison is integer, through BigInt, never lexical: "10" is after "9".
54
+ *
55
+ * Never throws for a malformed marker. A marker this function cannot read is one it cannot
56
+ * place, which is `unplaceable`, and throwing on the read path of a state comparison would
57
+ * turn a data problem into a crash in a verifier.
58
+ */
59
+ export declare function compareStateMarker(established: StateMarker | null | undefined, presented: StateMarker | null | undefined): MonotonicityOutcome;
60
+ /**
61
+ * The high-water mark a verifier holds after reading a presented view.
62
+ *
63
+ * It only ever moves forward. A regressed view does not lower it, an unplaceable view does
64
+ * not replace it, and a verifier that had none adopts the presented one. This is the
65
+ * "monotonicity against what the verifier has established" limb of CAND-08, which is
66
+ * weaker than a rule against global truth and is the honest strength available: a verifier
67
+ * that has never seen the newer state cannot detect a regression and is not at fault.
68
+ */
69
+ export declare function advanceHighWaterMark(established: StateMarker | null | undefined, presented: StateMarker | null | undefined): StateMarker | null;
70
+ //# sourceMappingURL=marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-state/marker.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAA;AAEnB;;wDAEwD;AACxD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAIxC;CACF;AAMD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,sBAAsB,CAExF;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAgChE;AAED,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAEjE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC3C,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACxC,mBAAmB,CAMrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EAC3C,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACxC,WAAW,GAAG,IAAI,CAIpB"}