cesr-ts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +32 -0
- package/esm/_dnt.polyfills.js +127 -0
- package/esm/mod.js +2 -0
- package/esm/package.json +3 -0
- package/esm/src/adapters/async-iterable.js +17 -0
- package/esm/src/adapters/effection.js +9 -0
- package/esm/src/annotate/annotator.js +36 -0
- package/esm/src/annotate/cli-node.js +53 -0
- package/esm/src/annotate/cli.js +89 -0
- package/esm/src/annotate/comments.js +43 -0
- package/esm/src/annotate/denot.js +17 -0
- package/esm/src/annotate/render.js +246 -0
- package/esm/src/annotate/types.js +1 -0
- package/esm/src/core/bytes.js +70 -0
- package/esm/src/core/errors.js +45 -0
- package/esm/src/core/parser-engine.js +589 -0
- package/esm/src/core/types.js +1 -0
- package/esm/src/index.js +46 -0
- package/esm/src/parser/attachment-parser.js +4 -0
- package/esm/src/parser/cold-start.js +17 -0
- package/esm/src/parser/group-dispatch.js +420 -0
- package/esm/src/primitives/aggor.js +41 -0
- package/esm/src/primitives/bexter.js +20 -0
- package/esm/src/primitives/blinder.js +23 -0
- package/esm/src/primitives/cigar.js +18 -0
- package/esm/src/primitives/compactor.js +16 -0
- package/esm/src/primitives/counter.js +100 -0
- package/esm/src/primitives/dater.js +22 -0
- package/esm/src/primitives/diger.js +22 -0
- package/esm/src/primitives/ilker.js +15 -0
- package/esm/src/primitives/indexer.js +84 -0
- package/esm/src/primitives/labeler.js +31 -0
- package/esm/src/primitives/mapper.js +158 -0
- package/esm/src/primitives/matter.js +109 -0
- package/esm/src/primitives/mediar.js +21 -0
- package/esm/src/primitives/noncer.js +18 -0
- package/esm/src/primitives/number.js +31 -0
- package/esm/src/primitives/pather.js +23 -0
- package/esm/src/primitives/prefixer.js +23 -0
- package/esm/src/primitives/registry.js +17 -0
- package/esm/src/primitives/saider.js +22 -0
- package/esm/src/primitives/sealer.js +35 -0
- package/esm/src/primitives/seqner.js +23 -0
- package/esm/src/primitives/texter.js +20 -0
- package/esm/src/primitives/tholder.js +27 -0
- package/esm/src/primitives/traitor.js +20 -0
- package/esm/src/primitives/verfer.js +28 -0
- package/esm/src/primitives/verser.js +30 -0
- package/esm/src/router/router-stub.js +17 -0
- package/esm/src/serder/serder.js +22 -0
- package/esm/src/serder/serdery.js +12 -0
- package/esm/src/serder/smell.js +56 -0
- package/esm/src/tables/counter-codex.js +10 -0
- package/esm/src/tables/counter.tables.generated.js +178 -0
- package/esm/src/tables/indexer.tables.js +30 -0
- package/esm/src/tables/matter.tables.generated.js +238 -0
- package/esm/src/tables/table-types.js +1 -0
- package/esm/src/tables/versions.js +12 -0
- package/package.json +52 -0
- package/types/_dnt.polyfills.d.ts +101 -0
- package/types/_dnt.polyfills.d.ts.map +1 -0
- package/types/mod.d.ts +3 -0
- package/types/mod.d.ts.map +1 -0
- package/types/src/adapters/async-iterable.d.ts +4 -0
- package/types/src/adapters/async-iterable.d.ts.map +1 -0
- package/types/src/adapters/effection.d.ts +8 -0
- package/types/src/adapters/effection.d.ts.map +1 -0
- package/types/src/annotate/annotator.d.ts +4 -0
- package/types/src/annotate/annotator.d.ts.map +1 -0
- package/types/src/annotate/cli-node.d.ts +2 -0
- package/types/src/annotate/cli-node.d.ts.map +1 -0
- package/types/src/annotate/cli.d.ts +10 -0
- package/types/src/annotate/cli.d.ts.map +1 -0
- package/types/src/annotate/comments.d.ts +6 -0
- package/types/src/annotate/comments.d.ts.map +1 -0
- package/types/src/annotate/denot.d.ts +2 -0
- package/types/src/annotate/denot.d.ts.map +1 -0
- package/types/src/annotate/render.d.ts +5 -0
- package/types/src/annotate/render.d.ts.map +1 -0
- package/types/src/annotate/types.d.ts +15 -0
- package/types/src/annotate/types.d.ts.map +1 -0
- package/types/src/core/bytes.d.ts +12 -0
- package/types/src/core/bytes.d.ts.map +1 -0
- package/types/src/core/errors.d.ts +21 -0
- package/types/src/core/errors.d.ts.map +1 -0
- package/types/src/core/parser-engine.d.ts +58 -0
- package/types/src/core/parser-engine.d.ts.map +1 -0
- package/types/src/core/types.d.ts +52 -0
- package/types/src/core/types.d.ts.map +1 -0
- package/types/src/index.d.ts +47 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/parser/attachment-parser.d.ts +8 -0
- package/types/src/parser/attachment-parser.d.ts.map +1 -0
- package/types/src/parser/cold-start.d.ts +3 -0
- package/types/src/parser/cold-start.d.ts.map +1 -0
- package/types/src/parser/group-dispatch.d.ts +29 -0
- package/types/src/parser/group-dispatch.d.ts.map +1 -0
- package/types/src/primitives/aggor.d.ts +13 -0
- package/types/src/primitives/aggor.d.ts.map +1 -0
- package/types/src/primitives/bexter.d.ts +10 -0
- package/types/src/primitives/bexter.d.ts.map +1 -0
- package/types/src/primitives/blinder.d.ts +12 -0
- package/types/src/primitives/blinder.d.ts.map +1 -0
- package/types/src/primitives/cigar.d.ts +11 -0
- package/types/src/primitives/cigar.d.ts.map +1 -0
- package/types/src/primitives/compactor.d.ts +5 -0
- package/types/src/primitives/compactor.d.ts.map +1 -0
- package/types/src/primitives/counter.d.ts +14 -0
- package/types/src/primitives/counter.d.ts.map +1 -0
- package/types/src/primitives/dater.d.ts +11 -0
- package/types/src/primitives/dater.d.ts.map +1 -0
- package/types/src/primitives/diger.d.ts +11 -0
- package/types/src/primitives/diger.d.ts.map +1 -0
- package/types/src/primitives/ilker.d.ts +10 -0
- package/types/src/primitives/ilker.d.ts.map +1 -0
- package/types/src/primitives/indexer.d.ts +12 -0
- package/types/src/primitives/indexer.d.ts.map +1 -0
- package/types/src/primitives/labeler.d.ts +15 -0
- package/types/src/primitives/labeler.d.ts.map +1 -0
- package/types/src/primitives/mapper.d.ts +28 -0
- package/types/src/primitives/mapper.d.ts.map +1 -0
- package/types/src/primitives/matter.d.ts +12 -0
- package/types/src/primitives/matter.d.ts.map +1 -0
- package/types/src/primitives/mediar.d.ts +12 -0
- package/types/src/primitives/mediar.d.ts.map +1 -0
- package/types/src/primitives/noncer.d.ts +10 -0
- package/types/src/primitives/noncer.d.ts.map +1 -0
- package/types/src/primitives/number.d.ts +11 -0
- package/types/src/primitives/number.d.ts.map +1 -0
- package/types/src/primitives/pather.d.ts +10 -0
- package/types/src/primitives/pather.d.ts.map +1 -0
- package/types/src/primitives/prefixer.d.ts +10 -0
- package/types/src/primitives/prefixer.d.ts.map +1 -0
- package/types/src/primitives/registry.d.ts +10 -0
- package/types/src/primitives/registry.d.ts.map +1 -0
- package/types/src/primitives/saider.d.ts +11 -0
- package/types/src/primitives/saider.d.ts.map +1 -0
- package/types/src/primitives/sealer.d.ts +12 -0
- package/types/src/primitives/sealer.d.ts.map +1 -0
- package/types/src/primitives/seqner.d.ts +11 -0
- package/types/src/primitives/seqner.d.ts.map +1 -0
- package/types/src/primitives/texter.d.ts +10 -0
- package/types/src/primitives/texter.d.ts.map +1 -0
- package/types/src/primitives/tholder.d.ts +10 -0
- package/types/src/primitives/tholder.d.ts.map +1 -0
- package/types/src/primitives/traitor.d.ts +10 -0
- package/types/src/primitives/traitor.d.ts.map +1 -0
- package/types/src/primitives/verfer.d.ts +11 -0
- package/types/src/primitives/verfer.d.ts.map +1 -0
- package/types/src/primitives/verser.d.ts +14 -0
- package/types/src/primitives/verser.d.ts.map +1 -0
- package/types/src/router/router-stub.d.ts +11 -0
- package/types/src/router/router-stub.d.ts.map +1 -0
- package/types/src/serder/serder.d.ts +4 -0
- package/types/src/serder/serder.d.ts.map +1 -0
- package/types/src/serder/serdery.d.ts +6 -0
- package/types/src/serder/serdery.d.ts.map +1 -0
- package/types/src/serder/smell.d.ts +7 -0
- package/types/src/serder/smell.d.ts.map +1 -0
- package/types/src/tables/counter-codex.d.ts +6 -0
- package/types/src/tables/counter-codex.d.ts.map +1 -0
- package/types/src/tables/counter.tables.generated.d.ts +92 -0
- package/types/src/tables/counter.tables.generated.d.ts.map +1 -0
- package/types/src/tables/indexer.tables.d.ts +12 -0
- package/types/src/tables/indexer.tables.d.ts.map +1 -0
- package/types/src/tables/matter.tables.generated.d.ts +116 -0
- package/types/src/tables/matter.tables.generated.d.ts.map +1 -0
- package/types/src/tables/table-types.d.ts +19 -0
- package/types/src/tables/table-types.d.ts.map +1 -0
- package/types/src/tables/versions.d.ts +16 -0
- package/types/src/tables/versions.d.ts.map +1 -0
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
import { concatBytes } from "./bytes.js";
|
|
2
|
+
import { sniff } from "../parser/cold-start.js";
|
|
3
|
+
import { reapSerder } from "../serder/serdery.js";
|
|
4
|
+
import { parseAttachmentGroup } from "../parser/attachment-parser.js";
|
|
5
|
+
import { ColdStartError, DeserializeError, ParserError, ShortageError, UnknownCodeError, } from "./errors.js";
|
|
6
|
+
import { parseCounter } from "../primitives/counter.js";
|
|
7
|
+
import { parseMatter } from "../primitives/matter.js";
|
|
8
|
+
import { parseVerser } from "../primitives/verser.js";
|
|
9
|
+
import { parseIlker } from "../primitives/ilker.js";
|
|
10
|
+
import { isLabelerCode, parseLabeler } from "../primitives/labeler.js";
|
|
11
|
+
import { parseMapperBody } from "../primitives/mapper.js";
|
|
12
|
+
import { CtrDexV1, CtrDexV2 } from "../tables/counter-codex.js";
|
|
13
|
+
import { b64ToInt, intToB64 } from "./bytes.js";
|
|
14
|
+
import { Kinds, Protocols } from "../tables/versions.js";
|
|
15
|
+
const DEFAULT_VERSION = { major: 2, minor: 0 };
|
|
16
|
+
const BODY_WITH_ATTACH_CODES = new Set([
|
|
17
|
+
CtrDexV1.BodyWithAttachmentGroup,
|
|
18
|
+
CtrDexV1.BigBodyWithAttachmentGroup,
|
|
19
|
+
CtrDexV2.BodyWithAttachmentGroup,
|
|
20
|
+
CtrDexV2.BigBodyWithAttachmentGroup,
|
|
21
|
+
]);
|
|
22
|
+
const NON_NATIVE_BODY_CODES = new Set([
|
|
23
|
+
CtrDexV1.NonNativeBodyGroup,
|
|
24
|
+
CtrDexV1.BigNonNativeBodyGroup,
|
|
25
|
+
CtrDexV2.NonNativeBodyGroup,
|
|
26
|
+
CtrDexV2.BigNonNativeBodyGroup,
|
|
27
|
+
]);
|
|
28
|
+
const FIX_BODY_CODES = new Set([
|
|
29
|
+
CtrDexV2.FixBodyGroup,
|
|
30
|
+
CtrDexV2.BigFixBodyGroup,
|
|
31
|
+
]);
|
|
32
|
+
const MAP_BODY_CODES = new Set([
|
|
33
|
+
CtrDexV2.MapBodyGroup,
|
|
34
|
+
CtrDexV2.BigMapBodyGroup,
|
|
35
|
+
]);
|
|
36
|
+
const GENUS_VERSION_CODE = CtrDexV2.KERIACDCGenusVersion;
|
|
37
|
+
function tokenSize(token, cold) {
|
|
38
|
+
return cold === "bny" ? token.fullSizeB2 : token.fullSize;
|
|
39
|
+
}
|
|
40
|
+
function quadletUnit(cold) {
|
|
41
|
+
return cold === "bny" ? 3 : 4;
|
|
42
|
+
}
|
|
43
|
+
function isAttachmentDomain(cold) {
|
|
44
|
+
return cold === "txt" || cold === "bny";
|
|
45
|
+
}
|
|
46
|
+
export class CesrParserCore {
|
|
47
|
+
constructor(options = {}) {
|
|
48
|
+
Object.defineProperty(this, "state", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
configurable: true,
|
|
51
|
+
writable: true,
|
|
52
|
+
value: { buffer: new Uint8Array(0), offset: 0 }
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(this, "framed", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
configurable: true,
|
|
57
|
+
writable: true,
|
|
58
|
+
value: void 0
|
|
59
|
+
});
|
|
60
|
+
Object.defineProperty(this, "attachmentDispatchMode", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
configurable: true,
|
|
63
|
+
writable: true,
|
|
64
|
+
value: void 0
|
|
65
|
+
});
|
|
66
|
+
Object.defineProperty(this, "onAttachmentVersionFallback", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
configurable: true,
|
|
69
|
+
writable: true,
|
|
70
|
+
value: void 0
|
|
71
|
+
});
|
|
72
|
+
Object.defineProperty(this, "pendingFrame", {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
configurable: true,
|
|
75
|
+
writable: true,
|
|
76
|
+
value: null
|
|
77
|
+
});
|
|
78
|
+
this.framed = options.framed ?? false;
|
|
79
|
+
this.attachmentDispatchMode = options.attachmentDispatchMode ?? "compat";
|
|
80
|
+
this.onAttachmentVersionFallback = options.onAttachmentVersionFallback;
|
|
81
|
+
}
|
|
82
|
+
/** Append bytes and emit any complete parse events. */
|
|
83
|
+
feed(chunk) {
|
|
84
|
+
this.state.buffer = concatBytes(this.state.buffer, chunk);
|
|
85
|
+
return this.drain();
|
|
86
|
+
}
|
|
87
|
+
/** Flush pending state at end-of-stream, emitting frame/error if needed. */
|
|
88
|
+
flush() {
|
|
89
|
+
const out = [];
|
|
90
|
+
if (this.pendingFrame) {
|
|
91
|
+
out.push({ type: "frame", frame: this.pendingFrame.frame });
|
|
92
|
+
this.pendingFrame = null;
|
|
93
|
+
}
|
|
94
|
+
if (this.state.buffer.length === 0)
|
|
95
|
+
return out;
|
|
96
|
+
out.push({
|
|
97
|
+
type: "error",
|
|
98
|
+
error: new ShortageError(this.state.buffer.length + 1, this.state.buffer.length, this.state.offset),
|
|
99
|
+
});
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
reset() {
|
|
103
|
+
this.state = { buffer: new Uint8Array(0), offset: 0 };
|
|
104
|
+
this.pendingFrame = null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Core streaming loop.
|
|
108
|
+
* Keeps state machine behavior explicit: consume separators, parse a base
|
|
109
|
+
* frame, then greedily collect trailing attachment groups.
|
|
110
|
+
*/
|
|
111
|
+
drain() {
|
|
112
|
+
const out = [];
|
|
113
|
+
while (this.state.buffer.length > 0) {
|
|
114
|
+
try {
|
|
115
|
+
this.consumeLeadingAno();
|
|
116
|
+
if (this.state.buffer.length === 0) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
if (this.pendingFrame) {
|
|
120
|
+
if (!this.resumePendingFrame(out)) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const base = this.parseFrame(this.state.buffer);
|
|
126
|
+
this.consume(base.consumed);
|
|
127
|
+
const attachments = [...base.frame.attachments];
|
|
128
|
+
const version = base.version;
|
|
129
|
+
let pausedForAttachmentShortage = false;
|
|
130
|
+
try {
|
|
131
|
+
while (this.state.buffer.length > 0) {
|
|
132
|
+
const nextCold = sniff(this.state.buffer);
|
|
133
|
+
if (nextCold === "msg")
|
|
134
|
+
break;
|
|
135
|
+
if (nextCold === "ano") {
|
|
136
|
+
this.consumeLeadingAno();
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (!isAttachmentDomain(nextCold)) {
|
|
140
|
+
throw new ColdStartError(`Unsupported attachment cold code ${nextCold}`);
|
|
141
|
+
}
|
|
142
|
+
const { group, consumed } = parseAttachmentGroup(this.state.buffer, version, nextCold, {
|
|
143
|
+
mode: this.attachmentDispatchMode,
|
|
144
|
+
onVersionFallback: this.onAttachmentVersionFallback,
|
|
145
|
+
});
|
|
146
|
+
attachments.push(group);
|
|
147
|
+
this.consume(consumed);
|
|
148
|
+
if (this.framed)
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof ShortageError) {
|
|
154
|
+
this.pendingFrame = {
|
|
155
|
+
frame: { serder: base.frame.serder, attachments },
|
|
156
|
+
version,
|
|
157
|
+
};
|
|
158
|
+
pausedForAttachmentShortage = true;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (pausedForAttachmentShortage) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
const completed = {
|
|
168
|
+
serder: base.frame.serder,
|
|
169
|
+
attachments,
|
|
170
|
+
};
|
|
171
|
+
if (!this.framed && attachments.length === 0 &&
|
|
172
|
+
this.state.buffer.length === 0) {
|
|
173
|
+
this.pendingFrame = { frame: completed, version };
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
out.push({ type: "frame", frame: completed });
|
|
177
|
+
if (this.framed)
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
if (error instanceof ShortageError) {
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
const normalized = error instanceof ParserError
|
|
185
|
+
? error
|
|
186
|
+
: new ParserError(String(error), this.state.offset);
|
|
187
|
+
out.push({ type: "error", error: normalized });
|
|
188
|
+
this.reset();
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
resumePendingFrame(out) {
|
|
195
|
+
if (!this.pendingFrame)
|
|
196
|
+
return false;
|
|
197
|
+
if (this.state.buffer.length === 0)
|
|
198
|
+
return false;
|
|
199
|
+
const nextCold = sniff(this.state.buffer);
|
|
200
|
+
if (nextCold === "ano") {
|
|
201
|
+
this.consumeLeadingAno();
|
|
202
|
+
return this.state.buffer.length > 0;
|
|
203
|
+
}
|
|
204
|
+
if (nextCold === "msg") {
|
|
205
|
+
out.push({ type: "frame", frame: this.pendingFrame.frame });
|
|
206
|
+
this.pendingFrame = null;
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
if (!isAttachmentDomain(nextCold)) {
|
|
210
|
+
throw new ColdStartError(`Unsupported pending-frame continuation cold code ${nextCold}`);
|
|
211
|
+
}
|
|
212
|
+
if (this.pendingFrame.frame.serder.kind === Kinds.cesr) {
|
|
213
|
+
const peek = parseCounter(this.state.buffer, this.pendingFrame.version, nextCold);
|
|
214
|
+
if (BODY_WITH_ATTACH_CODES.has(peek.code) ||
|
|
215
|
+
NON_NATIVE_BODY_CODES.has(peek.code) ||
|
|
216
|
+
FIX_BODY_CODES.has(peek.code) ||
|
|
217
|
+
MAP_BODY_CODES.has(peek.code) ||
|
|
218
|
+
peek.code === GENUS_VERSION_CODE) {
|
|
219
|
+
out.push({ type: "frame", frame: this.pendingFrame.frame });
|
|
220
|
+
this.pendingFrame = null;
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const { group, consumed } = parseAttachmentGroup(this.state.buffer, this.pendingFrame.version, nextCold, {
|
|
225
|
+
mode: this.attachmentDispatchMode,
|
|
226
|
+
onVersionFallback: this.onAttachmentVersionFallback,
|
|
227
|
+
});
|
|
228
|
+
this.pendingFrame.frame.attachments.push(group);
|
|
229
|
+
this.consume(consumed);
|
|
230
|
+
if (this.framed) {
|
|
231
|
+
out.push({ type: "frame", frame: this.pendingFrame.frame });
|
|
232
|
+
this.pendingFrame = null;
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
if (this.state.buffer.length === 0) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
const afterCold = sniff(this.state.buffer);
|
|
239
|
+
if (afterCold === "ano") {
|
|
240
|
+
this.consumeLeadingAno();
|
|
241
|
+
return this.state.buffer.length > 0;
|
|
242
|
+
}
|
|
243
|
+
if (afterCold === "msg") {
|
|
244
|
+
out.push({ type: "frame", frame: this.pendingFrame.frame });
|
|
245
|
+
this.pendingFrame = null;
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
consume(length) {
|
|
251
|
+
this.state.buffer = this.state.buffer.slice(length);
|
|
252
|
+
this.state.offset += length;
|
|
253
|
+
}
|
|
254
|
+
consumeLeadingAno() {
|
|
255
|
+
while (this.state.buffer.length > 0 && sniff(this.state.buffer) === "ano") {
|
|
256
|
+
this.consume(1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Parse a single top-level frame start from current buffer head.
|
|
261
|
+
* Supports message-domain serders and CESR-native body groups.
|
|
262
|
+
*/
|
|
263
|
+
parseFrame(input, inheritedVersion = DEFAULT_VERSION) {
|
|
264
|
+
let offset = 0;
|
|
265
|
+
let activeVersion = inheritedVersion;
|
|
266
|
+
let cold = sniff(input.slice(offset));
|
|
267
|
+
while (cold === "ano") {
|
|
268
|
+
offset += 1;
|
|
269
|
+
if (input.length <= offset) {
|
|
270
|
+
throw new ShortageError(offset + 1, input.length);
|
|
271
|
+
}
|
|
272
|
+
cold = sniff(input.slice(offset));
|
|
273
|
+
}
|
|
274
|
+
if (cold === "txt" || cold === "bny") {
|
|
275
|
+
const peek = parseCounter(input.slice(offset), activeVersion, cold);
|
|
276
|
+
if (peek.code === GENUS_VERSION_CODE) {
|
|
277
|
+
offset += tokenSize(peek, cold);
|
|
278
|
+
activeVersion = this.decodeVersionCounter(peek);
|
|
279
|
+
if (input.length <= offset) {
|
|
280
|
+
throw new ShortageError(offset + 1, input.length);
|
|
281
|
+
}
|
|
282
|
+
cold = sniff(input.slice(offset));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (cold === "msg") {
|
|
286
|
+
const { serder, consumed } = reapSerder(input.slice(offset));
|
|
287
|
+
return {
|
|
288
|
+
frame: { serder, attachments: [] },
|
|
289
|
+
consumed: offset + consumed,
|
|
290
|
+
version: serder.gvrsn ?? serder.pvrsn,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (!isAttachmentDomain(cold)) {
|
|
294
|
+
throw new ColdStartError(`Expected message or CESR body group at frame start but got ${cold}`);
|
|
295
|
+
}
|
|
296
|
+
const counter = parseCounter(input.slice(offset), activeVersion, cold);
|
|
297
|
+
const headerSize = tokenSize(counter, cold);
|
|
298
|
+
const unit = quadletUnit(cold);
|
|
299
|
+
if (BODY_WITH_ATTACH_CODES.has(counter.code)) {
|
|
300
|
+
return this.parseBodyWithAttachmentGroup(input, offset, headerSize, counter.count, unit, activeVersion);
|
|
301
|
+
}
|
|
302
|
+
if (NON_NATIVE_BODY_CODES.has(counter.code)) {
|
|
303
|
+
return this.parseNonNativeBodyGroup(input, offset, headerSize, counter.count, unit, cold, activeVersion);
|
|
304
|
+
}
|
|
305
|
+
if (FIX_BODY_CODES.has(counter.code) || MAP_BODY_CODES.has(counter.code)) {
|
|
306
|
+
return this.parseNativeBodyGroup(input, offset, headerSize, counter.count, unit, cold, activeVersion, counter.code);
|
|
307
|
+
}
|
|
308
|
+
throw new ColdStartError(`Unsupported body-group counter at frame start: ${counter.code}`);
|
|
309
|
+
}
|
|
310
|
+
/** Parse wrapped body+attachments payloads as a complete nested frame. */
|
|
311
|
+
parseBodyWithAttachmentGroup(input, offset, headerSize, count, unit, version) {
|
|
312
|
+
const payloadSize = count * unit;
|
|
313
|
+
const total = headerSize + payloadSize;
|
|
314
|
+
if (input.length < offset + total) {
|
|
315
|
+
throw new ShortageError(offset + total, input.length);
|
|
316
|
+
}
|
|
317
|
+
const payload = input.slice(offset + headerSize, offset + total);
|
|
318
|
+
const nested = this.parseCompleteFrame(payload, version, false);
|
|
319
|
+
if (nested.consumed !== payload.length) {
|
|
320
|
+
throw new ColdStartError("BodyWithAttachmentGroup payload did not parse to a complete frame");
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
frame: nested.frame,
|
|
324
|
+
consumed: offset + total,
|
|
325
|
+
version: nested.frame.serder.gvrsn ?? nested.frame.serder.pvrsn,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
/** Parse a non-native body group; keep opaque fallback when serder reap fails. */
|
|
329
|
+
parseNonNativeBodyGroup(input, offset, headerSize, count, unit, cold, version) {
|
|
330
|
+
const matter = parseMatter(input.slice(offset + headerSize), cold);
|
|
331
|
+
const bodySize = tokenSize(matter, cold);
|
|
332
|
+
const payloadSize = count * unit;
|
|
333
|
+
if (payloadSize !== bodySize) {
|
|
334
|
+
throw new ColdStartError(`NonNativeBodyGroup payload size mismatch: expected=${payloadSize} actual=${bodySize}`);
|
|
335
|
+
}
|
|
336
|
+
try {
|
|
337
|
+
const { serder } = reapSerder(matter.raw);
|
|
338
|
+
return {
|
|
339
|
+
frame: { serder, attachments: [] },
|
|
340
|
+
consumed: offset + headerSize + bodySize,
|
|
341
|
+
version: serder.gvrsn ?? serder.pvrsn,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
catch (_error) {
|
|
345
|
+
// Intentional recovery: NonNativeBodyGroup payload is opaque CESR body data.
|
|
346
|
+
// If it cannot be interpreted as a KERI/ACDC Serder, preserve bytes and
|
|
347
|
+
// continue with conservative metadata instead of failing the frame parse.
|
|
348
|
+
return {
|
|
349
|
+
frame: {
|
|
350
|
+
serder: {
|
|
351
|
+
raw: matter.raw,
|
|
352
|
+
ked: null,
|
|
353
|
+
proto: Protocols.keri,
|
|
354
|
+
kind: Kinds.cesr,
|
|
355
|
+
size: matter.raw.length,
|
|
356
|
+
pvrsn: version,
|
|
357
|
+
gvrsn: version,
|
|
358
|
+
ilk: null,
|
|
359
|
+
said: null,
|
|
360
|
+
},
|
|
361
|
+
attachments: [],
|
|
362
|
+
},
|
|
363
|
+
consumed: offset + headerSize + bodySize,
|
|
364
|
+
version,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/** Parse fixed/map native body groups and extract semantic native fields. */
|
|
369
|
+
parseNativeBodyGroup(input, offset, headerSize, count, unit, cold, version, bodyCode) {
|
|
370
|
+
const payloadSize = count * unit;
|
|
371
|
+
const total = headerSize + payloadSize;
|
|
372
|
+
if (input.length < offset + total) {
|
|
373
|
+
throw new ShortageError(offset + total, input.length);
|
|
374
|
+
}
|
|
375
|
+
const raw = input.slice(offset, offset + total);
|
|
376
|
+
const metadata = this.extractNativeMetadata(raw, cold, version);
|
|
377
|
+
const fields = this.extractNativeFields(raw, cold, version);
|
|
378
|
+
return {
|
|
379
|
+
frame: {
|
|
380
|
+
serder: {
|
|
381
|
+
raw,
|
|
382
|
+
ked: null,
|
|
383
|
+
proto: metadata.proto,
|
|
384
|
+
kind: Kinds.cesr,
|
|
385
|
+
size: raw.length,
|
|
386
|
+
pvrsn: metadata.pvrsn,
|
|
387
|
+
gvrsn: metadata.gvrsn,
|
|
388
|
+
ilk: metadata.ilk,
|
|
389
|
+
said: metadata.said,
|
|
390
|
+
native: {
|
|
391
|
+
bodyCode,
|
|
392
|
+
fields,
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
attachments: [],
|
|
396
|
+
},
|
|
397
|
+
consumed: offset + total,
|
|
398
|
+
version,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/** Decode genus-version counter suffix to active CESR version. */
|
|
402
|
+
decodeVersionCounter(counter) {
|
|
403
|
+
const triplet = counter.qb64.length >= 3
|
|
404
|
+
? counter.qb64.slice(-3)
|
|
405
|
+
: intToB64(counter.count, 3);
|
|
406
|
+
const majorRaw = b64ToInt(triplet[0] ?? "A");
|
|
407
|
+
const minorRaw = b64ToInt(triplet[1] ?? "A");
|
|
408
|
+
const major = majorRaw === 1 ? 1 : 2;
|
|
409
|
+
return {
|
|
410
|
+
major,
|
|
411
|
+
minor: minorRaw,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Best-effort native metadata extraction.
|
|
416
|
+
* This is intentionally advisory and may recover instead of failing hard.
|
|
417
|
+
*/
|
|
418
|
+
extractNativeMetadata(raw, cold, fallbackVersion) {
|
|
419
|
+
let offset = 0;
|
|
420
|
+
let proto = Protocols.keri;
|
|
421
|
+
let pvrsn = fallbackVersion;
|
|
422
|
+
let gvrsn = fallbackVersion;
|
|
423
|
+
let ilk = null;
|
|
424
|
+
let said = null;
|
|
425
|
+
try {
|
|
426
|
+
const bodyCounter = parseCounter(raw, fallbackVersion, cold);
|
|
427
|
+
offset += cold === "bny" ? bodyCounter.fullSizeB2 : bodyCounter.fullSize;
|
|
428
|
+
// In map-body mode, labels may appear between semantic fields.
|
|
429
|
+
// Metadata extraction skips those labels before reading core fields.
|
|
430
|
+
if (MAP_BODY_CODES.has(bodyCounter.code)) {
|
|
431
|
+
offset = this.skipNativeLabelers(raw, offset, cold);
|
|
432
|
+
}
|
|
433
|
+
const verser = parseVerser(raw.slice(offset), cold);
|
|
434
|
+
offset += tokenSize(verser, cold);
|
|
435
|
+
proto = verser.proto;
|
|
436
|
+
pvrsn = verser.pvrsn;
|
|
437
|
+
gvrsn = verser.gvrsn;
|
|
438
|
+
if (MAP_BODY_CODES.has(bodyCounter.code)) {
|
|
439
|
+
offset = this.skipNativeLabelers(raw, offset, cold);
|
|
440
|
+
}
|
|
441
|
+
const ilker = parseIlker(raw.slice(offset), cold);
|
|
442
|
+
offset += tokenSize(ilker, cold);
|
|
443
|
+
ilk = ilker.ilk;
|
|
444
|
+
if (MAP_BODY_CODES.has(bodyCounter.code)) {
|
|
445
|
+
offset = this.skipNativeLabelers(raw, offset, cold);
|
|
446
|
+
}
|
|
447
|
+
const saider = parseMatter(raw.slice(offset), cold);
|
|
448
|
+
if (saider.code.startsWith("E")) {
|
|
449
|
+
said = saider.qb64;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch (_error) {
|
|
453
|
+
// Intentional recovery: native metadata extraction is advisory only.
|
|
454
|
+
// Strict token validation happens in extractNativeFields/mapper parsing.
|
|
455
|
+
}
|
|
456
|
+
return { proto, pvrsn, gvrsn, ilk, said };
|
|
457
|
+
}
|
|
458
|
+
/** Skip consecutive native label tokens (V/W) from an offset. */
|
|
459
|
+
skipNativeLabelers(raw, offset, cold) {
|
|
460
|
+
let out = offset;
|
|
461
|
+
while (out < raw.length) {
|
|
462
|
+
const item = parseMatter(raw.slice(out), cold);
|
|
463
|
+
if (!isLabelerCode(item.code)) {
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
out += tokenSize(item, cold);
|
|
467
|
+
}
|
|
468
|
+
return out;
|
|
469
|
+
}
|
|
470
|
+
/** Strict native field extraction for annotation and higher-level processing. */
|
|
471
|
+
extractNativeFields(raw, cold, fallbackVersion) {
|
|
472
|
+
const bodyCounter = parseCounter(raw, fallbackVersion, cold);
|
|
473
|
+
if (MAP_BODY_CODES.has(bodyCounter.code)) {
|
|
474
|
+
const mapper = parseMapperBody(raw, fallbackVersion, cold);
|
|
475
|
+
return mapper.fields.map((field) => ({
|
|
476
|
+
label: field.label,
|
|
477
|
+
code: field.code,
|
|
478
|
+
qb64: field.qb64,
|
|
479
|
+
}));
|
|
480
|
+
}
|
|
481
|
+
const fields = [];
|
|
482
|
+
const total = tokenSize(bodyCounter, cold);
|
|
483
|
+
const payloadBytes = bodyCounter.count * quadletUnit(cold);
|
|
484
|
+
const start = total;
|
|
485
|
+
const end = start + payloadBytes;
|
|
486
|
+
let offset = start;
|
|
487
|
+
let pendingLabel = null;
|
|
488
|
+
while (offset < end) {
|
|
489
|
+
const at = raw.slice(offset, end);
|
|
490
|
+
const ctr = this.tryParseCounter(at, fallbackVersion, cold);
|
|
491
|
+
if (ctr) {
|
|
492
|
+
const size = tokenSize(ctr, cold);
|
|
493
|
+
offset += size;
|
|
494
|
+
fields.push({
|
|
495
|
+
label: pendingLabel,
|
|
496
|
+
code: ctr.code,
|
|
497
|
+
qb64: ctr.qb64,
|
|
498
|
+
});
|
|
499
|
+
pendingLabel = null;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
const token = parseMatter(at, cold);
|
|
503
|
+
const size = tokenSize(token, cold);
|
|
504
|
+
offset += size;
|
|
505
|
+
if (isLabelerCode(token.code)) {
|
|
506
|
+
pendingLabel = parseLabeler(at, cold).label;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
fields.push({
|
|
510
|
+
label: pendingLabel,
|
|
511
|
+
code: token.code,
|
|
512
|
+
qb64: token.qb64,
|
|
513
|
+
});
|
|
514
|
+
pendingLabel = null;
|
|
515
|
+
}
|
|
516
|
+
if (offset !== end) {
|
|
517
|
+
throw new ShortageError(end, offset);
|
|
518
|
+
}
|
|
519
|
+
if (pendingLabel !== null) {
|
|
520
|
+
throw new ColdStartError("Dangling native map label without value");
|
|
521
|
+
}
|
|
522
|
+
return fields;
|
|
523
|
+
}
|
|
524
|
+
/** Counter probe with ordered version fallback; throws on shortage. */
|
|
525
|
+
tryParseCounter(input, version, cold) {
|
|
526
|
+
const attempts = [
|
|
527
|
+
version,
|
|
528
|
+
{ major: 2, minor: 0 },
|
|
529
|
+
{ major: 1, minor: 0 },
|
|
530
|
+
];
|
|
531
|
+
for (const attempt of attempts) {
|
|
532
|
+
try {
|
|
533
|
+
return parseCounter(input, attempt, cold);
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
if (error instanceof ShortageError) {
|
|
537
|
+
throw error;
|
|
538
|
+
}
|
|
539
|
+
if (error instanceof UnknownCodeError ||
|
|
540
|
+
error instanceof DeserializeError) {
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
/** Parse one complete frame plus optional attachments from a standalone slice. */
|
|
549
|
+
parseCompleteFrame(input, inheritedVersion = DEFAULT_VERSION, stopAtNextMessage = true) {
|
|
550
|
+
const base = this.parseFrame(input, inheritedVersion);
|
|
551
|
+
const version = base.version;
|
|
552
|
+
const attachments = [];
|
|
553
|
+
let offset = base.consumed;
|
|
554
|
+
while (offset < input.length) {
|
|
555
|
+
const nextCold = sniff(input.slice(offset));
|
|
556
|
+
if (nextCold === "ano") {
|
|
557
|
+
offset += 1;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
if (nextCold === "msg") {
|
|
561
|
+
if (stopAtNextMessage)
|
|
562
|
+
break;
|
|
563
|
+
throw new ColdStartError("Enclosed frame payload encountered unexpected nested message start");
|
|
564
|
+
}
|
|
565
|
+
if (!isAttachmentDomain(nextCold)) {
|
|
566
|
+
throw new ColdStartError(`Unsupported attachment cold code ${nextCold}`);
|
|
567
|
+
}
|
|
568
|
+
const { group, consumed } = parseAttachmentGroup(input.slice(offset), version, nextCold, {
|
|
569
|
+
mode: this.attachmentDispatchMode,
|
|
570
|
+
onVersionFallback: this.onAttachmentVersionFallback,
|
|
571
|
+
});
|
|
572
|
+
attachments.push(group);
|
|
573
|
+
offset += consumed;
|
|
574
|
+
if (this.framed)
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
frame: { serder: base.frame.serder, attachments },
|
|
579
|
+
consumed: offset,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
export function createParser(options = {}) {
|
|
584
|
+
return new CesrParserCore(options);
|
|
585
|
+
}
|
|
586
|
+
export function parseBytes(bytes, options = {}) {
|
|
587
|
+
const parser = createParser(options);
|
|
588
|
+
return [...parser.feed(bytes), ...parser.flush()];
|
|
589
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/esm/src/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export * from "./core/types.js";
|
|
2
|
+
export * from "./core/errors.js";
|
|
3
|
+
export * from "./core/parser-engine.js";
|
|
4
|
+
export * from "./parser/cold-start.js";
|
|
5
|
+
export * from "./parser/group-dispatch.js";
|
|
6
|
+
export * from "./serder/smell.js";
|
|
7
|
+
export * from "./serder/serder.js";
|
|
8
|
+
export * from "./serder/serdery.js";
|
|
9
|
+
export * from "./primitives/matter.js";
|
|
10
|
+
export * from "./primitives/counter.js";
|
|
11
|
+
export * from "./primitives/indexer.js";
|
|
12
|
+
export * from "./primitives/verser.js";
|
|
13
|
+
export * from "./primitives/ilker.js";
|
|
14
|
+
export * from "./primitives/labeler.js";
|
|
15
|
+
export * from "./primitives/texter.js";
|
|
16
|
+
export * from "./primitives/bexter.js";
|
|
17
|
+
export * from "./primitives/pather.js";
|
|
18
|
+
export * from "./primitives/mapper.js";
|
|
19
|
+
export * from "./primitives/number.js";
|
|
20
|
+
export * from "./primitives/seqner.js";
|
|
21
|
+
export * from "./primitives/dater.js";
|
|
22
|
+
export * from "./primitives/diger.js";
|
|
23
|
+
export * from "./primitives/prefixer.js";
|
|
24
|
+
export * from "./primitives/noncer.js";
|
|
25
|
+
export * from "./primitives/saider.js";
|
|
26
|
+
export * from "./primitives/cigar.js";
|
|
27
|
+
export * from "./primitives/verfer.js";
|
|
28
|
+
export * from "./primitives/traitor.js";
|
|
29
|
+
export * from "./primitives/tholder.js";
|
|
30
|
+
export * from "./primitives/sealer.js";
|
|
31
|
+
export * from "./primitives/blinder.js";
|
|
32
|
+
export * from "./primitives/mediar.js";
|
|
33
|
+
export * from "./primitives/compactor.js";
|
|
34
|
+
export * from "./primitives/aggor.js";
|
|
35
|
+
export * from "./primitives/registry.js";
|
|
36
|
+
export * from "./adapters/async-iterable.js";
|
|
37
|
+
export * from "./adapters/effection.js";
|
|
38
|
+
export * from "./router/router-stub.js";
|
|
39
|
+
export * from "./tables/versions.js";
|
|
40
|
+
export * from "./tables/table-types.js";
|
|
41
|
+
export * from "./tables/counter-codex.js";
|
|
42
|
+
export * from "./annotate/types.js";
|
|
43
|
+
export * from "./annotate/comments.js";
|
|
44
|
+
export * from "./annotate/render.js";
|
|
45
|
+
export * from "./annotate/annotator.js";
|
|
46
|
+
export * from "./annotate/denot.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ColdStartError, ShortageError } from "../core/errors.js";
|
|
2
|
+
export function sniff(ims) {
|
|
3
|
+
if (ims.length === 0) {
|
|
4
|
+
throw new ShortageError(1, 0);
|
|
5
|
+
}
|
|
6
|
+
const tritet = ims[0] >> 5;
|
|
7
|
+
if (tritet === 0o3 || tritet === 0o4 || tritet === 0o5 || tritet === 0o6) {
|
|
8
|
+
return "msg";
|
|
9
|
+
}
|
|
10
|
+
if (tritet === 0o1 || tritet === 0o2)
|
|
11
|
+
return "txt";
|
|
12
|
+
if (tritet === 0o7)
|
|
13
|
+
return "bny";
|
|
14
|
+
if (tritet === 0o0)
|
|
15
|
+
return "ano";
|
|
16
|
+
throw new ColdStartError(`Unexpected tritet=${tritet} at stream start`);
|
|
17
|
+
}
|