@bcts/provenance-mark 1.0.0-alpha.9 → 1.0.0-beta.1

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