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
@@ -0,0 +1,44 @@
1
+ import { UnknownCodeError } from "../core/errors.js";
2
+ import { MATTER_SIZES } from "../tables/matter.tables.generated.js";
3
+ import { TAG_CODES } from "./codex.js";
4
+ import { Matter, parseMatter } from "./matter.js";
5
+ /**
6
+ * Extract unpadded tag payload from a tag-coded qb64 token.
7
+ *
8
+ * Tag codes store the value in soft-code characters, optionally with xtra
9
+ * prepad (`xs`) that must be removed before exposing the semantic tag value.
10
+ */
11
+ function extractTag(code, qb64) {
12
+ const sizage = MATTER_SIZES.get(code);
13
+ if (!sizage) {
14
+ throw new UnknownCodeError(`Unknown tag code ${code}`);
15
+ }
16
+ const soft = qb64.slice(sizage.hs, sizage.hs + sizage.ss);
17
+ return soft.slice(sizage.xs);
18
+ }
19
+ /** True when `code` belongs to KERIpy `TagCodex` family. */
20
+ export function isTaggerCode(code) {
21
+ return TAG_CODES.has(code);
22
+ }
23
+ /**
24
+ * Compact "special" primitive for CESR tag values stored in soft-code fields.
25
+ *
26
+ * Invariant: instances always represent one of `TagCodex` codes.
27
+ */
28
+ export class Tagger extends Matter {
29
+ constructor(init) {
30
+ const matter = init instanceof Matter ? init : new Matter(init);
31
+ super(matter);
32
+ if (!isTaggerCode(this.code)) {
33
+ throw new UnknownCodeError(`Expected tag code, got ${this.code}`);
34
+ }
35
+ }
36
+ /** Decoded tag value with prepad removed. */
37
+ get tag() {
38
+ return extractTag(this.code, this.qb64);
39
+ }
40
+ }
41
+ /** Parse and hydrate a `Tagger` from txt or qb2 stream bytes. */
42
+ export function parseTagger(input, cold) {
43
+ return new Tagger(parseMatter(input, cold));
44
+ }
@@ -1,20 +1,29 @@
1
+ import { t } from "../core/bytes.js";
1
2
  import { UnknownCodeError } from "../core/errors.js";
2
- import { parseMatter } from "./matter.js";
3
- import { MATTER_CODE_NAMES } from "../tables/matter.tables.generated.js";
3
+ import { TEXTER_CODES } from "./codex.js";
4
+ import { Matter, parseMatter } from "./matter.js";
4
5
  function isTexterCode(code) {
5
- const name = MATTER_CODE_NAMES[code] ?? "";
6
- return name.startsWith("Bytes_") || name.startsWith("Bytes_Big_");
6
+ return TEXTER_CODES.has(code);
7
7
  }
