@bcts/provenance-mark 1.0.0-alpha.8 → 1.0.0-beta.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/dist/index.cjs CHANGED
@@ -1,63 +1,82 @@
1
- let __bcts_dcbor = require("@bcts/dcbor");
2
- let __noble_hashes_sha256 = require("@noble/hashes/sha256");
3
- let __noble_hashes_hkdf = require("@noble/hashes/hkdf");
4
- let __noble_ciphers_chacha = require("@noble/ciphers/chacha");
5
- let __bcts_rand = require("@bcts/rand");
6
- let __bcts_tags = require("@bcts/tags");
7
- let __bcts_uniform_resources = require("@bcts/uniform-resources");
8
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _bcts_dcbor = require("@bcts/dcbor");
3
+ let _bcts_rand = require("@bcts/rand");
4
+ let _noble_hashes_sha2_js = require("@noble/hashes/sha2.js");
5
+ let _noble_hashes_hkdf_js = require("@noble/hashes/hkdf.js");
6
+ let _noble_ciphers_chacha_js = require("@noble/ciphers/chacha.js");
7
+ let _bcts_tags = require("@bcts/tags");
8
+ let _bcts_uniform_resources = require("@bcts/uniform-resources");
9
+ let _bcts_envelope = require("@bcts/envelope");
9
10
  //#region src/error.ts
10
11
  /**
12
+ * Copyright © 2023-2026 Blockchain Commons, LLC
13
+ * Copyright © 2025-2026 Parity Technologies
14
+ *
15
+ */
16
+ /**
11
17
  * Error types for Provenance Mark operations.
12
18
  */
13
- let ProvenanceMarkErrorType = /* @__PURE__ */ function(ProvenanceMarkErrorType$1) {
19
+ let ProvenanceMarkErrorType = /* @__PURE__ */ function(ProvenanceMarkErrorType) {
14
20
  /** Invalid Seed length */
15
- ProvenanceMarkErrorType$1["InvalidSeedLength"] = "InvalidSeedLength";
21
+ ProvenanceMarkErrorType["InvalidSeedLength"] = "InvalidSeedLength";
16
22
  /** Duplicate key */
17
- ProvenanceMarkErrorType$1["DuplicateKey"] = "DuplicateKey";
23
+ ProvenanceMarkErrorType["DuplicateKey"] = "DuplicateKey";
18
24
  /** Missing key */
19
- ProvenanceMarkErrorType$1["MissingKey"] = "MissingKey";
25
+ ProvenanceMarkErrorType["MissingKey"] = "MissingKey";
20
26
  /** Invalid key */
21
- ProvenanceMarkErrorType$1["InvalidKey"] = "InvalidKey";
27
+ ProvenanceMarkErrorType["InvalidKey"] = "InvalidKey";
22
28
  /** Extra keys */
23
- ProvenanceMarkErrorType$1["ExtraKeys"] = "ExtraKeys";
29
+ ProvenanceMarkErrorType["ExtraKeys"] = "ExtraKeys";
24
30
  /** Invalid key length for the given resolution */
25
- ProvenanceMarkErrorType$1["InvalidKeyLength"] = "InvalidKeyLength";
31
+ ProvenanceMarkErrorType["InvalidKeyLength"] = "InvalidKeyLength";
26
32
  /** Invalid next key length for the given resolution */
27
- ProvenanceMarkErrorType$1["InvalidNextKeyLength"] = "InvalidNextKeyLength";
33
+ ProvenanceMarkErrorType["InvalidNextKeyLength"] = "InvalidNextKeyLength";
28
34
  /** Invalid chain ID length for the given resolution */
29
- ProvenanceMarkErrorType$1["InvalidChainIdLength"] = "InvalidChainIdLength";
35
+ ProvenanceMarkErrorType["InvalidChainIdLength"] = "InvalidChainIdLength";
30
36
  /** Invalid message length for the given resolution */
31
- ProvenanceMarkErrorType$1["InvalidMessageLength"] = "InvalidMessageLength";
37
+ ProvenanceMarkErrorType["InvalidMessageLength"] = "InvalidMessageLength";
32
38
  /** Invalid CBOR data in info field */
33
- ProvenanceMarkErrorType$1["InvalidInfoCbor"] = "InvalidInfoCbor";
39
+ ProvenanceMarkErrorType["InvalidInfoCbor"] = "InvalidInfoCbor";
34
40
  /** Date out of range for serialization */
35
- ProvenanceMarkErrorType$1["DateOutOfRange"] = "DateOutOfRange";
41
+ ProvenanceMarkErrorType["DateOutOfRange"] = "DateOutOfRange";
36
42
  /** Invalid date components */
37
- ProvenanceMarkErrorType$1["InvalidDate"] = "InvalidDate";
43
+ ProvenanceMarkErrorType["InvalidDate"] = "InvalidDate";
38
44
  /** Missing required URL parameter */
39
- ProvenanceMarkErrorType$1["MissingUrlParameter"] = "MissingUrlParameter";
45
+ ProvenanceMarkErrorType["MissingUrlParameter"] = "MissingUrlParameter";
40
46
  /** Year out of range for 2-byte serialization */
41
- ProvenanceMarkErrorType$1["YearOutOfRange"] = "YearOutOfRange";
47
+ ProvenanceMarkErrorType["YearOutOfRange"] = "YearOutOfRange";
42
48
  /** Invalid month or day */
43
- ProvenanceMarkErrorType$1["InvalidMonthOrDay"] = "InvalidMonthOrDay";
49
+ ProvenanceMarkErrorType["InvalidMonthOrDay"] = "InvalidMonthOrDay";
44
50
  /** Resolution serialization error */
45
- ProvenanceMarkErrorType$1["ResolutionError"] = "ResolutionError";
51
+ ProvenanceMarkErrorType["ResolutionError"] = "ResolutionError";
46
52
  /** Bytewords encoding/decoding error */
47
- ProvenanceMarkErrorType$1["BytewordsError"] = "BytewordsError";
53
+ ProvenanceMarkErrorType["BytewordsError"] = "BytewordsError";
48
54
  /** CBOR encoding/decoding error */
49
- ProvenanceMarkErrorType$1["CborError"] = "CborError";
55
+ ProvenanceMarkErrorType["CborError"] = "CborError";
50
56
  /** URL parsing error */
51
- ProvenanceMarkErrorType$1["UrlError"] = "UrlError";
57
+ ProvenanceMarkErrorType["UrlError"] = "UrlError";
52
58
  /** Base64 decoding error */
53
- ProvenanceMarkErrorType$1["Base64Error"] = "Base64Error";
59
+ ProvenanceMarkErrorType["Base64Error"] = "Base64Error";
54
60
  /** JSON serialization error */
55
- ProvenanceMarkErrorType$1["JsonError"] = "JsonError";
61
+ ProvenanceMarkErrorType["JsonError"] = "JsonError";
56
62
  /** Integer conversion error */
57
- ProvenanceMarkErrorType$1["IntegerConversionError"] = "IntegerConversionError";
63
+ ProvenanceMarkErrorType["IntegerConversionError"] = "IntegerConversionError";
58
64
  /** Validation error */
59
- ProvenanceMarkErrorType$1["ValidationError"] = "ValidationError";
60
- return ProvenanceMarkErrorType$1;
65
+ ProvenanceMarkErrorType["ValidationError"] = "ValidationError";
66
+ /**
67
+ * Envelope serialization/deserialization error.
68
+ *
69
+ * Mirrors Rust `Error::Envelope(...)`
70
+ * (`provenance-mark-rust/src/error.rs`). The Rust enum surfaces
71
+ * envelope-format failures as their own variant; in earlier
72
+ * revisions of this port they collapsed into `CborError`. Both
73
+ * shapes are still emitted in practice (CBOR errors during envelope
74
+ * round-trip stay as `CborError`); this variant exists for the
75
+ * structural-level mismatches the Rust port tags as
76
+ * `Error::Envelope`.
77
+ */
78
+ ProvenanceMarkErrorType["EnvelopeError"] = "EnvelopeError";
79
+ return ProvenanceMarkErrorType;
61
80
  }({});
62
81
  /**
63
82
  * Error class for Provenance Mark operations.
@@ -80,37 +99,42 @@ var ProvenanceMarkError = class ProvenanceMarkError extends Error {
80
99
  return JSON.stringify(value);
81
100
  };
82
101
  switch (type) {
83
- case ProvenanceMarkErrorType.InvalidSeedLength: return `invalid seed length: expected 32 bytes, got ${d("actual")} bytes`;
84
- case ProvenanceMarkErrorType.DuplicateKey: return `duplicate key: ${d("key")}`;
85
- case ProvenanceMarkErrorType.MissingKey: return `missing key: ${d("key")}`;
86
- case ProvenanceMarkErrorType.InvalidKey: return `invalid key: ${d("key")}`;
87
- case ProvenanceMarkErrorType.ExtraKeys: return `wrong number of keys: expected ${d("expected")}, got ${d("actual")}`;
88
- case ProvenanceMarkErrorType.InvalidKeyLength: return `invalid key length: expected ${d("expected")}, got ${d("actual")}`;
89
- case ProvenanceMarkErrorType.InvalidNextKeyLength: return `invalid next key length: expected ${d("expected")}, got ${d("actual")}`;
90
- case ProvenanceMarkErrorType.InvalidChainIdLength: return `invalid chain ID length: expected ${d("expected")}, got ${d("actual")}`;
91
- case ProvenanceMarkErrorType.InvalidMessageLength: return `invalid message length: expected at least ${d("expected")}, got ${d("actual")}`;
92
- case ProvenanceMarkErrorType.InvalidInfoCbor: return "invalid CBOR data in info field";
93
- case ProvenanceMarkErrorType.DateOutOfRange: return `date out of range: ${d("details")}`;
94
- case ProvenanceMarkErrorType.InvalidDate: return `invalid date: ${d("details")}`;
95
- case ProvenanceMarkErrorType.MissingUrlParameter: return `missing required URL parameter: ${d("parameter")}`;
96
- case ProvenanceMarkErrorType.YearOutOfRange: return `year out of range for 2-byte serialization: must be between 2023-2150, got ${d("year")}`;
97
- case ProvenanceMarkErrorType.InvalidMonthOrDay: return `invalid month (${d("month")}) or day (${d("day")}) for year ${d("year")}`;
98
- case ProvenanceMarkErrorType.ResolutionError: return `resolution serialization error: ${d("details")}`;
99
- case ProvenanceMarkErrorType.BytewordsError: return `bytewords error: ${d("message")}`;
100
- case ProvenanceMarkErrorType.CborError: return `CBOR error: ${d("message")}`;
101
- case ProvenanceMarkErrorType.UrlError: return `URL parsing error: ${d("message")}`;
102
- case ProvenanceMarkErrorType.Base64Error: return `base64 decoding error: ${d("message")}`;
103
- case ProvenanceMarkErrorType.JsonError: return `JSON error: ${d("message")}`;
104
- case ProvenanceMarkErrorType.IntegerConversionError: return `integer conversion error: ${d("message")}`;
105
- case ProvenanceMarkErrorType.ValidationError: return `validation error: ${d("message")}`;
102
+ case "InvalidSeedLength": return `invalid seed length: expected 32 bytes, got ${d("actual")} bytes`;
103
+ case "DuplicateKey": return `duplicate key: ${d("key")}`;
104
+ case "MissingKey": return `missing key: ${d("key")}`;
105
+ case "InvalidKey": return `invalid key: ${d("key")}`;
106
+ case "ExtraKeys": return `wrong number of keys: expected ${d("expected")}, got ${d("actual")}`;
107
+ case "InvalidKeyLength": return `invalid key length: expected ${d("expected")}, got ${d("actual")}`;
108
+ case "InvalidNextKeyLength": return `invalid next key length: expected ${d("expected")}, got ${d("actual")}`;
109
+ case "InvalidChainIdLength": return `invalid chain ID length: expected ${d("expected")}, got ${d("actual")}`;
110
+ case "InvalidMessageLength": return `invalid message length: expected at least ${d("expected")}, got ${d("actual")}`;
111
+ case "InvalidInfoCbor": return "invalid CBOR data in info field";
112
+ case "DateOutOfRange": return `date out of range: ${d("details")}`;
113
+ case "InvalidDate": return `invalid date: ${d("details")}`;
114
+ case "MissingUrlParameter": return `missing required URL parameter: ${d("parameter")}`;
115
+ case "YearOutOfRange": return `year out of range for 2-byte serialization: must be between 2023-2150, got ${d("year")}`;
116
+ case "InvalidMonthOrDay": return `invalid month (${d("month")}) or day (${d("day")}) for year ${d("year")}`;
117
+ case "ResolutionError": return `resolution serialization error: ${d("details")}`;
118
+ case "BytewordsError": return `bytewords error: ${d("message")}`;
119
+ case "CborError": return `CBOR error: ${d("message")}`;
120
+ case "UrlError": return `URL parsing error: ${d("message")}`;
121
+ case "Base64Error": return `base64 decoding error: ${d("message")}`;
122
+ case "JsonError": return `JSON error: ${d("message")}`;
123
+ case "IntegerConversionError": return `integer conversion error: ${d("message")}`;
124
+ case "ValidationError": return `validation error: ${d("message")}`;
125
+ case "EnvelopeError": return `envelope error: ${d("message")}`;
106
126
  default: return type;
107
127
  }
108
128
  }
109
129
  };
110
-
111
130
  //#endregion
112
131
  //#region src/date.ts
113
132
  /**
133
+ * Copyright © 2023-2026 Blockchain Commons, LLC
134
+ * Copyright © 2025-2026 Parity Technologies
135
+ *
136
+ */
137
+ /**
114
138
  * Reference date for 4-byte and 6-byte serialization (2001-01-01T00:00:00Z).
115
139
  */
116
140
  const REFERENCE_DATE = Date.UTC(2001, 0, 1, 0, 0, 0, 0);
@@ -141,8 +165,8 @@ function serialize2Bytes(date) {
141
165
  const month = date.getUTCMonth() + 1;
142
166
  const day = date.getUTCDate();
143
167
  const yy = year - 2023;
144
- if (yy < 0 || yy >= 128) throw new ProvenanceMarkError(ProvenanceMarkErrorType.YearOutOfRange, void 0, { year });
145
- if (month < 1 || month > 12 || day < 1 || day > 31) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidMonthOrDay, void 0, {
168
+ if (yy < 0 || yy >= 128) throw new ProvenanceMarkError("YearOutOfRange", void 0, { year });
169
+ if (month < 1 || month > 12 || day < 1 || day > 31) throw new ProvenanceMarkError("InvalidMonthOrDay", void 0, {
146
170
  year,
147
171
  month,
148
172
  day
@@ -157,12 +181,12 @@ function serialize2Bytes(date) {
157
181
  * Deserialize 2 bytes to a date.
158
182
  */
159
183
  function deserialize2Bytes(bytes) {
160
- if (bytes.length !== 2) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidDate, void 0, { details: `expected 2 bytes, got ${bytes.length}` });
184
+ if (bytes.length !== 2) throw new ProvenanceMarkError("InvalidDate", void 0, { details: `expected 2 bytes, got ${bytes.length}` });
161
185
  const value = bytes[0] << 8 | bytes[1];
162
186
  const day = value & 31;
163
187
  const month = value >> 5 & 15;
164
188
  const year = (value >> 9 & 127) + 2023;
165
- if (month < 1 || month > 12 || !isValidDay(year, month, day)) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidMonthOrDay, void 0, {
189
+ if (month < 1 || month > 12 || !isValidDay(year, month, day)) throw new ProvenanceMarkError("InvalidMonthOrDay", void 0, {
166
190
  year,
167
191
  month,
168
192
  day
@@ -175,7 +199,7 @@ function deserialize2Bytes(bytes) {
175
199
  function serialize4Bytes(date) {
176
200
  const duration = date.getTime() - REFERENCE_DATE;
177
201
  const seconds = Math.floor(duration / 1e3);
178
- if (seconds < 0 || seconds > 4294967295) throw new ProvenanceMarkError(ProvenanceMarkErrorType.DateOutOfRange, void 0, { details: "seconds value out of range for u32" });
202
+ if (seconds < 0 || seconds > 4294967295) throw new ProvenanceMarkError("DateOutOfRange", void 0, { details: "seconds value out of range for u32" });
179
203
  const buf = new Uint8Array(4);
180
204
  buf[0] = seconds >> 24 & 255;
181
205
  buf[1] = seconds >> 16 & 255;
@@ -187,7 +211,7 @@ function serialize4Bytes(date) {
187
211
  * Deserialize 4 bytes to a date.
188
212
  */
189
213
  function deserialize4Bytes(bytes) {
190
- if (bytes.length !== 4) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidDate, void 0, { details: `expected 4 bytes, got ${bytes.length}` });
214
+ if (bytes.length !== 4) throw new ProvenanceMarkError("InvalidDate", void 0, { details: `expected 4 bytes, got ${bytes.length}` });
191
215
  const seconds = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) >>> 0;
192
216
  return new Date(REFERENCE_DATE + seconds * 1e3);
193
217
  }
@@ -197,7 +221,7 @@ function deserialize4Bytes(bytes) {
197
221
  function serialize6Bytes(date) {
198
222
  const duration = date.getTime() - REFERENCE_DATE;
199
223
  const milliseconds = BigInt(duration);
200
- if (milliseconds < 0n || milliseconds > BigInt(MAX_6_BYTE_VALUE)) throw new ProvenanceMarkError(ProvenanceMarkErrorType.DateOutOfRange, void 0, { details: "date exceeds maximum representable value" });
224
+ if (milliseconds < 0n || milliseconds > BigInt(MAX_6_BYTE_VALUE)) throw new ProvenanceMarkError("DateOutOfRange", void 0, { details: "date exceeds maximum representable value" });
201
225
  const buf = new Uint8Array(6);
202
226
  buf[0] = Number(milliseconds >> 40n & 255n);
203
227
  buf[1] = Number(milliseconds >> 32n & 255n);
@@ -211,9 +235,9 @@ function serialize6Bytes(date) {
211
235
  * Deserialize 6 bytes to a date.
212
236
  */
213
237
  function deserialize6Bytes(bytes) {
214
- if (bytes.length !== 6) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidDate, void 0, { details: `expected 6 bytes, got ${bytes.length}` });
238
+ if (bytes.length !== 6) throw new ProvenanceMarkError("InvalidDate", void 0, { details: `expected 6 bytes, got ${bytes.length}` });
215
239
  const milliseconds = BigInt(bytes[0]) << 40n | BigInt(bytes[1]) << 32n | BigInt(bytes[2]) << 24n | BigInt(bytes[3]) << 16n | BigInt(bytes[4]) << 8n | BigInt(bytes[5]);
216
- if (milliseconds > BigInt(MAX_6_BYTE_VALUE)) throw new ProvenanceMarkError(ProvenanceMarkErrorType.DateOutOfRange, void 0, { details: "date exceeds maximum representable value" });
240
+ if (milliseconds > BigInt(MAX_6_BYTE_VALUE)) throw new ProvenanceMarkError("DateOutOfRange", void 0, { details: "date exceeds maximum representable value" });
217
241
  return new Date(REFERENCE_DATE + Number(milliseconds));
218
242
  }
219
243
  /**
@@ -236,7 +260,7 @@ function dateToIso8601(date) {
236
260
  */
237
261
  function dateFromIso8601(str) {
238
262
  const date = new Date(str);
239
- if (isNaN(date.getTime())) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidDate, void 0, { details: `cannot parse date: ${str}` });
263
+ if (isNaN(date.getTime())) throw new ProvenanceMarkError("InvalidDate", void 0, { details: `cannot parse date: ${str}` });
240
264
  return date;
241
265
  }
242
266
  /**
@@ -245,19 +269,50 @@ function dateFromIso8601(str) {
245
269
  function dateToDateString(date) {
246
270
  return `${date.getUTCFullYear()}-${(date.getUTCMonth() + 1).toString().padStart(2, "0")}-${date.getUTCDate().toString().padStart(2, "0")}`;
247
271
  }
248
-
272
+ /**
273
+ * Renders a `Date` the way Rust's `dcbor::Date::Display` does
274
+ * (`bc-dcbor-rust/src/date.rs:485-492`):
275
+ *
276
+ * - When the UTC time is exactly `00:00:00` (subsecond precision is
277
+ * ignored — Rust's check is `hour == 0 && minute == 0 && second == 0`,
278
+ * matching `chrono::SecondsFormat::Secs`), emit just `YYYY-MM-DD`.
279
+ * - Otherwise emit RFC 3339 with second precision (no fractional
280
+ * seconds), e.g. `2023-02-08T15:30:45Z`.
281
+ *
282
+ * This is the canonical "Rust string" for dates across the
283
+ * provenance-mark public surface — `mark.toDebugString`,
284
+ * `mark.precedesOpt` `DateOrdering` issue, `markdownSummary`, and the
285
+ * validation report's `DateOrdering` payload all use it. Centralising
286
+ * here keeps every call site in lockstep with the Rust output.
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * dateToDisplay(new Date("2023-06-20T00:00:00Z")); // "2023-06-20"
291
+ * dateToDisplay(new Date("2023-06-20T15:30:45Z")); // "2023-06-20T15:30:45Z"
292
+ * dateToDisplay(new Date("2023-06-20T15:30:45.123Z")); // "2023-06-20T15:30:45Z"
293
+ * ```
294
+ */
295
+ function dateToDisplay(date) {
296
+ if (!(date.getUTCHours() !== 0 || date.getUTCMinutes() !== 0 || date.getUTCSeconds() !== 0)) return dateToDateString(date);
297
+ return date.toISOString().replace(/\.\d{3}Z$/, "Z");
298
+ }
249
299
  //#endregion
250
300
  //#region src/resolution.ts
251
301
  /**
302
+ * Copyright © 2023-2026 Blockchain Commons, LLC
303
+ * Copyright © 2025-2026 Parity Technologies
304
+ *
305
+ */
306
+ /**
252
307
  * Resolution levels for provenance marks.
253
308
  * Higher resolution provides more security but larger mark sizes.
254
309
  */
255
- let ProvenanceMarkResolution = /* @__PURE__ */ function(ProvenanceMarkResolution$1) {
256
- ProvenanceMarkResolution$1[ProvenanceMarkResolution$1["Low"] = 0] = "Low";
257
- ProvenanceMarkResolution$1[ProvenanceMarkResolution$1["Medium"] = 1] = "Medium";
258
- ProvenanceMarkResolution$1[ProvenanceMarkResolution$1["Quartile"] = 2] = "Quartile";
259
- ProvenanceMarkResolution$1[ProvenanceMarkResolution$1["High"] = 3] = "High";
260
- return ProvenanceMarkResolution$1;
310
+ let ProvenanceMarkResolution = /* @__PURE__ */ function(ProvenanceMarkResolution) {
311
+ ProvenanceMarkResolution[ProvenanceMarkResolution["Low"] = 0] = "Low";
312
+ ProvenanceMarkResolution[ProvenanceMarkResolution["Medium"] = 1] = "Medium";
313
+ ProvenanceMarkResolution[ProvenanceMarkResolution["Quartile"] = 2] = "Quartile";
314
+ ProvenanceMarkResolution[ProvenanceMarkResolution["High"] = 3] = "High";
315
+ return ProvenanceMarkResolution;
261
316
  }({});
262
317
  /**
263
318
  * Convert a resolution to its numeric value.
@@ -270,11 +325,11 @@ function resolutionToNumber(res) {
270
325
  */
271
326
  function resolutionFromNumber(value) {
272
327
  switch (value) {
273
- case 0: return ProvenanceMarkResolution.Low;
274
- case 1: return ProvenanceMarkResolution.Medium;
275
- case 2: return ProvenanceMarkResolution.Quartile;
276
- case 3: return ProvenanceMarkResolution.High;
277
- default: throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid provenance mark resolution value: ${value}` });
328
+ case 0: return 0;
329
+ case 1: return 1;
330
+ case 2: return 2;
331
+ case 3: return 3;
332
+ default: throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid provenance mark resolution value: ${value}` });
278
333
  }
279
334
  }
280
335
  /**
@@ -282,10 +337,10 @@ function resolutionFromNumber(value) {
282
337
  */
283
338
  function linkLength(res) {
284
339
  switch (res) {
285
- case ProvenanceMarkResolution.Low: return 4;
286
- case ProvenanceMarkResolution.Medium: return 8;
287
- case ProvenanceMarkResolution.Quartile: return 16;
288
- case ProvenanceMarkResolution.High: return 32;
340
+ case 0: return 4;
341
+ case 1: return 8;
342
+ case 2: return 16;
343
+ case 3: return 32;
289
344
  }
290
345
  }
291
346
  /**
@@ -293,10 +348,10 @@ function linkLength(res) {
293
348
  */
294
349
  function seqBytesLength(res) {
295
350
  switch (res) {
296
- case ProvenanceMarkResolution.Low: return 2;
297
- case ProvenanceMarkResolution.Medium:
298
- case ProvenanceMarkResolution.Quartile:
299
- case ProvenanceMarkResolution.High: return 4;
351
+ case 0: return 2;
352
+ case 1:
353
+ case 2:
354
+ case 3: return 4;
300
355
  }
301
356
  }
302
357
  /**
@@ -304,10 +359,10 @@ function seqBytesLength(res) {
304
359
  */
305
360
  function dateBytesLength(res) {
306
361
  switch (res) {
307
- case ProvenanceMarkResolution.Low: return 2;
308
- case ProvenanceMarkResolution.Medium: return 4;
309
- case ProvenanceMarkResolution.Quartile:
310
- case ProvenanceMarkResolution.High: return 6;
362
+ case 0: return 2;
363
+ case 1: return 4;
364
+ case 2:
365
+ case 3: return 6;
311
366
  }
312
367
  }
313
368
  /**
@@ -375,10 +430,10 @@ function infoRangeStart(res) {
375
430
  */
376
431
  function serializeDate(res, date) {
377
432
  switch (res) {
378
- case ProvenanceMarkResolution.Low: return serialize2Bytes(date);
379
- case ProvenanceMarkResolution.Medium: return serialize4Bytes(date);
380
- case ProvenanceMarkResolution.Quartile:
381
- case ProvenanceMarkResolution.High: return serialize6Bytes(date);
433
+ case 0: return serialize2Bytes(date);
434
+ case 1: return serialize4Bytes(date);
435
+ case 2:
436
+ case 3: return serialize6Bytes(date);
382
437
  }
383
438
  }
384
439
  /**
@@ -386,46 +441,55 @@ function serializeDate(res, date) {
386
441
  */
387
442
  function deserializeDate(res, data) {
388
443
  switch (res) {
389
- case ProvenanceMarkResolution.Low:
390
- if (data.length !== 2) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid date length: expected 2 bytes, got ${data.length}` });
444
+ case 0:
445
+ if (data.length !== 2) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid date length: expected 2 bytes, got ${data.length}` });
391
446
  return deserialize2Bytes(data);
392
- case ProvenanceMarkResolution.Medium:
393
- if (data.length !== 4) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid date length: expected 4 bytes, got ${data.length}` });
447
+ case 1:
448
+ if (data.length !== 4) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid date length: expected 4 bytes, got ${data.length}` });
394
449
  return deserialize4Bytes(data);
395
- case ProvenanceMarkResolution.Quartile:
396
- case ProvenanceMarkResolution.High:
397
- if (data.length !== 6) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid date length: expected 6 bytes, got ${data.length}` });
450
+ case 2:
451
+ case 3:
452
+ if (data.length !== 6) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid date length: expected 6 bytes, got ${data.length}` });
398
453
  return deserialize6Bytes(data);
399
454
  }
400
455
  }
401
456
  /**
402
457
  * Serialize a sequence number into bytes based on the resolution.
458
+ *
459
+ * Mirrors Rust's typed `u32` parameter (`generator.rs::serialize_seq`)
460
+ * — the input must be a non-negative integer in `[0, 2^32-1]` (a u32).
461
+ * For Low resolution the upper bound additionally narrows to `2^16-1`
462
+ * (a u16) per Rust `if seq > 0xFFFF`. Earlier revisions of this port
463
+ * accepted any JS `number` for the 4-byte branch and would silently
464
+ * truncate values above `2^32-1`; now we raise `ResolutionError` so
465
+ * the wire output never deviates from Rust's u32 contract.
403
466
  */
404
467
  function serializeSeq(res, seq) {
468
+ if (!Number.isInteger(seq) || seq < 0) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `sequence number must be a non-negative integer, got ${seq}` });
405
469
  if (seqBytesLength(res) === 2) {
406
- if (seq > 65535) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `sequence number ${seq} out of range for 2-byte format (max 65535)` });
470
+ if (seq > 65535) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `sequence number ${seq} out of range for 2-byte format (max 65535)` });
407
471
  const buf = new Uint8Array(2);
