@affiant/core 0.1.0-alpha.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/LICENSE +202 -0
- package/README.md +354 -0
- package/dist/context.d.ts +136 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +30 -0
- package/dist/context.js.map +1 -0
- package/dist/docket/entry.d.ts +421 -0
- package/dist/docket/entry.d.ts.map +1 -0
- package/dist/docket/entry.js +155 -0
- package/dist/docket/entry.js.map +1 -0
- package/dist/docket/expiry.d.ts +82 -0
- package/dist/docket/expiry.d.ts.map +1 -0
- package/dist/docket/expiry.js +106 -0
- package/dist/docket/expiry.js.map +1 -0
- package/dist/docket/memory.d.ts +163 -0
- package/dist/docket/memory.d.ts.map +1 -0
- package/dist/docket/memory.js +528 -0
- package/dist/docket/memory.js.map +1 -0
- package/dist/docket/store.d.ts +387 -0
- package/dist/docket/store.d.ts.map +1 -0
- package/dist/docket/store.js +51 -0
- package/dist/docket/store.js.map +1 -0
- package/dist/errors.d.ts +153 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +164 -0
- package/dist/errors.js.map +1 -0
- package/dist/gate/coverage.d.ts +152 -0
- package/dist/gate/coverage.d.ts.map +1 -0
- package/dist/gate/coverage.js +114 -0
- package/dist/gate/coverage.js.map +1 -0
- package/dist/gate/decide.d.ts +207 -0
- package/dist/gate/decide.d.ts.map +1 -0
- package/dist/gate/decide.js +559 -0
- package/dist/gate/decide.js.map +1 -0
- package/dist/gate/gate.d.ts +212 -0
- package/dist/gate/gate.d.ts.map +1 -0
- package/dist/gate/gate.js +175 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/pipeline.d.ts +285 -0
- package/dist/gate/pipeline.d.ts.map +1 -0
- package/dist/gate/pipeline.js +515 -0
- package/dist/gate/pipeline.js.map +1 -0
- package/dist/gate/policy.d.ts +272 -0
- package/dist/gate/policy.d.ts.map +1 -0
- package/dist/gate/policy.js +396 -0
- package/dist/gate/policy.js.map +1 -0
- package/dist/gate/wrap.d.ts +107 -0
- package/dist/gate/wrap.d.ts.map +1 -0
- package/dist/gate/wrap.js +164 -0
- package/dist/gate/wrap.js.map +1 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/model/affidavit.d.ts +354 -0
- package/dist/model/affidavit.d.ts.map +1 -0
- package/dist/model/affidavit.js +417 -0
- package/dist/model/affidavit.js.map +1 -0
- package/dist/model/amendments.d.ts +160 -0
- package/dist/model/amendments.d.ts.map +1 -0
- package/dist/model/amendments.js +183 -0
- package/dist/model/amendments.js.map +1 -0
- package/dist/model/canonical.d.ts +311 -0
- package/dist/model/canonical.d.ts.map +1 -0
- package/dist/model/canonical.js +665 -0
- package/dist/model/canonical.js.map +1 -0
- package/dist/model/money.d.ts +127 -0
- package/dist/model/money.d.ts.map +1 -0
- package/dist/model/money.js +177 -0
- package/dist/model/money.js.map +1 -0
- package/dist/model/provenance.d.ts +315 -0
- package/dist/model/provenance.d.ts.map +1 -0
- package/dist/model/provenance.js +223 -0
- package/dist/model/provenance.js.map +1 -0
- package/dist/ports.d.ts +269 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +34 -0
- package/dist/ports.js.map +1 -0
- package/dist/store-memory.d.ts +21 -0
- package/dist/store-memory.d.ts.map +1 -0
- package/dist/store-memory.js +20 -0
- package/dist/store-memory.js.map +1 -0
- package/dist/telemetry-keys.d.ts +65 -0
- package/dist/telemetry-keys.d.ts.map +1 -0
- package/dist/telemetry-keys.js +72 -0
- package/dist/telemetry-keys.js.map +1 -0
- package/dist/telemetry.d.ts +77 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +43 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/testing.d.ts +574 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1291 -0
- package/dist/testing.js.map +1 -0
- package/package.json +75 -0
- package/telemetry-keys.json +92 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amendments: what a reviewer's correction means, and what it does to the record.
|
|
3
|
+
*
|
|
4
|
+
* **Rules served: DK-2** (in an amendment map `null` means *cleared* and an absent
|
|
5
|
+
* key means *untouched*, and an implementation never conflates them), **AF-1** (a
|
|
6
|
+
* field with unknown provenance is present and tagged `Empty`; a field the operation
|
|
7
|
+
* does not propose is absent), **AF-2** (the three numbers, with `Empty` counting as
|
|
8
|
+
* `0`), **AF-4** (an accepted amendment recomputes the three confidence numbers, and
|
|
9
|
+
* the amended field's provenance is the reviewer's act — never the machine's
|
|
10
|
+
* pre-correction tag), **PV-2** (that act carries a `reviewer-act` binding naming
|
|
11
|
+
* the Docket decision it was made on).
|
|
12
|
+
*
|
|
13
|
+
* ## What clearing a field does to the numbers
|
|
14
|
+
*
|
|
15
|
+
* A cleared field has no value, so it cannot have confidence in one. Writing the
|
|
16
|
+
* reviewer's `UserStated`/`1.0` tag over an emptied field would make the three
|
|
17
|
+
* numbers *rise* as a reviewer wiped the Affidavit — clear every field and the record
|
|
18
|
+
* reports perfect confidence over nothing, which is the arithmetic hole AF-2 exists
|
|
19
|
+
* to close, arriving through the amendment path. So a clear is resolved against the
|
|
20
|
+
* field rather than pasted onto it:
|
|
21
|
+
*
|
|
22
|
+
* - **A mandatory field stays and is tagged `Empty`** (confidence `0`, AF-1). The
|
|
23
|
+
* entity still requires it, so it is still proposed and still on the card — now
|
|
24
|
+
* visibly with nothing behind it, counted in `emptyFieldCount` and dragging
|
|
25
|
+
* `aggregateConfidence` to `0`.
|
|
26
|
+
* - **An optional field is removed from `fields[]`** (AF-1). A reviewer clearing an
|
|
27
|
+
* optional field is saying "do not write this one", which is a field the write no
|
|
28
|
+
* longer proposes, and AF-1 says a field the operation does not propose is absent
|
|
29
|
+
* rather than present-and-`Empty`.
|
|
30
|
+
*
|
|
31
|
+
* Either way the reviewer's act is not lost: the `Empty` tag carries the same
|
|
32
|
+
* `reviewer-act` binding and the same note a set would (PV-2), and the machine's
|
|
33
|
+
* displaced tag stays in the chain behind it.
|
|
34
|
+
*
|
|
35
|
+
* Why DK-2 needs saying at all: `undefined` and `null` are one keystroke apart in
|
|
36
|
+
* JavaScript and `{ Status: undefined }` reads to a careless consumer as "clear
|
|
37
|
+
* Status", when it is in fact "say nothing about Status". Conflating them silently
|
|
38
|
+
* either wipes a field nobody asked to wipe or ignores a correction a person made
|
|
39
|
+
* on purpose. So this module resolves a map into {@link Amendment} values — `set`
|
|
40
|
+
* or `clear`, both explicit — and a field nobody amended is simply not in the
|
|
41
|
+
* resolved list. `undefined` under a key is refused, loudly.
|
|
42
|
+
*
|
|
43
|
+
* Why AF-4 needs saying: the shipped demo hosts return an amended Affidavit still
|
|
44
|
+
* carrying the machine's pre-correction confidence, so a card can show a corrected
|
|
45
|
+
* value under a number that was never about that value.
|
|
46
|
+
*
|
|
47
|
+
* @packageDocumentation
|
|
48
|
+
*/
|
|
49
|
+
import { mintTag, supersede } from "./provenance.js";
|
|
50
|
+
import { withConfidence, } from "./affidavit.js";
|
|
51
|
+
/** Whether `map` says anything at all about `fieldName` (DK-2). */
|
|
52
|
+
export function hasAmendment(map, fieldName) {
|
|
53
|
+
return Object.hasOwn(map, fieldName);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve `map` into explicit {@link Amendment} values, in the map's own key order.
|
|
57
|
+
*
|
|
58
|
+
* @throws RangeError if a key is present holding `undefined` — the one thing an
|
|
59
|
+
* amendment map may not say, because it is indistinguishable at a glance
|
|
60
|
+
* from both of DK-2's meanings and is neither.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveAmendments(map) {
|
|
63
|
+
const resolved = [];
|
|
64
|
+
for (const name of Object.keys(map)) {
|
|
65
|
+
const value = map[name];
|
|
66
|
+
if (value === undefined) {
|
|
67
|
+
throw new RangeError(`DK-2: amendment ${JSON.stringify(name)} is undefined; ` +
|
|
68
|
+
`use null to clear the field, or omit the key to leave it untouched`);
|
|
69
|
+
}
|
|
70
|
+
resolved.push(value === null
|
|
71
|
+
? { name, amendment: { kind: "clear" } }
|
|
72
|
+
: { name, amendment: { kind: "set", value } });
|
|
73
|
+
}
|
|
74
|
+
return resolved;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The provenance tag an accepted amendment puts in force on the field it names
|
|
78
|
+
* (PV-2, AF-2).
|
|
79
|
+
*
|
|
80
|
+
* One function so there is one answer. The canonical form (SR-1) is defined over
|
|
81
|
+
* "the Affidavit and its accepted amendments", and an implementation that minted a
|
|
82
|
+
* *nearly* identical tag on the serialization path would produce different bytes
|
|
83
|
+
* from the same decision — which is the one thing a canonical form exists to make
|
|
84
|
+
* impossible. `model/canonical.ts` calls this, and so does {@link applyAmendments}.
|
|
85
|
+
*
|
|
86
|
+
* A set mints `UserStated` at confidence `1`: a reviewer typing a value is the
|
|
87
|
+
* person stating it, and PV-3 makes that the one place the grade is legitimate. A
|
|
88
|
+
* clear mints `Empty` at confidence `0`: an emptied field has no value to be
|
|
89
|
+
* confident in, so a clearing can never raise a confidence number.
|
|
90
|
+
*
|
|
91
|
+
* Either way the binding is `reviewer-act`, naming the decision *and the instant*,
|
|
92
|
+
* so an auditor can follow a clearing as readily as a correction.
|
|
93
|
+
*
|
|
94
|
+
* @param amendment What the reviewer did to the field.
|
|
95
|
+
* @param act The decision it arrived on.
|
|
96
|
+
* @param conversationTurn The turn the Affidavit belongs to, carried onto the tag.
|
|
97
|
+
*/
|
|
98
|
+
export function amendmentTag(amendment, act, conversationTurn) {
|
|
99
|
+
const cleared = amendment.kind === "clear";
|
|
100
|
+
return mintTag({
|
|
101
|
+
source: cleared ? "Empty" : "UserStated",
|
|
102
|
+
confidence: cleared ? 0 : 1,
|
|
103
|
+
note: cleared
|
|
104
|
+
? `Cleared by ${act.by} on Docket entry ${act.entryId}`
|
|
105
|
+
: `Amended by ${act.by} on Docket entry ${act.entryId}`,
|
|
106
|
+
at: act.decisionAt,
|
|
107
|
+
conversationTurn,
|
|
108
|
+
binding: { kind: "reviewer-act", ref: { entryId: act.entryId, decisionAt: act.decisionAt } },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Apply `map` to `affidavit` as `act`, returning a new Affidavit.
|
|
113
|
+
*
|
|
114
|
+
* What happens to a field the reviewer **set**: its value becomes the amended value,
|
|
115
|
+
* and a `UserStated` tag carrying a `reviewer-act` binding goes **on top of** its
|
|
116
|
+
* chain (PV-2, AF-4). On top rather than merged: a reviewer's correction is not a
|
|
117
|
+
* confidence contest it might lose to the machine's own tag, and the displaced tag
|
|
118
|
+
* stays in `prior` so the card can still show what the machine had proposed.
|
|
119
|
+
*
|
|
120
|
+
* What happens to a field the reviewer **cleared** (`null`, DK-2): a mandatory field
|
|
121
|
+
* keeps its place with value `null` under an `Empty` tag at confidence `0`, and an
|
|
122
|
+
* optional field leaves `fields[]` entirely. See the module note above for why the
|
|
123
|
+
* reviewer's `1.0` is not written over an emptied field.
|
|
124
|
+
*
|
|
125
|
+
* What happens to everything else: nothing. A field the map does not name keeps its
|
|
126
|
+
* value, its `previousValue` and its whole chain, byte for byte (DK-2). And
|
|
127
|
+
* `previousValue` never moves — it is what the entity holds now, which an
|
|
128
|
+
* amendment does not change.
|
|
129
|
+
*
|
|
130
|
+
* The three numbers are recomputed over the amended fields (AF-4).
|
|
131
|
+
*
|
|
132
|
+
* @throws RangeError if `map` names a field the Affidavit does not propose. Not an
|
|
133
|
+
* {@link AffiantError}: the error-code registry names refusals the gate
|
|
134
|
+
* makes at runtime about a proposal's substance or a decider's identity,
|
|
135
|
+
* and this is a caller passing a field name that is not there — a
|
|
136
|
+
* programming error, in the same class as an out-of-range index.
|
|
137
|
+
*/
|
|
138
|
+
export function applyAmendments(affidavit, map, act) {
|
|
139
|
+
const resolved = resolveAmendments(map);
|
|
140
|
+
if (resolved.length === 0)
|
|
141
|
+
return affidavit;
|
|
142
|
+
const byName = new Map(resolved.map((entry) => [entry.name, entry.amendment]));
|
|
143
|
+
for (const name of byName.keys()) {
|
|
144
|
+
if (!affidavit.fields.some((field) => field.name === name)) {
|
|
145
|
+
throw new RangeError(`amendment names field ${JSON.stringify(name)}, which this Affidavit does not propose`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const fields = affidavit.fields.flatMap((field) => {
|
|
149
|
+
const amendment = byName.get(field.name);
|
|
150
|
+
if (amendment === undefined)
|
|
151
|
+
return [field];
|
|
152
|
+
// AF-1: a cleared optional field is a field the write no longer proposes, so it
|
|
153
|
+
// is absent rather than present with nothing in it.
|
|
154
|
+
if (amendment.kind === "clear" && !field.isMandatory)
|
|
155
|
+
return [];
|
|
156
|
+
const cleared = amendment.kind === "clear";
|
|
157
|
+
const value = cleared ? null : amendment.value;
|
|
158
|
+
const tag = amendmentTag(amendment, act, affidavit.conversationTurn);
|
|
159
|
+
return [
|
|
160
|
+
{
|
|
161
|
+
name: field.name,
|
|
162
|
+
kind: field.kind,
|
|
163
|
+
value,
|
|
164
|
+
previousValue: field.previousValue,
|
|
165
|
+
provenance: supersede(field.provenance, tag),
|
|
166
|
+
isMandatory: field.isMandatory,
|
|
167
|
+
},
|
|
168
|
+
];
|
|
169
|
+
});
|
|
170
|
+
// AF-4: the numbers are the amended Affidavit's, not the proposal's.
|
|
171
|
+
return withConfidence({
|
|
172
|
+
// SR-4: an amendment corrects values, never the version the record conforms
|
|
173
|
+
// to. Carried through so the accepted state canonicalizes to the same bytes
|
|
174
|
+
// the same record would on the wire.
|
|
175
|
+
protocolVersion: affidavit.protocolVersion,
|
|
176
|
+
operationType: affidavit.operationType,
|
|
177
|
+
entityType: affidavit.entityType,
|
|
178
|
+
entityId: affidavit.entityId,
|
|
179
|
+
conversationTurn: affidavit.conversationTurn,
|
|
180
|
+
createdAt: affidavit.createdAt,
|
|
181
|
+
}, fields);
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=amendments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amendments.js","sourceRoot":"","sources":["../../src/model/amendments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical form of an Affidavit and its accepted amendments, and the SHA-256
|
|
3
|
+
* hash over it.
|
|
4
|
+
*
|
|
5
|
+
* **Rules served: SR-1, SR-2, RT-1.**
|
|
6
|
+
*
|
|
7
|
+
* **SR-1** — *the canonical form of a filed proposal is a deterministic byte
|
|
8
|
+
* sequence over the Affidavit **and its accepted amendments** (the amended field
|
|
9
|
+
* values with their reviewer-act tags, in the same field order), with UTF-8, object
|
|
10
|
+
* keys sorted by Unicode code point, no insignificant whitespace, numbers as their
|
|
11
|
+
* shortest round-trip decimal representation, `null` written and absent omitted.
|
|
12
|
+
* `canonicalHash` is the SHA-256 of that form.*
|
|
13
|
+
*
|
|
14
|
+
* **Why the amendments are inside the form and not beside it.** A host's execution
|
|
15
|
+
* grant binds to `canonicalHash(Affidavit + amendments)`. If the form covered the
|
|
16
|
+
* Affidavit alone, a grant minted for the proposal a reviewer *was shown* would
|
|
17
|
+
* still validate the proposal they *amended* — the one substitution the whole
|
|
18
|
+
* framework exists to prevent. Two conformance fixtures in this package's vector
|
|
19
|
+
* set differ only by an amendment, and their hashes differ; that is the rule made
|
|
20
|
+
* checkable. On a Docket row the same thing is spelled {@link canonicalizeEntry}:
|
|
21
|
+
* the row keeps the proposal and the accepted state separately, and the form is
|
|
22
|
+
* taken over the accepted state where there is one.
|
|
23
|
+
*
|
|
24
|
+
* **What the form is taken over: the Affidavit as the schema defines it.** Every
|
|
25
|
+
* property of the record is in the bytes, `protocolVersion` included — the schema
|
|
26
|
+
* requires it on an Affidavit, and the promoted byte vectors carry it. The card
|
|
27
|
+
* *envelope*'s presentation is not: `allowedValues`, `pattern`, `warnings` and
|
|
28
|
+
* `requiresConfirmation` are a host's rendering of a proposal rather than its sworn
|
|
29
|
+
* substance, and putting a rendering decision inside a hash a grant is checked
|
|
30
|
+
* against would let restyling an input invalidate a grant minted over evidence that
|
|
31
|
+
* did not change. Until this version the runtime model omitted `protocolVersion`
|
|
32
|
+
* and only `toWire` stamped it, so the bytes a Docket row's hash was taken over
|
|
33
|
+
* were not the bytes of the same record on a card. The model carries it now
|
|
34
|
+
* (`model/affidavit.ts`), and both paths produce one document for one record.
|
|
35
|
+
*
|
|
36
|
+
* **What applying an amendment does, exactly**, is `model/amendments.ts`'s answer and
|
|
37
|
+
* not this module's: the tag in force comes from `amendmentTag`, so the bytes a
|
|
38
|
+
* decision produces here and the row that decision writes cannot disagree. That
|
|
39
|
+
* carries AF-1's clearing rule with it — a cleared **mandatory** field stays, tagged
|
|
40
|
+
* `Empty` at confidence `0`, and a cleared **optional** field leaves the field list,
|
|
41
|
+
* because a field the write no longer proposes is absent rather than present with
|
|
42
|
+
* nothing in it — and AF-4's recompute, where the document carries an aggregate.
|
|
43
|
+
*
|
|
44
|
+
* **Why a canonical form at all.** Three things depend on two independent
|
|
45
|
+
* implementations agreeing byte for byte: the conformance suite compares canonical
|
|
46
|
+
* forms across the .NET and TypeScript lines; an `utterance-span` provenance
|
|
47
|
+
* binding hashes the span it points at, so an auditor can re-derive it years later;
|
|
48
|
+
* and the execution grant above. `JSON.stringify` cannot do any of that — its key
|
|
49
|
+
* order is insertion order, so the same Affidavit built by two code paths produces
|
|
50
|
+
* two different documents and two different hashes.
|
|
51
|
+
*
|
|
52
|
+
* ## The form, precisely
|
|
53
|
+
*
|
|
54
|
+
* A JSON document with no space, tab or newline between tokens. Within it:
|
|
55
|
+
*
|
|
56
|
+
* - **Objects** — `{`, then each own enumerable string-keyed property whose value is
|
|
57
|
+
* not `undefined`, sorted by **Unicode code point** of the key, as `"key":value`
|
|
58
|
+
* separated by `,`, then `}`. Sorting by code point rather than by UTF-16 code
|
|
59
|
+
* unit matters above U+FFFF: a key starting with an emoji sorts *after* a key
|
|
60
|
+
* starting with U+E000, though a naive JavaScript `<` puts it first. Symbol keys
|
|
61
|
+
* are not JSON and are ignored; inherited properties are not own properties and
|
|
62
|
+
* are ignored.
|
|
63
|
+
* - **Arrays** — `[`, elements in their own order, separated by `,`, then `]`.
|
|
64
|
+
* Array order is data, never sorted. An `undefined` element is refused rather
|
|
65
|
+
* than written as `null`: "absent omitted" is meaningful for a property and
|
|
66
|
+
* meaningless for a position, and silently substituting `null` would put a value
|
|
67
|
+
* on an audit record that the producer never wrote.
|
|
68
|
+
* - **Strings** — JSON escaping and nothing more: `"` and `\` escaped, the C0
|
|
69
|
+
* control characters escaped (`\b`, `\t`, `\n`, `\f`, `\r`, else `\u00xx` with
|
|
70
|
+
* lowercase hex), unpaired surrogates escaped as `\udxxx`. Every other character
|
|
71
|
+
* is written as itself and encoded as UTF-8 — **no `\u` escapes for non-ASCII**,
|
|
72
|
+
* so `"é"` is two bytes and not six, and `/` is never escaped.
|
|
73
|
+
* - **Numbers** — the shortest round-trip decimal, written positionally: never an
|
|
74
|
+
* exponent, `-0` written as `0`, non-finite refused. See {@link canonicalJson}
|
|
75
|
+
* for what "positionally" costs and why it is the safer half of the trade.
|
|
76
|
+
* - **`null`** — written. **`true` / `false`** — written.
|
|
77
|
+
* - **Money** — `{ amount, currency }` is two strings (SR-2). A value shaped like
|
|
78
|
+
* money whose amount is a number is refused here rather than hashed, because a
|
|
79
|
+
* float amount that reached the canonical form would be sworn to.
|
|
80
|
+
*
|
|
81
|
+
* ## What is refused
|
|
82
|
+
*
|
|
83
|
+
* A non-finite number is a `RangeError`. Everything else that has no canonical form
|
|
84
|
+
* is a `TypeError`: `undefined` in an array position, a `bigint`, a function, a
|
|
85
|
+
* symbol, a `Date` or `Map` or typed array (anything whose `Object.prototype.toString`
|
|
86
|
+
* tag is not `[object Object]` or `[object Array]`), a cycle, and money with a
|
|
87
|
+
* numeric amount. An audit form never guesses: a value it cannot write exactly is a
|
|
88
|
+
* value it refuses to write at all.
|
|
89
|
+
*
|
|
90
|
+
* ## Integers beyond 2^53 (the documented limit of the rule)
|
|
91
|
+
*
|
|
92
|
+
* JSON numbers are IEEE 754 doubles by the time any implementation sees them, so
|
|
93
|
+
* `9007199254740993` has already become `9007199254740992` in the parser, before the
|
|
94
|
+
* canonical form is reached. This module therefore writes the shortest round-trip
|
|
95
|
+
* decimal of the double it was given and **does not** convert large numbers to strings: a
|
|
96
|
+
* canonical form cannot recover precision the parse already lost, and a form that
|
|
97
|
+
* quietly restringified some numbers and not others would be harder to reimplement,
|
|
98
|
+
* not easier. A host that needs exact integers beyond 2^53 — an account number, a
|
|
99
|
+
* minor-unit amount, an accounting record's id — carries them as strings on the
|
|
100
|
+
* wire. Money
|
|
101
|
+
* already does, by SR-2.
|
|
102
|
+
*
|
|
103
|
+
* ## Runtime (RT-1)
|
|
104
|
+
*
|
|
105
|
+
* `canonicalHash` digests through `globalThis.crypto.subtle`, which has no
|
|
106
|
+
* synchronous form, so every hash path in this framework is asynchronous end to end
|
|
107
|
+
* — the stated portability choice, and the reason `canonicalHash` returns a
|
|
108
|
+
* `Promise` on Node, on Bun and inside workerd alike. No `node:crypto`, no
|
|
109
|
+
* filesystem, no Node global.
|
|
110
|
+
*
|
|
111
|
+
* @packageDocumentation
|
|
112
|
+
*/
|
|
113
|
+
import type { AmendmentMap } from "@affiant/contract";
|
|
114
|
+
import type { DocketEntry } from "../docket/entry.js";
|
|
115
|
+
import type { Affidavit } from "./affidavit.js";
|
|
116
|
+
import type { ReviewerAct } from "./amendments.js";
|
|
117
|
+
/**
|
|
118
|
+
* One field of the Affidavit, as much of it as canonicalization needs to know.
|
|
119
|
+
*
|
|
120
|
+
* Deliberately minimal. This module serializes *whatever object it is handed* —
|
|
121
|
+
* every own enumerable property, at every depth — so it does not need the Affidavit
|
|
122
|
+
* type to do its work, and stating a full one here would couple the canonical form
|
|
123
|
+
* to a model that is still being written (`model/affidavit.ts`, pull request C2).
|
|
124
|
+
* What it does need is the two properties amendment application reads: the `name`
|
|
125
|
+
* an amendment is keyed by, and the `value` an amendment replaces. Everything else
|
|
126
|
+
* on a real `AffidavitField` — `previousValue`, `provenance`, `isMandatory`,
|
|
127
|
+
* `kind`, `allowedValues`, `pattern` — is carried through untouched and appears in
|
|
128
|
+
* the bytes, because the bytes are of the object, not of this interface.
|
|
129
|
+
*/
|
|
130
|
+
export interface CanonicalField {
|
|
131
|
+
/** The field's name. The key {@link AmendmentMap} is keyed by. */
|
|
132
|
+
readonly name: string;
|
|
133
|
+
/** The proposed value. Any JSON value, including `null`. */
|
|
134
|
+
readonly value?: unknown;
|
|
135
|
+
/** The provenance chain behind the value, if the caller carries one. */
|
|
136
|
+
readonly provenance?: unknown;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The Affidavit being canonicalized, as much of it as this module needs to know.
|
|
140
|
+
*
|
|
141
|
+
* `fields` is optional so the same function can canonicalize the byte vectors that
|
|
142
|
+
* exercise the *form* — key ordering, number shapes, escaping — without dressing
|
|
143
|
+
* them up as Affidavits. A real `Affidavit` from `@affiant/contract` satisfies this
|
|
144
|
+
* interface structurally, and so will C2's core model.
|
|
145
|
+
*/
|
|
146
|
+
export interface CanonicalInput {
|
|
147
|
+
/** The sworn fields, in the order the Affidavit carries them. */
|
|
148
|
+
readonly fields?: readonly CanonicalField[];
|
|
149
|
+
/**
|
|
150
|
+
* The protocol version the record conforms to (SR-4).
|
|
151
|
+
*
|
|
152
|
+
* Named here — optional, like `fields`, so a bare byte vector need not dress
|
|
153
|
+
* itself up as an Affidavit — because it is the property whose absence from the
|
|
154
|
+
* runtime model made the canonical form of a Docket row differ from the canonical
|
|
155
|
+
* form of the same record on the wire. A real `Affidavit` always carries it; a
|
|
156
|
+
* record handed here without it is canonicalized without it, because this module
|
|
157
|
+
* serializes the object it is given and never adds a property to a document.
|
|
158
|
+
*/
|
|
159
|
+
readonly protocolVersion?: string;
|
|
160
|
+
}
|
|
161
|
+
/** Options for {@link canonicalize}, {@link canonicalString} and {@link canonicalHash}. */
|
|
162
|
+
export interface CanonicalizeOptions {
|
|
163
|
+
/**
|
|
164
|
+
* The decision the amendments arrived on — its entry, **its instant** and its
|
|
165
|
+
* principal. Required whenever a non-empty {@link AmendmentMap} is applied,
|
|
166
|
+
* because PV-2 says a `reviewer-act` binding names the decision that amended the
|
|
167
|
+
* field, and a binding that names nothing is not a binding.
|
|
168
|
+
*/
|
|
169
|
+
readonly reviewerAct?: ReviewerAct;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Apply an {@link AmendmentMap} to an Affidavit, returning a new object: each
|
|
173
|
+
* amended field's `value` replaced and the reviewer's own tag put in force on its
|
|
174
|
+
* provenance chain, with the tag it supersedes preserved beneath it.
|
|
175
|
+
*
|
|
176
|
+
* **The tag is `model/amendments.ts`'s, not this module's.** `amendmentTag` is the
|
|
177
|
+
* single definition of what an accepted amendment does to a field's provenance, and
|
|
178
|
+
* both paths call it — so the bytes this function produces for a decision are the
|
|
179
|
+
* bytes the Docket row's own `amendedAffidavit` produces for the same decision.
|
|
180
|
+
* There is no second, nearly-identical tag to drift.
|
|
181
|
+
*
|
|
182
|
+
* **DK-2**: `null` under a key clears the field; an absent key leaves it untouched.
|
|
183
|
+
* The two are never conflated.
|
|
184
|
+
*
|
|
185
|
+
* **AF-1**, on what a clear does: a **mandatory** field keeps its place with value
|
|
186
|
+
* `null` under an `Empty` tag at confidence `0`, and an **optional** field leaves
|
|
187
|
+
* `fields[]` entirely — a reviewer clearing an optional field is saying "do not
|
|
188
|
+
* write this one", and a field the write no longer proposes is absent rather than
|
|
189
|
+
* present with nothing in it. A field with no `isMandatory` property is read as
|
|
190
|
+
* optional, which is what the property's absence means everywhere else.
|
|
191
|
+
*
|
|
192
|
+
* **AF-4**: every confidence number the document carries — the aggregate, the
|
|
193
|
+
* populated minimum and the empty-field count — is recomputed over the amended
|
|
194
|
+
* fields. A canonical form that kept a pre-correction number would let a grant bind
|
|
195
|
+
* to an Affidavit whose own summary contradicts its fields.
|
|
196
|
+
*
|
|
197
|
+
* @param affidavit The Affidavit as filed.
|
|
198
|
+
* @param amendments The reviewer's accepted amendments, keyed by field name.
|
|
199
|
+
* @param act The decision the amendments arrived on (PV-2).
|
|
200
|
+
* @throws TypeError when the input carries no `fields` array, when a field is not
|
|
201
|
+
* an object, or when an amendment names a field the Affidavit does not
|
|
202
|
+
* carry — an amendment to something nobody swore to is a bug in the caller,
|
|
203
|
+
* and swallowing it would let two implementations disagree in silence.
|
|
204
|
+
* @throws RangeError when `amendments` holds `undefined` under a key (DK-2).
|
|
205
|
+
*/
|
|
206
|
+
export declare function applyAmendmentsForCanonical(affidavit: CanonicalInput, amendments: AmendmentMap, act: ReviewerAct): CanonicalInput;
|
|
207
|
+
/**
|
|
208
|
+
* The canonical form of `affidavit` and its accepted `amendments`, as UTF-8 bytes
|
|
209
|
+
* (SR-1).
|
|
210
|
+
*
|
|
211
|
+
* @param affidavit The Affidavit as filed.
|
|
212
|
+
* @param amendments The accepted amendments, or `null` / omitted for none. An empty
|
|
213
|
+
* map is the same as none and needs no `reviewerAct`.
|
|
214
|
+
* @param options {@link CanonicalizeOptions.reviewerAct}, required whenever
|
|
215
|
+
* `amendments` is non-empty.
|
|
216
|
+
* @throws RangeError on a non-finite number; TypeError on anything else with no
|
|
217
|
+
* canonical form (see the module header).
|
|
218
|
+
*/
|
|
219
|
+
export declare function canonicalize(affidavit: CanonicalInput, amendments?: AmendmentMap | null, options?: CanonicalizeOptions): Uint8Array;
|
|
220
|
+
/**
|
|
221
|
+
* The canonical form of `affidavit` and its accepted `amendments`, as a string —
|
|
222
|
+
* the same document {@link canonicalize} returns, before UTF-8 encoding.
|
|
223
|
+
*
|
|
224
|
+
* Useful where the bytes are not what is wanted: a fixture that has to be readable
|
|
225
|
+
* in a diff, a log line, a comparison in a test. The bytes are the contract; this is
|
|
226
|
+
* the same document one encoding step earlier.
|
|
227
|
+
*/
|
|
228
|
+
export declare function canonicalString(affidavit: CanonicalInput, amendments?: AmendmentMap | null, options?: CanonicalizeOptions): string;
|
|
229
|
+
/**
|
|
230
|
+
* The SHA-256 of the canonical form, as lowercase hex (SR-1, RT-1).
|
|
231
|
+
*
|
|
232
|
+
* Asynchronous on every runtime because Web Crypto has no synchronous digest, and
|
|
233
|
+
* Web Crypto is the only digest a package that must run on Node, Bun and workerd
|
|
234
|
+
* can reach (RT-1). This is a stated portability choice, not an oversight: the
|
|
235
|
+
* .NET line may hash synchronously, since the conformance fixtures assert *values*,
|
|
236
|
+
* not call shapes.
|
|
237
|
+
*
|
|
238
|
+
* @returns 64 lowercase hex characters.
|
|
239
|
+
*/
|
|
240
|
+
export declare function canonicalHash(affidavit: CanonicalInput, amendments?: AmendmentMap | null, options?: CanonicalizeOptions): Promise<string>;
|
|
241
|
+
/**
|
|
242
|
+
* The Affidavit a Docket row's canonical form is taken over: the state a reviewer's
|
|
243
|
+
* amendments produced if there is one, and the proposal otherwise (SR-1).
|
|
244
|
+
*
|
|
245
|
+
* This is what SR-1's "the Affidavit **and its accepted amendments**" means on a
|
|
246
|
+
* row. The row keeps both — `affidavit` as the agent proposed it, never edited, and
|
|
247
|
+
* `amendedAffidavit` as the approval accepted it — so the sworn form and the
|
|
248
|
+
* proposal are separately readable and only one of them is what a grant binds to.
|
|
249
|
+
*/
|
|
250
|
+
export declare function swornAffidavitOf(entry: DocketEntry): Affidavit;
|
|
251
|
+
/**
|
|
252
|
+
* The canonical form of a Docket row, as UTF-8 bytes (SR-1).
|
|
253
|
+
*
|
|
254
|
+
* Equivalent to `canonicalize(entry.amendedAffidavit ?? entry.affidavit)`, with no
|
|
255
|
+
* amendment argument: the amendments were applied when the approval was recorded,
|
|
256
|
+
* by the same `amendmentTag` this module uses, so there is nothing left to apply.
|
|
257
|
+
*
|
|
258
|
+
* **This is the function a host's execution grant hashes over.** Binding a grant to
|
|
259
|
+
* the proposal instead would let a grant minted for the Affidavit a reviewer was
|
|
260
|
+
* shown validate the one they amended — the substitution the framework exists to
|
|
261
|
+
* prevent.
|
|
262
|
+
*/
|
|
263
|
+
export declare function canonicalizeEntry(entry: DocketEntry): Uint8Array;
|
|
264
|
+
/** The canonical form of a Docket row as a string — {@link canonicalizeEntry} one encoding step earlier. */
|
|
265
|
+
export declare function canonicalStringEntry(entry: DocketEntry): string;
|
|
266
|
+
/** The SHA-256 of a Docket row's canonical form, as lowercase hex (SR-1, RT-1). */
|
|
267
|
+
export declare function canonicalHashEntry(entry: DocketEntry): Promise<string>;
|
|
268
|
+
/**
|
|
269
|
+
* SHA-256 over arbitrary bytes, as lowercase hex, through Web Crypto (RT-1).
|
|
270
|
+
*
|
|
271
|
+
* Exported because the canonical form is not the only thing this framework hashes:
|
|
272
|
+
* an `utterance-span` binding hashes the span it points at, so an auditor can
|
|
273
|
+
* re-derive it, and a host's execution grant hashes what it grants over.
|
|
274
|
+
*
|
|
275
|
+
* @throws Error when the runtime exposes no `crypto.subtle` — which, on a runtime
|
|
276
|
+
* this package claims to support, means the host has replaced a standard
|
|
277
|
+
* global rather than that the digest is unavailable.
|
|
278
|
+
*/
|
|
279
|
+
export declare function sha256Hex(bytes: Uint8Array): Promise<string>;
|
|
280
|
+
/**
|
|
281
|
+
* The canonical form of any JSON value (SR-1), as a string.
|
|
282
|
+
*
|
|
283
|
+
* The general writer the Affidavit entry points are built on, exported because
|
|
284
|
+
* SR-1's form is defined over JSON and not over one type: a binding, a grant
|
|
285
|
+
* payload and a fixture all need the same bytes.
|
|
286
|
+
*
|
|
287
|
+
* **Numbers, and the one place this is stricter than RFC 8785.** The shortest
|
|
288
|
+
* round-trip decimal for a value is what JavaScript's `Number#toString` produces,
|
|
289
|
+
* and that is the form RFC 8785 (JSON Canonicalization Scheme) adopts wholesale —
|
|
290
|
+
* exponent notation included, so `1e21` serializes as `1e+21`. This writer instead
|
|
291
|
+
* writes every number **positionally**: `1000000000000000000000`, and `1e-7` as
|
|
292
|
+
* `0.0000001`. The digits are the same digits; only the decimal point moves, so the
|
|
293
|
+
* value denoted is identical and it parses back to the identical double. What is
|
|
294
|
+
* bought is that a second implementation — in .NET, in Go, in a database function —
|
|
295
|
+
* has to agree about *digits*, not about ECMAScript's exponent thresholds and its
|
|
296
|
+
* `e+21` spelling, which is the part of RFC 8785 that needs an appendix. What is
|
|
297
|
+
* paid is length: a denormal near `5e-324` writes out as roughly a thousand
|
|
298
|
+
* characters. That is a bad number to have in an audit record for reasons that have
|
|
299
|
+
* nothing to do with this function.
|
|
300
|
+
*
|
|
301
|
+
* "Positionally" means the **shortest round-trip digits** with the point moved, not
|
|
302
|
+
* the double's exact binary value: `1.2345678901234569e23` is written
|
|
303
|
+
* `123456789012345690000000`, not the exact `123456789012345685803008`. The two
|
|
304
|
+
* parse to the same double, and SR-1 asks for the shortest round-trip form — so the
|
|
305
|
+
* digits are the ones `Number#toString` chose, and nothing else.
|
|
306
|
+
*
|
|
307
|
+
* @throws RangeError on `NaN` or an infinity — a number with no decimal form at all.
|
|
308
|
+
* @throws TypeError on a value with no canonical form (see the module header).
|
|
309
|
+
*/
|
|
310
|
+
export declare function canonicalJson(value: unknown): string;
|
|
311
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/model/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+GG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AASnD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,2FAA2F;AAC3F,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACpC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,YAAY,EACxB,GAAG,EAAE,WAAW,GACf,cAAc,CAsEhB;AAiFD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,UAAU,CAEZ;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAER;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,EAChC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAEjB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CAE9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAEhE;AAED,4GAA4G;AAC5G,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE/D;AAED,mFAAmF;AACnF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBlE;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIpD"}
|