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.
- package/SECURITY.md +11 -0
- package/dist/src/core/tool-integrity.d.ts +13 -0
- package/dist/src/core/tool-integrity.d.ts.map +1 -1
- package/dist/src/core/tool-integrity.js +1 -1
- package/dist/src/core/tool-integrity.js.map +1 -1
- package/dist/src/index.d.ts +52 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +282 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/v2/activation/canonical.d.ts +40 -0
- package/dist/src/v2/activation/canonical.d.ts.map +1 -0
- package/dist/src/v2/activation/canonical.js +64 -0
- package/dist/src/v2/activation/canonical.js.map +1 -0
- package/dist/src/v2/activation/index.d.ts +4 -0
- package/dist/src/v2/activation/index.d.ts.map +1 -0
- package/dist/src/v2/activation/index.js +11 -0
- package/dist/src/v2/activation/index.js.map +1 -0
- package/dist/src/v2/activation/types.d.ts +268 -0
- package/dist/src/v2/activation/types.d.ts.map +1 -0
- package/dist/src/v2/activation/types.js +198 -0
- package/dist/src/v2/activation/types.js.map +1 -0
- package/dist/src/v2/activation/verify.d.ts +132 -0
- package/dist/src/v2/activation/verify.d.ts.map +1 -0
- package/dist/src/v2/activation/verify.js +406 -0
- package/dist/src/v2/activation/verify.js.map +1 -0
- package/dist/src/v2/authority-revocation/canonical.d.ts +46 -0
- package/dist/src/v2/authority-revocation/canonical.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/canonical.js +68 -0
- package/dist/src/v2/authority-revocation/canonical.js.map +1 -0
- package/dist/src/v2/authority-revocation/index.d.ts +9 -0
- package/dist/src/v2/authority-revocation/index.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/index.js +11 -0
- package/dist/src/v2/authority-revocation/index.js.map +1 -0
- package/dist/src/v2/authority-revocation/issue.d.ts +54 -0
- package/dist/src/v2/authority-revocation/issue.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/issue.js +111 -0
- package/dist/src/v2/authority-revocation/issue.js.map +1 -0
- package/dist/src/v2/authority-revocation/record.d.ts +69 -0
- package/dist/src/v2/authority-revocation/record.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/record.js +51 -0
- package/dist/src/v2/authority-revocation/record.js.map +1 -0
- package/dist/src/v2/authority-revocation/resolver.d.ts +30 -0
- package/dist/src/v2/authority-revocation/resolver.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/resolver.js +52 -0
- package/dist/src/v2/authority-revocation/resolver.js.map +1 -0
- package/dist/src/v2/authority-revocation/schema.d.ts +15 -0
- package/dist/src/v2/authority-revocation/schema.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/schema.js +107 -0
- package/dist/src/v2/authority-revocation/schema.js.map +1 -0
- package/dist/src/v2/authority-revocation/store.d.ts +55 -0
- package/dist/src/v2/authority-revocation/store.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/store.js +69 -0
- package/dist/src/v2/authority-revocation/store.js.map +1 -0
- package/dist/src/v2/authority-revocation/types.d.ts +136 -0
- package/dist/src/v2/authority-revocation/types.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/types.js +11 -0
- package/dist/src/v2/authority-revocation/types.js.map +1 -0
- package/dist/src/v2/authority-revocation/verify.d.ts +38 -0
- package/dist/src/v2/authority-revocation/verify.d.ts.map +1 -0
- package/dist/src/v2/authority-revocation/verify.js +139 -0
- package/dist/src/v2/authority-revocation/verify.js.map +1 -0
- package/dist/src/v2/authority-state/fencing.d.ts +49 -0
- package/dist/src/v2/authority-state/fencing.d.ts.map +1 -0
- package/dist/src/v2/authority-state/fencing.js +92 -0
- package/dist/src/v2/authority-state/fencing.js.map +1 -0
- package/dist/src/v2/authority-state/index.d.ts +7 -0
- package/dist/src/v2/authority-state/index.d.ts.map +1 -0
- package/dist/src/v2/authority-state/index.js +14 -0
- package/dist/src/v2/authority-state/index.js.map +1 -0
- package/dist/src/v2/authority-state/marker.d.ts +70 -0
- package/dist/src/v2/authority-state/marker.d.ts.map +1 -0
- package/dist/src/v2/authority-state/marker.js +122 -0
- package/dist/src/v2/authority-state/marker.js.map +1 -0
- package/dist/src/v2/authority-state/report.d.ts +55 -0
- package/dist/src/v2/authority-state/report.d.ts.map +1 -0
- package/dist/src/v2/authority-state/report.js +51 -0
- package/dist/src/v2/authority-state/report.js.map +1 -0
- package/dist/src/v2/authority-state/retained.d.ts +82 -0
- package/dist/src/v2/authority-state/retained.d.ts.map +1 -0
- package/dist/src/v2/authority-state/retained.js +93 -0
- package/dist/src/v2/authority-state/retained.js.map +1 -0
- package/dist/src/v2/authority-state/types.d.ts +198 -0
- package/dist/src/v2/authority-state/types.d.ts.map +1 -0
- package/dist/src/v2/authority-state/types.js +103 -0
- package/dist/src/v2/authority-state/types.js.map +1 -0
- package/dist/src/v2/authority-state/withdrawal.d.ts +80 -0
- package/dist/src/v2/authority-state/withdrawal.d.ts.map +1 -0
- package/dist/src/v2/authority-state/withdrawal.js +199 -0
- package/dist/src/v2/authority-state/withdrawal.js.map +1 -0
- package/dist/src/v2/bounds/canonical.d.ts +30 -0
- package/dist/src/v2/bounds/canonical.d.ts.map +1 -0
- package/dist/src/v2/bounds/canonical.js +69 -0
- package/dist/src/v2/bounds/canonical.js.map +1 -0
- package/dist/src/v2/bounds/evaluate.d.ts +107 -0
- package/dist/src/v2/bounds/evaluate.d.ts.map +1 -0
- package/dist/src/v2/bounds/evaluate.js +315 -0
- package/dist/src/v2/bounds/evaluate.js.map +1 -0
- package/dist/src/v2/bounds/index.d.ts +6 -0
- package/dist/src/v2/bounds/index.d.ts.map +1 -0
- package/dist/src/v2/bounds/index.js +13 -0
- package/dist/src/v2/bounds/index.js.map +1 -0
- package/dist/src/v2/bounds/purpose.d.ts +2 -0
- package/dist/src/v2/bounds/purpose.d.ts.map +1 -0
- package/dist/src/v2/bounds/purpose.js +23 -0
- package/dist/src/v2/bounds/purpose.js.map +1 -0
- package/dist/src/v2/bounds/record.d.ts +78 -0
- package/dist/src/v2/bounds/record.d.ts.map +1 -0
- package/dist/src/v2/bounds/record.js +170 -0
- package/dist/src/v2/bounds/record.js.map +1 -0
- package/dist/src/v2/bounds/types.d.ts +275 -0
- package/dist/src/v2/bounds/types.d.ts.map +1 -0
- package/dist/src/v2/bounds/types.js +124 -0
- package/dist/src/v2/bounds/types.js.map +1 -0
- package/dist/src/v2/capability-binding/binding.d.ts +67 -0
- package/dist/src/v2/capability-binding/binding.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/binding.js +267 -0
- package/dist/src/v2/capability-binding/binding.js.map +1 -0
- package/dist/src/v2/capability-binding/digest.d.ts +33 -0
- package/dist/src/v2/capability-binding/digest.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/digest.js +55 -0
- package/dist/src/v2/capability-binding/digest.js.map +1 -0
- package/dist/src/v2/capability-binding/identifier.d.ts +103 -0
- package/dist/src/v2/capability-binding/identifier.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/identifier.js +281 -0
- package/dist/src/v2/capability-binding/identifier.js.map +1 -0
- package/dist/src/v2/capability-binding/index.d.ts +6 -0
- package/dist/src/v2/capability-binding/index.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/index.js +13 -0
- package/dist/src/v2/capability-binding/index.js.map +1 -0
- package/dist/src/v2/capability-binding/pins.d.ts +30 -0
- package/dist/src/v2/capability-binding/pins.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/pins.js +109 -0
- package/dist/src/v2/capability-binding/pins.js.map +1 -0
- package/dist/src/v2/capability-binding/types.d.ts +213 -0
- package/dist/src/v2/capability-binding/types.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/types.js +150 -0
- package/dist/src/v2/capability-binding/types.js.map +1 -0
- package/dist/src/v2/chain-selection/index.d.ts +4 -0
- package/dist/src/v2/chain-selection/index.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/index.js +11 -0
- package/dist/src/v2/chain-selection/index.js.map +1 -0
- package/dist/src/v2/chain-selection/select.d.ts +62 -0
- package/dist/src/v2/chain-selection/select.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/select.js +390 -0
- package/dist/src/v2/chain-selection/select.js.map +1 -0
- package/dist/src/v2/chain-selection/types.d.ts +189 -0
- package/dist/src/v2/chain-selection/types.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/types.js +81 -0
- package/dist/src/v2/chain-selection/types.js.map +1 -0
- package/dist/src/v2/lifecycle-state/index.d.ts +4 -0
- package/dist/src/v2/lifecycle-state/index.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/index.js +10 -0
- package/dist/src/v2/lifecycle-state/index.js.map +1 -0
- package/dist/src/v2/lifecycle-state/map.d.ts +52 -0
- package/dist/src/v2/lifecycle-state/map.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/map.js +122 -0
- package/dist/src/v2/lifecycle-state/map.js.map +1 -0
- package/dist/src/v2/lifecycle-state/state.d.ts +60 -0
- package/dist/src/v2/lifecycle-state/state.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/state.js +157 -0
- package/dist/src/v2/lifecycle-state/state.js.map +1 -0
- package/dist/src/v2/lifecycle-state/types.d.ts +163 -0
- package/dist/src/v2/lifecycle-state/types.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/types.js +121 -0
- package/dist/src/v2/lifecycle-state/types.js.map +1 -0
- package/dist/src/v2/receipt-core/composite.d.ts +69 -3
- package/dist/src/v2/receipt-core/composite.d.ts.map +1 -1
- package/dist/src/v2/receipt-core/composite.js +75 -9
- package/dist/src/v2/receipt-core/composite.js.map +1 -1
- package/dist/src/v2/receipt-core/predecessor.d.ts +95 -0
- package/dist/src/v2/receipt-core/predecessor.d.ts.map +1 -0
- package/dist/src/v2/receipt-core/predecessor.js +115 -0
- package/dist/src/v2/receipt-core/predecessor.js.map +1 -0
- package/dist/src/v2/status-coverage/decide.d.ts +52 -0
- package/dist/src/v2/status-coverage/decide.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/decide.js +398 -0
- package/dist/src/v2/status-coverage/decide.js.map +1 -0
- package/dist/src/v2/status-coverage/index.d.ts +3 -0
- package/dist/src/v2/status-coverage/index.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/index.js +10 -0
- package/dist/src/v2/status-coverage/index.js.map +1 -0
- package/dist/src/v2/status-coverage/types.d.ts +258 -0
- package/dist/src/v2/status-coverage/types.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/types.js +127 -0
- package/dist/src/v2/status-coverage/types.js.map +1 -0
- package/dist/src/v2/suspension/evaluate.d.ts +88 -0
- package/dist/src/v2/suspension/evaluate.d.ts.map +1 -0
- package/dist/src/v2/suspension/evaluate.js +404 -0
- package/dist/src/v2/suspension/evaluate.js.map +1 -0
- package/dist/src/v2/suspension/index.d.ts +3 -0
- package/dist/src/v2/suspension/index.d.ts.map +1 -0
- package/dist/src/v2/suspension/index.js +10 -0
- package/dist/src/v2/suspension/index.js.map +1 -0
- package/dist/src/v2/suspension/types.d.ts +243 -0
- package/dist/src/v2/suspension/types.d.ts.map +1 -0
- package/dist/src/v2/suspension/types.js +135 -0
- package/dist/src/v2/suspension/types.js.map +1 -0
- package/package.json +10 -7
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Authority state markers, write fencing, and withdrawal of a recorded
|
|
5
|
+
// revocation.
|
|
6
|
+
//
|
|
7
|
+
// NOT REQUIRED BY draft-pidlisnyi-aps-03. The published text contains no occurrence of
|
|
8
|
+
// `epoch`, `fencing`, `snapshot`, `replica` or `restore`, and defines no record for
|
|
9
|
+
// withdrawing a revocation. What it does fix, and what this module is careful not to
|
|
10
|
+
// disturb, is section 3.3: "Verification returns one of valid, invalid, indeterminate, or
|
|
11
|
+
// unsupported with a stable failure code", and section 3.5: "Revocation is irreversible."
|
|
12
|
+
// `AuthorityValidationState`, `AuthorityValidationResult`, `AuthorityRevocationStore` and
|
|
13
|
+
// everything `verifyAuthorityDelegationChain` returns are unchanged, and a caller that does
|
|
14
|
+
// not import this module sees exactly today's behaviour.
|
|
15
|
+
//
|
|
16
|
+
// Concept source: the aeoess/agent-authority-lifecycle concept document
|
|
17
|
+
// (AUTHORITY-LIFECYCLE.md, the `Authority epoch` concept and invariants L3, L7 and L11;
|
|
18
|
+
// OPEN-QUESTIONS.md, `Authority rollback`) and its invariant candidates CAND-08 (no silent
|
|
19
|
+
// restoration from rollback or stale state) and CAND-02 (later evidence does not rewrite
|
|
20
|
+
// earlier evidence). Every one of those is proposed, not specified. Nothing here claims
|
|
21
|
+
// otherwise, and `OPEN-QUESTIONS.md` keeps open both the mechanism and what a verifier
|
|
22
|
+
// should return after a restore.
|
|
23
|
+
//
|
|
24
|
+
// Three deliberate non-decisions are encoded as types rather than as behaviour:
|
|
25
|
+
//
|
|
26
|
+
// 1. The proposed text says an authority epoch is "where a system uses generations" and
|
|
27
|
+
// stops. It does not say who advances one, whether it is global or per delegation,
|
|
28
|
+
// whether it is signed, or what evidence carries it. `StateMarker` is therefore an
|
|
29
|
+
// opaque comparable supplied by the caller, and this module defines only the comparison.
|
|
30
|
+
// 2. A verifier with no prior observation has nothing to compare against. That is
|
|
31
|
+
// `unplaceable`, and it is not a verdict. The caller says what to do with it.
|
|
32
|
+
// 3. Who may withdraw a revocation is not stated anywhere. Standing is resolved through an
|
|
33
|
+
// injected callback and never read from the record asserting it.
|
|
34
|
+
/** What a marker is counted within. Comparing two markers from different scopes orders
|
|
35
|
+
* nothing, so the comparison reports `unplaceable` rather than inventing an order.
|
|
36
|
+
*
|
|
37
|
+
* The proposed text names none of these. They exist because the fixture that forced this
|
|
38
|
+
* module had to pick one (it picked a global integer on a state view) and recorded that
|
|
39
|
+
* the choice was not read from the text. Carrying the scope makes that choice visible in
|
|
40
|
+
* the record instead of implicit in the deployment. Proposed. */
|
|
41
|
+
export const STATE_MARKER_SCOPES = ['global', 'per_delegation', 'per_principal', 'per_store'];
|
|
42
|
+
/** The result of placing a presented marker against what a verifier has established.
|
|
43
|
+
*
|
|
44
|
+
* - `forward` the presented marker advanced, or held equal. Read the view normally.
|
|
45
|
+
* - `regressed` the presented marker went backwards against an established high-water
|
|
46
|
+
* mark. CAND-08's refusal case.
|
|
47
|
+
* - `unplaceable` there is nothing to compare against, or the two markers are counted in
|
|
48
|
+
* different scopes. **Deliberately not a verdict.** A high-water mark has
|
|
49
|
+
* to start somewhere and neither the proposed text nor draft-03 says
|
|
50
|
+
* whether a first read is trusted or refused. Both are defensible and the
|
|
51
|
+
* outcomes differ, so this module reports the fact and the caller
|
|
52
|
+
* decides. See `UnplaceableDisposition`. */
|
|
53
|
+
export const MONOTONICITY_OUTCOMES = ['forward', 'regressed', 'unplaceable'];
|
|
54
|
+
/** What a caller wants done with an `unplaceable` presented view. Required, with no
|
|
55
|
+
* default, because the SDK picking one would be the SDK deciding a question its own
|
|
56
|
+
* concept source records as undecided. */
|
|
57
|
+
export const UNPLACEABLE_DISPOSITIONS = ['read_presented', 'refuse'];
|
|
58
|
+
/** Why a fenced write was refused.
|
|
59
|
+
*
|
|
60
|
+
* - `stale_fencing_token` the token went backwards against the highest already seen.
|
|
61
|
+
* The only one of the three the source states.
|
|
62
|
+
* - `fencing_scope_mismatch` the token is counted in a different scope from the log's, so
|
|
63
|
+
* it cannot be ordered against what the log holds.
|
|
64
|
+
* - `fencing_token_unreadable` the token is absent or not a well-formed `StateMarker`.
|
|
65
|
+
*
|
|
66
|
+
* A write path that cannot order a token is not fenced, so the second and third refuse
|
|
67
|
+
* rather than guess. Neither is in any source; both are this module's choice. */
|
|
68
|
+
export const FENCED_WRITE_REFUSAL_CODES = [
|
|
69
|
+
'stale_fencing_token',
|
|
70
|
+
'fencing_scope_mismatch',
|
|
71
|
+
'fencing_token_unreadable',
|
|
72
|
+
];
|
|
73
|
+
/** The record type a withdrawal carries.
|
|
74
|
+
*
|
|
75
|
+
* `proposed:` is load-bearing. Record fields, failure-class names and verifier semantics
|
|
76
|
+
* are conformance vocabulary reserved to the maintainer, and neither draft-03 nor the
|
|
77
|
+
* proposed text defines a record for withdrawing a recorded revocation or says what a
|
|
78
|
+
* verifier should do with one. This is a placeholder to argue about, not APS vocabulary. */
|
|
79
|
+
export const REVOCATION_WITHDRAWAL_RECORD_TYPE = 'proposed:aps:revocation-withdrawal:v0';
|
|
80
|
+
export const REVOCATION_WITHDRAWAL_VERSION = '0';
|
|
81
|
+
/** What an injected standing resolver may answer.
|
|
82
|
+
*
|
|
83
|
+
* `unknown` is a first-class answer and is not `no_standing`. A verifier that cannot
|
|
84
|
+
* establish whether the withdrawer had standing has not established that they lacked it,
|
|
85
|
+
* and the refusal reason says which of the two happened. */
|
|
86
|
+
export const WITHDRAWAL_STANDINGS = ['has_standing', 'no_standing', 'unknown'];
|
|
87
|
+
/** Why a withdrawal was accepted or refused. Stable, module-local codes. */
|
|
88
|
+
export const WITHDRAWAL_OUTCOME_CODES = [
|
|
89
|
+
/** Accepted as a record. Accepted never means the revocation is gone. */
|
|
90
|
+
'WITHDRAWAL_ACCEPTED',
|
|
91
|
+
/** The record is not a well-formed `RevocationWithdrawalV0`. */
|
|
92
|
+
'WITHDRAWAL_SCHEMA_INVALID',
|
|
93
|
+
/** No revocation in the held set carries the `revocation_id` this record names. */
|
|
94
|
+
'WITHDRAWAL_NAMES_NO_HELD_REVOCATION',
|
|
95
|
+
/** The named revocation exists but is a revocation of a different delegation. */
|
|
96
|
+
'WITHDRAWAL_TARGET_MISMATCH',
|
|
97
|
+
/** The resolver established that this party may not withdraw this revocation. */
|
|
98
|
+
'WITHDRAWAL_SIGNER_WITHOUT_STANDING',
|
|
99
|
+
/** The resolver could not establish standing either way. Not the same finding as the
|
|
100
|
+
* one above, and reported as `not_established` rather than as a denial. */
|
|
101
|
+
'WITHDRAWAL_STANDING_NOT_ESTABLISHED',
|
|
102
|
+
];
|
|
103
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/v2/authority-state/types.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,yFAAyF;AACzF,cAAc;AACd,EAAE;AACF,uFAAuF;AACvF,oFAAoF;AACpF,qFAAqF;AACrF,0FAA0F;AAC1F,0FAA0F;AAC1F,0FAA0F;AAC1F,4FAA4F;AAC5F,yDAAyD;AACzD,EAAE;AACF,wEAAwE;AACxE,wFAAwF;AACxF,2FAA2F;AAC3F,yFAAyF;AACzF,wFAAwF;AACxF,uFAAuF;AACvF,iCAAiC;AACjC,EAAE;AACF,gFAAgF;AAChF,EAAE;AACF,yFAAyF;AACzF,uFAAuF;AACvF,uFAAuF;AACvF,6FAA6F;AAC7F,mFAAmF;AACnF,kFAAkF;AAClF,4FAA4F;AAC5F,qEAAqE;AAIrE;;;;;;kEAMkE;AAClE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,gBAAgB,EAAE,eAAe,EAAE,WAAW,CAAU,CAAA;AAsBtG;;;;;;;;;;8DAU8D;AAC9D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,aAAa,CAAU,CAAA;AAIrF;;2CAE2C;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,gBAAgB,EAAE,QAAQ,CAAU,CAAA;AA6B7E;;;;;;;;;kFASkF;AAClF,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,qBAAqB;IACrB,wBAAwB;IACxB,0BAA0B;CAClB,CAAA;AAoBV;;;;;6FAK6F;AAC7F,MAAM,CAAC,MAAM,iCAAiC,GAAG,uCAAgD,CAAA;AACjG,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAY,CAAA;AAkCzD;;;;6DAI6D;AAC7D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,cAAc,EAAE,aAAa,EAAE,SAAS,CAAU,CAAA;AAgBvF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,yEAAyE;IACzE,qBAAqB;IACrB,gEAAgE;IAChE,2BAA2B;IAC3B,mFAAmF;IACnF,qCAAqC;IACrC,iFAAiF;IACjF,4BAA4B;IAC5B,iFAAiF;IACjF,oCAAoC;IACpC;gFAC4E;IAC5E,qCAAqC;CAC7B,CAAA"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { AuthorityRevocationV1 } from '../authority-revocation/types.js';
|
|
2
|
+
import { type CorrectedRevocationView, type RevocationWithdrawalV0, type WithdrawalEvaluation, type WithdrawalStanding, type WithdrawalStandingResolver } from './types.js';
|
|
3
|
+
export declare function isWithdrawalStanding(value: unknown): value is WithdrawalStanding;
|
|
4
|
+
export interface RevocationWithdrawalInput {
|
|
5
|
+
readonly revocation_id: string;
|
|
6
|
+
readonly delegation_id: string;
|
|
7
|
+
readonly withdrawn_by: string;
|
|
8
|
+
readonly withdrawn_at: string;
|
|
9
|
+
readonly reason_code: string;
|
|
10
|
+
readonly detail?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build a `RevocationWithdrawalV0`.
|
|
14
|
+
*
|
|
15
|
+
* A shape constructor and nothing more. It does not sign, does not canonicalize, and does
|
|
16
|
+
* not compute an identifier, because minting the signed form of a record type is a
|
|
17
|
+
* conformance-vocabulary decision reserved to the maintainer and this module is not making
|
|
18
|
+
* it. `record_type` carries the `proposed:` namespace for the same reason.
|
|
19
|
+
*
|
|
20
|
+
* An absent `detail` is absent, never `null`: the key is not present at all, matching how
|
|
21
|
+
* the revocation record treats its own optional detail.
|
|
22
|
+
*/
|
|
23
|
+
export declare function revocationWithdrawal(input: RevocationWithdrawalInput): RevocationWithdrawalV0;
|
|
24
|
+
/** A standing resolver that accepts a withdrawal only from the party the revocation itself
|
|
25
|
+
* names as revoker.
|
|
26
|
+
*
|
|
27
|
+
* Supplied because it is the rule the forcing fixture chose and it needs to be runnable.
|
|
28
|
+
* IT IS A CHOICE, NOT A RULE READ FROM ANY TEXT. Draft-03 section 3.5 names the issuer as
|
|
29
|
+
* the party who may revoke; nothing in draft-03 or in the proposed text says who may
|
|
30
|
+
* withdraw a revocation, and the concept document's own `Lifecycle standing` entry says
|
|
31
|
+
* the party who may change an artifact "is not always the issuer". A deployment whose
|
|
32
|
+
* authority model gives a security function, a successor or a quorum standing to correct a
|
|
33
|
+
* publication error should pass its own resolver instead of this one. */
|
|
34
|
+
export declare const withdrawalSignerIsRevoker: WithdrawalStandingResolver;
|
|
35
|
+
/**
|
|
36
|
+
* Decide whether one withdrawal record is accepted against a set of held revocations.
|
|
37
|
+
*
|
|
38
|
+
* Four questions, kept separate on purpose, each with its own code:
|
|
39
|
+
*
|
|
40
|
+
* 1. Is the record a well-formed withdrawal? `WITHDRAWAL_SCHEMA_INVALID`.
|
|
41
|
+
* 2. Does it name a revocation the held set actually contains?
|
|
42
|
+
* `WITHDRAWAL_NAMES_NO_HELD_REVOCATION`.
|
|
43
|
+
* 3. Does that revocation revoke the delegation this record names?
|
|
44
|
+
* `WITHDRAWAL_TARGET_MISMATCH`.
|
|
45
|
+
* 4. May this party withdraw it? Asked of the injected resolver, never of the record.
|
|
46
|
+
* `WITHDRAWAL_SIGNER_WITHOUT_STANDING` when the resolver establishes they may not, and
|
|
47
|
+
* `WITHDRAWAL_STANDING_NOT_ESTABLISHED` when it cannot establish either way.
|
|
48
|
+
*
|
|
49
|
+
* The last split is the wording rule, executable: a standing question the verifier could
|
|
50
|
+
* not answer is not established, and that is not the same finding as a party established to
|
|
51
|
+
* lack standing. Both refuse the withdrawal, and a caller reporting the refusal has to be
|
|
52
|
+
* able to say which one happened.
|
|
53
|
+
*
|
|
54
|
+
* AUTHENTICATION IS THE CALLER'S. This function never checks a signature, because a
|
|
55
|
+
* withdrawal has no signed form in this SDK, on purpose; see `RevocationWithdrawalV0`.
|
|
56
|
+
* Whoever calls it is the party asserting the record is genuine, exactly as whoever calls
|
|
57
|
+
* `insertVerifiedRevocation` asserts the revocation was verified.
|
|
58
|
+
*
|
|
59
|
+
* NOTHING HERE REMOVES A REVOCATION, on any path. An accepted withdrawal is a record about
|
|
60
|
+
* a record. The held set handed in is not mutated and no store is touched.
|
|
61
|
+
*/
|
|
62
|
+
export declare function evaluateRevocationWithdrawal(withdrawal: RevocationWithdrawalV0, heldRevocations: readonly AuthorityRevocationV1[], resolveStanding: WithdrawalStandingResolver): WithdrawalEvaluation;
|
|
63
|
+
/**
|
|
64
|
+
* The current position of one revocation together with every withdrawal referencing it.
|
|
65
|
+
*
|
|
66
|
+
* This is the field that did not exist. A verifier that must report "revoked, and the
|
|
67
|
+
* revoker later said this was recorded in error" had nowhere to put the second half, in
|
|
68
|
+
* either reference SDK or in the proposed text, so it could only report the first half and
|
|
69
|
+
* drop the rest.
|
|
70
|
+
*
|
|
71
|
+
* `revocation` is present and unchanged whether or not anything was accepted. Accepted
|
|
72
|
+
* withdrawals are listed, refused ones are listed with their codes, and neither list makes
|
|
73
|
+
* the revocation ineffective: a later finding is a new record that references the earlier
|
|
74
|
+
* one and states its own effect, never an edit of it and never its removal.
|
|
75
|
+
*
|
|
76
|
+
* Withdrawals naming a different revocation are not silently dropped. They are evaluated,
|
|
77
|
+
* refused `WITHDRAWAL_NAMES_NO_HELD_REVOCATION`, and appear in `refused`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function correctedRevocationView(revocation: AuthorityRevocationV1, withdrawals: readonly RevocationWithdrawalV0[], resolveStanding: WithdrawalStandingResolver): CorrectedRevocationView;
|
|
80
|
+
//# sourceMappingURL=withdrawal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withdrawal.d.ts","sourceRoot":"","sources":["../../../../src/v2/authority-state/withdrawal.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAE7E,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAChC,MAAM,YAAY,CAAA;AAInB,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,sBAAsB,CA8C7F;AAED;;;;;;;;;0EAS0E;AAC1E,eAAO,MAAM,yBAAyB,EAAE,0BACyC,CAAA;AAgBjF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,sBAAsB,EAClC,eAAe,EAAE,SAAS,qBAAqB,EAAE,EACjD,eAAe,EAAE,0BAA0B,GAC1C,oBAAoB,CAqDtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,qBAAqB,EACjC,WAAW,EAAE,SAAS,sBAAsB,EAAE,EAC9C,eAAe,EAAE,0BAA0B,GAC1C,uBAAuB,CAUzB"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Withdrawal, or correction, of a recorded revocation.
|
|
5
|
+
// See ./types.ts for the specification position. Concept source:
|
|
6
|
+
// aeoess/agent-authority-lifecycle, invariant candidate CAND-02 (later evidence does not
|
|
7
|
+
// rewrite earlier evidence) and invariant L3 (reauthorization creates new authority).
|
|
8
|
+
// Proposed.
|
|
9
|
+
//
|
|
10
|
+
// THE ONE SENTENCE THIS FILE EXISTS FOR. A corrected false revocation is a separate record,
|
|
11
|
+
// not a resurrection. Draft-03 section 3.5 states "Revocation is irreversible", and nothing
|
|
12
|
+
// below relaxes that: an accepted withdrawal leaves the revocation held, leaves it
|
|
13
|
+
// verifying byte for byte, and leaves every chain verdict exactly where it was. What the
|
|
14
|
+
// withdrawal changes is what a verifier can REPORT, which had no representation at all.
|
|
15
|
+
//
|
|
16
|
+
// Continuity after a correction still needs a fresh grant from a principal who currently
|
|
17
|
+
// holds authority. This module mints no grant and no authority of any kind.
|
|
18
|
+
import { AuthorityStateError } from './marker.js';
|
|
19
|
+
import { REVOCATION_WITHDRAWAL_RECORD_TYPE, REVOCATION_WITHDRAWAL_VERSION, WITHDRAWAL_STANDINGS, } from './types.js';
|
|
20
|
+
const ID = /^sha256:[0-9a-f]{64}$/;
|
|
21
|
+
export function isWithdrawalStanding(value) {
|
|
22
|
+
return typeof value === 'string' && WITHDRAWAL_STANDINGS.includes(value);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build a `RevocationWithdrawalV0`.
|
|
26
|
+
*
|
|
27
|
+
* A shape constructor and nothing more. It does not sign, does not canonicalize, and does
|
|
28
|
+
* not compute an identifier, because minting the signed form of a record type is a
|
|
29
|
+
* conformance-vocabulary decision reserved to the maintainer and this module is not making
|
|
30
|
+
* it. `record_type` carries the `proposed:` namespace for the same reason.
|
|
31
|
+
*
|
|
32
|
+
* An absent `detail` is absent, never `null`: the key is not present at all, matching how
|
|
33
|
+
* the revocation record treats its own optional detail.
|
|
34
|
+
*/
|
|
35
|
+
export function revocationWithdrawal(input) {
|
|
36
|
+
if (input === null || typeof input !== 'object') {
|
|
37
|
+
throw new AuthorityStateError('WITHDRAWAL_MALFORMED', 'a withdrawal input must be an object');
|
|
38
|
+
}
|
|
39
|
+
for (const field of ['revocation_id', 'delegation_id']) {
|
|
40
|
+
if (typeof input[field] !== 'string' || !ID.test(input[field])) {
|
|
41
|
+
throw new AuthorityStateError('WITHDRAWAL_ID_NONCANONICAL', `${field} must be sha256:<64 lowercase hex>`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const field of ['withdrawn_by', 'withdrawn_at', 'reason_code']) {
|
|
45
|
+
if (typeof input[field] !== 'string' || input[field].length === 0) {
|
|
46
|
+
throw new AuthorityStateError('WITHDRAWAL_FIELD_REQUIRED', `${field} must be a non-empty string`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (input.detail !== undefined && (typeof input.detail !== 'string' || input.detail.length === 0)) {
|
|
50
|
+
throw new AuthorityStateError('WITHDRAWAL_DETAIL_INVALID', 'detail must be a non-empty string when present');
|
|
51
|
+
}
|
|
52
|
+
const record = {
|
|
53
|
+
record_type: REVOCATION_WITHDRAWAL_RECORD_TYPE,
|
|
54
|
+
version: REVOCATION_WITHDRAWAL_VERSION,
|
|
55
|
+
revocation_id: input.revocation_id,
|
|
56
|
+
delegation_id: input.delegation_id,
|
|
57
|
+
withdrawn_by: input.withdrawn_by,
|
|
58
|
+
withdrawn_at: input.withdrawn_at,
|
|
59
|
+
reason_code: input.reason_code,
|
|
60
|
+
};
|
|
61
|
+
if (input.detail !== undefined)
|
|
62
|
+
record.detail = input.detail;
|
|
63
|
+
return Object.freeze(record);
|
|
64
|
+
}
|
|
65
|
+
/** A standing resolver that accepts a withdrawal only from the party the revocation itself
|
|
66
|
+
* names as revoker.
|
|
67
|
+
*
|
|
68
|
+
* Supplied because it is the rule the forcing fixture chose and it needs to be runnable.
|
|
69
|
+
* IT IS A CHOICE, NOT A RULE READ FROM ANY TEXT. Draft-03 section 3.5 names the issuer as
|
|
70
|
+
* the party who may revoke; nothing in draft-03 or in the proposed text says who may
|
|
71
|
+
* withdraw a revocation, and the concept document's own `Lifecycle standing` entry says
|
|
72
|
+
* the party who may change an artifact "is not always the issuer". A deployment whose
|
|
73
|
+
* authority model gives a security function, a successor or a quorum standing to correct a
|
|
74
|
+
* publication error should pass its own resolver instead of this one. */
|
|
75
|
+
export const withdrawalSignerIsRevoker = (withdrawal, revocation) => withdrawal.withdrawn_by === revocation.revoker ? 'has_standing' : 'no_standing';
|
|
76
|
+
function malformed(withdrawal) {
|
|
77
|
+
const w = withdrawal;
|
|
78
|
+
if (w === null || typeof w !== 'object')
|
|
79
|
+
return true;
|
|
80
|
+
if (w.record_type !== REVOCATION_WITHDRAWAL_RECORD_TYPE)
|
|
81
|
+
return true;
|
|
82
|
+
if (w.version !== REVOCATION_WITHDRAWAL_VERSION)
|
|
83
|
+
return true;
|
|
84
|
+
if (typeof w.revocation_id !== 'string' || !ID.test(w.revocation_id))
|
|
85
|
+
return true;
|
|
86
|
+
if (typeof w.delegation_id !== 'string' || !ID.test(w.delegation_id))
|
|
87
|
+
return true;
|
|
88
|
+
for (const field of ['withdrawn_by', 'withdrawn_at', 'reason_code']) {
|
|
89
|
+
const value = w[field];
|
|
90
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Decide whether one withdrawal record is accepted against a set of held revocations.
|
|
97
|
+
*
|
|
98
|
+
* Four questions, kept separate on purpose, each with its own code:
|
|
99
|
+
*
|
|
100
|
+
* 1. Is the record a well-formed withdrawal? `WITHDRAWAL_SCHEMA_INVALID`.
|
|
101
|
+
* 2. Does it name a revocation the held set actually contains?
|
|
102
|
+
* `WITHDRAWAL_NAMES_NO_HELD_REVOCATION`.
|
|
103
|
+
* 3. Does that revocation revoke the delegation this record names?
|
|
104
|
+
* `WITHDRAWAL_TARGET_MISMATCH`.
|
|
105
|
+
* 4. May this party withdraw it? Asked of the injected resolver, never of the record.
|
|
106
|
+
* `WITHDRAWAL_SIGNER_WITHOUT_STANDING` when the resolver establishes they may not, and
|
|
107
|
+
* `WITHDRAWAL_STANDING_NOT_ESTABLISHED` when it cannot establish either way.
|
|
108
|
+
*
|
|
109
|
+
* The last split is the wording rule, executable: a standing question the verifier could
|
|
110
|
+
* not answer is not established, and that is not the same finding as a party established to
|
|
111
|
+
* lack standing. Both refuse the withdrawal, and a caller reporting the refusal has to be
|
|
112
|
+
* able to say which one happened.
|
|
113
|
+
*
|
|
114
|
+
* AUTHENTICATION IS THE CALLER'S. This function never checks a signature, because a
|
|
115
|
+
* withdrawal has no signed form in this SDK, on purpose; see `RevocationWithdrawalV0`.
|
|
116
|
+
* Whoever calls it is the party asserting the record is genuine, exactly as whoever calls
|
|
117
|
+
* `insertVerifiedRevocation` asserts the revocation was verified.
|
|
118
|
+
*
|
|
119
|
+
* NOTHING HERE REMOVES A REVOCATION, on any path. An accepted withdrawal is a record about
|
|
120
|
+
* a record. The held set handed in is not mutated and no store is touched.
|
|
121
|
+
*/
|
|
122
|
+
export function evaluateRevocationWithdrawal(withdrawal, heldRevocations, resolveStanding) {
|
|
123
|
+
if (malformed(withdrawal)) {
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
accepted: false,
|
|
126
|
+
reason_code: 'WITHDRAWAL_SCHEMA_INVALID',
|
|
127
|
+
standing: null,
|
|
128
|
+
withdrawal,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const target = (heldRevocations ?? []).find(r => r?.revocation_id === withdrawal.revocation_id);
|
|
132
|
+
if (target === undefined) {
|
|
133
|
+
return Object.freeze({
|
|
134
|
+
accepted: false,
|
|
135
|
+
reason_code: 'WITHDRAWAL_NAMES_NO_HELD_REVOCATION',
|
|
136
|
+
standing: null,
|
|
137
|
+
withdrawal,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (target.delegation_id !== withdrawal.delegation_id) {
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
accepted: false,
|
|
143
|
+
reason_code: 'WITHDRAWAL_TARGET_MISMATCH',
|
|
144
|
+
standing: null,
|
|
145
|
+
withdrawal,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
let standing;
|
|
149
|
+
try {
|
|
150
|
+
standing = resolveStanding(withdrawal, target);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
standing = 'unknown';
|
|
154
|
+
}
|
|
155
|
+
if (!isWithdrawalStanding(standing))
|
|
156
|
+
standing = 'unknown';
|
|
157
|
+
if (standing === 'has_standing') {
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
accepted: true,
|
|
160
|
+
reason_code: 'WITHDRAWAL_ACCEPTED',
|
|
161
|
+
standing,
|
|
162
|
+
withdrawal,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return Object.freeze({
|
|
166
|
+
accepted: false,
|
|
167
|
+
reason_code: standing === 'no_standing'
|
|
168
|
+
? 'WITHDRAWAL_SIGNER_WITHOUT_STANDING'
|
|
169
|
+
: 'WITHDRAWAL_STANDING_NOT_ESTABLISHED',
|
|
170
|
+
standing,
|
|
171
|
+
withdrawal,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The current position of one revocation together with every withdrawal referencing it.
|
|
176
|
+
*
|
|
177
|
+
* This is the field that did not exist. A verifier that must report "revoked, and the
|
|
178
|
+
* revoker later said this was recorded in error" had nowhere to put the second half, in
|
|
179
|
+
* either reference SDK or in the proposed text, so it could only report the first half and
|
|
180
|
+
* drop the rest.
|
|
181
|
+
*
|
|
182
|
+
* `revocation` is present and unchanged whether or not anything was accepted. Accepted
|
|
183
|
+
* withdrawals are listed, refused ones are listed with their codes, and neither list makes
|
|
184
|
+
* the revocation ineffective: a later finding is a new record that references the earlier
|
|
185
|
+
* one and states its own effect, never an edit of it and never its removal.
|
|
186
|
+
*
|
|
187
|
+
* Withdrawals naming a different revocation are not silently dropped. They are evaluated,
|
|
188
|
+
* refused `WITHDRAWAL_NAMES_NO_HELD_REVOCATION`, and appear in `refused`.
|
|
189
|
+
*/
|
|
190
|
+
export function correctedRevocationView(revocation, withdrawals, resolveStanding) {
|
|
191
|
+
const held = [revocation];
|
|
192
|
+
const evaluations = (withdrawals ?? []).map(w => evaluateRevocationWithdrawal(w, held, resolveStanding));
|
|
193
|
+
return Object.freeze({
|
|
194
|
+
revocation,
|
|
195
|
+
accepted: Object.freeze(evaluations.filter(e => e.accepted)),
|
|
196
|
+
refused: Object.freeze(evaluations.filter(e => !e.accepted)),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=withdrawal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withdrawal.js","sourceRoot":"","sources":["../../../../src/v2/authority-state/withdrawal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AuthorityBoundFulfilment, AuthorityBoundFulfilmentBody, AuthorityExhaustion, AuthorityExhaustionBody } from './types.js';
|
|
2
|
+
/** Domain tags. Each is a distinct tag followed by one zero byte, the same discipline
|
|
3
|
+
* `AuthorityDelegationV1` and `AuthorityRevocationV1` follow, so bytes minted for one
|
|
4
|
+
* construction can never be read as bytes minted for another. The `PROPOSED-` prefix is
|
|
5
|
+
* part of the tag: if any of this is ever specified, the specified construction will use a
|
|
6
|
+
* different tag and records minted under this one will not verify under it. That is the
|
|
7
|
+
* intended behaviour, not a migration problem to solve later. */
|
|
8
|
+
export declare const AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN = "PROPOSED-APS-AUTHORITY-BOUND-FULFILMENT-SIGNATURE-V0\0";
|
|
9
|
+
export declare const AUTHORITY_EXHAUSTION_ID_DOMAIN = "PROPOSED-APS-AUTHORITY-EXHAUSTION-ID-V0\0";
|
|
10
|
+
export declare const AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN = "PROPOSED-APS-AUTHORITY-EXHAUSTION-SIGNATURE-V0\0";
|
|
11
|
+
/** Exact Ed25519 preimage for a fulfilment attestation: the domain tag plus RFC 8785 JCS of
|
|
12
|
+
* the record with `signature` absent. */
|
|
13
|
+
export declare function authorityBoundFulfilmentSignatureInput(body: AuthorityBoundFulfilmentBody): string;
|
|
14
|
+
/** Write-boundary twin. Use when ISSUING. The verification path keeps calling the
|
|
15
|
+
* unrestricted form, so a record minted before the write rule still verifies. */
|
|
16
|
+
export declare function authorityBoundFulfilmentSignatureInputForWrite(body: AuthorityBoundFulfilmentBody): string;
|
|
17
|
+
export declare function signAuthorityBoundFulfilment(body: AuthorityBoundFulfilmentBody, privateKeyHex: string): string;
|
|
18
|
+
export declare function verifyAuthorityBoundFulfilmentSignature(record: AuthorityBoundFulfilment, publicKeyHex: string): boolean;
|
|
19
|
+
/** Exact preimage for `exhaustion_id`: the ID domain tag plus JCS of the body. */
|
|
20
|
+
export declare function authorityExhaustionIdInput(body: AuthorityExhaustionBody): string;
|
|
21
|
+
export declare function computeAuthorityExhaustionId(body: AuthorityExhaustionBody): string;
|
|
22
|
+
export declare function computeAuthorityExhaustionIdForWrite(body: AuthorityExhaustionBody): string;
|
|
23
|
+
/** Exact Ed25519 preimage for the exhaustion record: the signature domain tag plus JCS of
|
|
24
|
+
* the record with `signature` absent. `exhaustion_id` IS inside this preimage, so the
|
|
25
|
+
* identifier is signed rather than being an unauthenticated label beside the signature. */
|
|
26
|
+
export declare function authorityExhaustionSignatureInput(record: Omit<AuthorityExhaustion, 'signature'>): string;
|
|
27
|
+
export declare function authorityExhaustionSignatureInputForWrite(record: Omit<AuthorityExhaustion, 'signature'>): string;
|
|
28
|
+
export declare function signAuthorityExhaustion(record: Omit<AuthorityExhaustion, 'signature'>, privateKeyHex: string): string;
|
|
29
|
+
export declare function verifyAuthorityExhaustionSignature(record: AuthorityExhaustion, publicKeyHex: string): boolean;
|
|
30
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/canonical.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAEnB;;;;;kEAKkE;AAClE,eAAO,MAAM,2CAA2C,2DACE,CAAA;AAC1D,eAAO,MAAM,8BAA8B,8CAA8C,CAAA;AACzF,eAAO,MAAM,qCAAqC,qDACE,CAAA;AAWpD;0CAC0C;AAC1C,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,4BAA4B,GACjC,MAAM,CAER;AAED;kFACkF;AAClF,wBAAgB,8CAA8C,CAC5D,IAAI,EAAE,4BAA4B,GACjC,MAAM,CAER;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,4BAA4B,EAClC,aAAa,EAAE,MAAM,GACpB,MAAM,CAER;AAED,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,wBAAwB,EAChC,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT;AAED,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAEhF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAElF;AAED,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAI1F;AAED;;4FAE4F;AAC5F,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAC7C,MAAM,CAER;AAED,wBAAgB,yCAAyC,CACvD,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAC7C,MAAM,CAER;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,EAC9C,aAAa,EAAE,MAAM,GACpB,MAAM,CAER;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,mBAAmB,EAC3B,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Content addressing and Ed25519 signing for the two records this module
|
|
5
|
+
// declares. Nothing here reimplements JCS, SHA-256 or Ed25519: each comes from the helper
|
|
6
|
+
// the rest of this package already uses.
|
|
7
|
+
//
|
|
8
|
+
// Not required by draft-pidlisnyi-aps-03. See ./types.ts for the specification position.
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { canonicalizeJCS, canonicalizeJCSForWrite } from '../../core/canonical-jcs.js';
|
|
11
|
+
import { sign, verify } from '../../crypto/keys.js';
|
|
12
|
+
/** Domain tags. Each is a distinct tag followed by one zero byte, the same discipline
|
|
13
|
+
* `AuthorityDelegationV1` and `AuthorityRevocationV1` follow, so bytes minted for one
|
|
14
|
+
* construction can never be read as bytes minted for another. The `PROPOSED-` prefix is
|
|
15
|
+
* part of the tag: if any of this is ever specified, the specified construction will use a
|
|
16
|
+
* different tag and records minted under this one will not verify under it. That is the
|
|
17
|
+
* intended behaviour, not a migration problem to solve later. */
|
|
18
|
+
export const AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN = 'PROPOSED-APS-AUTHORITY-BOUND-FULFILMENT-SIGNATURE-V0\0';
|
|
19
|
+
export const AUTHORITY_EXHAUSTION_ID_DOMAIN = 'PROPOSED-APS-AUTHORITY-EXHAUSTION-ID-V0\0';
|
|
20
|
+
export const AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN = 'PROPOSED-APS-AUTHORITY-EXHAUSTION-SIGNATURE-V0\0';
|
|
21
|
+
function sha256Hex(value) {
|
|
22
|
+
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
23
|
+
}
|
|
24
|
+
function withoutSignature(record) {
|
|
25
|
+
const { signature: _signature, ...body } = record;
|
|
26
|
+
return body;
|
|
27
|
+
}
|
|
28
|
+
/** Exact Ed25519 preimage for a fulfilment attestation: the domain tag plus RFC 8785 JCS of
|
|
29
|
+
* the record with `signature` absent. */
|
|
30
|
+
export function authorityBoundFulfilmentSignatureInput(body) {
|
|
31
|
+
return AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN + canonicalizeJCS(body);
|
|
32
|
+
}
|
|
33
|
+
/** Write-boundary twin. Use when ISSUING. The verification path keeps calling the
|
|
34
|
+
* unrestricted form, so a record minted before the write rule still verifies. */
|
|
35
|
+
export function authorityBoundFulfilmentSignatureInputForWrite(body) {
|
|
36
|
+
return AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN + canonicalizeJCSForWrite(body);
|
|
37
|
+
}
|
|
38
|
+
export function signAuthorityBoundFulfilment(body, privateKeyHex) {
|
|
39
|
+
return sign(authorityBoundFulfilmentSignatureInputForWrite(body), privateKeyHex);
|
|
40
|
+
}
|
|
41
|
+
export function verifyAuthorityBoundFulfilmentSignature(record, publicKeyHex) {
|
|
42
|
+
return verify(authorityBoundFulfilmentSignatureInput(withoutSignature(record)), record.signature, publicKeyHex);
|
|
43
|
+
}
|
|
44
|
+
/** Exact preimage for `exhaustion_id`: the ID domain tag plus JCS of the body. */
|
|
45
|
+
export function authorityExhaustionIdInput(body) {
|
|
46
|
+
return AUTHORITY_EXHAUSTION_ID_DOMAIN + canonicalizeJCS(body);
|
|
47
|
+
}
|
|
48
|
+
export function computeAuthorityExhaustionId(body) {
|
|
49
|
+
return `sha256:${sha256Hex(authorityExhaustionIdInput(body))}`;
|
|
50
|
+
}
|
|
51
|
+
export function computeAuthorityExhaustionIdForWrite(body) {
|
|
52
|
+
return `sha256:${sha256Hex(AUTHORITY_EXHAUSTION_ID_DOMAIN + canonicalizeJCSForWrite(body))}`;
|
|
53
|
+
}
|
|
54
|
+
/** Exact Ed25519 preimage for the exhaustion record: the signature domain tag plus JCS of
|
|
55
|
+
* the record with `signature` absent. `exhaustion_id` IS inside this preimage, so the
|
|
56
|
+
* identifier is signed rather than being an unauthenticated label beside the signature. */
|
|
57
|
+
export function authorityExhaustionSignatureInput(record) {
|
|
58
|
+
return AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN + canonicalizeJCS(record);
|
|
59
|
+
}
|
|
60
|
+
export function authorityExhaustionSignatureInputForWrite(record) {
|
|
61
|
+
return AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN + canonicalizeJCSForWrite(record);
|
|
62
|
+
}
|
|
63
|
+
export function signAuthorityExhaustion(record, privateKeyHex) {
|
|
64
|
+
return sign(authorityExhaustionSignatureInputForWrite(record), privateKeyHex);
|
|
65
|
+
}
|
|
66
|
+
export function verifyAuthorityExhaustionSignature(record, publicKeyHex) {
|
|
67
|
+
return verify(authorityExhaustionSignatureInput(withoutSignature(record)), record.signature, publicKeyHex);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../../src/v2/bounds/canonical.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,yCAAyC;AACzC,EAAE;AACF,yFAAyF;AAEzF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAQnD;;;;;kEAKkE;AAClE,MAAM,CAAC,MAAM,2CAA2C,GACtD,wDAAwD,CAAA;AAC1D,MAAM,CAAC,MAAM,8BAA8B,GAAG,2CAA2C,CAAA;AACzF,MAAM,CAAC,MAAM,qCAAqC,GAChD,kDAAkD,CAAA;AAEpD,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,gBAAgB,CAAkC,MAAS;IAClE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IACjD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;0CAC0C;AAC1C,MAAM,UAAU,sCAAsC,CACpD,IAAkC;IAElC,OAAO,2CAA2C,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;AAC5E,CAAC;AAED;kFACkF;AAClF,MAAM,UAAU,8CAA8C,CAC5D,IAAkC;IAElC,OAAO,2CAA2C,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,IAAkC,EAClC,aAAqB;IAErB,OAAO,IAAI,CAAC,8CAA8C,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,uCAAuC,CACrD,MAAgC,EAChC,YAAoB;IAEpB,OAAO,MAAM,CACX,sCAAsC,CACpC,gBAAgB,CAAC,MAAM,CAAiC,CACzD,EACD,MAAM,CAAC,SAAS,EAChB,YAAY,CACb,CAAA;AACH,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,0BAA0B,CAAC,IAA6B;IACtE,OAAO,8BAA8B,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAA6B;IACxE,OAAO,UAAU,SAAS,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,EAAE,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,oCAAoC,CAAC,IAA6B;IAChF,OAAO,UAAU,SAAS,CACxB,8BAA8B,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAC/D,EAAE,CAAA;AACL,CAAC;AAED;;4FAE4F;AAC5F,MAAM,UAAU,iCAAiC,CAC/C,MAA8C;IAE9C,OAAO,qCAAqC,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,MAA8C;IAE9C,OAAO,qCAAqC,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAA;AAChF,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAA8C,EAC9C,aAAqB;IAErB,OAAO,IAAI,CAAC,yCAAyC,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,MAA2B,EAC3B,YAAoB;IAEpB,OAAO,MAAM,CACX,iCAAiC,CAC/B,gBAAgB,CAAC,MAAM,CAA2C,CACnE,EACD,MAAM,CAAC,SAAS,EAChB,YAAY,CACb,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type AttestorRoleAnswer, type AttestorRoleResolver, type AuthorityBound, type AuthorityBoundFulfilment, type BoundEvaluation, type BoundKind, type BoundVerificationKeyResolver, type FulfilmentAssessment } from './types.js';
|
|
2
|
+
/** Thrown when an input this module cannot read at all is passed. A malformed BOUND is a
|
|
3
|
+
* programming error, not a verdict: the module was asked a question about nothing. A
|
|
4
|
+
* malformed FULFILMENT RECORD is different and never throws, because a record somebody
|
|
5
|
+
* else wrote is data, and the right answer about it is a rejection with a reason code. */
|
|
6
|
+
export declare class AuthorityBoundError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
constructor(code: string, message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function isBoundKind(value: unknown): value is BoundKind;
|
|
11
|
+
export declare function isAttestorRoleAnswer(value: unknown): value is AttestorRoleAnswer;
|
|
12
|
+
/** Shape check for a bound declaration. Throws, for the reason `AuthorityBoundError`
|
|
13
|
+
* documents. */
|
|
14
|
+
export declare function assertAuthorityBound(bound: AuthorityBound): void;
|
|
15
|
+
export interface AssessFulfilmentInput {
|
|
16
|
+
readonly bound: AuthorityBound;
|
|
17
|
+
readonly record: AuthorityBoundFulfilment;
|
|
18
|
+
/** The instant the question is asked at. A record attested later than this is not read:
|
|
19
|
+
* a verifier asked about Tuesday does not get to use Wednesday's evidence. */
|
|
20
|
+
readonly atInstant: string;
|
|
21
|
+
readonly resolveAttestorRole: AttestorRoleResolver;
|
|
22
|
+
readonly resolveVerificationKey: BoundVerificationKeyResolver;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Assess ONE fulfilment record against one bound.
|
|
26
|
+
*
|
|
27
|
+
* The order of the checks is the substance of this function, not an implementation detail.
|
|
28
|
+
* Standing is asked FIRST and authenticity SECOND, and each produces its own code, because
|
|
29
|
+
* "authenticated by somebody who may not say this" and "not authenticated at all" are
|
|
30
|
+
* different failures and collapsing them loses the distinction CAND-01 turns on. A valid
|
|
31
|
+
* signature establishes who signed. It does not establish that the signer was allowed to
|
|
32
|
+
* make this statement.
|
|
33
|
+
*
|
|
34
|
+
* `FULFILMENT_OUTCOME_NOT_FULFILLED` carries no `missing` limbs, and that is deliberate: a
|
|
35
|
+
* record from a party with standing saying the purpose was NOT met is a conclusion the
|
|
36
|
+
* verifier reached, not a gap in its evidence. Every other rejection names a limb.
|
|
37
|
+
*
|
|
38
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant candidate CAND-01 and
|
|
39
|
+
* invariant candidate BROAD-L7. Proposed.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assessFulfilment(input: AssessFulfilmentInput): FulfilmentAssessment;
|
|
42
|
+
export interface EvaluateBoundInput {
|
|
43
|
+
readonly bound: AuthorityBound;
|
|
44
|
+
/** Every fulfilment claim the caller holds for this bound. Order is preserved in the
|
|
45
|
+
* result and does not change the verdict: see the resolution rule below. Empty for a
|
|
46
|
+
* `use_count` or `budget` bound, where no attestation is involved. */
|
|
47
|
+
readonly fulfilments?: readonly AuthorityBoundFulfilment[];
|
|
48
|
+
readonly atInstant: string;
|
|
49
|
+
readonly resolveAttestorRole?: AttestorRoleResolver;
|
|
50
|
+
readonly resolveVerificationKey?: BoundVerificationKeyResolver;
|
|
51
|
+
/** kind `use_count` only: admissions already counted against this bound, as a canonical
|
|
52
|
+
* unsigned decimal integer string. The caller's ledger owns this number. This module
|
|
53
|
+
* does not count admissions, because counting them means holding state across events and
|
|
54
|
+
* a pure function has none. */
|
|
55
|
+
readonly consumed?: string;
|
|
56
|
+
/** kind `budget` only: the committed and reserved totals, exactly as
|
|
57
|
+
* `InMemoryAuthorityBudgetLedger.counter(delegationId)` returns them. The budget kind
|
|
58
|
+
* delegates to that ledger and never reimplements it: draft-03 section 3.4 already
|
|
59
|
+
* states the rule, and the ledger already enforces it. */
|
|
60
|
+
readonly budgetCounter?: {
|
|
61
|
+
readonly committed: string;
|
|
62
|
+
readonly reserved: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Evaluate one bound's state at one instant.
|
|
67
|
+
*
|
|
68
|
+
* THE RESOLUTION RULE, and why it is this way round. For a purpose bound:
|
|
69
|
+
*
|
|
70
|
+
* 1. If any fulfilment record was ACCEPTED, the state is `exhausted`.
|
|
71
|
+
* 2. Otherwise, if any record was rejected on an EVIDENTIAL ground (signature, standing,
|
|
72
|
+
* unresolved role, unresolved key, unreadable shape), the state is `not_established`.
|
|
73
|
+
* 3. Otherwise the state is `not_reached`.
|
|
74
|
+
*
|
|
75
|
+
* Step 1 comes before step 2 on purpose, and it is invariant CAND-02's rule made
|
|
76
|
+
* executable: an exhaustion that WAS established is never downgraded by a later claim
|
|
77
|
+
* nobody could authenticate. A later finding is a new record about an earlier one, never a
|
|
78
|
+
* rewrite of it. Because the rule is a fold over the whole set rather than a running
|
|
79
|
+
* mutation, the verdict is the same whatever order the records arrive in, which is what
|
|
80
|
+
* makes it safe for a caller to keep them in an unordered store.
|
|
81
|
+
*
|
|
82
|
+
* Step 3 reads `not_reached` from an empty record set, and that is the one reading here
|
|
83
|
+
* worth arguing with. It is a positive claim: the bound is declared, no evidence reaches
|
|
84
|
+
* it, and under the applicable authority model a purpose that nobody has recorded as met is
|
|
85
|
+
* a purpose that is not met. A model whose default runs the other way (absence of a
|
|
86
|
+
* periodic fulfilment report is itself the trigger) is a model this function cannot
|
|
87
|
+
* express, and a caller in that position should report `not_established` with a `source`
|
|
88
|
+
* limb rather than passing an empty set and reading the answer as a finding. CAND-01's
|
|
89
|
+
* carve-out for a declared default on absence is the reason the disclaimer is here and not
|
|
90
|
+
* a silent assumption.
|
|
91
|
+
*
|
|
92
|
+
* A `use_count` bound needs no records at all: the ADMISSION reaches it, so `consumed`
|
|
93
|
+
* against `value` is the whole computation. A `budget` bound is answered by the ledger's
|
|
94
|
+
* counter, per draft-03 section 3.4, verbatim: "Signatures establish static limits; they do
|
|
95
|
+
* not establish the current cumulative total."
|
|
96
|
+
*
|
|
97
|
+
* Reported ALONGSIDE a chain result, never merged into it, and never in place of it. A
|
|
98
|
+
* grant can be exhausted while its chain still verifies `valid`, which is the whole point:
|
|
99
|
+
* exhaustion is invisible to chain verification. A grant can also be expired AND exhausted,
|
|
100
|
+
* and then the chain result says `EXPIRED` and this says `exhaustion` and neither
|
|
101
|
+
* overwrites the other. Invariant L10.
|
|
102
|
+
*
|
|
103
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant L10 and invariant candidates
|
|
104
|
+
* CAND-01 and CAND-02. All proposed.
|
|
105
|
+
*/
|
|
106
|
+
export declare function evaluateBound(input: EvaluateBoundInput): BoundEvaluation;
|
|
107
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/evaluate.ts"],"names":[],"mappings":"AAYA,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAE7B,KAAK,eAAe,EACpB,KAAK,SAAS,EAGd,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAA;AAEnB;;;2FAG2F;AAC3F,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAIxC;CACF;AAMD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAIhF;AAED;iBACiB;AACjB,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAgDhE;AA+CD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAA;IACzC;mFAC+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,mBAAmB,EAAE,oBAAoB,CAAA;IAClD,QAAQ,CAAC,sBAAsB,EAAE,4BAA4B,CAAA;CAC9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,oBAAoB,CAiFnF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B;;2EAEuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAA;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,CAAA;IACnD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,4BAA4B,CAAA;IAC9D;;;oCAGgC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;+DAG2D;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CACnF;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,eAAe,CA6FxE"}
|