cesr-ts 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +6 -1
  2. package/esm/src/annotate/annotator.js +4 -7
  3. package/esm/src/annotate/comments.js +1 -1
  4. package/esm/src/annotate/render.js +66 -75
  5. package/esm/src/core/bytes.js +47 -0
  6. package/esm/src/core/cbor.js +122 -0
  7. package/esm/src/core/errors.js +13 -0
  8. package/esm/src/core/parser-attachment-collector.js +1 -2
  9. package/esm/src/core/parser-engine.js +7 -7
  10. package/esm/src/core/parser-frame-parser.js +14 -20
  11. package/esm/src/index.js +59 -33
  12. package/esm/src/parser/attachment-parser.js +1 -1
  13. package/esm/src/parser/group-dispatch.js +27 -41
  14. package/esm/src/primitives/aggor.js +74 -31
  15. package/esm/src/primitives/bexter.js +60 -16
  16. package/esm/src/primitives/blinder.js +27 -20
  17. package/esm/src/primitives/cigar.js +25 -15
  18. package/esm/src/primitives/cipher.js +18 -0
  19. package/esm/src/primitives/codex.js +74 -0
  20. package/esm/src/primitives/compactor.js +1 -7
  21. package/esm/src/primitives/counter.js +203 -13
  22. package/esm/src/primitives/dater.js +31 -16
  23. package/esm/src/primitives/decimer.js +65 -0
  24. package/esm/src/primitives/decrypter.js +18 -0
  25. package/esm/src/primitives/diger.js +24 -18
  26. package/esm/src/primitives/encrypter.js +19 -0
  27. package/esm/src/primitives/ilker.js +24 -12
  28. package/esm/src/primitives/indexer.js +199 -7
  29. package/esm/src/primitives/labeler.js +74 -24
  30. package/esm/src/primitives/mapper.js +14 -35
  31. package/esm/src/primitives/matter.js +160 -6
  32. package/esm/src/primitives/mediar.js +27 -18
  33. package/esm/src/primitives/noncer.js +33 -15
  34. package/esm/src/primitives/number.js +28 -27
  35. package/esm/src/primitives/pather.js +30 -18
  36. package/esm/src/primitives/prefixer.js +23 -20
  37. package/esm/src/primitives/primitive.js +9 -0
  38. package/esm/src/primitives/registry.js +3 -3
  39. package/esm/src/primitives/saider.js +24 -18
  40. package/esm/src/primitives/salter.js +22 -0
  41. package/esm/src/primitives/sealer.js +27 -32
  42. package/esm/src/primitives/seqner.js +28 -19
  43. package/esm/src/primitives/siger.js +29 -0
  44. package/esm/src/primitives/signer.js +23 -0
  45. package/esm/src/primitives/structor.js +104 -0
  46. package/esm/src/primitives/tagger.js +44 -0
  47. package/esm/src/primitives/texter.js +24 -15
  48. package/esm/src/primitives/tholder.js +27 -24
  49. package/esm/src/primitives/traitor.js +23 -16
  50. package/esm/src/primitives/unknown.js +89 -0
  51. package/esm/src/primitives/verfer.js +25 -25
  52. package/esm/src/primitives/verser.js +54 -23
  53. package/esm/src/serder/serder.js +190 -10
  54. package/esm/src/serder/serdery.js +2 -2
  55. package/esm/src/tables/codex-utils.js +9 -0
  56. package/esm/src/tables/counter-codex.js +1 -1
  57. package/esm/src/tables/counter-groups.js +46 -0
  58. package/esm/src/tables/counter-version-registry.js +1 -1
  59. package/esm/src/tables/indexer.codex.generated.js +64 -0
  60. package/esm/src/tables/indexer.tables.generated.js +72 -0
  61. package/esm/src/tables/matter.codex.generated.js +399 -0
  62. package/esm/src/tables/matter.tables.generated.js +112 -0
  63. package/esm/src/tables/trait.codex.generated.js +10 -0
  64. package/esm/src/version.js +2 -2
  65. package/package.json +1 -1
  66. package/types/src/adapters/async-iterable.d.ts +1 -1
  67. package/types/src/adapters/async-iterable.d.ts.map +1 -1
  68. package/types/src/adapters/effection.d.ts +1 -1
  69. package/types/src/adapters/effection.d.ts.map +1 -1
  70. package/types/src/annotate/annotator.d.ts.map +1 -1
  71. package/types/src/annotate/comments.d.ts.map +1 -1
  72. package/types/src/annotate/render.d.ts.map +1 -1
  73. package/types/src/bench/parser-benchmark.d.ts.map +1 -1
  74. package/types/src/core/bytes.d.ts +22 -0
  75. package/types/src/core/bytes.d.ts.map +1 -1
  76. package/types/src/core/cbor.d.ts +30 -0
  77. package/types/src/core/cbor.d.ts.map +1 -0
  78. package/types/src/core/errors.d.ts +13 -0
  79. package/types/src/core/errors.d.ts.map +1 -1
  80. package/types/src/core/parser-attachment-collector.d.ts.map +1 -1
  81. package/types/src/core/parser-engine.d.ts +1 -1
  82. package/types/src/core/parser-engine.d.ts.map +1 -1
  83. package/types/src/core/parser-frame-parser.d.ts +1 -1
  84. package/types/src/core/parser-frame-parser.d.ts.map +1 -1
  85. package/types/src/core/types.d.ts +7 -36
  86. package/types/src/core/types.d.ts.map +1 -1
  87. package/types/src/index.d.ts +59 -33
  88. package/types/src/index.d.ts.map +1 -1
  89. package/types/src/parser/attachment-fallback-policy.d.ts.map +1 -1
  90. package/types/src/parser/attachment-parser.d.ts.map +1 -1
  91. package/types/src/parser/group-dispatch.d.ts +2 -2
  92. package/types/src/parser/group-dispatch.d.ts.map +1 -1
  93. package/types/src/primitives/aggor.d.ts +34 -8
  94. package/types/src/primitives/aggor.d.ts.map +1 -1
  95. package/types/src/primitives/bexter.d.ts +28 -6
  96. package/types/src/primitives/bexter.d.ts.map +1 -1
  97. package/types/src/primitives/blinder.d.ts +16 -8
  98. package/types/src/primitives/blinder.d.ts.map +1 -1
  99. package/types/src/primitives/cigar.d.ts +12 -7
  100. package/types/src/primitives/cigar.d.ts.map +1 -1
  101. package/types/src/primitives/cipher.d.ts +11 -0
  102. package/types/src/primitives/cipher.d.ts.map +1 -0
  103. package/types/src/primitives/codex.d.ts +54 -0
  104. package/types/src/primitives/codex.d.ts.map +1 -0
  105. package/types/src/primitives/compactor.d.ts.map +1 -1
  106. package/types/src/primitives/counter.d.ts +63 -2
  107. package/types/src/primitives/counter.d.ts.map +1 -1
  108. package/types/src/primitives/dater.d.ts +12 -7
  109. package/types/src/primitives/dater.d.ts.map +1 -1
  110. package/types/src/primitives/decimer.d.ts +23 -0
  111. package/types/src/primitives/decimer.d.ts.map +1 -0
  112. package/types/src/primitives/decrypter.d.ts +11 -0
  113. package/types/src/primitives/decrypter.d.ts.map +1 -0
  114. package/types/src/primitives/diger.d.ts +16 -7
  115. package/types/src/primitives/diger.d.ts.map +1 -1
  116. package/types/src/primitives/encrypter.d.ts +12 -0
  117. package/types/src/primitives/encrypter.d.ts.map +1 -0
  118. package/types/src/primitives/ilker.d.ts +13 -6
  119. package/types/src/primitives/ilker.d.ts.map +1 -1
  120. package/types/src/primitives/indexer.d.ts +52 -1
  121. package/types/src/primitives/indexer.d.ts.map +1 -1
  122. package/types/src/primitives/labeler.d.ts +28 -11
  123. package/types/src/primitives/labeler.d.ts.map +1 -1
  124. package/types/src/primitives/mapper.d.ts +4 -6
  125. package/types/src/primitives/mapper.d.ts.map +1 -1
  126. package/types/src/primitives/matter.d.ts +44 -1
  127. package/types/src/primitives/matter.d.ts.map +1 -1
  128. package/types/src/primitives/mediar.d.ts +16 -8
  129. package/types/src/primitives/mediar.d.ts.map +1 -1
  130. package/types/src/primitives/noncer.d.ts +20 -6
  131. package/types/src/primitives/noncer.d.ts.map +1 -1
  132. package/types/src/primitives/number.d.ts +12 -7
  133. package/types/src/primitives/number.d.ts.map +1 -1
  134. package/types/src/primitives/pather.d.ts +12 -6
  135. package/types/src/primitives/pather.d.ts.map +1 -1
  136. package/types/src/primitives/prefixer.d.ts +12 -6
  137. package/types/src/primitives/prefixer.d.ts.map +1 -1
  138. package/types/src/primitives/primitive.d.ts +25 -0
  139. package/types/src/primitives/primitive.d.ts.map +1 -0
  140. package/types/src/primitives/registry.d.ts.map +1 -1
  141. package/types/src/primitives/saider.d.ts +12 -7
  142. package/types/src/primitives/saider.d.ts.map +1 -1
  143. package/types/src/primitives/salter.d.ts +13 -0
  144. package/types/src/primitives/salter.d.ts.map +1 -0
  145. package/types/src/primitives/sealer.d.ts +16 -8
  146. package/types/src/primitives/sealer.d.ts.map +1 -1
  147. package/types/src/primitives/seqner.d.ts +12 -7
  148. package/types/src/primitives/seqner.d.ts.map +1 -1
  149. package/types/src/primitives/siger.d.ts +16 -0
  150. package/types/src/primitives/siger.d.ts.map +1 -0
  151. package/types/src/primitives/signer.d.ts +14 -0
  152. package/types/src/primitives/signer.d.ts.map +1 -0
  153. package/types/src/primitives/structor.d.ts +44 -0
  154. package/types/src/primitives/structor.d.ts.map +1 -0
  155. package/types/src/primitives/tagger.d.ts +17 -0
  156. package/types/src/primitives/tagger.d.ts.map +1 -0
  157. package/types/src/primitives/texter.d.ts +11 -6
  158. package/types/src/primitives/texter.d.ts.map +1 -1
  159. package/types/src/primitives/tholder.d.ts +11 -6
  160. package/types/src/primitives/tholder.d.ts.map +1 -1
  161. package/types/src/primitives/traitor.d.ts +13 -6
  162. package/types/src/primitives/traitor.d.ts.map +1 -1
  163. package/types/src/primitives/unknown.d.ts +31 -0
  164. package/types/src/primitives/unknown.d.ts.map +1 -0
  165. package/types/src/primitives/verfer.d.ts +12 -7
  166. package/types/src/primitives/verfer.d.ts.map +1 -1
  167. package/types/src/primitives/verser.d.ts +18 -8
  168. package/types/src/primitives/verser.d.ts.map +1 -1
  169. package/types/src/serder/serder.d.ts +69 -3
  170. package/types/src/serder/serder.d.ts.map +1 -1
  171. package/types/src/serder/serdery.d.ts.map +1 -1
  172. package/types/src/tables/codex-utils.d.ts +4 -0
  173. package/types/src/tables/codex-utils.d.ts.map +1 -0
  174. package/types/src/tables/counter-codex.d.ts.map +1 -1
  175. package/types/src/tables/counter-groups.d.ts +8 -0
  176. package/types/src/tables/counter-groups.d.ts.map +1 -0
  177. package/types/src/tables/indexer.codex.generated.d.ts +127 -0
  178. package/types/src/tables/indexer.codex.generated.d.ts.map +1 -0
  179. package/types/src/tables/indexer.tables.generated.d.ts +46 -0
  180. package/types/src/tables/indexer.tables.generated.d.ts.map +1 -0
  181. package/types/src/tables/matter.codex.generated.d.ts +797 -0
  182. package/types/src/tables/matter.codex.generated.d.ts.map +1 -0
  183. package/types/src/tables/matter.tables.generated.d.ts +112 -0
  184. package/types/src/tables/matter.tables.generated.d.ts.map +1 -1
  185. package/types/src/tables/table-types.d.ts +7 -0
  186. package/types/src/tables/table-types.d.ts.map +1 -1
  187. package/types/src/tables/trait.codex.generated.d.ts +19 -0
  188. package/types/src/tables/trait.codex.generated.d.ts.map +1 -0
  189. package/types/src/version.d.ts +2 -2
  190. package/esm/src/tables/indexer.tables.js +0 -30
  191. package/types/src/tables/indexer.tables.d.ts +0 -12
  192. package/types/src/tables/indexer.tables.d.ts.map +0 -1