408
472
  buf[0] = seq >> 8 & 255;
409
473
  buf[1] = seq & 255;
410
474
  return buf;
411
- } else {
412
- const buf = new Uint8Array(4);
413
- buf[0] = seq >> 24 & 255;
414
- buf[1] = seq >> 16 & 255;
415
- buf[2] = seq >> 8 & 255;
416
- buf[3] = seq & 255;
417
- return buf;
418
475
  }
476
+ if (seq > 4294967295) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `sequence number ${seq} out of range for 4-byte format (max 4294967295)` });
477
+ const buf = new Uint8Array(4);
478
+ buf[0] = seq >>> 24 & 255;
479
+ buf[1] = seq >>> 16 & 255;
480
+ buf[2] = seq >>> 8 & 255;
481
+ buf[3] = seq & 255;
482
+ return buf;
419
483
  }
420
484
  /**
421
485
  * Deserialize bytes into a sequence number based on the resolution.
422
486
  */
423
487
  function deserializeSeq(res, data) {
424
488
  if (seqBytesLength(res) === 2) {
425
- if (data.length !== 2) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid sequence number length: expected 2 bytes, got ${data.length}` });
489
+ if (data.length !== 2) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid sequence number length: expected 2 bytes, got ${data.length}` });
426
490
  return data[0] << 8 | data[1];
427
491
  } else {
428
- if (data.length !== 4) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ResolutionError, void 0, { details: `invalid sequence number length: expected 4 bytes, got ${data.length}` });
492
+ if (data.length !== 4) throw new ProvenanceMarkError("ResolutionError", void 0, { details: `invalid sequence number length: expected 4 bytes, got ${data.length}` });
429
493
  return (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]) >>> 0;