8
- export function parseTexter(input, cold) {
9
- const matter = parseMatter(input, cold);
10
- if (!isTexterCode(matter.code)) {
11
- throw new UnknownCodeError(`Expected texter bytes code, got ${matter.code}`);
8
+ /**
9
+ * Raw-bytes text primitive.
10
+ *
11
+ * KERIpy substance: `Texter` carries variable-length byte-string text (UTF-8
12
+ * friendly) with Bytes codex families.
13
+ */
14
+ export class Texter extends Matter {
15
+ constructor(init) {
16
+ const matter = init instanceof Matter ? init : new Matter(init);
17
+ super(matter);
18
+ if (!isTexterCode(this.code)) {
19
+ throw new UnknownCodeError(`Expected texter bytes code, got ${this.code}`);
20
+ }
21
+ }
22
+ get text() {
23
+ return t(this.raw);
12
24
  }
13
- return {
14
- code: matter.code,
15
- qb64: matter.qb64,
16
- text: new TextDecoder().decode(matter.raw),
17
- fullSize: matter.fullSize,
18
- fullSizeB2: matter.fullSizeB2,
19
- };
25
+ }
26
+ /** Parse and hydrate `Texter` from txt/qb2 bytes. */
27
+ export function parseTexter(input, cold) {
28
+ return new Texter(parseMatter(input, cold));
20
29
  }
@@ -1,28 +1,31 @@
1
+ import { t } from "../core/bytes.js";
1
2
  import { UnknownCodeError } from "../core/errors.js";
2
- import { parseMatter } from "./matter.js";
3
- import { MATTER_CODE_NAMES } from "../tables/matter.tables.generated.js";
4
- function isNumericName(name) {
5
- return name === "Short" || name === "Long" || name === "Big" ||
6
- name === "Tall" ||
7
- name === "Large" || name === "Great" || name === "Vast";
8
- }
9
- function isWeightedName(name) {
10
- return name.startsWith("StrB64_") || name.startsWith("StrB64_Big_");
3
+ import { THOLDER_NUMERIC_CODES, THOLDER_WEIGHTED_CODES } from "./codex.js";
4
+ import { Matter, parseMatter } from "./matter.js";
5
+ /**
6
+ * Threshold expression primitive.
7
+ *
8
+ * KERIpy substance: `Tholder` supports both numeric thresholds and weighted
9
+ * threshold expressions encoded as StrB64 payloads.
10
+ */
11
+ export class Tholder extends Matter {
12
+ constructor(init) {
13
+ const matter = init instanceof Matter ? init : new Matter(init);
14
+ super(matter);
15
+ if (!THOLDER_NUMERIC_CODES.has(this.code)
16
+ && !THOLDER_WEIGHTED_CODES.has(this.code)) {
17
+ throw new UnknownCodeError(`Expected threshold code, got ${this.code}`);
18
+ }
19
+ }
20
+ get sith() {
21
+ if (THOLDER_NUMERIC_CODES.has(this.code)) {
22
+ return [...this.raw].reduce((acc, b) => (acc << 8n) | BigInt(b), 0n)
23
+ .toString(16);
24
+ }
25
+ return t(this.raw);
26
+ }
11
27
  }
28
+ /** Parse and hydrate `Tholder` from txt/qb2 bytes. */
12
29
  export function parseTholder(input, cold) {
13
- const matter = parseMatter(input, cold);
14
- const name = MATTER_CODE_NAMES[matter.code] ?? "";
15
- if (!isNumericName(name) && !isWeightedName(name)) {
16
- throw new UnknownCodeError(`Expected threshold code, got ${matter.code}`);
17
- }
18
- const sith = isNumericName(name)
19
- ? [...matter.raw].reduce((acc, b) => (acc << 8n) | BigInt(b), 0n).toString(16)
20
- : new TextDecoder().decode(matter.raw);
21
- return {
22
- code: matter.code,
23
- qb64: matter.qb64,
24
- sith,
25
- fullSize: matter.fullSize,
26
- fullSizeB2: matter.fullSizeB2,
27
- };
30
+ return new Tholder(parseMatter(input, cold));
28
31
  }
@@ -1,20 +1,27 @@
1
1
  import { UnknownCodeError } from "../core/errors.js";
2
- import { parseMatter } from "./matter.js";
3
- import { MATTER_CODE_NAMES } from "../tables/matter.tables.generated.js";
4
- function isTraitName(name) {
5
- return name.startsWith("Tag") || name === "No" || name === "Yes";
2
+ import { TRAIT_TAGS } from "./codex.js";
3
+ import { Matter, parseMatter } from "./matter.js";
4
+ import { Tagger } from "./tagger.js";
5
+ /**
6
+ * Configuration-trait primitive for key-event trait tags.
7
+ *
8
+ * KERIpy semantics: trait values are compact tags validated against canonical
9
+ * `TraitDex` membership rather than a local string list.
10
+ */
11
+ export class Traitor extends Tagger {
12
+ constructor(init) {
13
+ const matter = init instanceof Matter ? init : new Matter(init);
14
+ super(matter);
15
+ if (!TRAIT_TAGS.has(this.tag)) {
16
+ throw new UnknownCodeError(`Invalid trait tag for Traitor: ${this.tag}`);
17
+ }
18
+ }
19
+ /** Trait string token (alias of validated tag payload). */
20
+ get trait() {
21
+ return this.tag;
22
+ }
6
23
  }
24
+ /** Parse and hydrate `Traitor` from txt/qb2 bytes. */
7
25
  export function parseTraitor(input, cold) {
8
- const matter = parseMatter(input, cold);
9
- const name = MATTER_CODE_NAMES[matter.code] ?? "";
10
- if (!isTraitName(name)) {
11
- throw new UnknownCodeError(`Expected trait code, got ${matter.code}`);
12
- }
13
- return {
14
- code: matter.code,
15
- qb64: matter.qb64,
16
- trait: name,
17
- fullSize: matter.fullSize,
18
- fullSizeB2: matter.fullSizeB2,
19
- };
26
+ return new Traitor(parseMatter(input, cold));
20
27
  }
@@ -0,0 +1,89 @@
1
+ import { codeB64ToB2, encodeB64 } from "../core/bytes.js";
2
+ /**
3
+ * Lossless placeholder for unrecognized CESR units encountered during parse.
4
+ *
5
+ * In compat fallback paths we preserve unknown payload bytes as instances of
6
+ * this class so roundtrip serialization can remain byte-accurate.
7
+ */
8
+ export class UnknownPrimitive {
9
+ constructor(qb64, qb2, sourceDomain) {
10
+ Object.defineProperty(this, "code", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: void 0
15
+ });
16
+ Object.defineProperty(this, "qb64", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ Object.defineProperty(this, "qb2", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "fullSize", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ Object.defineProperty(this, "fullSizeB2", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
40
+ Object.defineProperty(this, "raw", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: void 0
45
+ });
46
+ Object.defineProperty(this, "sourceDomain", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: void 0
51
+ });
52
+ this.code = "?";
53
+ this.qb64 = qb64;
54
+ this.qb2 = qb2.slice();
55
+ this.fullSize = qb64.length;
56
+ this.fullSizeB2 = qb2.length;
57
+ this.raw = qb2.slice();
58
+ this.sourceDomain = sourceDomain;
59
+ }
60
+ /**
61
+ * Build an unknown primitive directly from parser payload bytes.
62
+ *
63
+ * When `domain="txt"` and content is not valid base64, `qb2` intentionally
64
+ * keeps the original bytes to remain lossless.
65
+ */
66
+ static fromPayload(payload, domain) {
67
+ if (domain === "bny") {
68
+ return new UnknownPrimitive(encodeB64(payload), payload, domain);
69
+ }
70
+ const qb64 = String.fromCharCode(...payload);
71
+ let qb2;
72
+ try {
73
+ qb2 = codeB64ToB2(qb64);
74
+ }
75
+ catch {
76
+ // Keep unknown text tokens lossless even when not valid base64 quads.
77
+ qb2 = payload.slice();
78
+ }
79
+ return new UnknownPrimitive(qb64, qb2, domain);
80
+ }
81
+ /** Equality by canonical text form used throughout primitive graph comparisons. */
82
+ equals(other) {
83
+ return this.qb64 === other.qb64;
84
+ }
85
+ /** String coercion returns canonical qb64 text token. */
86
+ toString() {
87
+ return this.qb64;
88
+ }
89
+ }
@@ -1,28 +1,28 @@
1
1
  import { UnknownCodeError } from "../core/errors.js";
2
- import { parseMatter } from "./matter.js";
3
- import { MATTER_CODE_NAMES } from "../tables/matter.tables.generated.js";
4
- const VERFER_CODE_NAMES = new Set([
5
- "Ed25519N",
6
- "Ed25519",
7
- "ECDSA_256k1N",
8
- "ECDSA_256k1",
9
- "ECDSA_256r1N",
10
- "ECDSA_256r1",
11
- "Ed448N",
12
- "Ed448",
13
- ]);
14
- export function parseVerfer(input, cold) {
15
- const matter = parseMatter(input, cold);
16
- const name = MATTER_CODE_NAMES[matter.code] ?? "";
17
- if (!VERFER_CODE_NAMES.has(name)) {
18
- throw new UnknownCodeError(`Expected verification key code, got ${matter.code}`);
2
+ import { matterCodexName, VERFER_CODES } from "./codex.js";
3
+ import { Matter, parseMatter } from "./matter.js";
4
+ /**
5
+ * Verification-key primitive.
6
+ *
7
+ * KERIpy substance: `Verfer` wraps public verification key material and
8
+ * constrains accepted derivation codes to verifier key families.
9
+ */
10
+ export class Verfer extends Matter {
11
+ constructor(init) {
12
+ const matter = init instanceof Matter ? init : new Matter(init);
13
+ super(matter);
14
+ if (!VERFER_CODES.has(this.code)) {
15
+ throw new UnknownCodeError(`Expected verification key code, got ${this.code}`);
16
+ }
17
+ }
18
+ get key() {
19
+ return this.raw;
20
+ }
21
+ get algorithm() {
22
+ return matterCodexName(this.code) ?? "UnknownKey";
19
23
  }
20
- return {
21
- code: matter.code,
22
- qb64: matter.qb64,
23
- key: matter.raw,
24
- algorithm: name,
25
- fullSize: matter.fullSize,
26
- fullSizeB2: matter.fullSizeB2,
27
- };
24
+ }
25
+ /** Parse and hydrate `Verfer` from txt/qb2 bytes. */
26
+ export function parseVerfer(input, cold) {
27
+ return new Verfer(parseMatter(input, cold));
28
28
  }
@@ -1,30 +1,61 @@
1
1
  import { b64ToInt } from "../core/bytes.js";
2
2
  import { DeserializeError, UnknownCodeError } from "../core/errors.js";
3
- import { parseMatter } from "./matter.js";
4
- const PROTOCOLS = new Set(["KERI", "ACDC"]);
5
- export function parseVerser(input, cold) {
6
- const matter = parseMatter(input, cold);
7
- if (matter.code !== "0O" && matter.code !== "1O") {
8
- throw new UnknownCodeError(`Expected verser code (0O/1O), got ${matter.code}`);
9
- }
10
- const body = matter.qb64.slice(matter.code.length);
11
- if (body.length < 6) {
12
- throw new DeserializeError(`Invalid verser body length=${body.length}`);
3
+ import { VERSER_CODES, VERSER_PROTOCOLS } from "./codex.js";
4
+ import { Matter, parseMatter } from "./matter.js";
5
+ import { Tagger } from "./tagger.js";
6
+ /** Decode 3-char CESR version token (`Mmm`) into major/minor version tuple. */
7
+ function parseVersion(text) {
8
+ if (text.length !== 3) {
9
+ throw new DeserializeError(`Invalid version text length=${text.length}`);
13
10
  }
14
- const proto = body.slice(0, 4);
15
- if (!PROTOCOLS.has(proto)) {
16
- throw new DeserializeError(`Unsupported verser proto=${proto}`);
11
+ const major = b64ToInt(text[0]);
12
+ if (major !== 1 && major !== 2) {
13
+ throw new DeserializeError(`Unsupported version major=${major}`);
17
14
  }
18
- const major = b64ToInt(body[4]) === 1 ? 1 : 2;
19
- const minor = b64ToInt(body[5]);
20
- const versage = { major, minor };
21
15
  return {
22
- code: matter.code,
23
- qb64: matter.qb64,
24
- fullSize: matter.fullSize,
25
- fullSizeB2: matter.fullSizeB2,
26
- proto,
27
- pvrsn: versage,
28
- gvrsn: versage,
16
+ major,
17
+ minor: b64ToInt(text.slice(1)),
29
18
  };
30
19
  }
20
+ /**
21
+ * Compact version primitive for protocol/genus version metadata.
22
+ *
23
+ * KERIpy semantics: payload tag is `proto + pvrsn (+ gvrsn optional)` where
24
+ * proto is `KERI|ACDC`, `pvrsn` is always present, and `gvrsn` is present only
25
+ * for 10-char tags.
26
+ */
27
+ export class Verser extends Tagger {
28
+ constructor(init) {
29
+ const tagger = init instanceof Matter ? init : new Matter(init);
30
+ super(tagger);
31
+ if (!VERSER_CODES.has(this.code)) {
32
+ throw new UnknownCodeError(`Expected verser code (Y/0O), got ${this.code}`);
33
+ }
34
+ const body = this.tag;
35
+ if (body.length !== 7 && body.length !== 10) {
36
+ throw new DeserializeError(`Invalid verser tag length=${body.length}`);
37
+ }
38
+ if (!VERSER_PROTOCOLS.has(body.slice(0, 4))) {
39
+ throw new DeserializeError(`Unsupported verser proto=${body.slice(0, 4)}`);
40
+ }
41
+ parseVersion(body.slice(4, 7));
42
+ if (body.length === 10)
43
+ parseVersion(body.slice(7, 10));
44
+ }
45
+ /** Protocol namespace extracted from verser tag payload. */
46
+ get proto() {
47
+ return this.tag.slice(0, 4);
48
+ }
49
+ /** Protocol-version tuple (`major`, `minor`) decoded from tag payload. */
50
+ get pvrsn() {
51
+ return parseVersion(this.tag.slice(4, 7));
52
+ }
53
+ /** Optional genus-version tuple decoded when 10-char verser payload is present. */
54
+ get gvrsn() {
55
+ return this.tag.length === 10 ? parseVersion(this.tag.slice(7, 10)) : null;
56
+ }
57
+ }
58
+ /** Parse and hydrate `Verser` from txt/qb2 bytes. */
59
+ export function parseVerser(input, cold) {
60
+ return new Verser(parseMatter(input, cold));
61
+ }
@@ -1,6 +1,13 @@
1
- import { DeserializeError } from "../core/errors.js";
2
1
  import { decode as decodeMsgpack } from "@msgpack/msgpack";
3
- import { decode as decodeCbor } from "cbor-x/decode";
2
+ import { t } from "../core/bytes.js";
3
+ import { decodeKeriCbor } from "../core/cbor.js";
4
+ import { DeserializeError } from "../core/errors.js";
5
+ import { Aggor, isAggorCode } from "../primitives/aggor.js";
6
+ import { Blinder, isBlinderCode } from "../primitives/blinder.js";
7
+ import { isMediarCode, Mediar } from "../primitives/mediar.js";
8
+ import { isCounterGroupLike, isPrimitiveTuple, } from "../primitives/primitive.js";
9
+ import { isSealerCode, Sealer } from "../primitives/sealer.js";
10
+ import { Protocols } from "../tables/versions.js";
4
11
  function normalizeDecodedMap(value, kind) {
5
12
  if (value && typeof value === "object" && !Array.isArray(value)) {
6
13
  if (value instanceof Map) {
@@ -17,9 +24,171 @@ function normalizeDecodedMap(value, kind) {
17
24
  }
18
25
  throw new DeserializeError(`${kind} root must be a map/object`);
19
26
  }
20
- // TODO should this be called parseBody?
21
- // If we're going to say parseSerder then it should doo a full deserialization
22
- // and the CesrBody should be a Serder with subclasses for SerderKERI and SerderACDC
27
+ function collectNestedGroups(entries, out) {
28
+ for (const entry of entries) {
29
+ if (isPrimitiveTuple(entry)) {
30
+ collectNestedGroups(entry, out);
31
+ continue;
32
+ }
33
+ if (isCounterGroupLike(entry)) {
34
+ out.push(entry);
35
+ collectNestedGroups(entry.items, out);
36
+ }
37
+ }
38
+ }
39
+ /** Extract all top-level + nested counted groups from one parsed message. */
40
+ function collectMessageGroups(message) {
41
+ const groups = [];
42
+ for (const attachment of message.attachments) {
43
+ groups.push(attachment);
44
+ collectNestedGroups(attachment.items, groups);
45
+ }
46
+ return groups;
47
+ }
48
+ /**
49
+ * Base Serder body class.
50
+ *
51
+ * KERIpy substance: Serders carry raw serialized event bytes plus decoded KED
52
+ * projections (`ilk`/`said`) and protocol/version metadata.
53
+ */
54
+ export class Serder {
55
+ constructor(init) {
56
+ Object.defineProperty(this, "raw", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: void 0
61
+ });
62
+ Object.defineProperty(this, "ked", {
63
+ enumerable: true,
64
+ configurable: true,
65
+ writable: true,
66
+ value: void 0
67
+ });
68
+ Object.defineProperty(this, "kind", {
69
+ enumerable: true,
70
+ configurable: true,
71
+ writable: true,
72
+ value: void 0
73
+ });
74
+ Object.defineProperty(this, "size", {
75
+ enumerable: true,
76
+ configurable: true,
77
+ writable: true,
78
+ value: void 0
79
+ });
80
+ Object.defineProperty(this, "proto", {
81
+ enumerable: true,
82
+ configurable: true,
83
+ writable: true,
84
+ value: void 0
85
+ });
86
+ Object.defineProperty(this, "pvrsn", {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value: void 0
91
+ });
92
+ Object.defineProperty(this, "gvrsn", {
93
+ enumerable: true,
94
+ configurable: true,
95
+ writable: true,
96
+ value: void 0
97
+ });
98
+ Object.defineProperty(this, "ilk", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: void 0
103
+ });
104
+ Object.defineProperty(this, "said", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: void 0
109
+ });
110
+ Object.defineProperty(this, "native", {
111
+ enumerable: true,
112
+ configurable: true,
113
+ writable: true,
114
+ value: void 0
115
+ });
116
+ this.raw = init.raw;
117
+ this.ked = init.ked;
118
+ this.kind = init.smellage.kind;
119
+ this.size = init.smellage.size;
120
+ this.proto = init.smellage.proto;
121
+ this.pvrsn = init.smellage.pvrsn;
122
+ this.gvrsn = init.smellage.gvrsn;
123
+ this.ilk = init.ilk;
124
+ this.said = init.said;
125
+ }
126
+ /** True when this body belongs to KERI protocol domain. */
127
+ get isKeri() {
128
+ return this.proto === Protocols.keri;
129
+ }
130
+ /** True when this body belongs to ACDC protocol domain. */
131
+ get isAcdc() {
132
+ return this.proto === Protocols.acdc;
133
+ }
134
+ /**
135
+ * Project counted attachment groups into structor subclasses.
136
+ *
137
+ * This keeps Serder + attachment processing cohesive for consumers that
138
+ * immediately need typed structor families after frame parsing.
139
+ */
140
+ projectStructors(message) {
141
+ const groups = collectMessageGroups(message);
142
+ const projection = {
143
+ aggor: [],
144
+ sealer: [],
145
+ blinder: [],
146
+ mediar: [],
147
+ other: [],
148
+ };
149
+ for (const group of groups) {
150
+ if (isSealerCode(group.code)) {
151
+ projection.sealer.push(Sealer.fromGroup(group));
152
+ continue;
153
+ }
154
+ if (isBlinderCode(group.code)) {
155
+ projection.blinder.push(Blinder.fromGroup(group));
156
+ continue;
157
+ }
158
+ if (isMediarCode(group.code)) {
159
+ projection.mediar.push(Mediar.fromGroup(group));
160
+ continue;
161
+ }
162
+ if (isAggorCode(group.code)) {
163
+ projection.aggor.push(Aggor.fromGroup(group));
164
+ continue;
165
+ }
166
+ projection.other.push(group);
167
+ }
168
+ return projection;
169
+ }
170
+ }
171
+ /** KERI-protocol Serder subtype (`proto=KERI`). */
172
+ export class SerderKERI extends Serder {
173
+ constructor(init) {
174
+ super(init);
175
+ if (!this.isKeri) {
176
+ throw new DeserializeError(`Expected KERI protocol serder, got ${this.proto}`);
177
+ }
178
+ }
179
+ }
180
+ /** ACDC-protocol Serder subtype (`proto=ACDC`). */
181
+ export class SerderACDC extends Serder {
182
+ constructor(init) {
183
+ super(init);
184
+ if (!this.isAcdc) {
185
+ throw new DeserializeError(`Expected ACDC protocol serder, got ${this.proto}`);
186
+ }
187
+ }
188
+ }
189
+ /**
190
+ * Parse one raw Serder body and hydrate protocol-specific Serder subclasses.
191
+ */
23
192
  export function parseSerder(raw, smellage) {
24
193
  const { proto, kind, pvrsn, gvrsn, size } = smellage;
25
194
  let ked = null;
@@ -27,14 +196,14 @@ export function parseSerder(raw, smellage) {
27
196
  let said = null;
28
197
  try {
29
198
  if (kind === "JSON") {
30
- const text = new TextDecoder().decode(raw);
199
+ const text = t(raw);
31
200
  ked = JSON.parse(text);
32
201
  }
33
202
  else if (kind === "MGPK") {
34
203
  ked = normalizeDecodedMap(decodeMsgpack(raw), kind);
35
204
  }
36
205
  else if (kind === "CBOR") {
37
- ked = normalizeDecodedMap(decodeCbor(raw), kind);
206
+ ked = normalizeDecodedMap(decodeKeriCbor(raw), kind);
38
207
  }
39
208
  if (ked) {
40
209
  ilk = typeof ked.t === "string" ? ked.t : null;
@@ -53,7 +222,18 @@ export function parseSerder(raw, smellage) {
53
222
  }
54
223
  throw error;
55
224
  }
56
- // TODO support SerderKERI and SerderACDC.
57
- // Is that done at this level or the next level up?
58
- return { raw, ked, proto, kind, size, pvrsn, gvrsn, ilk, said };
225
+ const init = {
226
+ raw,
227
+ smellage: { proto, kind, pvrsn, gvrsn, size },
228
+ ked,
229
+ ilk,
230
+ said,
231
+ };
232
+ if (proto === Protocols.keri) {
233
+ return new SerderKERI(init);
234
+ }
235
+ if (proto === Protocols.acdc) {
236
+ return new SerderACDC(init);
237
+ }
238
+ return new Serder(init);
59
239
  }
@@ -1,6 +1,6 @@
1
- import { smell } from "./smell.js";
2
- import { parseSerder } from "./serder.js";
3
1
  import { ShortageError } from "../core/errors.js";
2
+ import { parseSerder } from "./serder.js";
3
+ import { smell } from "./smell.js";
4
4
  export function reapSerder(input) {
5
5
  const { smellage } = smell(input);
6
6
  if (input.length < smellage.size) {
@@ -0,0 +1,9 @@
1
+ export function codexValues(codex) {
2
+ return new Set(Object.values(codex));
3
+ }
4
+ export function invertCodex(codex) {
5
+ return new Map(Object.entries(codex).map(([name, code]) => [
6
+ code,
7
+ name,
8
+ ]));
9
+ }
@@ -1,4 +1,4 @@
1
- import { COUNTER_CODE_NAMES_V1, COUNTER_CODE_NAMES_V2, } from "./counter.tables.generated.js";
1
+ import { COUNTER_CODE_NAMES_V1, COUNTER_CODE_NAMES_V2 } from "./counter.tables.generated.js";
2
2
  function invertCodeNames(map) {
3
3
  const out = {};
4
4
  for (const [code, name] of Object.entries(map)) {