@@ -1,10 +1,15 @@
1
- import { b64ToInt, codeB2ToB64, codeB64ToB2, decodeB64, nabSextets, sceil, } from "../core/bytes.js";
2
- import { DeserializeError, ShortageError, UnknownCodeError, } from "../core/errors.js";
3
- import { INDEXER_HARDS, INDEXER_SIZES } from "../tables/indexer.tables.js";
1
+ import { b, b64ToInt, codeB2ToB64, codeB64ToB2, concatBytes, decodeB64, encodeB64, intToB64, nabSextets, sceil, } from "../core/bytes.js";
2
+ import { DeserializeError, ShortageError, UnknownCodeError } from "../core/errors.js";
3
+ import { INDEXER_HARDS, INDEXER_SIZES } from "../tables/indexer.tables.generated.js";
4
4
  const INDEXER_BARDS = new Map([...INDEXER_HARDS.entries()].map(([code, hs]) => [
5
5
  String.fromCharCode(codeB64ToB2(code)[0]),
6
6
  hs,
7
7
  ]));
8
+ function isIndexerData(value) {
9
+ return typeof value === "object" && value !== null
10
+ && "code" in value && "raw" in value && "qb64" in value
11
+ && "fullSize" in value && "fullSizeB2" in value && "index" in value;
12
+ }
8
13
  function parseIndexerCodeFromText(txt) {
9
14
  const hs = INDEXER_HARDS.get(txt[0]);
10
15
  if (!hs) {
@@ -16,7 +21,19 @@ function parseIndexerCodeFromText(txt) {
16
21
  }
17
22
  return { code };
18
23
  }
19
- export function parseIndexerFromText(input) {
24
+ function parseIndexFields(code, qb64) {
25
+ const sizage = INDEXER_SIZES.get(code);
26
+ if (!sizage) {
27
+ throw new UnknownCodeError(`Unknown indexer code ${code}`);
28
+ }
29
+ const cs = sizage.hs + sizage.ss;
30
+ const soft = qb64.slice(sizage.hs, cs);
31
+ const ms = sizage.ss - sizage.os;
32
+ const index = ms > 0 ? b64ToInt(soft.slice(0, ms)) : 0;
33
+ const ondex = sizage.os > 0 ? b64ToInt(soft.slice(ms, sizage.ss)) : undefined;
34
+ return { index, ondex };
35
+ }
36
+ function parseIndexerFromTextData(input) {
20
37
  const txt = String.fromCharCode(...input);
21
38
  if (txt.length === 0) {
22
39
  throw new DeserializeError("Empty indexer input");
@@ -29,16 +46,20 @@ export function parseIndexerFromText(input) {
29
46
  if (txt.length < fullSize) {
30
47
  throw new ShortageError(fullSize, txt.length);
31
48
  }
32
- const raw = decodeB64(txt.slice(cs, fullSize)).slice(sizage.ls);
49
+ const qb64 = txt.slice(0, fullSize);
50
+ const raw = decodeB64(qb64.slice(cs)).slice(sizage.ls);
51
+ const { index, ondex } = parseIndexFields(code, qb64);
33
52
  return {
34
53
  code,
35
54
  raw,
36
- qb64: txt.slice(0, fullSize),
55
+ qb64,
37
56
  fullSize,
38
57
  fullSizeB2: sceil((fullSize * 3) / 4),
58
+ index,
59
+ ondex,
39
60
  };
40
61
  }
41
- export function parseIndexerFromBinary(input) {
62
+ function parseIndexerFromBinaryData(input) {
42
63
  if (input.length === 0) {
43
64
  throw new ShortageError(1, 0);
44
65
  }
@@ -71,14 +92,185 @@ export function parseIndexerFromBinary(input) {
71
92
  const qb2 = input.slice(0, bfs);
72
93
  const qb64 = codeB2ToB64(qb2, fs);
73
94
  const raw = decodeB64(qb64.slice(cs)).slice(sizage.ls);
95
+ const { index, ondex } = parseIndexFields(hard, qb64);
74
96
  return {
75
97
  code: hard,
76
98
  raw,
77
99
  qb64,
78
100
  fullSize: fs,
79
101
  fullSizeB2: bfs,
102
+ index,
103
+ ondex,
104
+ };
105
+ }
106
+ function encodeIndexerFromRaw(code, raw, index, ondex) {
107
+ const sizage = INDEXER_SIZES.get(code);
108
+ if (!sizage) {
109
+ throw new UnknownCodeError(`Unknown indexer code ${code}`);
110
+ }
111
+ const ms = sizage.ss - sizage.os;
112
+ if (ms < 0) {
113
+ throw new DeserializeError(`Invalid indexer sizage for ${code}`);
114
+ }
115
+ if (!Number.isInteger(index) || index < 0) {
116
+ throw new DeserializeError(`Invalid index ${index} for ${code}`);
117
+ }
118
+ const ondexValue = sizage.os > 0 ? (ondex ?? index) : undefined;
119
+ if (sizage.os > 0 && (ondexValue === undefined || ondexValue < 0)) {
120
+ throw new DeserializeError(`Invalid ondex ${ondexValue} for ${code}`);
121
+ }
122
+ const cs = sizage.hs + sizage.ss;
123
+ const ps = cs % 4;
124
+ const paw = concatBytes(new Uint8Array(ps + sizage.ls), raw);
125
+ const body = encodeB64(paw).slice(ps);
126
+ const soft = `${intToB64(index, ms)}${sizage.os > 0 ? intToB64(ondexValue ?? 0, sizage.os) : ""}`;
127
+ const qb64 = `${code}${soft}${body}`;
128
+ const fullSize = qb64.length;
129
+ if (sizage.fs !== null && fullSize !== sizage.fs) {
130
+ throw new DeserializeError(`Encoded indexer size mismatch for ${code}: expected=${sizage.fs} got=${fullSize}`);
131
+ }
132
+ return {
133
+ code,
134
+ raw: raw.slice(),
135
+ qb64,
136
+ fullSize,
137
+ fullSizeB2: sceil((fullSize * 3) / 4),
138
+ index,
139
+ ondex: ondexValue,
80
140
  };
81
141
  }
142
+ function parseIndexerInit(init) {
143
+ if (init.raw && init.code) {
144
+ return encodeIndexerFromRaw(init.code, init.raw, init.index ?? 0, init.ondex);
145
+ }
146
+ if (init.qb64b) {
147
+ return parseIndexerFromTextData(init.qb64b);
148
+ }
149
+ if (init.qb64) {
150
+ return parseIndexerFromTextData(b(init.qb64));
151
+ }
152
+ if (init.qb2) {
153
+ return parseIndexerFromBinaryData(init.qb2);
154
+ }
155
+ throw new DeserializeError("Indexer requires (raw + code) or qb64/qb64b/qb2 initialization");
156
+ }
157
+ /**
158
+ * Base indexed CESR primitive.
159
+ *
160
+ * KERIpy substance: `Indexer` extends matter semantics with index/ondex fields
161
+ * used by indexed signatures and other attachment-indexed material families.
162
+ */
163
+ export class Indexer {
164
+ constructor(init) {
165
+ Object.defineProperty(this, "_code", {
166
+ enumerable: true,
167
+ configurable: true,
168
+ writable: true,
169
+ value: void 0
170
+ });
171
+ Object.defineProperty(this, "_raw", {
172
+ enumerable: true,
173
+ configurable: true,
174
+ writable: true,
175
+ value: void 0
176
+ });
177
+ Object.defineProperty(this, "_qb64", {
178
+ enumerable: true,
179
+ configurable: true,
180
+ writable: true,
181
+ value: void 0
182
+ });
183
+ Object.defineProperty(this, "_fullSize", {
184
+ enumerable: true,
185
+ configurable: true,
186
+ writable: true,
187
+ value: void 0
188
+ });
189
+ Object.defineProperty(this, "_fullSizeB2", {
190
+ enumerable: true,
191
+ configurable: true,
192
+ writable: true,
193
+ value: void 0
194
+ });
195
+ Object.defineProperty(this, "_index", {
196
+ enumerable: true,
197
+ configurable: true,
198
+ writable: true,
199
+ value: void 0
200
+ });
201
+ Object.defineProperty(this, "_ondex", {
202
+ enumerable: true,
203
+ configurable: true,
204
+ writable: true,
205
+ value: void 0
206
+ });
207
+ const data = init instanceof Indexer
208
+ ? init.toIndexerData()
209
+ : isIndexerData(init)
210
+ ? init
211
+ : parseIndexerInit(init);
212
+ this._code = data.code;
213
+ this._raw = data.raw.slice();
214
+ this._qb64 = data.qb64;
215
+ this._fullSize = data.fullSize;
216
+ this._fullSizeB2 = data.fullSizeB2;
217
+ this._index = data.index;
218
+ this._ondex = data.ondex;
219
+ }
220
+ toIndexerData() {
221
+ return {
222
+ code: this._code,
223
+ raw: this._raw.slice(),
224
+ qb64: this._qb64,
225
+ fullSize: this._fullSize,
226
+ fullSizeB2: this._fullSizeB2,
227
+ index: this._index,
228
+ ondex: this._ondex,
229
+ };
230
+ }
231
+ get code() {
232
+ return this._code;
233
+ }
234
+ get raw() {
235
+ return this._raw;
236
+ }
237
+ get qb64() {
238
+ return this._qb64;
239
+ }
240
+ get qb64b() {
241
+ return b(this._qb64);
242
+ }
243
+ get qb2() {
244
+ return codeB64ToB2(this._qb64);
245
+ }
246
+ get fullSize() {
247
+ return this._fullSize;
248
+ }
249
+ get fullSizeB2() {
250
+ return this._fullSizeB2;
251
+ }
252
+ get index() {
253
+ return this._index;
254
+ }
255
+ get ondex() {
256
+ return this._ondex;
257
+ }
258
+ equals(other) {
259
+ return this._qb64 === other.qb64;
260
+ }
261
+ toString() {
262
+ return this._qb64;
263
+ }
264
+ }
265
+ /** Parse indexer material from text-domain CESR bytes. */
266
+ export function parseIndexerFromText(input) {
267
+ return new Indexer(parseIndexerFromTextData(input));
268
+ }
269
+ /** Parse indexer material from binary-domain CESR bytes. */
270
+ export function parseIndexerFromBinary(input) {
271
+ return new Indexer(parseIndexerFromBinaryData(input));
272
+ }
273
+ /** Parse indexer using caller-provided cold-start domain hint (`txt` or `bny`). */
82
274
  export function parseIndexer(input, cold) {
83
275
  return cold === "bny"
84
276
  ? parseIndexerFromBinary(input)
@@ -1,31 +1,81 @@
1
1
  import { UnknownCodeError } from "../core/errors.js";
2
- import { parseMatter } from "./matter.js";
2
+ import { Bexter } from "./bexter.js";
3
+ import { BEXTER_CODES, isAttLabel, LABELER_CODES, TAG_CODES } from "./codex.js";
4
+ import { Matter, parseMatter } from "./matter.js";
5
+ import { Tagger } from "./tagger.js";
3
6
  const TEXT_DECODER = new TextDecoder();
4
- const LABELER_CODES = new Set(["V", "W"]);
7
+ /** True when code belongs to KERIpy `LabelCodex` accepted by native map labels. */
5
8
  export function isLabelerCode(code) {
6
9
  return LABELER_CODES.has(code);
7
10
  }
8
- /** Parse a V/W label primitive into decoded map-label metadata. */
11
+ /**
12
+ * Decode a label/text token according to LabelCodex encoding rules.
13
+ *
14
+ * Tag/Bext encodings require specialized decoding logic; all other label forms
15
+ * project directly from raw bytes.
16
+ */
17
+ function decodeLabelText(matter) {
18
+ if (TAG_CODES.has(matter.code)) {
19
+ return new Tagger(matter).tag;
20
+ }
21
+ if (BEXTER_CODES.has(matter.code)) {
22
+ const bext = Bexter.derawify(matter.raw, matter.code);
23
+ return bext.startsWith("-") && isAttLabel(bext.slice(1))
24
+ ? bext.slice(1)
25
+ : bext;
26
+ }
27
+ return TEXT_DECODER.decode(matter.raw);
28
+ }
29
+ /**
30
+ * Label/text primitive used for native map keys and textual field values.
31
+ *
32
+ * KERIpy semantics: `Labeler` accepts Tag/Bext/Bytes families (plus compact
33
+ * label codes) and provides both strict attribute-label projection (`label`)
34
+ * and generic text projection (`text`).
35
+ */
36
+ export class Labeler extends Matter {
37
+ constructor(init) {
38
+ const matter = init instanceof Matter ? init : new Matter(init);
39
+ super(matter);
40
+ if (!isLabelerCode(this.code)) {
41
+ throw new UnknownCodeError(`Expected labeler code, got ${this.code}`);
42
+ }
43
+ }
44
+ /** Canonical qb64 token for emit/roundtrip paths. */
45
+ get token() {
46
+ return this.qb64;
47
+ }
48
+ /** Attribute-safe label projection used for map key semantics. */
49
+ get label() {
50
+ const label = decodeLabelText(this);
51
+ if (!isAttLabel(label)) {
52
+ throw new UnknownCodeError(`Invalid label text: ${label}`);
53
+ }
54
+ return label;
55
+ }
56
+ /** Raw text projection without attribute-name validation. */
57
+ get text() {
58
+ return decodeLabelText(this);
59
+ }
60
+ /** Numeric projection helper used for compact fixed-width label values. */
61
+ get index() {
62
+ let index = 0;
63
+ for (const b of this.raw) {
64
+ index = (index << 8) | b;
65
+ }
66
+ return index;
67
+ }
68
+ /** Raw decoded bytes backing the label/text token. */
69
+ get bytes() {
70
+ return this.raw;
71
+ }
72
+ }
73
+ /**
74
+ * Parse and hydrate a `Labeler` from txt/qb2 bytes.
75
+ *
76
+ * Boundary contract: parsing is syntactic; semantic label validity is enforced
77
+ * when `label` accessor is read.
78
+ */
9
79
  export function parseLabeler(input, cold) {
10
- // Labelers are fixed-size matter primitives used as map field keys.
11
- const matter = parseMatter(input, cold);
12
- if (!isLabelerCode(matter.code)) {
13
- throw new UnknownCodeError(`Expected labeler code (V/W), got ${matter.code}`);
14
- }
15
- let index = 0;
16
- for (const b of matter.raw) {
17
- index = (index << 8) | b;
18
- }
19
- const text = TEXT_DECODER.decode(matter.raw).replace(/\u0000/g, "");
20
- const label = text.length > 0 ? text : matter.qb64.slice(matter.code.length);
21
- return {
22
- code: matter.code,
23
- qb64: matter.qb64,
24
- fullSize: matter.fullSize,
25
- fullSizeB2: matter.fullSizeB2,
26
- token: matter.qb64,
27
- label,
28
- index,
29
- bytes: matter.raw,
30
- };
80
+ return new Labeler(parseMatter(input, cold));
31
81
  }
@@ -1,30 +1,14 @@
1
- import { encodeB64 } from "../core/bytes.js";
2
1
  import { DeserializeError, SemanticInterpretationError, ShortageError, SyntaxParseError, UnknownCodeError, } from "../core/errors.js";
3
2
  import { parseAttachmentDispatch } from "../parser/group-dispatch.js";
4
- import { CtrDexV2 } from "../tables/counter-codex.js";
3
+ import { AGGOR_LIST_CODES, AGGOR_MAP_CODES } from "../tables/counter-groups.js";
5
4
  import { parseCounter } from "./counter.js";
6
5
  import { parseLabeler } from "./labeler.js";
7
6
  import { parseMatter } from "./matter.js";
8
- const MAP_GROUP_CODES = new Set([
9
- CtrDexV2.MapBodyGroup,
10
- CtrDexV2.BigMapBodyGroup,
11
- CtrDexV2.GenericMapGroup,
12
- CtrDexV2.BigGenericMapGroup,
13
- ]);
14
- const LIST_GROUP_CODES = new Set([
15
- CtrDexV2.GenericGroup,
16
- CtrDexV2.BigGenericGroup,
17
- CtrDexV2.GenericListGroup,
18
- CtrDexV2.BigGenericListGroup,
19
- ]);
20
7
  function tokenSize(token, domain) {
21
8
  return domain === "bny" ? token.fullSizeB2 : token.fullSize;
22
9
  }
23
10
  function isMapGroupCode(code) {
24
- return MAP_GROUP_CODES.has(code);
25
- }
26
- function asQb64(raw, domain) {
27
- return domain === "txt" ? String.fromCharCode(...raw) : encodeB64(raw);
11
+ return AGGOR_MAP_CODES.has(code);
28
12
  }
29
13
  function parseCounterProbe(input, version, domain) {
30
14
  /**
@@ -46,8 +30,8 @@ function parseCounterProbe(input, version, domain) {
46
30
  if (error instanceof ShortageError) {
47
31
  throw error;
48
32
  }
49
- if (error instanceof UnknownCodeError ||
50
- error instanceof DeserializeError) {
33
+ if (error instanceof UnknownCodeError
34
+ || error instanceof DeserializeError) {
51
35
  continue;
52
36
  }
53
37
  throw error;
@@ -64,8 +48,8 @@ function parseLabelProbe(input, domain) {
64
48
  if (error instanceof ShortageError) {
65
49
  throw error;
66
50
  }
67
- if (error instanceof UnknownCodeError ||
68
- error instanceof DeserializeError) {
51
+ if (error instanceof UnknownCodeError
52
+ || error instanceof DeserializeError) {
69
53
  return null;
70
54
  }
71
55
  throw error;
@@ -81,11 +65,9 @@ function parseMapperValueSyntax(input, version, domain) {
81
65
  const counter = parseCounterProbe(input, version, domain);
82
66
  if (counter) {
83
67
  const dispatch = parseAttachmentDispatch(input, version, domain);
84
- const raw = input.slice(0, dispatch.consumed);
85
68
  const value = {
86
69
  kind: "value",
87
- code: dispatch.group.code,
88
- qb64: asQb64(raw, domain),
70
+ primitive: dispatch.group,
89
71
  isCounter: true,
90
72
  consumed: dispatch.consumed,
91
73
  };
@@ -97,8 +79,7 @@ function parseMapperValueSyntax(input, version, domain) {
97
79
  const matter = parseMatter(input, domain);
98
80
  return {
99
81
  kind: "value",
100
- code: matter.code,
101
- qb64: matter.qb64,
82
+ primitive: matter,
102
83
  isCounter: false,
103
84
  consumed: tokenSize(matter, domain),
104
85
  };
@@ -119,8 +100,7 @@ function parseMapPayloadSyntax(input, version, domain, start, end) {
119
100
  const consumed = tokenSize(maybeLabel, domain);
120
101
  entries.push({
121
102
  kind: "label",
122
- code: maybeLabel.code,
123
- qb64: maybeLabel.token,
103
+ primitive: parseMatter(at, domain),
124
104
  label: maybeLabel.label,
125
105
  consumed,
126
106
  });
@@ -147,8 +127,7 @@ export function interpretMapperBodySyntax(syntax) {
147
127
  }
148
128
  fields.push({
149
129
  label: pendingLabel,
150
- code: entry.code,
151
- qb64: entry.qb64,
130
+ primitive: entry.primitive,
152
131
  isCounter: entry.isCounter,
153
132
  children: entry.children
154
133
  ? interpretMapperBodySyntax(entry.children)
@@ -190,9 +169,9 @@ export function parseMapperBodySyntax(input, version, domain) {
190
169
  };
191
170
  }
192
171
  catch (error) {
193
- if (error instanceof ShortageError ||
194
- error instanceof UnknownCodeError ||
195
- error instanceof DeserializeError) {
172
+ if (error instanceof ShortageError
173
+ || error instanceof UnknownCodeError
174
+ || error instanceof DeserializeError) {
196
175
  throw new SyntaxParseError(`Map-body syntax parse failed: ${error.message}`, error);
197
176
  }
198
177
  throw error;
@@ -235,5 +214,5 @@ export function parseMapperBody(input, version, domain) {
235
214
  }
236
215
  /** True for counter codes that represent map/list-native aggregate primitives. */
237
216
  export function isMapperCounterCode(code) {
238
- return MAP_GROUP_CODES.has(code) || LIST_GROUP_CODES.has(code);
217
+ return AGGOR_MAP_CODES.has(code) || AGGOR_LIST_CODES.has(code);
239
218
  }
@@ -1,10 +1,19 @@
1
- import { b64ToInt, codeB2ToB64, codeB64ToB2, decodeB64, nabSextets, sceil, } from "../core/bytes.js";
2
- import { DeserializeError, ShortageError, UnknownCodeError, } from "../core/errors.js";
3
- import { MATTER_HARDS, MATTER_SIZES, } from "../tables/matter.tables.generated.js";
1
+ import { b, b64ToInt, codeB2ToB64, codeB64ToB2, concatBytes, decodeB64, encodeB64, intToB64, nabSextets, sceil, } from "../core/bytes.js";
2
+ import { DeserializeError, ShortageError, UnknownCodeError } from "../core/errors.js";
3
+ import { MATTER_HARDS, MATTER_SIZES } from "../tables/matter.tables.generated.js";
4
4
  const MATTER_BARDS = new Map([...MATTER_HARDS.entries()].map(([code, hs]) => [
5
5
  String.fromCharCode(codeB64ToB2(code)[0]),
6
6
  hs,
7
7
  ]));
8
+ function isMatterData(value) {
9
+ return typeof value === "object"
10
+ && value !== null
11
+ && "code" in value
12
+ && "raw" in value
13
+ && "qb64" in value
14
+ && "fullSize" in value
15
+ && "fullSizeB2" in value;
16
+ }
8
17
  function parseMatterCodeFromText(txt) {
9
18
  const hs = MATTER_HARDS.get(txt[0]);
10
19
  if (!hs) {
@@ -23,7 +32,7 @@ function parseMatterCodeFromText(txt) {
23
32
  }
24
33
  return { code, hs: sizage.hs };
25
34
  }
26
- export function parseMatterFromText(input) {
35
+ function parseMatterFromTextData(input) {
27
36
  const txt = String.fromCharCode(...input);
28
37
  if (txt.length === 0) {
29
38
  throw new ShortageError(1, 0);
@@ -48,7 +57,7 @@ export function parseMatterFromText(input) {
48
57
  fullSizeB2: sceil((fullSize * 3) / 4),
49
58
  };
50
59
  }
51
- export function parseMatterFromBinary(input) {
60
+ function parseMatterFromBinaryData(input) {
52
61
  if (input.length === 0) {
53
62
  throw new ShortageError(1, 0);
54
63
  }
@@ -93,7 +102,8 @@ export function parseMatterFromBinary(input) {
93
102
  }
94
103
  }
95
104
  const qb64 = codeB2ToB64(qb2, fs);
96
- const raw = decodeB64(qb64.slice(cs)).slice(sizage.ls);
105
+ const paw = decodeB64("A".repeat(ps) + qb64.slice(cs));
106
+ const raw = paw.slice(ps + sizage.ls);
97
107
  return {
98
108
  code: hard,
99
109
  raw,
@@ -102,6 +112,150 @@ export function parseMatterFromBinary(input) {
102
112
  fullSizeB2: bfs,
103
113
  };
104
114
  }
115
+ function encodeMatterFromRaw(code, raw) {
116
+ const sizage = MATTER_SIZES.get(code);
117
+ if (!sizage) {
118
+ throw new UnknownCodeError(`Unknown matter code ${code}`);
119
+ }
120
+ const cs = sizage.hs + sizage.ss;
121
+ const ps = cs % 4;
122
+ const paw = concatBytes(new Uint8Array(ps + sizage.ls), raw);
123
+ const body = encodeB64(paw).slice(ps);
124
+ let soft = "";
125
+ if (sizage.ss > 0) {
126
+ const softLen = sizage.ss - sizage.xs;
127
+ if (softLen < 0) {
128
+ throw new DeserializeError(`Invalid sizage soft width for code ${code}`);
129
+ }
130
+ const count = sizage.fs === null ? body.length / 4 : (sizage.fs - cs) / 4;
131
+ if (!Number.isInteger(count) || count < 0) {
132
+ throw new DeserializeError(`Invalid computed count for code ${code}`);
133
+ }
134
+ soft = "_".repeat(sizage.xs) + intToB64(count, softLen);
135
+ }
136
+ const qb64 = `${code}${soft}${body}`;
137
+ const fullSize = qb64.length;
138
+ if (sizage.fs !== null && fullSize !== sizage.fs) {
139
+ throw new DeserializeError(`Encoded size mismatch for ${code}: expected=${sizage.fs} got=${fullSize}`);
140
+ }
141
+ return {
142
+ code,
143
+ raw: raw.slice(),
144
+ qb64,
145
+ fullSize,
146
+ fullSizeB2: sceil((fullSize * 3) / 4),
147
+ };
148
+ }
149
+ function parseMatterInit(init) {
150
+ if (init.raw && init.code) {
151
+ return encodeMatterFromRaw(init.code, init.raw);
152
+ }
153
+ if (init.qb64b) {
154
+ return parseMatterFromTextData(init.qb64b);
155
+ }
156
+ if (init.qb64) {
157
+ return parseMatterFromTextData(b(init.qb64));
158
+ }
159
+ if (init.qb2) {
160
+ return parseMatterFromBinaryData(init.qb2);
161
+ }
162
+ throw new DeserializeError("Matter requires (raw + code) or qb64/qb64b/qb2 initialization");
163
+ }
164
+ /**
165
+ * Base CESR primitive carrying qualified matter material.
166
+ *
167
+ * KERIpy substance: `Matter` is the foundational primitive abstraction that
168
+ * handles exfil/infil between raw bytes and qualified CESR encodings.
169
+ */
170
+ export class Matter {
171
+ constructor(init) {
172
+ Object.defineProperty(this, "_code", {
173
+ enumerable: true,
174
+ configurable: true,
175
+ writable: true,
176
+ value: void 0
177
+ });
178
+ Object.defineProperty(this, "_raw", {
179
+ enumerable: true,
180
+ configurable: true,
181
+ writable: true,
182
+ value: void 0
183
+ });
184
+ Object.defineProperty(this, "_qb64", {
185
+ enumerable: true,
186
+ configurable: true,
187
+ writable: true,
188
+ value: void 0
189
+ });
190
+ Object.defineProperty(this, "_fullSize", {
191
+ enumerable: true,
192
+ configurable: true,
193
+ writable: true,
194
+ value: void 0
195
+ });
196
+ Object.defineProperty(this, "_fullSizeB2", {
197
+ enumerable: true,
198
+ configurable: true,
199
+ writable: true,
200
+ value: void 0
201
+ });
202
+ const data = init instanceof Matter
203
+ ? init.toMatterData()
204
+ : isMatterData(init)
205
+ ? init
206
+ : parseMatterInit(init);
207
+ this._code = data.code;
208
+ this._raw = data.raw.slice();
209
+ this._qb64 = data.qb64;
210
+ this._fullSize = data.fullSize;
211
+ this._fullSizeB2 = data.fullSizeB2;
212
+ }
213
+ toMatterData() {
214
+ return {
215
+ code: this._code,
216
+ raw: this._raw.slice(),
217
+ qb64: this._qb64,
218
+ fullSize: this._fullSize,
219
+ fullSizeB2: this._fullSizeB2,
220
+ };
221
+ }
222
+ get code() {
223
+ return this._code;
224
+ }
225
+ get raw() {
226
+ return this._raw;
227
+ }
228
+ get qb64() {
229
+ return this._qb64;
230
+ }
231
+ get qb64b() {
232
+ return b(this._qb64);
233
+ }
234
+ get qb2() {
235
+ return codeB64ToB2(this._qb64);
236
+ }
237
+ get fullSize() {
238
+ return this._fullSize;
239
+ }
240
+ get fullSizeB2() {
241
+ return this._fullSizeB2;
242
+ }
243
+ equals(other) {
244
+ return this._qb64 === other.qb64;
245
+ }
246
+ toString() {
247
+ return this._qb64;
248
+ }
249
+ }
250
+ /** Parse matter from text-domain CESR bytes. */
251
+ export function parseMatterFromText(input) {
252
+ return new Matter(parseMatterFromTextData(input));
253
+ }
254
+ /** Parse matter from binary-domain CESR bytes. */
255
+ export function parseMatterFromBinary(input) {
256
+ return new Matter(parseMatterFromBinaryData(input));
257
+ }
258
+ /** Parse matter using caller-provided cold-start domain hint (`txt` or `bny`). */
105
259
  export function parseMatter(input, cold) {
106
260
  return cold === "bny"
107
261
  ? parseMatterFromBinary(input)