430
494
  }
431
495
  }
@@ -434,34 +498,38 @@ function deserializeSeq(res, data) {
434
498
  */
435
499
  function resolutionToString(res) {
436
500
  switch (res) {
437
- case ProvenanceMarkResolution.Low: return "low";
438
- case ProvenanceMarkResolution.Medium: return "medium";
439
- case ProvenanceMarkResolution.Quartile: return "quartile";
440
- case ProvenanceMarkResolution.High: return "high";
501
+ case 0: return "low";
502
+ case 1: return "medium";
503
+ case 2: return "quartile";
504
+ case 3: return "high";
441
505
  }
442
506
  }
443
507
  /**
444
508
  * Convert a resolution to CBOR.
445
509
  */
446
510
  function resolutionToCbor(res) {
447
- return (0, __bcts_dcbor.cbor)(res);
511
+ return (0, _bcts_dcbor.cbor)(res);
448
512
  }
449
513
  /**
450
514
  * Create a resolution from CBOR.
451
515
  */
452
516
  function resolutionFromCbor(cborValue) {
453
- const value = (0, __bcts_dcbor.expectUnsigned)(cborValue);
517
+ const value = (0, _bcts_dcbor.expectUnsigned)(cborValue);
454
518
  return resolutionFromNumber(Number(value));
455
519
  }
456
-
457
520
  //#endregion
458
521
  //#region src/crypto-utils.ts
522
+ /**
523
+ * Copyright © 2023-2026 Blockchain Commons, LLC
524
+ * Copyright © 2025-2026 Parity Technologies
525
+ *
526
+ */
459
527
  const SHA256_SIZE = 32;
460
528
  /**
461
529
  * Compute SHA-256 hash of data.
462
530
  */
463
531
  function sha256(data) {
464
- return (0, __noble_hashes_sha256.sha256)(data);
532
+ return (0, _noble_hashes_sha2_js.sha256)(data);
465
533
  }
466
534
  /**
467
535
  * Compute SHA-256 hash and return a prefix of the given length.
@@ -479,7 +547,7 @@ function extendKey(data) {
479
547
  * Compute HKDF-HMAC-SHA-256 for the given key material.
480
548
  */
481
549
  function hkdfHmacSha256(keyMaterial, salt, keyLen) {
482
- return (0, __noble_hashes_hkdf.hkdf)(__noble_hashes_sha256.sha256, keyMaterial, salt.length > 0 ? salt : void 0, new Uint8Array(0), keyLen);
550
+ return (0, _noble_hashes_hkdf_js.hkdf)(_noble_hashes_sha2_js.sha256, keyMaterial, salt.length > 0 ? salt : void 0, new Uint8Array(0), keyLen);
483
551
  }
484
552
  /**
485
553
  * Obfuscate (or deobfuscate) a message using ChaCha20.
@@ -490,12 +558,183 @@ function obfuscate(key, message) {
490
558
  const extendedKey = extendKey(key instanceof Uint8Array ? key : new Uint8Array(key));
491
559
  const iv = new Uint8Array(12);
492
560
  for (let i = 0; i < 12; i++) iv[i] = extendedKey[31 - i];
493
- return (0, __noble_ciphers_chacha.chacha20)(extendedKey, iv, message instanceof Uint8Array ? message : new Uint8Array(message));
561
+ return (0, _noble_ciphers_chacha_js.chacha20)(extendedKey, iv, message instanceof Uint8Array ? message : new Uint8Array(message));
562
+ }
563
+ //#endregion
564
+ //#region src/seed.ts
565
+ /**
566
+ * Copyright © 2023-2026 Blockchain Commons, LLC
567
+ * Copyright © 2025-2026 Parity Technologies
568
+ *
569
+ */
570
+ const PROVENANCE_SEED_LENGTH = 32;
571
+ /**
572
+ * A seed for generating provenance marks.
573
+ */
574
+ var ProvenanceSeed = class ProvenanceSeed {
575
+ data;
576
+ constructor(data) {
577
+ this.data = data;
578
+ }
579
+ /**
580
+ * Create a new random seed using secure random number generation.
581
+ */
582
+ static new() {
583
+ const data = (0, _bcts_rand.randomData)(32);
584
+ return ProvenanceSeed.fromBytes(data);
585
+ }
586
+ /**
587
+ * Create a new seed using custom random data.
588
+ */
589
+ static newUsing(randomData) {
590
+ if (randomData.length < 32) throw new ProvenanceMarkError("InvalidSeedLength", void 0, { actual: randomData.length });
591
+ return ProvenanceSeed.fromBytes(randomData.slice(0, 32));
592
+ }
593
+ /**
594
+ * Create a new seed from a passphrase.
595
+ */
596
+ static newWithPassphrase(passphrase) {
597
+ const seedData = extendKey(new TextEncoder().encode(passphrase));
598
+ return ProvenanceSeed.fromBytes(seedData);
599
+ }
600
+ /**
601
+ * Get the raw bytes.
602
+ */
603
+ toBytes() {
604
+ return new Uint8Array(this.data);
605
+ }
606
+ /**
607
+ * Create from a 32-byte array.
608
+ */
609
+ static fromBytes(bytes) {
610
+ if (bytes.length !== 32) throw new ProvenanceMarkError("InvalidSeedLength", void 0, { actual: bytes.length });
611
+ return new ProvenanceSeed(new Uint8Array(bytes));
612
+ }
613
+ /**
614
+ * Create from a slice (validates length).
615
+ */
616
+ static fromSlice(bytes) {
617
+ return ProvenanceSeed.fromBytes(bytes);
618
+ }
619
+ /**
620
+ * Get the hex representation.
621
+ */
622
+ hex() {
623
+ return Array.from(this.data).map((b) => b.toString(16).padStart(2, "0")).join("");
624
+ }
625
+ /**
626
+ * Convert to CBOR (byte string).
627
+ */
628
+ toCbor() {
629
+ return (0, _bcts_dcbor.cbor)(this.data);
630
+ }
631
+ /**
632
+ * Create from CBOR (byte string).
633
+ */
634
+ static fromCbor(cborValue) {
635
+ const bytes = (0, _bcts_dcbor.expectBytes)(cborValue);
636
+ return ProvenanceSeed.fromBytes(bytes);
637
+ }
638
+ };
639
+ //#endregion
640
+ //#region src/utils.ts
641
+ /**
642
+ * Copyright © 2023-2026 Blockchain Commons, LLC
643
+ * Copyright © 2025-2026 Parity Technologies
644
+ *
645
+ *
646
+ * Utility functions for byte array conversions.
647
+ *
648
+ * These functions provide cross-platform support for common byte manipulation
649
+ * operations needed in provenance mark encoding.
650
+ */
651
+ /**
652
+ * Convert a Uint8Array to a lowercase hexadecimal string.
653
+ *
654
+ * @param data - The byte array to convert
655
+ * @returns A lowercase hex string representation (2 characters per byte)
656
+ */
657
+ function bytesToHex(data) {
658
+ return Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join("");
659
+ }
660
+ /**
661
+ * Convert a Uint8Array to a base64-encoded string.
662
+ *
663
+ * This function works in both browser and Node.js environments.
664
+ *
665
+ * @param data - The byte array to encode
666
+ * @returns A base64-encoded string
667
+ */
668
+ function toBase64(data) {
669
+ let binary = "";
670
+ for (const byte of data) binary += String.fromCharCode(byte);
671
+ return btoa(binary);
672
+ }
673
+ /**
674
+ * Convert a base64-encoded string to a Uint8Array.
675
+ *
676
+ * This function works in both browser and Node.js environments.
677
+ *
678
+ * @param base64 - A base64-encoded string
679
+ * @returns The decoded byte array
680
+ */
681
+ function fromBase64(base64) {
682
+ const binary = atob(base64);
683
+ const bytes = new Uint8Array(binary.length);
684
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
685
+ return bytes;
686
+ }
687
+ /**
688
+ * Parse a base64-encoded provenance seed.
689
+ *
690
+ * Mirrors Rust's `parse_seed` user helper
691
+ * (`provenance-mark-rust/src/util.rs:34-38`), which round-trips the
692
+ * input through serde JSON / `deserialize_block` and so requires the
693
+ * decoded bytes to be exactly {@link PROVENANCE_SEED_LENGTH} (32) long.
694
+ * The TS equivalent decodes the base64 directly and delegates to
695
+ * {@link ProvenanceSeed.fromBytes} for the length check.
696
+ *
697
+ * @param s - Base64-encoded 32-byte seed string.
698
+ * @returns The decoded {@link ProvenanceSeed}.
699
+ * @throws {ProvenanceMarkError} If the input is not valid base64 or the
700
+ * decoded length is not exactly 32 bytes.
701
+ */
702
+ function parseSeed(s) {
703
+ let bytes;
704
+ try {
705
+ bytes = fromBase64(s);
706
+ } catch (e) {
707
+ throw new ProvenanceMarkError("Base64Error", "invalid base64 encoding for provenance seed", { details: e instanceof Error ? e.message : String(e) });
708
+ }
709
+ return ProvenanceSeed.fromBytes(bytes);
710
+ }
711
+ /**
712
+ * Parse a date string (`YYYY-MM-DD` or full RFC 3339) into a `Date`.
713
+ *
714
+ * Mirrors Rust's `parse_date` user helper
715
+ * (`provenance-mark-rust/src/util.rs:40-42`), which delegates to
716
+ * `Date::from_string` (the same parser the JSON deserializer uses).
717
+ * Accepts the same shapes the Rust parser does:
718
+ *
719
+ * - `YYYY-MM-DD` (interpreted as UTC midnight, matching JS spec).
720
+ * - Full RFC 3339, e.g. `2023-06-20T15:30:45Z` or
721
+ * `2023-06-20T15:30:45.123Z`.
722
+ *
723
+ * @throws {ProvenanceMarkError} If the input fails to parse.
724
+ */
725
+ function parseDate(s) {
726
+ const date = new Date(s);
727
+ if (Number.isNaN(date.getTime())) throw new ProvenanceMarkError("InvalidDate", `cannot parse date: ${s}`);
728
+ return date;
494
729
  }
495
-
496
730
  //#endregion
497
731
  //#region src/xoshiro256starstar.ts
498
732
  /**
733
+ * Copyright © 2023-2026 Blockchain Commons, LLC
734
+ * Copyright © 2025-2026 Parity Technologies
735
+ *
736
+ */
737
+ /**
499
738
  * Xoshiro256** PRNG implementation.
500
739
  * A fast, high-quality pseudorandom number generator.
501
740
  */
@@ -615,9 +854,13 @@ var Xoshiro256StarStar = class Xoshiro256StarStar {
615
854
  this.s[3] = this.rotateLeft64(this.s[3], 45n);
616
855
  }
617
856
  };
618
-
619
857
  //#endregion
620
858
  //#region src/rng-state.ts
859
+ /**
860
+ * Copyright © 2023-2026 Blockchain Commons, LLC
861
+ * Copyright © 2025-2026 Parity Technologies
862
+ *
863
+ */
621
864
  const RNG_STATE_LENGTH = 32;
622
865
  /**
623
866
  * RNG state for provenance marks (32 bytes).
@@ -637,7 +880,7 @@ var RngState = class RngState {
637
880
  * Create from a 32-byte array.
638
881
  */
639
882
  static fromBytes(bytes) {
640
- if (bytes.length !== RNG_STATE_LENGTH) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidSeedLength, void 0, { actual: bytes.length });
883
+ if (bytes.length !== 32) throw new ProvenanceMarkError("InvalidSeedLength", void 0, { actual: bytes.length });
641
884
  return new RngState(new Uint8Array(bytes));
642
885
  }
643
886
  /**
@@ -656,149 +899,302 @@ var RngState = class RngState {
656
899
  * Convert to CBOR (byte string).
657
900
  */
658
901
  toCbor() {
659
- return (0, __bcts_dcbor.cbor)(this.data);
902
+ return (0, _bcts_dcbor.cbor)(this.data);
660
903
  }
661
904
  /**
662
905
  * Create from CBOR (byte string).
663
906
  */
664
907
  static fromCbor(cborValue) {
665
- const bytes = (0, __bcts_dcbor.expectBytes)(cborValue);
908
+ const bytes = (0, _bcts_dcbor.expectBytes)(cborValue);
666
909
  return RngState.fromBytes(bytes);
667
910
  }
668
911
  };
669
-
670
912
  //#endregion
671
- //#region src/seed.ts
672
- const PROVENANCE_SEED_LENGTH = 32;
913
+ //#region src/validate.ts
673
914
  /**
674
- * A seed for generating provenance marks.
915
+ * Format for validation report output.
675
916
  */
676
- var ProvenanceSeed = class ProvenanceSeed {
677
- data;
678
- constructor(data) {
679
- this.data = data;
680
- }
681
- /**
682
- * Create a new random seed using secure random number generation.
683
- */
684
- static new() {
685
- const data = (0, __bcts_rand.randomData)(PROVENANCE_SEED_LENGTH);
686
- return ProvenanceSeed.fromBytes(data);
687
- }
688
- /**
689
- * Create a new seed using custom random data.
690
- */
691
- static newUsing(randomData$1) {
692
- if (randomData$1.length < PROVENANCE_SEED_LENGTH) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidSeedLength, void 0, { actual: randomData$1.length });
693
- return ProvenanceSeed.fromBytes(randomData$1.slice(0, PROVENANCE_SEED_LENGTH));
694
- }
695
- /**
696
- * Create a new seed from a passphrase.
697
- */
698
- static newWithPassphrase(passphrase) {
699
- const seedData = extendKey(new TextEncoder().encode(passphrase));
700
- return ProvenanceSeed.fromBytes(seedData);
701
- }
702
- /**
703
- * Get the raw bytes.
704
- */
705
- toBytes() {
706
- return new Uint8Array(this.data);
707
- }
708
- /**
709
- * Create from a 32-byte array.
710
- */
711
- static fromBytes(bytes) {
712
- if (bytes.length !== PROVENANCE_SEED_LENGTH) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidSeedLength, void 0, { actual: bytes.length });
713
- return new ProvenanceSeed(new Uint8Array(bytes));
714
- }
715
- /**
716
- * Create from a slice (validates length).
717
- */
718
- static fromSlice(bytes) {
719
- return ProvenanceSeed.fromBytes(bytes);
720
- }
721
- /**
722
- * Get the hex representation.
723
- */
724
- hex() {
725
- return Array.from(this.data).map((b) => b.toString(16).padStart(2, "0")).join("");
726
- }
727
- /**
728
- * Convert to CBOR (byte string).
729
- */
730
- toCbor() {
731
- return (0, __bcts_dcbor.cbor)(this.data);
732
- }
733
- /**
734
- * Create from CBOR (byte string).
735
- */
736
- static fromCbor(cborValue) {
737
- const bytes = (0, __bcts_dcbor.expectBytes)(cborValue);
738
- return ProvenanceSeed.fromBytes(bytes);
739
- }
740
- };
741
-
742
- //#endregion
743
- //#region src/utils.ts
917
+ let ValidationReportFormat = /* @__PURE__ */ function(ValidationReportFormat) {
918
+ /** Human-readable text format */
919
+ ValidationReportFormat["Text"] = "text";
920
+ /** Compact JSON format (no whitespace) */
921
+ ValidationReportFormat["JsonCompact"] = "json-compact";
922
+ /** Pretty-printed JSON format (with indentation) */
923
+ ValidationReportFormat["JsonPretty"] = "json-pretty";
924
+ return ValidationReportFormat;
925
+ }({});
744
926
  /**
745
- * Convert a Uint8Array to a lowercase hexadecimal string.
746
- *
747
- * @param data - The byte array to convert
748
- * @returns A lowercase hex string representation (2 characters per byte)
927
+ * Format a validation issue as a string.
749
928
  */
750
- function bytesToHex(data) {
751
- return Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join("");
929
+ function formatValidationIssue(issue) {
930
+ switch (issue.type) {
931
+ case "HashMismatch": return `hash mismatch: expected ${issue.expected}, got ${issue.actual}`;
932
+ case "KeyMismatch": return "key mismatch: current hash was not generated from next key";
933
+ case "SequenceGap": return `sequence number gap: expected ${issue.expected}, got ${issue.actual}`;
934
+ case "DateOrdering": return `date must be equal or later: previous is ${issue.previous}, next is ${issue.next}`;
935
+ case "NonGenesisAtZero": return "non-genesis mark at sequence 0";
936
+ case "InvalidGenesisKey": return "genesis mark must have key equal to chain_id";
937
+ }
752
938
  }
753
939
  /**
754
- * Convert a Uint8Array to a base64-encoded string.
755
- *
756
- * This function works in both browser and Node.js environments.
757
- *
758
- * @param data - The byte array to encode
759
- * @returns A base64-encoded string
940
+ * Get the chain ID as a hex string for display.
760
941
  */
761
- function toBase64(data) {
762
- const globalBtoa = globalThis.btoa;
763
- if (typeof globalBtoa === "function") {
764
- let binary = "";
765
- for (const byte of data) binary += String.fromCharCode(byte);
766
- return globalBtoa(binary);
767
- }
768
- const requireFn = require;
769
- if (typeof requireFn === "function") {
770
- const { Buffer: NodeBuffer } = requireFn("buffer");
771
- return NodeBuffer.from(data).toString("base64");
772
- }
773
- throw new Error("btoa not available and require is not defined");
942
+ function chainIdHex(report) {
943
+ return hexEncode(report.chainId);
774
944
  }
775
945
  /**
776
- * Convert a base64-encoded string to a Uint8Array.
777
- *
778
- * This function works in both browser and Node.js environments.
779
- *
780
- * @param base64 - A base64-encoded string
781
- * @returns The decoded byte array
946
+ * Check if the validation report has any issues.
782
947
  */
783
- function fromBase64(base64) {
784
- const globalAtob = globalThis.atob;
785
- if (typeof globalAtob === "function") {
786
- const binary = globalAtob(base64);
787
- const bytes = new Uint8Array(binary.length);
788
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
789
- return bytes;
790
- }
791
- const requireFn = require;
792
- if (typeof requireFn === "function") {
793
- const { Buffer: NodeBuffer } = requireFn("buffer");
794
- return new Uint8Array(NodeBuffer.from(base64, "base64"));
948
+ function hasIssues(report) {
949
+ for (const chain of report.chains) if (!chain.hasGenesis) return true;
950
+ for (const chain of report.chains) for (const seq of chain.sequences) for (const mark of seq.marks) if (mark.issues.length > 0) return true;
951
+ if (report.chains.length > 1) return true;
952
+ if (report.chains.length === 1 && report.chains[0].sequences.length > 1) return true;
953
+ return false;
954
+ }
955
+ /**
956
+ * Check if the validation report contains interesting information.
957
+ */
958
+ function isInteresting(report) {
959
+ if (report.chains.length === 0) return false;
960
+ for (const chain of report.chains) if (!chain.hasGenesis) return true;
961
+ if (report.chains.length === 1) {
962
+ const chain = report.chains[0];
963
+ if (chain.sequences.length === 1) {
964
+ if (chain.sequences[0].marks.every((m) => m.issues.length === 0)) return false;
965
+ }
795
966
  }
796
- throw new Error("atob not available and require is not defined");
967
+ return true;
968
+ }
969
+ /**
970
+ * Format the validation report as human-readable text.
971
+ */
972
+ function formatText(report) {
973
+ if (!isInteresting(report)) return "";
974
+ const lines = [];
975
+ lines.push(`Total marks: ${report.marks.length}`);
976
+ lines.push(`Chains: ${report.chains.length}`);
977
+ lines.push("");
978
+ for (let chainIdx = 0; chainIdx < report.chains.length; chainIdx++) {
979
+ const chain = report.chains[chainIdx];
980
+ const chainIdStr = chainIdHex(chain);
981
+ const shortChainId = chainIdStr.length > 8 ? chainIdStr.slice(0, 8) : chainIdStr;
982
+ lines.push(`Chain ${chainIdx + 1}: ${shortChainId}`);
983
+ if (!chain.hasGenesis) lines.push(" Warning: No genesis mark found");
984
+ for (const seq of chain.sequences) for (const flaggedMark of seq.marks) {
985
+ const mark = flaggedMark.mark;
986
+ const shortId = mark.idHex().slice(0, 8);
987
+ const seqNum = mark.seq();
988
+ const annotations = [];
989
+ if (mark.isGenesis()) annotations.push("genesis mark");
990
+ for (const issue of flaggedMark.issues) {
991
+ let issueStr;
992
+ switch (issue.type) {
993
+ case "SequenceGap":
994
+ issueStr = `gap: ${issue.expected} missing`;
995
+ break;
996
+ case "DateOrdering":
997
+ issueStr = `date ${issue.previous} < ${issue.next}`;
998
+ break;
999
+ case "HashMismatch":
1000
+ issueStr = "hash mismatch";
1001
+ break;
1002
+ case "KeyMismatch":
1003
+ issueStr = "key mismatch";
1004
+ break;
1005
+ case "NonGenesisAtZero":
1006
+ issueStr = "non-genesis at seq 0";
1007
+ break;
1008
+ case "InvalidGenesisKey":
1009
+ issueStr = "invalid genesis key";
1010
+ break;
1011
+ }
1012
+ annotations.push(issueStr);
1013
+ }
1014
+ if (annotations.length === 0) lines.push(` ${seqNum}: ${shortId}`);
1015
+ else lines.push(` ${seqNum}: ${shortId} (${annotations.join(", ")})`);
1016
+ }
1017
+ lines.push("");
1018
+ }
1019
+ return lines.join("\n").trimEnd();
1020
+ }
1021
+ /**
1022
+ * Format the validation report.
1023
+ */
1024
+ function formatReport(report, format) {
1025
+ switch (format) {
1026
+ case "text": return formatText(report);
1027
+ case "json-compact": return JSON.stringify(reportToJSON(report));
1028
+ case "json-pretty": return JSON.stringify(reportToJSON(report), null, 2);
1029
+ }
1030
+ }
1031
+ /**
1032
+ * Convert a report to a JSON-serializable object.
1033
+ */
1034
+ function reportToJSON(report) {
1035
+ return {
1036
+ marks: report.marks.map((m) => m.urString()),
1037
+ chains: report.chains.map((chain) => ({
1038
+ chain_id: hexEncode(chain.chainId),
1039
+ has_genesis: chain.hasGenesis,
1040
+ marks: chain.marks.map((m) => m.urString()),
1041
+ sequences: chain.sequences.map((seq) => ({
1042
+ start_seq: seq.startSeq,
1043
+ end_seq: seq.endSeq,
1044
+ marks: seq.marks.map((fm) => ({
1045
+ mark: fm.mark.urString(),
1046
+ issues: fm.issues.map(issueToJSON)
1047
+ }))
1048
+ }))
1049
+ }))
1050
+ };
1051
+ }
1052
+ /**
1053
+ * Convert a ValidationIssue to JSON matching Rust's serde format.
1054
+ *
1055
+ * Rust uses `#[serde(tag = "type", content = "data")]` which wraps
1056
+ * struct variant data in a `"data"` field. Unit variants have no
1057
+ * `"data"` field.
1058
+ */
1059
+ function issueToJSON(issue) {
1060
+ switch (issue.type) {
1061
+ case "HashMismatch": return {
1062
+ type: "HashMismatch",
1063
+ data: {
1064
+ expected: issue.expected,
1065
+ actual: issue.actual
1066
+ }
1067
+ };
1068
+ case "SequenceGap": return {
1069
+ type: "SequenceGap",
1070
+ data: {
1071
+ expected: issue.expected,
1072
+ actual: issue.actual
1073
+ }
1074
+ };
1075
+ case "DateOrdering": return {
1076
+ type: "DateOrdering",
1077
+ data: {
1078
+ previous: issue.previous,
1079
+ next: issue.next
1080
+ }
1081
+ };
1082
+ case "KeyMismatch": return { type: "KeyMismatch" };
1083
+ case "NonGenesisAtZero": return { type: "NonGenesisAtZero" };
1084
+ case "InvalidGenesisKey": return { type: "InvalidGenesisKey" };
1085
+ }
1086
+ }
1087
+ /**
1088
+ * Build sequence bins for a chain.
1089
+ */
1090
+ function buildSequenceBins(marks) {
1091
+ const sequences = [];
1092
+ let currentSequence = [];
1093
+ for (let i = 0; i < marks.length; i++) {
1094
+ const mark = marks[i];
1095
+ if (i === 0) currentSequence.push({
1096
+ mark,
1097
+ issues: []
1098
+ });
1099
+ else {
1100
+ const prev = marks[i - 1];
1101
+ try {
1102
+ prev.precedesOpt(mark);
1103
+ currentSequence.push({
1104
+ mark,
1105
+ issues: []
1106
+ });
1107
+ } catch (e) {
1108
+ if (currentSequence.length > 0) sequences.push(createSequenceReport(currentSequence));
1109
+ let issue;
1110
+ if (e instanceof ProvenanceMarkError && e.details?.["validationIssue"] !== void 0) issue = e.details["validationIssue"];
1111
+ else issue = { type: "KeyMismatch" };
1112
+ currentSequence = [{
1113
+ mark,
1114
+ issues: [issue]
1115
+ }];
1116
+ }
1117
+ }
1118
+ }
1119
+ if (currentSequence.length > 0) sequences.push(createSequenceReport(currentSequence));
1120
+ return sequences;
1121
+ }
1122
+ /**
1123
+ * Create a sequence report from flagged marks.
1124
+ */
1125
+ function createSequenceReport(marks) {
1126
+ return {
1127
+ startSeq: marks.length > 0 ? marks[0].mark.seq() : 0,
1128
+ endSeq: marks.length > 0 ? marks[marks.length - 1].mark.seq() : 0,
1129
+ marks
1130
+ };
1131
+ }
1132
+ /**
1133
+ * Validate a collection of provenance marks.
1134
+ */
1135
+ function validate(marks) {
1136
+ const seen = /* @__PURE__ */ new Set();
1137
+ const deduplicatedMarks = [];
1138
+ for (const mark of marks) {
1139
+ const key = `${mark.res()}:${hexEncode(mark.message())}`;
1140
+ if (!seen.has(key)) {
1141
+ seen.add(key);
1142
+ deduplicatedMarks.push(mark);
1143
+ }
1144
+ }
1145
+ const chainBins = /* @__PURE__ */ new Map();
1146
+ for (const mark of deduplicatedMarks) {
1147
+ const chainIdKey = hexEncode(mark.chainId());
1148
+ const bin = chainBins.get(chainIdKey);
1149
+ if (bin !== void 0) bin.push(mark);
1150
+ else chainBins.set(chainIdKey, [mark]);
1151
+ }
1152
+ const chains = [];
1153
+ for (const [chainIdKey, chainMarks] of chainBins) {
1154
+ chainMarks.sort((a, b) => a.seq() - b.seq());
1155
+ const hasGenesis = chainMarks.length > 0 && chainMarks[0].seq() === 0 && chainMarks[0].isGenesis();
1156
+ const sequences = buildSequenceBins(chainMarks);
1157
+ chains.push({
1158
+ chainId: hexDecode(chainIdKey),
1159
+ hasGenesis,
1160
+ marks: chainMarks,
1161
+ sequences
1162
+ });
1163
+ }
1164
+ chains.sort((a, b) => {
1165
+ const aHex = hexEncode(a.chainId);
1166
+ const bHex = hexEncode(b.chainId);
1167
+ if (aHex < bHex) return -1;
1168
+ if (aHex > bHex) return 1;
1169
+ return 0;
1170
+ });
1171
+ return {
1172
+ marks: deduplicatedMarks,
1173
+ chains
1174
+ };
1175
+ }
1176
+ /**
1177
+ * Helper function to encode bytes as hex.
1178
+ */
1179
+ function hexEncode(bytes) {
1180
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1181
+ }
1182
+ /**
1183
+ * Helper function to decode hex to bytes.
1184
+ */
1185
+ function hexDecode(hex) {
1186
+ const bytes = new Uint8Array(hex.length / 2);
1187
+ for (let i = 0; i < hex.length; i += 2) bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
1188
+ return bytes;
797
1189
  }
798
-
799
1190
  //#endregion
800
1191
  //#region src/mark.ts
801
1192
  /**
1193
+ * Copyright © 2023-2026 Blockchain Commons, LLC
1194
+ * Copyright © 2025-2026 Parity Technologies
1195
+ *
1196
+ */
1197
+ /**
802
1198
  * A cryptographically-secured provenance mark.
803
1199
  */
804
1200
  var ProvenanceMark = class ProvenanceMark {
@@ -865,29 +1261,29 @@ var ProvenanceMark = class ProvenanceMark {
865
1261
  */
866
1262
  info() {
867
1263
  if (this._infoBytes.length === 0) return;
868
- return (0, __bcts_dcbor.decodeCbor)(this._infoBytes);
1264
+ return (0, _bcts_dcbor.decodeCbor)(this._infoBytes);
869
1265
  }
870
1266
  /**
871
1267
  * Create a new provenance mark.
872
1268
  */
873
1269
  static new(res, key, nextKey, chainId, seq, date, info) {
874
1270
  const linkLen = linkLength(res);
875
- if (key.length !== linkLen) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidKeyLength, void 0, {
1271
+ if (key.length !== linkLen) throw new ProvenanceMarkError("InvalidKeyLength", void 0, {
876
1272
  expected: linkLen,
877
1273
  actual: key.length
878
1274
  });
879
- if (nextKey.length !== linkLen) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidNextKeyLength, void 0, {
1275
+ if (nextKey.length !== linkLen) throw new ProvenanceMarkError("InvalidNextKeyLength", void 0, {
880
1276
  expected: linkLen,
881
1277
  actual: nextKey.length
882
1278
  });
883
- if (chainId.length !== linkLen) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidChainIdLength, void 0, {
1279
+ if (chainId.length !== linkLen) throw new ProvenanceMarkError("InvalidChainIdLength", void 0, {
884
1280
  expected: linkLen,
885
1281
  actual: chainId.length
886
1282
  });
887
1283
  const dateBytes = serializeDate(res, date);
888
1284
  const seqBytes = serializeSeq(res, seq);
889
1285
  const normalizedDate = deserializeDate(res, dateBytes);
890
- const infoBytes = info !== void 0 ? (0, __bcts_dcbor.cborData)(info) : new Uint8Array(0);
1286
+ const infoBytes = info !== void 0 ? (0, _bcts_dcbor.cborData)(info) : new Uint8Array(0);
891
1287
  const hash = ProvenanceMark.makeHash(res, key, nextKey, chainId, seqBytes, dateBytes, infoBytes);
892
1288
  return new ProvenanceMark(res, new Uint8Array(key), hash, new Uint8Array(chainId), seqBytes, dateBytes, infoBytes, seq, normalizedDate);
893
1289
  }
@@ -896,7 +1292,7 @@ var ProvenanceMark = class ProvenanceMark {
896
1292
  */
897
1293
  static fromMessage(res, message) {
898
1294
  const minLen = fixedLength(res);
899
- if (message.length < minLen) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidMessageLength, void 0, {
1295
+ if (message.length < minLen) throw new ProvenanceMarkError("InvalidMessageLength", void 0, {
900
1296
  expected: minLen,
901
1297
  actual: message.length
902
1298
  });
@@ -917,9 +1313,9 @@ var ProvenanceMark = class ProvenanceMark {
917
1313
  const infoStart = infoRangeStart(res);
918
1314
  const infoBytes = payload.slice(infoStart);
919
1315
  if (infoBytes.length > 0) try {
920
- (0, __bcts_dcbor.decodeCbor)(infoBytes);
1316
+ (0, _bcts_dcbor.decodeCbor)(infoBytes);
921
1317
  } catch {
922
- throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidInfoCbor);
1318
+ throw new ProvenanceMarkError("InvalidInfoCbor");
923
1319
  }
924
1320
  return new ProvenanceMark(res, new Uint8Array(key), new Uint8Array(hash), new Uint8Array(chainId), new Uint8Array(seqBytes), new Uint8Array(dateBytes), new Uint8Array(infoBytes), seq, date);
925
1321
  }
@@ -934,24 +1330,174 @@ var ProvenanceMark = class ProvenanceMark {
934
1330
  ]), linkLength(res));
935
1331
  }
936
1332
  /**
937
- * Get the first four bytes of the hash as a hex string identifier.
1333
+ * The 32-byte Mark ID.
1334
+ *
1335
+ * The first `linkLength` bytes are the mark's stored hash. The remaining
1336
+ * bytes come from the mark's fingerprint (SHA-256 of CBOR encoding),
1337
+ * ensuring a full 32-byte value is always available regardless of
1338
+ * resolution.
1339
+ */
1340
+ id() {
1341
+ const result = new Uint8Array(32);
1342
+ const n = this._hash.length;
1343
+ result.set(this._hash, 0);
1344
+ if (n < 32) {
1345
+ const fp = this.fingerprint();
1346
+ result.set(fp.subarray(0, 32 - n), n);
1347
+ }
1348
+ return result;
1349
+ }
1350
+ /**
1351
+ * The full 32-byte Mark ID as a 64-character hex string.
1352
+ */
1353
+ idHex() {
1354
+ return bytesToHex(this.id());
1355
+ }
1356
+ /**
1357
+ * The first `wordCount` bytes of the Mark ID as upper-case ByteWords.
1358
+ *
1359
+ * @param wordCount Number of bytes to encode, must be in `4..=32`.
1360
+ * @param prefix If `true`, prepends the provenance-mark prefix character.
1361
+ * @throws if `wordCount` is not in the range `4..=32`.
1362
+ */
1363
+ idBytewords(wordCount, prefix) {
1364
+ if (!Number.isInteger(wordCount) || wordCount < 4 || wordCount > 32) throw new Error(`word_count must be 4..=32, got ${wordCount}`);
1365
+ const s = (0, _bcts_uniform_resources.encodeToWords)(this.id().subarray(0, wordCount)).toUpperCase();
1366
+ return prefix ? `\u{1F15F} ${s}` : s;
1367
+ }
1368
+ /**
1369
+ * The first `wordCount` bytes of the Mark ID as Bytemoji.
1370
+ *
1371
+ * @param wordCount Number of bytes to encode, must be in `4..=32`.
1372
+ * @param prefix If `true`, prepends the provenance-mark prefix character.
1373
+ * @throws if `wordCount` is not in the range `4..=32`.
1374
+ */
1375
+ idBytemoji(wordCount, prefix) {
1376
+ if (!Number.isInteger(wordCount) || wordCount < 4 || wordCount > 32) throw new Error(`word_count must be 4..=32, got ${wordCount}`);
1377
+ const s = (0, _bcts_uniform_resources.encodeToBytemojis)(this.id().subarray(0, wordCount)).toUpperCase();
1378
+ return prefix ? `\u{1F15F} ${s}` : s;
1379
+ }
1380
+ /**
1381
+ * The first `wordCount` bytes of the Mark ID as upper-case minimal
1382
+ * ByteWords (2 letters per byte, concatenated without separator).
1383
+ *
1384
+ * @param wordCount Number of bytes to encode, must be in `4..=32`.
1385
+ * @param prefix If `true`, prepends the provenance-mark prefix character.
1386
+ * @throws if `wordCount` is not in the range `4..=32`.
1387
+ */
1388
+ idBytewordsMinimal(wordCount, prefix) {
1389
+ if (!Number.isInteger(wordCount) || wordCount < 4 || wordCount > 32) throw new Error(`word_count must be 4..=32, got ${wordCount}`);
1390
+ const s = (0, _bcts_uniform_resources.encodeToMinimalBytewords)(this.id().subarray(0, wordCount)).toUpperCase();
1391
+ return prefix ? `\u{1F15F} ${s}` : s;
1392
+ }
1393
+ /**
1394
+ * Legacy 8-character hex identifier — the first 4 bytes of the Mark ID.
1395
+ *
1396
+ * @deprecated Use {@link idHex} for the full 64-char hex, or
1397
+ * `idHex().slice(0, 8)` for this legacy short form. Retained for
1398
+ * backwards compatibility; will be removed in a future alpha.
938
1399
  */
939
1400
  identifier() {
940
- return Array.from(this._hash.slice(0, 4)).map((b) => b.toString(16).padStart(2, "0")).join("");
1401
+ return this.idHex().slice(0, 8);
941
1402
  }
942
1403
  /**
943
- * Get the first four bytes of the hash as upper-case ByteWords.
1404
+ * Legacy 4-byte upper-case ByteWords identifier.
1405
+ *
1406
+ * @deprecated Equivalent to `idBytewords(4, prefix)`. Retained for
1407
+ * backwards compatibility; will be removed in a future alpha.
944
1408
  */
945
1409
  bytewordsIdentifier(prefix) {
946
- const s = (0, __bcts_uniform_resources.encodeBytewordsIdentifier)(this._hash.slice(0, 4)).toUpperCase();
947
- return prefix ? `\u{1F151} ${s}` : s;
1410
+ return this.idBytewords(4, prefix);
948
1411
  }
949
1412
  /**
950
- * Get the first four bytes of the hash as Bytemoji.
1413
+ * Legacy 8-letter minimal ByteWords identifier (first+last letter of each
1414
+ * of the 4 ByteWords). Example: "ABLE ACID ALSO APEX" -> "AEADAOAX".
1415
+ *
1416
+ * @deprecated Equivalent to `idBytewordsMinimal(4, prefix)`. Retained
1417
+ * for backwards compatibility; will be removed in a future alpha.
1418
+ */
1419
+ bytewordsMinimalIdentifier(prefix) {
1420
+ return this.idBytewordsMinimal(4, prefix);
1421
+ }
1422
+ /**
1423
+ * Legacy 4-byte upper-case Bytemoji identifier.
1424
+ *
1425
+ * @deprecated Equivalent to `idBytemoji(4, prefix)`. Retained for
1426
+ * backwards compatibility; will be removed in a future alpha.
951
1427
  */
952
1428
  bytemojiIdentifier(prefix) {
953
- const s = (0, __bcts_uniform_resources.encodeBytemojisIdentifier)(this._hash.slice(0, 4)).toUpperCase();
954
- return prefix ? `\u{1F151} ${s}` : s;
1429
+ return this.idBytemoji(4, prefix);
1430
+ }
1431
+ /**
1432
+ * Computes the minimum prefix length (in bytes, `4..=32`) each mark needs
1433
+ * so that every mark in the set has a unique Mark ID prefix.
1434
+ *
1435
+ * Non-colliding marks get the minimum of 4. Only marks whose 4-byte
1436
+ * prefixes collide are extended.
1437
+ */
1438
+ static minimalNoncollidingPrefixLengths(ids) {
1439
+ const n = ids.length;
1440
+ const lengths = new Array(n).fill(4);
1441
+ const groups = /* @__PURE__ */ new Map();
1442
+ for (let i = 0; i < n; i++) {
1443
+ const key = bytesToHex(ids[i].subarray(0, 4));
1444
+ const g = groups.get(key);
1445
+ if (g !== void 0) g.push(i);
1446
+ else groups.set(key, [i]);
1447
+ }
1448
+ for (const indices of groups.values()) {
1449
+ if (indices.length <= 1) continue;
1450
+ ProvenanceMark.resolveCollisionGroup(ids, indices, lengths);
1451
+ }
1452
+ return lengths;
1453
+ }
1454
+ static resolveCollisionGroup(ids, initialIndices, lengths) {
1455
+ let unresolved = [...initialIndices];
1456
+ for (let prefixLen = 5; prefixLen <= 32; prefixLen++) {
1457
+ const subGroups = /* @__PURE__ */ new Map();
1458
+ for (const i of unresolved) {
1459
+ const key = bytesToHex(ids[i].subarray(0, prefixLen));
1460
+ const g = subGroups.get(key);
1461
+ if (g !== void 0) g.push(i);
1462
+ else subGroups.set(key, [i]);
1463
+ }
1464
+ const nextUnresolved = [];
1465
+ for (const subIndices of subGroups.values()) if (subIndices.length === 1) lengths[subIndices[0]] = prefixLen;
1466
+ else nextUnresolved.push(...subIndices);
1467
+ if (nextUnresolved.length === 0) return;
1468
+ unresolved = nextUnresolved;
1469
+ }
1470
+ for (const i of unresolved) lengths[i] = 32;
1471
+ }
1472
+ /**
1473
+ * Returns disambiguated upper-case ByteWords Mark IDs for a set of marks.
1474
+ *
1475
+ * Non-colliding marks get 4-word identifiers. Only marks whose 4-byte
1476
+ * prefixes collide are extended with additional words (up to 32 bytes
1477
+ * per identifier).
1478
+ */
1479
+ static disambiguatedIdBytewords(marks, prefix) {
1480
+ const ids = marks.map((m) => m.id());
1481
+ const lengths = ProvenanceMark.minimalNoncollidingPrefixLengths(ids);
1482
+ return ids.map((id, i) => {
1483
+ const s = (0, _bcts_uniform_resources.encodeToWords)(id.subarray(0, lengths[i])).toUpperCase();
1484
+ return prefix ? `\u{1F15F} ${s}` : s;
1485
+ });
1486
+ }
1487
+ /**
1488
+ * Returns disambiguated Bytemoji Mark IDs for a set of marks.
1489
+ *
1490
+ * Non-colliding marks get 4-emoji identifiers. Only marks whose 4-byte
1491
+ * prefixes collide are extended with additional emojis (up to 32 bytes
1492
+ * per identifier).
1493
+ */
1494
+ static disambiguatedIdBytemoji(marks, prefix) {
1495
+ const ids = marks.map((m) => m.id());
1496
+ const lengths = ProvenanceMark.minimalNoncollidingPrefixLengths(ids);
1497
+ return ids.map((id, i) => {
1498
+ const s = (0, _bcts_uniform_resources.encodeToBytemojis)(id.subarray(0, lengths[i])).toUpperCase();
1499
+ return prefix ? `\u{1F15F} ${s}` : s;
1500
+ });
955
1501
  }
956
1502
  /**
957
1503
  * Check if this mark precedes another mark in the chain.
@@ -966,18 +1512,39 @@ var ProvenanceMark = class ProvenanceMark {
966
1512
  }
967
1513
  /**
968
1514
  * Check if this mark precedes another mark, throwing on validation errors.
1515
+ * Errors carry a structured `validationIssue` in their details, matching Rust's
1516
+ * `Error::Validation(ValidationIssue)` pattern.
969
1517
  */
970
1518
  precedesOpt(next) {
971
- if (next._seq === 0) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ValidationError, void 0, { message: "non-genesis mark at sequence 0" });
972
- if (arraysEqual(next._key, next._chainId)) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ValidationError, void 0, { message: "genesis mark must have key equal to chain_id" });
973
- if (this._seq !== next._seq - 1) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ValidationError, void 0, { message: `sequence gap: expected ${this._seq + 1}, got ${next._seq}` });
974
- if (this._date > next._date) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ValidationError, void 0, { message: `date ordering: ${this._date.toISOString()} > ${next._date.toISOString()}` });
1519
+ if (next._seq === 0) throw new ProvenanceMarkError("ValidationError", "non-genesis mark at sequence 0", { validationIssue: { type: "NonGenesisAtZero" } });
1520
+ if (arraysEqual(next._key, next._chainId)) throw new ProvenanceMarkError("ValidationError", "genesis mark must have key equal to chain_id", { validationIssue: { type: "InvalidGenesisKey" } });
1521
+ if (this._seq !== next._seq - 1) {
1522
+ const issue = {
1523
+ type: "SequenceGap",
1524
+ expected: this._seq + 1,
1525
+ actual: next._seq
1526
+ };
1527
+ throw new ProvenanceMarkError("ValidationError", `sequence gap: expected ${this._seq + 1}, got ${next._seq}`, { validationIssue: issue });
1528
+ }
1529
+ if (this._date > next._date) {
1530
+ const dateStr = dateToDisplay(this._date);
1531
+ const nextDateStr = dateToDisplay(next._date);
1532
+ const issue = {
1533
+ type: "DateOrdering",
1534
+ previous: dateStr,
1535
+ next: nextDateStr
1536
+ };
1537
+ throw new ProvenanceMarkError("ValidationError", `date ordering: ${dateStr} > ${nextDateStr}`, { validationIssue: issue });
1538
+ }
975
1539
  const expectedHash = ProvenanceMark.makeHash(this._res, this._key, next._key, this._chainId, this._seqBytes, this._dateBytes, this._infoBytes);
976
- if (!arraysEqual(this._hash, expectedHash)) throw new ProvenanceMarkError(ProvenanceMarkErrorType.ValidationError, void 0, {
977
- message: "hash mismatch",
978
- expected: Array.from(expectedHash).map((b) => b.toString(16).padStart(2, "0")).join(""),
979
- actual: Array.from(this._hash).map((b) => b.toString(16).padStart(2, "0")).join("")
980
- });
1540
+ if (!arraysEqual(this._hash, expectedHash)) {
1541
+ const issue = {
1542
+ type: "HashMismatch",
1543
+ expected: bytesToHex(expectedHash),
1544
+ actual: bytesToHex(this._hash)
1545
+ };
1546
+ throw new ProvenanceMarkError("ValidationError", `hash mismatch: expected ${bytesToHex(expectedHash)}, got ${bytesToHex(this._hash)}`, { validationIssue: issue });
1547
+ }
981
1548
  }
982
1549
  /**
983
1550
  * Check if a sequence of marks is valid.
@@ -998,35 +1565,61 @@ var ProvenanceMark = class ProvenanceMark {
998
1565
  * Encode as bytewords with the given style.
999
1566
  */
1000
1567
  toBytewordsWithStyle(style) {
1001
- return (0, __bcts_uniform_resources.encodeBytewords)(this.message(), style);
1568
+ return (0, _bcts_uniform_resources.encodeBytewords)(this.message(), style);
1002
1569
  }
1003
1570
  /**
1004
1571
  * Encode as standard bytewords.
1005
1572
  */
1006
1573
  toBytewords() {
1007
- return this.toBytewordsWithStyle(__bcts_uniform_resources.BytewordsStyle.Standard);
1574
+ return this.toBytewordsWithStyle(_bcts_uniform_resources.BytewordsStyle.Standard);
1008
1575
  }
1009
1576
  /**
1010
1577
  * Decode from bytewords.
1011
1578
  */
1012
1579
  static fromBytewords(res, bytewords) {
1013
- const message = (0, __bcts_uniform_resources.decodeBytewords)(bytewords, __bcts_uniform_resources.BytewordsStyle.Standard);
1580
+ const message = (0, _bcts_uniform_resources.decodeBytewords)(bytewords, _bcts_uniform_resources.BytewordsStyle.Standard);
1014
1581
  return ProvenanceMark.fromMessage(res, message);
1015
1582
  }
1016
1583
  /**
1017
- * Encode for URL (minimal bytewords of CBOR).
1584
+ * Encode for URL (minimal bytewords of tagged CBOR).
1018
1585
  */
1019
1586
  toUrlEncoding() {
1020
- return (0, __bcts_uniform_resources.encodeBytewords)(this.toCborData(), __bcts_uniform_resources.BytewordsStyle.Minimal);
1587
+ return (0, _bcts_uniform_resources.encodeBytewords)(this.toCborData(), _bcts_uniform_resources.BytewordsStyle.Minimal);
1021
1588
  }
1022
1589
  /**
1023
1590
  * Decode from URL encoding.
1024
1591
  */
1025
1592
  static fromUrlEncoding(urlEncoding) {
1026
- const cborValue = (0, __bcts_dcbor.decodeCbor)((0, __bcts_uniform_resources.decodeBytewords)(urlEncoding, __bcts_uniform_resources.BytewordsStyle.Minimal));
1593
+ const cborValue = (0, _bcts_dcbor.decodeCbor)((0, _bcts_uniform_resources.decodeBytewords)(urlEncoding, _bcts_uniform_resources.BytewordsStyle.Minimal));
1027
1594
  return ProvenanceMark.fromTaggedCbor(cborValue);
1028
1595
  }
1029
1596
  /**
1597
+ * Returns the {@link UR} representation of this mark (untagged CBOR
1598
+ * with type `"provenance"`).
1599
+ *
1600
+ * Mirrors Rust `UREncodable::ur()` for `ProvenanceMark` — the
1601
+ * blanket impl on `CBORTaggedEncodable` produces a UR whose
1602
+ * payload is the *untagged* CBOR (the type name itself stands in
1603
+ * for the tag). See `bc-ur-rust/src/ur_encodable.rs:8-18`.
1604
+ */
1605
+ ur() {
1606
+ return _bcts_uniform_resources.UR.new("provenance", this.untaggedCbor());
1607
+ }
1608
+ /**
1609
+ * Get the UR string representation (e.g., "ur:provenance/...").
1610
+ */
1611
+ urString() {
1612
+ return this.ur().string();
1613
+ }
1614
+ /**
1615
+ * Create from a UR string.
1616
+ */
1617
+ static fromURString(urString) {
1618
+ const ur = _bcts_uniform_resources.UR.fromURString(urString);
1619
+ if (ur.urTypeStr() !== "provenance") throw new ProvenanceMarkError("CborError", void 0, { message: `Expected UR type 'provenance', got '${ur.urTypeStr()}'` });
1620
+ return ProvenanceMark.fromUntaggedCbor(ur.cbor());
1621
+ }
1622
+ /**
1030
1623
  * Build a URL with this mark as a query parameter.
1031
1624
  */
1032
1625
  toUrl(base) {
@@ -1039,21 +1632,21 @@ var ProvenanceMark = class ProvenanceMark {
1039
1632
  */
1040
1633
  static fromUrl(url) {
1041
1634
  const param = url.searchParams.get("provenance");
1042
- if (param === null || param === "") throw new ProvenanceMarkError(ProvenanceMarkErrorType.MissingUrlParameter, void 0, { parameter: "provenance" });
1635
+ if (param === null || param === "") throw new ProvenanceMarkError("MissingUrlParameter", void 0, { parameter: "provenance" });
1043
1636
  return ProvenanceMark.fromUrlEncoding(param);
1044
1637
  }
1045
1638
  /**
1046
1639
  * Get the untagged CBOR representation.
1047
1640
  */
1048
1641
  untaggedCbor() {
1049
- return (0, __bcts_dcbor.cbor)([resolutionToCbor(this._res), (0, __bcts_dcbor.cbor)(this.message())]);
1642
+ return (0, _bcts_dcbor.cbor)([resolutionToCbor(this._res), (0, _bcts_dcbor.cbor)(this.message())]);
1050
1643
  }
1051
1644
  /**
1052
1645
  * Get the tagged CBOR representation.
1053
1646
  */
1054
1647
  taggedCbor() {
1055
- return (0, __bcts_dcbor.cbor)({
1056
- tag: __bcts_tags.PROVENANCE_MARK.value,
1648
+ return (0, _bcts_dcbor.cbor)({
1649
+ tag: _bcts_tags.PROVENANCE_MARK.value,
1057
1650
  value: this.untaggedCbor()
1058
1651
  });
1059
1652
  }
@@ -1061,16 +1654,16 @@ var ProvenanceMark = class ProvenanceMark {
1061
1654
  * Serialize to CBOR bytes (tagged).
1062
1655
  */
1063
1656
  toCborData() {
1064
- return (0, __bcts_dcbor.cborData)(this.taggedCbor());
1657
+ return (0, _bcts_dcbor.cborData)(this.taggedCbor());
1065
1658
  }
1066
1659
  /**
1067
1660
  * Create from untagged CBOR.
1068
1661
  */
1069
1662
  static fromUntaggedCbor(cborValue) {
1070
- const arr = (0, __bcts_dcbor.expectArray)(cborValue);
1071
- if (arr.length !== 2) throw new ProvenanceMarkError(ProvenanceMarkErrorType.CborError, void 0, { message: "Invalid provenance mark length" });
1663
+ const arr = (0, _bcts_dcbor.expectArray)(cborValue);
1664
+ if (arr.length !== 2) throw new ProvenanceMarkError("CborError", void 0, { message: "Invalid provenance mark length" });
1072
1665
  const res = resolutionFromCbor(arr[0]);
1073
- const message = (0, __bcts_dcbor.expectBytes)(arr[1]);
1666
+ const message = (0, _bcts_dcbor.expectBytes)(arr[1]);
1074
1667
  return ProvenanceMark.fromMessage(res, message);
1075
1668
  }
1076
1669
  /**
@@ -1078,15 +1671,15 @@ var ProvenanceMark = class ProvenanceMark {
1078
1671
  */
1079
1672
  static fromTaggedCbor(cborValue) {
1080
1673
  const cborObj = cborValue;
1081
- if (cborObj.tag !== __bcts_tags.PROVENANCE_MARK.value) throw new ProvenanceMarkError(ProvenanceMarkErrorType.CborError, void 0, { message: `Expected tag ${__bcts_tags.PROVENANCE_MARK.value}, got ${String(cborObj.tag)}` });
1082
- if (cborObj.value === void 0) throw new ProvenanceMarkError(ProvenanceMarkErrorType.CborError, void 0, { message: "Tagged CBOR value is missing" });
1674
+ if (cborObj.tag !== _bcts_tags.PROVENANCE_MARK.value) throw new ProvenanceMarkError("CborError", void 0, { message: `Expected tag ${_bcts_tags.PROVENANCE_MARK.value}, got ${String(cborObj.tag)}` });
1675
+ if (cborObj.value === void 0) throw new ProvenanceMarkError("CborError", void 0, { message: "Tagged CBOR value is missing" });
1083
1676
  return ProvenanceMark.fromUntaggedCbor(cborObj.value);
1084
1677
  }
1085
1678
  /**
1086
1679
  * Create from CBOR bytes.
1087
1680
  */
1088
1681
  static fromCborData(data) {
1089
- const cborValue = (0, __bcts_dcbor.decodeCbor)(data);
1682
+ const cborValue = (0, _bcts_dcbor.decodeCbor)(data);
1090
1683
  return ProvenanceMark.fromTaggedCbor(cborValue);
1091
1684
  }
1092
1685
  /**
@@ -1097,23 +1690,42 @@ var ProvenanceMark = class ProvenanceMark {
1097
1690
  }
1098
1691
  /**
1099
1692
  * Debug string representation.
1693
+ *
1694
+ * As of provenance-mark v0.24, this includes the full 64-character Mark ID
1695
+ * hex (matching rust's `Display` impl). Pre-v0.24 callers that depended on
1696
+ * the 8-character prefix should use `idHex().slice(0, 8)` directly.
1100
1697
  */
1101
1698
  toString() {
1102
- return `ProvenanceMark(${this.identifier()})`;
1699
+ return `ProvenanceMark(${this.idHex()})`;
1103
1700
  }
1104
1701
  /**
1105
1702
  * Detailed debug representation.
1703
+ *
1704
+ * Mirrors Rust `Mark::Debug` exactly: every field is rendered
1705
+ * Rust-style (hex bytes for keys/hashes/IDs, plain integer for
1706
+ * `seq`, `Date::Display` for the date). The Low-resolution test
1707
+ * vector in Rust `tests/mark.rs::test_low_resolution` ends with
1708
+ * `date: 2023-06-20` — i.e. midnight-UTC dates are rendered without
1709
+ * a time suffix. We use {@link dateToDisplay} to mirror that
1710
+ * exactly; earlier revisions of this port stripped just the
1711
+ * `.000Z` fractional component, which left `2023-06-20T00:00:00Z`
1712
+ * and broke the Low-resolution debug-string parity.
1106
1713
  */
1107
1714
  toDebugString() {
1715
+ const dateStr = dateToDisplay(this._date);
1108
1716
  const components = [
1109
1717
  `key: ${bytesToHex(this._key)}`,
1110
1718
  `hash: ${bytesToHex(this._hash)}`,
1111
1719
  `chainID: ${bytesToHex(this._chainId)}`,
1112
1720
  `seq: ${this._seq}`,
1113
- `date: ${this._date.toISOString()}`
1721
+ `date: ${dateStr}`
1114
1722
  ];
1115
1723
  const info = this.info();
1116
- if (info !== void 0) components.push(`info: ${JSON.stringify(info)}`);
1724
+ if (info !== void 0) {
1725
+ const textValue = info.asText();
1726
+ if (textValue !== void 0) components.push(`info: "${textValue}"`);
1727
+ else components.push(`info: ${info.toDiagnostic()}`);
1728
+ }
1117
1729
  return `ProvenanceMark(${components.join(", ")})`;
1118
1730
  }
1119
1731
  /**
@@ -1123,16 +1735,20 @@ var ProvenanceMark = class ProvenanceMark {
1123
1735
  return this._res === other._res && arraysEqual(this.message(), other.message());
1124
1736
  }
1125
1737
  /**
1126
- * JSON serialization.
1738
+ * JSON serialization. Field order, names, and date format mirror Rust's
1739
+ * `#[derive(Serialize)]` on `ProvenanceMark` (provenance-mark-rust/src/mark.rs):
1740
+ * `seq, date, res, chain_id, key, hash[, info_bytes]`. The date uses
1741
+ * `dateToDisplay()` (date-only when midnight, RFC3339-seconds with `Z`
1742
+ * otherwise), matching Rust's `serialize_iso8601` / `Date::to_string()`.
1127
1743
  */
1128
1744
  toJSON() {
1129
1745
  const result = {
1746
+ seq: this._seq,
1747
+ date: dateToDisplay(this._date),
1130
1748
  res: this._res,
1749
+ chain_id: toBase64(this._chainId),
1131
1750
  key: toBase64(this._key),
1132
- hash: toBase64(this._hash),
1133
- chainID: toBase64(this._chainId),
1134
- seq: this._seq,
1135
- date: this._date.toISOString()
1751
+ hash: toBase64(this._hash)
1136
1752
  };
1137
1753
  if (this._infoBytes.length > 0) result["info_bytes"] = toBase64(this._infoBytes);
1138
1754
  return result;
@@ -1144,15 +1760,54 @@ var ProvenanceMark = class ProvenanceMark {
1144
1760
  const res = json["res"];
1145
1761
  const key = fromBase64(json["key"]);
1146
1762
  const hash = fromBase64(json["hash"]);
1147
- const chainId = fromBase64(json["chainID"]);
1763
+ const chainId = fromBase64(json["chain_id"] ?? json["chainID"]);
1148
1764
  const seq = json["seq"];
1149
1765
  const dateStr = json["date"];
1150
1766
  const date = new Date(dateStr);
1151
1767
  const seqBytes = serializeSeq(res, seq);
1152
1768
  const dateBytes = serializeDate(res, date);
1153
1769
  let infoBytes = new Uint8Array(0);
1154
- if (typeof json["info_bytes"] === "string") infoBytes = fromBase64(json["info_bytes"]);
1155
- return new ProvenanceMark(res, key, hash, chainId, seqBytes, dateBytes, infoBytes, seq, date);
1770
+ if (typeof json["info_bytes"] === "string") {
1771
+ infoBytes = fromBase64(json["info_bytes"]);
1772
+ if (infoBytes.length > 0) try {
1773
+ (0, _bcts_dcbor.decodeCbor)(infoBytes);
1774
+ } catch (e) {
1775
+ throw new ProvenanceMarkError("CborError", "info_bytes is not valid CBOR", { details: e instanceof Error ? e.message : String(e) });
1776
+ }
1777
+ }
1778
+ return new ProvenanceMark(res, key, hash, chainId, seqBytes, dateBytes, infoBytes, seq, date);
1779
+ }
1780
+ /**
1781
+ * Validate a collection of provenance marks.
1782
+ *
1783
+ * Matches Rust: `ProvenanceMark::validate()` which delegates to
1784
+ * `ValidationReport::validate()`.
1785
+ */
1786
+ static validate(marks) {
1787
+ return validate(marks);
1788
+ }
1789
+ /**
1790
+ * Convert this provenance mark to a Gordian Envelope.
1791
+ *
1792
+ * Creates a leaf envelope containing the tagged CBOR representation.
1793
+ * Matches Rust: `Envelope::new(mark.to_cbor())` which creates a CBOR leaf.
1794
+ */
1795
+ intoEnvelope() {
1796
+ return _bcts_envelope.Envelope.newLeaf(this.taggedCbor());
1797
+ }
1798
+ /**
1799
+ * Extract a ProvenanceMark from a Gordian Envelope.
1800
+ *
1801
+ * Matches Rust: `envelope.subject().try_leaf()?.try_into()`
1802
+ *
1803
+ * @param envelope - The envelope to extract from
1804
+ * @returns The extracted provenance mark
1805
+ * @throws ProvenanceMarkError if extraction fails
1806
+ */
1807
+ static fromEnvelope(envelope) {
1808
+ const leaf = envelope.subject().asLeaf();
1809
+ if (leaf !== void 0) return ProvenanceMark.fromTaggedCbor(leaf);
1810
+ throw new ProvenanceMarkError("CborError", void 0, { message: "Could not extract ProvenanceMark from envelope" });
1156
1811
  }
1157
1812
  };
1158
1813
  /**
@@ -1163,10 +1818,14 @@ function arraysEqual(a, b) {
1163
1818
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
1164
1819
  return true;
1165
1820
  }
1166
-
1167
1821
  //#endregion
1168
1822
  //#region src/generator.ts
1169
1823
  /**
1824
+ * Copyright © 2023-2026 Blockchain Commons, LLC
1825
+ * Copyright © 2025-2026 Parity Technologies
1826
+ *
1827
+ */
1828
+ /**
1170
1829
  * Generator for creating provenance mark chains.
1171
1830
  */
1172
1831
  var ProvenanceMarkGenerator = class ProvenanceMarkGenerator {
@@ -1216,8 +1875,8 @@ var ProvenanceMarkGenerator = class ProvenanceMarkGenerator {
1216
1875
  /**
1217
1876
  * Create a new generator with custom random data.
1218
1877
  */
1219
- static newUsing(res, randomData$1) {
1220
- const seed = ProvenanceSeed.newUsing(randomData$1);
1878
+ static newUsing(res, randomData) {
1879
+ const seed = ProvenanceSeed.newUsing(randomData);
1221
1880
  return ProvenanceMarkGenerator.newWithSeed(res, seed);
1222
1881
  }
1223
1882
  /**
@@ -1232,7 +1891,7 @@ var ProvenanceMarkGenerator = class ProvenanceMarkGenerator {
1232
1891
  */
1233
1892
  static new(res, seed, chainId, nextSeq, rngState) {
1234
1893
  const linkLen = linkLength(res);
1235
- if (chainId.length !== linkLen) throw new ProvenanceMarkError(ProvenanceMarkErrorType.InvalidChainIdLength, void 0, {
1894
+ if (chainId.length !== linkLen) throw new ProvenanceMarkError("InvalidChainIdLength", void 0, {
1236
1895
  expected: linkLen,
1237
1896
  actual: chainId.length
1238
1897
  });
@@ -1258,9 +1917,24 @@ var ProvenanceMarkGenerator = class ProvenanceMarkGenerator {
1258
1917
  }
1259
1918
  /**
1260
1919
  * String representation.
1920
+ *
1921
+ * Mirrors Rust `Display for ProvenanceMarkGenerator`
1922
+ * (`provenance-mark-rust/src/generator.rs:135-147`):
1923
+ *
1924
+ * ```rust
1925
+ * write!(f, "ProvenanceMarkGenerator(chainID: {}, res: {}, seed: {}, nextSeq: {}, rngState: {:?})",
1926
+ * hex::encode(&self.chain_id), self.res, self.seed.hex(), self.next_seq, self.rng_state)
1927
+ * ```
1928
+ *
1929
+ * The `rngState` field uses Rust's `{:?}` (Debug) format, which on a
1930
+ * `RngState([u8; 32])` tuple struct produces `RngState([n0, n1, ...])`
1931
+ * with each byte rendered as a decimal integer. Earlier revisions of
1932
+ * this port omitted `rngState` entirely from `toString()`, so the
1933
+ * output diverged from Rust's `Display`.
1261
1934
  */
1262
1935
  toString() {
1263
- return `ProvenanceMarkGenerator(chainID: ${bytesToHex(this._chainId)}, res: ${this._res}, seed: ${this._seed.hex()}, nextSeq: ${this._nextSeq})`;
1936
+ const rngBytes = Array.from(this._rngState.toBytes()).join(", ");
1937
+ return `ProvenanceMarkGenerator(chainID: ${bytesToHex(this._chainId)}, res: ${this._res}, seed: ${this._seed.hex()}, nextSeq: ${this._nextSeq}, rngState: RngState([${rngBytes}]))`;
1264
1938
  }
1265
1939
  /**
1266
1940
  * JSON serialization.
@@ -1285,278 +1959,64 @@ var ProvenanceMarkGenerator = class ProvenanceMarkGenerator {
1285
1959
  const rngState = RngState.fromBytes(fromBase64(json["rngState"]));
1286
1960
  return ProvenanceMarkGenerator.new(res, seed, chainId, nextSeq, rngState);
1287
1961
  }
1288
- };
1289
-
1290
- //#endregion
1291
- //#region src/validate.ts
1292
- /**
1293
- * Format for validation report output.
1294
- */
1295
- let ValidationReportFormat = /* @__PURE__ */ function(ValidationReportFormat$1) {
1296
- /** Human-readable text format */
1297
- ValidationReportFormat$1["Text"] = "text";
1298
- /** Compact JSON format (no whitespace) */
1299
- ValidationReportFormat$1["JsonCompact"] = "json-compact";
1300
- /** Pretty-printed JSON format (with indentation) */
1301
- ValidationReportFormat$1["JsonPretty"] = "json-pretty";
1302
- return ValidationReportFormat$1;
1303
- }({});
1304
- /**
1305
- * Format a validation issue as a string.
1306
- */
1307
- function formatValidationIssue(issue) {
1308
- switch (issue.type) {
1309
- case "HashMismatch": return `hash mismatch: expected ${issue.expected}, got ${issue.actual}`;
1310
- case "KeyMismatch": return "key mismatch: current hash was not generated from next key";
1311
- case "SequenceGap": return `sequence number gap: expected ${issue.expected}, got ${issue.actual}`;
1312
- case "DateOrdering": return `date must be equal or later: previous is ${issue.previous}, next is ${issue.next}`;
1313
- case "NonGenesisAtZero": return "non-genesis mark at sequence 0";
1314
- case "InvalidGenesisKey": return "genesis mark must have key equal to chain_id";
1315
- }
1316
- }
1317
- /**
1318
- * Get the chain ID as a hex string for display.
1319
- */
1320
- function chainIdHex(report) {
1321
- return hexEncode(report.chainId);
1322
- }
1323
- /**
1324
- * Check if the validation report has any issues.
1325
- */
1326
- function hasIssues(report) {
1327
- for (const chain of report.chains) if (!chain.hasGenesis) return true;
1328
- for (const chain of report.chains) for (const seq of chain.sequences) for (const mark of seq.marks) if (mark.issues.length > 0) return true;
1329
- if (report.chains.length > 1) return true;
1330
- if (report.chains.length === 1 && report.chains[0].sequences.length > 1) return true;
1331
- return false;
1332
- }
1333
- /**
1334
- * Check if the validation report contains interesting information.
1335
- */
1336
- function isInteresting(report) {
1337
- if (report.chains.length === 0) return false;
1338
- for (const chain of report.chains) if (!chain.hasGenesis) return true;
1339
- if (report.chains.length === 1) {
1340
- const chain = report.chains[0];
1341
- if (chain.sequences.length === 1) {
1342
- if (chain.sequences[0].marks.every((m) => m.issues.length === 0)) return false;
1343
- }
1344
- }
1345
- return true;
1346
- }
1347
- /**
1348
- * Format the validation report as human-readable text.
1349
- */
1350
- function formatText(report) {
1351
- if (!isInteresting(report)) return "";
1352
- const lines = [];
1353
- lines.push(`Total marks: ${report.marks.length}`);
1354
- lines.push(`Chains: ${report.chains.length}`);
1355
- lines.push("");
1356
- for (let chainIdx = 0; chainIdx < report.chains.length; chainIdx++) {
1357
- const chain = report.chains[chainIdx];
1358
- const chainIdStr = chainIdHex(chain);
1359
- const shortChainId = chainIdStr.length > 8 ? chainIdStr.slice(0, 8) : chainIdStr;
1360
- lines.push(`Chain ${chainIdx + 1}: ${shortChainId}`);
1361
- if (!chain.hasGenesis) lines.push(" Warning: No genesis mark found");
1362
- for (const seq of chain.sequences) for (const flaggedMark of seq.marks) {
1363
- const mark = flaggedMark.mark;
1364
- const shortId = mark.identifier();
1365
- const seqNum = mark.seq();
1366
- const annotations = [];
1367
- if (mark.isGenesis()) annotations.push("genesis mark");
1368
- for (const issue of flaggedMark.issues) {
1369
- let issueStr;
1370
- switch (issue.type) {
1371
- case "SequenceGap":
1372
- issueStr = `gap: ${issue.expected} missing`;
1373
- break;
1374
- case "DateOrdering":
1375
- issueStr = `date ${issue.previous} < ${issue.next}`;
1376
- break;
1377
- case "HashMismatch":
1378
- issueStr = "hash mismatch";
1379
- break;
1380
- case "KeyMismatch":
1381
- issueStr = "key mismatch";
1382
- break;
1383
- case "NonGenesisAtZero":
1384
- issueStr = "non-genesis at seq 0";
1385
- break;
1386
- case "InvalidGenesisKey":
1387
- issueStr = "invalid genesis key";
1388
- break;
1389
- }
1390
- annotations.push(issueStr);
1391
- }
1392
- if (annotations.length === 0) lines.push(` ${seqNum}: ${shortId}`);
1393
- else lines.push(` ${seqNum}: ${shortId} (${annotations.join(", ")})`);
1394
- }
1395
- lines.push("");
1396
- }
1397
- return lines.join("\n").trimEnd();
1398
- }
1399
- /**
1400
- * Format the validation report.
1401
- */
1402
- function formatReport(report, format) {
1403
- switch (format) {
1404
- case ValidationReportFormat.Text: return formatText(report);
1405
- case ValidationReportFormat.JsonCompact: return JSON.stringify(reportToJSON(report));
1406
- case ValidationReportFormat.JsonPretty: return JSON.stringify(reportToJSON(report), null, 2);
1407
- }
1408
- }
1409
- /**
1410
- * Convert a report to a JSON-serializable object.
1411
- */
1412
- function reportToJSON(report) {
1413
- return {
1414
- marks: report.marks.map((m) => m.toUrlEncoding()),
1415
- chains: report.chains.map((chain) => ({
1416
- chain_id: hexEncode(chain.chainId),
1417
- has_genesis: chain.hasGenesis,
1418
- marks: chain.marks.map((m) => m.toUrlEncoding()),
1419
- sequences: chain.sequences.map((seq) => ({
1420
- start_seq: seq.startSeq,
1421
- end_seq: seq.endSeq,
1422
- marks: seq.marks.map((fm) => ({
1423
- mark: fm.mark.toUrlEncoding(),
1424
- issues: fm.issues
1425
- }))
1426
- }))
1427
- }))
1428
- };
1429
- }
1430
- /**
1431
- * Build sequence bins for a chain.
1432
- */
1433
- function buildSequenceBins(marks) {
1434
- const sequences = [];
1435
- let currentSequence = [];
1436
- for (let i = 0; i < marks.length; i++) {
1437
- const mark = marks[i];
1438
- if (i === 0) currentSequence.push({
1439
- mark,
1440
- issues: []
1441
- });
1442
- else {
1443
- const prev = marks[i - 1];
1444
- try {
1445
- prev.precedesOpt(mark);
1446
- currentSequence.push({
1447
- mark,
1448
- issues: []
1449
- });
1450
- } catch (e) {
1451
- if (currentSequence.length > 0) sequences.push(createSequenceReport(currentSequence));
1452
- currentSequence = [{
1453
- mark,
1454
- issues: [parseValidationError(e, prev, mark)]
1455
- }];
1456
- }
1457
- }
1458
- }
1459
- if (currentSequence.length > 0) sequences.push(createSequenceReport(currentSequence));
1460
- return sequences;
1461
- }
1462
- /**
1463
- * Parse a validation error into a ValidationIssue.
1464
- */
1465
- function parseValidationError(e, prev, next) {
1466
- const message = e instanceof Error ? e.message : "";
1467
- if (message !== "" && message.includes("non-genesis mark at sequence 0")) return { type: "NonGenesisAtZero" };
1468
- if (message !== "" && message.includes("genesis mark must have key equal to chain_id")) return { type: "InvalidGenesisKey" };
1469
- if (message !== "" && message.includes("sequence gap")) {
1470
- const match = /expected (\d+), got (\d+)/.exec(message);
1471
- if (match !== null) return {
1472
- type: "SequenceGap",
1473
- expected: parseInt(match[1], 10),
1474
- actual: parseInt(match[2], 10)
1475
- };
1476
- }
1477
- if (message !== "" && message.includes("date ordering")) return {
1478
- type: "DateOrdering",
1479
- previous: prev.date().toISOString(),
1480
- next: next.date().toISOString()
1481
- };
1482
- if (message !== "" && message.includes("hash mismatch")) {
1483
- const match = /expected: (\w+), actual: (\w+)/.exec(message);
1484
- if (match !== null) return {
1485
- type: "HashMismatch",
1486
- expected: match[1],
1487
- actual: match[2]
1488
- };
1489
- return {
1490
- type: "HashMismatch",
1491
- expected: "",
1492
- actual: ""
1962
+ /**
1963
+ * Convert this generator to a Gordian Envelope.
1964
+ *
1965
+ * The envelope contains structured assertions for all generator fields:
1966
+ * - isA: "provenance-generator"
1967
+ * - res: The resolution
1968
+ * - seed: The seed
1969
+ * - next-seq: The next sequence number
1970
+ * - rng-state: The RNG state
1971
+ *
1972
+ * Note: Use provenanceMarkGeneratorToEnvelope() for a standalone function alternative.
1973
+ */
1974
+ intoEnvelope() {
1975
+ let envelope = _bcts_envelope.Envelope.new(this._chainId);
1976
+ envelope = envelope.addType("provenance-generator");
1977
+ envelope = envelope.addAssertion("res", resolutionToNumber(this._res));
1978
+ envelope = envelope.addAssertion("seed", this._seed.toBytes());
1979
+ envelope = envelope.addAssertion("next-seq", this._nextSeq);
1980
+ envelope = envelope.addAssertion("rng-state", this._rngState.toBytes());
1981
+ return envelope;
1982
+ }
1983
+ /**
1984
+ * Extract a ProvenanceMarkGenerator from a Gordian Envelope.
1985
+ *
1986
+ * @param envelope - The envelope to extract from
1987
+ * @returns The extracted generator
1988
+ * @throws ProvenanceMarkError if extraction fails
1989
+ */
1990
+ static fromEnvelope(envelope) {
1991
+ const env = envelope;
1992
+ if (!env.hasType("provenance-generator")) throw new ProvenanceMarkError("CborError", void 0, { message: "Envelope is not a provenance-generator" });
1993
+ const chainId = env.subject().asByteString();
1994
+ if (chainId === void 0) throw new ProvenanceMarkError("CborError", void 0, { message: "Could not extract chain ID" });
1995
+ const extractAssertion = (predicate) => {
1996
+ const assertions = env.assertionsWithPredicate(predicate);
1997
+ if (assertions.length === 0) throw new ProvenanceMarkError("CborError", void 0, { message: `Missing ${predicate} assertion` });
1998
+ const assertionCase = assertions[0].case();
1999
+ if (assertionCase.type !== "assertion") throw new ProvenanceMarkError("CborError", void 0, { message: `Invalid ${predicate} assertion` });
2000
+ const obj = assertionCase.assertion.object();
2001
+ const objCase = obj.case();
2002
+ if (objCase.type === "leaf") return {
2003
+ cbor: objCase.cbor,
2004
+ bytes: obj.asByteString()
2005
+ };
2006
+ throw new ProvenanceMarkError("CborError", void 0, { message: `Invalid ${predicate} value` });
1493
2007
  };
2008
+ const res = resolutionFromCbor(extractAssertion("res").cbor);
2009
+ const seedValue = extractAssertion("seed");
2010
+ if (seedValue.bytes === void 0) throw new ProvenanceMarkError("CborError", void 0, { message: "Invalid seed data" });
2011
+ const seed = ProvenanceSeed.fromBytes(seedValue.bytes);
2012
+ const seqValue = extractAssertion("next-seq");
2013
+ const nextSeq = Number(seqValue.cbor);
2014
+ const rngValue = extractAssertion("rng-state");
2015
+ if (rngValue.bytes === void 0) throw new ProvenanceMarkError("CborError", void 0, { message: "Invalid rng-state data" });
2016
+ const rngState = RngState.fromBytes(rngValue.bytes);
2017
+ return ProvenanceMarkGenerator.new(res, seed, chainId, nextSeq, rngState);
1494
2018
  }
1495
- return { type: "KeyMismatch" };
1496
- }
1497
- /**
1498
- * Create a sequence report from flagged marks.
1499
- */
1500
- function createSequenceReport(marks) {
1501
- return {
1502
- startSeq: marks.length > 0 ? marks[0].mark.seq() : 0,
1503
- endSeq: marks.length > 0 ? marks[marks.length - 1].mark.seq() : 0,
1504
- marks
1505
- };
1506
- }
1507
- /**
1508
- * Validate a collection of provenance marks.
1509
- */
1510
- function validate(marks) {
1511
- const seen = /* @__PURE__ */ new Set();
1512
- const deduplicatedMarks = [];
1513
- for (const mark of marks) {
1514
- const key = mark.toUrlEncoding();
1515
- if (!seen.has(key)) {
1516
- seen.add(key);
1517
- deduplicatedMarks.push(mark);
1518
- }
1519
- }
1520
- const chainBins = /* @__PURE__ */ new Map();
1521
- for (const mark of deduplicatedMarks) {
1522
- const chainIdKey = hexEncode(mark.chainId());
1523
- const bin = chainBins.get(chainIdKey);
1524
- if (bin !== void 0) bin.push(mark);
1525
- else chainBins.set(chainIdKey, [mark]);
1526
- }
1527
- const chains = [];
1528
- for (const [chainIdKey, chainMarks] of chainBins) {
1529
- chainMarks.sort((a, b) => a.seq() - b.seq());
1530
- const hasGenesis = chainMarks.length > 0 && chainMarks[0].seq() === 0 && chainMarks[0].isGenesis();
1531
- const sequences = buildSequenceBins(chainMarks);
1532
- chains.push({
1533
- chainId: hexDecode(chainIdKey),
1534
- hasGenesis,
1535
- marks: chainMarks,
1536
- sequences
1537
- });
1538
- }
1539
- chains.sort((a, b) => hexEncode(a.chainId).localeCompare(hexEncode(b.chainId)));
1540
- return {
1541
- marks: deduplicatedMarks,
1542
- chains
1543
- };
1544
- }
1545
- /**
1546
- * Helper function to encode bytes as hex.
1547
- */
1548
- function hexEncode(bytes) {
1549
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1550
- }
1551
- /**
1552
- * Helper function to decode hex to bytes.
1553
- */
1554
- function hexDecode(hex) {
1555
- const bytes = new Uint8Array(hex.length / 2);
1556
- for (let i = 0; i < hex.length; i += 2) bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
1557
- return bytes;
1558
- }
1559
-
2019
+ };
1560
2020
  //#endregion
1561
2021
  //#region src/mark-info.ts
1562
2022
  /**
@@ -1577,12 +2037,19 @@ var ProvenanceMarkInfo = class ProvenanceMarkInfo {
1577
2037
  }
1578
2038
  /**
1579
2039
  * Create a new ProvenanceMarkInfo from a mark.
2040
+ *
2041
+ * Mirrors Rust `ProvenanceMarkInfo::new`
2042
+ * (`provenance-mark-rust/src/mark_info.rs`), which calls
2043
+ * `mark.ur()` — i.e. the `UREncodable` implementation, whose
2044
+ * payload is the **untagged** CBOR with type `"provenance"`. Earlier
2045
+ * revisions of this port called `decodeCbor(mark.toCborData())` and
2046
+ * wrapped the resulting *tagged* CBOR in `UR.new("provenance", ...)`,
2047
+ * which prepended the CBOR tag to the UR bytewords and broke
2048
+ * cross-impl interop (UR strings produced by Rust would not parse,
2049
+ * and vice versa).
1580
2050
  */
1581
2051
  static new(mark, comment = "") {
1582
- const tagName = __bcts_tags.PROVENANCE_MARK.name;
1583
- if (tagName === void 0) throw new Error("PROVENANCE_MARK tag has no name");
1584
- const cborValue = (0, __bcts_dcbor.decodeCbor)(mark.toCborData());
1585
- return new ProvenanceMarkInfo(mark, __bcts_uniform_resources.UR.new(tagName, cborValue), mark.bytewordsIdentifier(true), mark.bytemojiIdentifier(true), comment);
2052
+ return new ProvenanceMarkInfo(mark, mark.ur(), mark.idBytewords(4, true), mark.idBytemoji(4, true), comment);
1586
2053
  }
1587
2054
  mark() {
1588
2055
  return this._mark;
@@ -1601,12 +2068,16 @@ var ProvenanceMarkInfo = class ProvenanceMarkInfo {
1601
2068
  }
1602
2069
  /**
1603
2070
  * Generate a markdown summary of the mark.
2071
+ *
2072
+ * Date rendering uses {@link dateToDisplay} so midnight-UTC dates
2073
+ * appear as `YYYY-MM-DD` (matching Rust `format!("{}",
2074
+ * self.mark.date())`), not as `YYYY-MM-DDT00:00:00Z`.
1604
2075
  */
1605
2076
  markdownSummary() {
1606
2077
  const lines = [];
1607
2078
  lines.push("---");
1608
2079
  lines.push("");
1609
- lines.push(this._mark.date().toISOString());
2080
+ lines.push(dateToDisplay(this._mark.date()));
1610
2081
  lines.push("");
1611
2082
  lines.push(`#### ${this._ur.toString()}`);
1612
2083
  lines.push("");
@@ -1621,33 +2092,142 @@ var ProvenanceMarkInfo = class ProvenanceMarkInfo {
1621
2092
  return lines.join("\n");
1622
2093
  }
1623
2094
  /**
1624
- * JSON serialization.
2095
+ * JSON serialization. Field order mirrors Rust's `#[derive(Serialize)]`
2096
+ * on `ProvenanceMarkInfo` (provenance-mark-rust/src/mark_info.rs):
2097
+ * `ur, bytewords, bytemoji, [comment,] mark` — `comment` (when present)
2098
+ * comes BEFORE `mark`. Rust uses `skip_serializing_if = "String::is_empty"`,
2099
+ * matched here by the `if (...length > 0)` guard.
1625
2100
  */
1626
2101
  toJSON() {
1627
2102
  const result = {
1628
2103
  ur: this._ur.toString(),
1629
2104
  bytewords: this._bytewords,
1630
- bytemoji: this._bytemoji,
1631
- mark: this._mark.toJSON()
2105
+ bytemoji: this._bytemoji
1632
2106
  };
1633
2107
  if (this._comment.length > 0) result["comment"] = this._comment;
2108
+ result["mark"] = this._mark.toJSON();
1634
2109
  return result;
1635
2110
  }
1636
2111
  /**
1637
2112
  * Create from JSON object.
2113
+ *
2114
+ * Decodes the UR string through {@link ProvenanceMark.fromURString},
2115
+ * which correctly handles the **untagged** CBOR payload that
2116
+ * `mark.ur()` produces — symmetric with the constructor.
1638
2117
  */
1639
2118
  static fromJSON(json) {
1640
2119
  const urString = json["ur"];
1641
- const ur = __bcts_uniform_resources.UR.fromURString(urString);
1642
- const cborBytes = (0, __bcts_dcbor.cborData)(ur.cbor());
1643
- const mark = ProvenanceMark.fromCborData(cborBytes);
2120
+ const mark = ProvenanceMark.fromURString(urString);
2121
+ const ur = mark.ur();
1644
2122
  const bytewords = json["bytewords"];
1645
2123
  const bytemoji = json["bytemoji"];
1646
2124
  return new ProvenanceMarkInfo(mark, ur, bytewords, bytemoji, typeof json["comment"] === "string" ? json["comment"] : "");
1647
2125
  }
1648
2126
  };
1649
-
1650
2127
  //#endregion
2128
+ //#region src/envelope.ts
2129
+ /**
2130
+ * Copyright © 2023-2026 Blockchain Commons, LLC
2131
+ * Copyright © 2025-2026 Parity Technologies
2132
+ *
2133
+ *
2134
+ * Envelope support for Provenance Marks
2135
+ *
2136
+ * This module provides Gordian Envelope integration for ProvenanceMark and
2137
+ * ProvenanceMarkGenerator, enabling them to be used with the bc-envelope
2138
+ * ecosystem.
2139
+ *
2140
+ * Ported from provenance-mark-rust/src/mark.rs and generator.rs (envelope feature)
2141
+ */
2142
+ /**
2143
+ * Registers provenance mark tags in the global format context.
2144
+ *
2145
+ * Matches Rust: register_tags()
2146
+ */
2147
+ function registerTags() {
2148
+ (0, _bcts_envelope.withFormatContextMut)((context) => {
2149
+ registerTagsIn(context);
2150
+ });
2151
+ }
2152
+ /**
2153
+ * Registers provenance mark tags in a specific format context.
2154
+ *
2155
+ * Matches Rust: register_tags_in()
2156
+ *
2157
+ * @param context - The format context to register tags in
2158
+ */
2159
+ function registerTagsIn(context) {
2160
+ (0, _bcts_envelope.registerTagsIn)(context);
2161
+ context.tags().setSummarizer(BigInt(_bcts_tags.PROVENANCE_MARK.value), (untaggedCbor, _flat) => {
2162
+ try {
2163
+ return {
2164
+ ok: true,
2165
+ value: ProvenanceMark.fromUntaggedCbor(untaggedCbor).toString()
2166
+ };
2167
+ } catch {
2168
+ return {
2169
+ ok: false,
2170
+ error: {
2171
+ type: "Custom",
2172
+ message: "invalid provenance mark"
2173
+ }
2174
+ };
2175
+ }
2176
+ });
2177
+ }
2178
+ /**
2179
+ * Convert a ProvenanceMark to an Envelope.
2180
+ *
2181
+ * Delegates to ProvenanceMark.intoEnvelope() — single source of truth.
2182
+ *
2183
+ * @param mark - The provenance mark to convert
2184
+ * @returns An envelope containing the mark
2185
+ */
2186
+ function provenanceMarkToEnvelope(mark) {
2187
+ return mark.intoEnvelope();
2188
+ }
2189
+ /**
2190
+ * Extract a ProvenanceMark from an Envelope.
2191
+ *
2192
+ * Delegates to ProvenanceMark.fromEnvelope() — single source of truth.
2193
+ *
2194
+ * @param envelope - The envelope to extract from
2195
+ * @returns The extracted provenance mark
2196
+ * @throws ProvenanceMarkError if extraction fails
2197
+ */
2198
+ function provenanceMarkFromEnvelope(envelope) {
2199
+ return ProvenanceMark.fromEnvelope(envelope);
2200
+ }
2201
+ /**
2202
+ * Convert a ProvenanceMarkGenerator to an Envelope.
2203
+ *
2204
+ * Delegates to ProvenanceMarkGenerator.intoEnvelope() — single source of truth.
2205
+ *
2206
+ * @param generator - The generator to convert
2207
+ * @returns An envelope containing the generator
2208
+ */
2209
+ function provenanceMarkGeneratorToEnvelope(generator) {
2210
+ return generator.intoEnvelope();
2211
+ }
2212
+ /**
2213
+ * Extract a ProvenanceMarkGenerator from an Envelope.
2214
+ *
2215
+ * Delegates to ProvenanceMarkGenerator.fromEnvelope() — single source of truth.
2216
+ *
2217
+ * @param envelope - The envelope to extract from
2218
+ * @returns The extracted generator
2219
+ * @throws ProvenanceMarkError if extraction fails
2220
+ */
2221
+ function provenanceMarkGeneratorFromEnvelope(envelope) {
2222
+ return ProvenanceMarkGenerator.fromEnvelope(envelope);
2223
+ }
2224
+ //#endregion
2225
+ Object.defineProperty(exports, "FormatContext", {
2226
+ enumerable: true,
2227
+ get: function() {
2228
+ return _bcts_envelope.FormatContext;
2229
+ }
2230
+ });
1651
2231
  exports.PROVENANCE_SEED_LENGTH = PROVENANCE_SEED_LENGTH;
1652
2232
  exports.ProvenanceMark = ProvenanceMark;
1653
2233
  exports.ProvenanceMarkError = ProvenanceMarkError;
@@ -1667,6 +2247,7 @@ exports.dateBytesLength = dateBytesLength;
1667
2247
  exports.dateBytesRange = dateBytesRange;
1668
2248
  exports.dateFromIso8601 = dateFromIso8601;
1669
2249
  exports.dateToDateString = dateToDateString;
2250
+ exports.dateToDisplay = dateToDisplay;
1670
2251
  exports.dateToIso8601 = dateToIso8601;
1671
2252
  exports.deserialize2Bytes = deserialize2Bytes;
1672
2253
  exports.deserialize4Bytes = deserialize4Bytes;
@@ -1684,7 +2265,15 @@ exports.infoRangeStart = infoRangeStart;
1684
2265
  exports.keyRange = keyRange;
1685
2266
  exports.linkLength = linkLength;
1686
2267
  exports.obfuscate = obfuscate;
2268
+ exports.parseDate = parseDate;
2269
+ exports.parseSeed = parseSeed;
2270
+ exports.provenanceMarkFromEnvelope = provenanceMarkFromEnvelope;
2271
+ exports.provenanceMarkGeneratorFromEnvelope = provenanceMarkGeneratorFromEnvelope;
2272
+ exports.provenanceMarkGeneratorToEnvelope = provenanceMarkGeneratorToEnvelope;
2273
+ exports.provenanceMarkToEnvelope = provenanceMarkToEnvelope;
1687
2274
  exports.rangeOfDaysInMonth = rangeOfDaysInMonth;
2275
+ exports.registerTags = registerTags;
2276
+ exports.registerTagsIn = registerTagsIn;
1688
2277
  exports.resolutionFromCbor = resolutionFromCbor;
1689
2278
  exports.resolutionFromNumber = resolutionFromNumber;
1690
2279
  exports.resolutionToCbor = resolutionToCbor;
@@ -1700,4 +2289,5 @@ exports.serializeSeq = serializeSeq;
1700
2289
  exports.sha256 = sha256;
1701
2290
  exports.sha256Prefix = sha256Prefix;
1702
2291
  exports.validate = validate;
2292
+
1703
2293
  //# sourceMappingURL=index.cjs.map