@bcts/dcbor 1.0.0-beta.3 → 1.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4187,13 +4187,19 @@ const tagWithStaticName = (value, name) => ({
4187
4187
  name
4188
4188
  });
4189
4189
  /**
4190
+ * Compare two tag values for equality, normalizing `number` vs `bigint`.
4191
+ * A raw `===` would treat `100n` and `100` as unequal, so a large tag that
4192
+ * decoded to a `bigint` wouldn't match the same value written as a `number`.
4193
+ */
4194
+ const tagValuesEqual = (a, b) => {
4195
+ if (typeof a === "bigint" || typeof b === "bigint") return BigInt(a) === BigInt(b);
4196
+ return a === b;
4197
+ };
4198
+ /**
4190
4199
  * Compare two tags for equality. Mirrors Rust's `PartialEq for Tag`, which
4191
4200
  * compares by `value` only and ignores the optional `name`.
4192
4201
  */
4193
- const tagsEqual = (a, b) => {
4194
- if (typeof a.value === "bigint" || typeof b.value === "bigint") return BigInt(a.value) === BigInt(b.value);
4195
- return a.value === b.value;
4196
- };
4202
+ const tagsEqual = (a, b) => tagValuesEqual(a.value, b.value);
4197
4203
  /**
4198
4204
  * Get the string representation of a tag.
4199
4205
  * Internal function used for error messages.
@@ -4612,6 +4618,33 @@ var import_byte_data = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((
4612
4618
  const hasFract = (n) => {
4613
4619
  return n % 1 !== 0;
4614
4620
  };
4621
+ const U64_MAX_BIG = 18446744073709551615n;
4622
+ const I64_MAX_BIG = 9223372036854775807n;
4623
+ const I64_MIN_BIG = -9223372036854775808n;
4624
+ /**
4625
+ * Truncate a float to u64 with Rust's saturating `as u64` semantics: NaN and
4626
+ * negatives clamp to 0, values at or above 2^64 clamp to u64::MAX. This lets the
4627
+ * exact-float checks below mirror Rust's `(f as u64) == source` round-trip, where
4628
+ * u64::MAX rounds to 2^64 in float but saturates back to u64::MAX.
4629
+ */
4630
+ const saturateFloatToU64 = (f) => {
4631
+ if (Number.isNaN(f)) return 0n;
4632
+ const t = Math.trunc(f);
4633
+ if (t <= 0) return 0n;
4634
+ const big = BigInt(t);
4635
+ return big > U64_MAX_BIG ? U64_MAX_BIG : big;
4636
+ };
4637
+ /**
4638
+ * Truncate a float to i64 with Rust's saturating `as i64` semantics: NaN clamps
4639
+ * to 0, values clamp to i64::MAX or i64::MIN at the bounds.
4640
+ */
4641
+ const saturateFloatToI64 = (f) => {
4642
+ if (Number.isNaN(f)) return 0n;
4643
+ const big = BigInt(Math.trunc(f));
4644
+ if (big > I64_MAX_BIG) return I64_MAX_BIG;
4645
+ if (big < I64_MIN_BIG) return I64_MIN_BIG;
4646
+ return big;
4647
+ };
4615
4648
  /**
4616
4649
  * Exact conversions for i128 (JavaScript bigint).
4617
4650
  */
@@ -4775,6 +4808,55 @@ var ExactU64 = class {
4775
4808
  return source <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(source) : source;
4776
4809
  }
4777
4810
  };
4811
+ /**
4812
+ * Exact conversions for f64 (double precision float).
4813
+ */
4814
+ var ExactF64 = class {
4815
+ static exactFromF16(source) {
4816
+ if (Number.isNaN(source)) return NaN;
4817
+ return source;
4818
+ }
4819
+ static exactFromF32(source) {
4820
+ if (Number.isNaN(source)) return NaN;
4821
+ return source;
4822
+ }
4823
+ static exactFromF64(source) {
4824
+ if (Number.isNaN(source)) return NaN;
4825
+ return source;
4826
+ }
4827
+ static exactFromU64(source) {
4828
+ const srcBig = typeof source === "bigint" ? source : BigInt(source);
4829
+ const n = Number(srcBig);
4830
+ if (!Number.isFinite(n)) return void 0;
4831
+ return saturateFloatToU64(n) === srcBig ? n : void 0;
4832
+ }
4833
+ static exactFromI64(source) {
4834
+ const srcBig = typeof source === "bigint" ? source : BigInt(source);
4835
+ const n = Number(srcBig);
4836
+ if (!Number.isFinite(n)) return void 0;
4837
+ return saturateFloatToI64(n) === srcBig ? n : void 0;
4838
+ }
4839
+ static exactFromU128(source) {
4840
+ const n = Number(source);
4841
+ return BigInt(Math.trunc(n)) === source ? n : void 0;
4842
+ }
4843
+ static exactFromI128(source) {
4844
+ if (source < -9223372036854775808n || source > 9223372036854775807n) return;
4845
+ const absSource = source < 0n ? -source : source;
4846
+ if (absSource <= 4503599627370495n) return Number(source);
4847
+ const trailingZeros = countTrailingZeros(absSource);
4848
+ if (trailingZeros >= 53 && trailingZeros <= 63) return Number(source);
4849
+ }
4850
+ };
4851
+ const countTrailingZeros = (n) => {
4852
+ if (n === 0n) return 0;
4853
+ let count = 0;
4854
+ while ((n & 1n) === 0n) {
4855
+ count++;
4856
+ n = n >> 1n;
4857
+ }
4858
+ return count;
4859
+ };
4778
4860
  //#endregion
4779
4861
  //#region src/float.ts
4780
4862
  /**
@@ -4883,11 +4965,11 @@ const f64CborData = (value) => {
4883
4965
  const i128 = ExactI128.exactFromF64(n);
4884
4966
  if (i128 !== void 0) {
4885
4967
  const i = ExactU64.exactFromI128(-1n - i128);
4886
- if (i !== void 0) return encodeVarInt(typeof i === "bigint" ? Number(i) : i, MajorType.Negative);
4968
+ if (i !== void 0) return encodeVarInt(i, MajorType.Negative);
4887
4969
  }
4888
4970
  }
4889
4971
  const u = ExactU64.exactFromF64(n);
4890
- if (u !== void 0) return encodeVarInt(typeof u === "bigint" ? Number(u) : u, MajorType.Unsigned);
4972
+ if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned);
4891
4973
  if (Number.isNaN(value)) return CBOR_NAN;
4892
4974
  const buffer = /* @__PURE__ */ new ArrayBuffer(8);
4893
4975
  new DataView(buffer).setFloat64(0, n, false);
@@ -4905,8 +4987,8 @@ const f32CborData = (value) => {
4905
4987
  const f = binary16ToNumber(numberToBinary16(n));
4906
4988
  if (f === n) return f16CborData(f);
4907
4989
  if (n < 0) {
4908
- const u = ExactU64.exactFromF32(-1 - n);
4909
- if (u !== void 0) return encodeVarInt(typeof u === "bigint" ? Number(u) : u, MajorType.Negative);
4990
+ const u = ExactU64.exactFromF32(Math.fround(-1 - n));
4991
+ if (u !== void 0) return encodeVarInt(u, MajorType.Negative);
4910
4992
  }
4911
4993
  const u = ExactU32.exactFromF32(n);
4912
4994
  if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned);
@@ -4924,7 +5006,7 @@ const f16CborData = (value) => {
4924
5006
  const n = value;
4925
5007
  if (n < 0) {
4926
5008
  const u = ExactU64.exactFromF64(-1 - n);
4927
- if (u !== void 0) return encodeVarInt(typeof u === "bigint" ? Number(u) : u, MajorType.Negative);
5009
+ if (u !== void 0) return encodeVarInt(u, MajorType.Negative);
4928
5010
  }
4929
5011
  const u = ExactU16.exactFromF64(n);
4930
5012
  if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned);
@@ -4932,6 +5014,31 @@ const f16CborData = (value) => {
4932
5014
  const bytes = numberToBinary16(value);
4933
5015
  return new Uint8Array([249, ...bytes]);
4934
5016
  };
5017
+ /**
5018
+ * Render a float to its diagnostic string, matching Rust's `Simple` Display.
5019
+ *
5020
+ * Finite non-zero values with magnitude in [1e-4, 1e16) print in decimal with
5021
+ * at least one fractional digit (whole values get a trailing `.0`); everything
5022
+ * else prints in exponential form. Zero prints as `0.0`/`-0.0`.
5023
+ *
5024
+ * JS already produces the same shortest round-tripping digits; we only fix up
5025
+ * the notation threshold, the `e+` → `e` exponent, and the `.0` suffix.
5026
+ *
5027
+ * @param value - The float value
5028
+ * @returns Rust-`Display`-compatible string
5029
+ */
5030
+ const floatDisplayString = (value) => {
5031
+ if (Number.isNaN(value)) return "NaN";
5032
+ if (!Number.isFinite(value)) return value > 0 ? "Infinity" : "-Infinity";
5033
+ if (value === 0) return Object.is(value, -0) ? "-0.0" : "0.0";
5034
+ const abs = Math.abs(value);
5035
+ if (abs >= 1e-4 && abs < 0x2386f26fc10000) {
5036
+ let str = String(value);
5037
+ if (!str.includes(".")) str = `${str}.0`;
5038
+ return str;
5039
+ }
5040
+ return value.toExponential().replace("e+", "e");
5041
+ };
4935
5042
  //#endregion
4936
5043
  //#region src/varint.ts
4937
5044
  /**
@@ -5196,6 +5303,34 @@ const getGlobalTagsStore = () => {
5196
5303
  globalTagsStore ??= new TagsStore();
5197
5304
  return globalTagsStore;
5198
5305
  };
5306
+ /**
5307
+ * Execute a function with access to the global tags store.
5308
+ *
5309
+ * @template T - Return type of the action function
5310
+ * @param action - Function to execute with the tags store
5311
+ * @returns Result of the action function
5312
+ *
5313
+ * @example
5314
+ * ```typescript
5315
+ * const tagName = withTags(store => store.nameForValue(1));
5316
+ * console.log(tagName); // 'date'
5317
+ * ```
5318
+ */
5319
+ const withTags = (action) => {
5320
+ return action(getGlobalTagsStore());
5321
+ };
5322
+ /**
5323
+ * Execute a function with mutable access to the global tags store.
5324
+ *
5325
+ * This is an alias for withTags() for consistency with Rust API.
5326
+ *
5327
+ * @template T - Return type of the action function
5328
+ * @param action - Function to execute with the tags store
5329
+ * @returns Result of the action function
5330
+ */
5331
+ const withTagsMut = (action) => {
5332
+ return action(getGlobalTagsStore());
5333
+ };
5199
5334
  //#endregion
5200
5335
  //#region src/dump.ts
5201
5336
  /**
@@ -5399,7 +5534,7 @@ function dumpItems(cbor, level, opts) {
5399
5534
  if (simple.type === "True") note = "true";
5400
5535
  else if (simple.type === "False") note = "false";
5401
5536
  else if (simple.type === "Null") note = "null";
5402
- else if (simple.type === "Float") note = `${simple.value}`;
5537
+ else if (simple.type === "Float") note = floatDisplayString(simple.value);
5403
5538
  else note = "simple";
5404
5539
  items.push(new DumpItem(level, [data], note));
5405
5540
  break;
@@ -5626,7 +5761,7 @@ function item_tagged(tag, content, opts) {
5626
5761
  if (summarizer !== void 0) {
5627
5762
  const result = summarizer(content, opts.flat ?? false);
5628
5763
  if (result.ok) return item(result.value);
5629
- return item(`<error: ${result.error.type === "Custom" ? result.error.message : result.error.type === "WrongTag" ? `expected CBOR tag ${result.error.expected.value}, but got ${result.error.actual.value}` : result.error.type}>`);
5764
+ return item(`<error: ${errorToString(result.error)}>`);
5630
5765
  }
5631
5766
  }
5632
5767
  let comment;
@@ -5649,7 +5784,7 @@ function formatBytes(value) {
5649
5784
  return `h'${bytesToHex(value)}'`;
5650
5785
  }
5651
5786
  function formatText(value) {
5652
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
5787
+ return `"${value.replace(/"/g, "\\\"")}"`;
5653
5788
  }
5654
5789
  function formatSimple(value) {
5655
5790
  switch (value.type) {
@@ -5660,20 +5795,11 @@ function formatSimple(value) {
5660
5795
  }
5661
5796
  }
5662
5797
  /**
5663
- * Format a finite CBOR float to match Rust `Simple::format!("{:?}", v)`.
5664
- *
5665
- * - `1.0` → `"1.0"` (Rust Debug). JS `String(1.0)` gives `"1"` so we append `.0`.
5666
- * - `1.5` → `"1.5"`.
5667
- * - `1e100` → `"1e100"` (Rust uses no `+` sign in the exponent). JS uses `1e+100`.
5668
- * - Specials (NaN / ±Infinity) produce the exact Rust strings.
5798
+ * Format a CBOR float for diagnostic output. Shared with the hex-dump
5799
+ * annotation path; see {@link floatDisplayString}.
5669
5800
  */
5670
5801
  function formatFloat(value) {
5671
- if (Number.isNaN(value)) return "NaN";
5672
- if (!Number.isFinite(value)) return value > 0 ? "Infinity" : "-Infinity";
5673
- let str = String(value);
5674
- str = str.replace(/e\+/, "e");
5675
- if (!str.includes(".") && !str.includes("e")) str = `${str}.0`;
5676
- return str;
5802
+ return floatDisplayString(value);
5677
5803
  }
5678
5804
  function resolveTagsStore(tags) {
5679
5805
  if (tags === "none") return void 0;
@@ -5763,7 +5889,7 @@ function at(data, index) {
5763
5889
  return data.getUint8(index);
5764
5890
  }
5765
5891
  function from(data, index) {
5766
- return new DataView(data.buffer, data.byteOffset + index);
5892
+ return new DataView(data.buffer, data.byteOffset + index, data.byteLength - index);
5767
5893
  }
5768
5894
  function range(data, start, end) {
5769
5895
  return new DataView(data.buffer, data.byteOffset + start, end - start);
@@ -5867,7 +5993,15 @@ function decodeCborInternal(data) {
5867
5993
  const textLen = value;
5868
5994
  if (typeof textLen === "bigint") throw new CborError({ type: "OutOfRange" });
5869
5995
  const textBuf = parseBytes(from(data, varIntLen), textLen);
5870
- const text = new TextDecoder().decode(textBuf);
5996
+ let text;
5997
+ try {
5998
+ text = new TextDecoder("utf-8", { fatal: true }).decode(textBuf);
5999
+ } catch (e) {
6000
+ throw new CborError({
6001
+ type: "InvalidUtf8",
6002
+ message: e instanceof Error ? e.message : String(e)
6003
+ });
6004
+ }
5871
6005
  if (text.normalize("NFC") !== text) throw new CborError({ type: "NonCanonicalString" });
5872
6006
  return {
5873
6007
  cbor: attachMethods({
@@ -6246,9 +6380,12 @@ const asBoolean = (cbor) => {
6246
6380
  * @returns Float or undefined
6247
6381
  */
6248
6382
  const asFloat = (cbor) => {
6249
- if (cbor.type !== MajorType.Simple) return;
6250
- const simple = cbor.value;
6251
- if (isFloat$1(simple)) return simple.value;
6383
+ if (cbor.type === MajorType.Unsigned) return ExactF64.exactFromU64(cbor.value);
6384
+ if (cbor.type === MajorType.Negative) {
6385
+ const f = ExactF64.exactFromU64(cbor.value);
6386
+ return f === void 0 ? void 0 : -1 - f;
6387
+ }
6388
+ if (cbor.type === MajorType.Simple) return isFloat$1(cbor.value) ? cbor.value.value : void 0;
6252
6389
  };
6253
6390
  /**
6254
6391
  * Extract any numeric value (integer or float).
@@ -6369,9 +6506,13 @@ const expectBoolean = (cbor) => {
6369
6506
  * @throws {CborError} With type 'WrongType' if cbor is not a float
6370
6507
  */
6371
6508
  const expectFloat = (cbor) => {
6372
- const value = asFloat(cbor);
6373
- if (value === void 0) throw new CborError({ type: "WrongType" });
6374
- return value;
6509
+ if (cbor.type === MajorType.Unsigned || cbor.type === MajorType.Negative) {
6510
+ const value = asFloat(cbor);
6511
+ if (value === void 0) throw new CborError({ type: "OutOfRange" });
6512
+ return value;
6513
+ }
6514
+ if (cbor.type === MajorType.Simple && isFloat$1(cbor.value)) return cbor.value.value;
6515
+ throw new CborError({ type: "WrongType" });
6375
6516
  };
6376
6517
  /**
6377
6518
  * Extract any numeric value, throwing if type doesn't match.
@@ -6509,7 +6650,7 @@ const tagContent = (cbor) => {
6509
6650
  */
6510
6651
  const hasTag = (cbor, tag) => {
6511
6652
  if (cbor.type !== MajorType.Tagged) return false;
6512
- return cbor.tag === tag;
6653
+ return tagValuesEqual(cbor.tag, tag);
6513
6654
  };
6514
6655
  /**
6515
6656
  * Extract content if has specific tag.
@@ -6519,7 +6660,7 @@ const hasTag = (cbor, tag) => {
6519
6660
  * @returns Tagged content or undefined
6520
6661
  */
6521
6662
  const getTaggedContent = (cbor, tag) => {
6522
- if (cbor.type === MajorType.Tagged && cbor.tag === tag) return cbor.value;
6663
+ if (cbor.type === MajorType.Tagged && tagValuesEqual(cbor.tag, tag)) return cbor.value;
6523
6664
  };
6524
6665
  /**
6525
6666
  * Extract content if has specific tag, throwing if not.
@@ -6534,7 +6675,7 @@ const getTaggedContent = (cbor, tag) => {
6534
6675
  */
6535
6676
  const expectTaggedContent = (cbor, tag) => {
6536
6677
  if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
6537
- if (cbor.tag !== tag) throw new CborError({
6678
+ if (!tagValuesEqual(cbor.tag, tag)) throw new CborError({
6538
6679
  type: "WrongTag",
6539
6680
  expected: { value: tag },
6540
6681
  actual: { value: cbor.tag }
@@ -6774,15 +6915,13 @@ var CborMap = class CborMap {
6774
6915
  * Matches Rust's Map::insert_next().
6775
6916
  */
6776
6917
  setNext(key, value) {
6777
- const lastEntry = this._dict.max();
6778
- if (lastEntry === void 0) {
6779
- this.set(key, value);
6780
- return;
6781
- }
6782
6918
  const keyCbor = cbor(key);
6783
6919
  const newKey = cborData(keyCbor);
6784
6920
  if (this._dict.has(newKey)) throw new CborError({ type: "DuplicateMapKey" });
6785
- if (lexicographicallyCompareBytes(newKey, this._makeKey(lastEntry.key)) <= 0) throw new CborError({ type: "MisorderedMapKey" });
6921
+ const greatest = this._dict.store.max();
6922
+ if (greatest !== void 0) {
6923
+ if (lexicographicallyCompareBytes(newKey, greatest.key) <= 0) throw new CborError({ type: "MisorderedMapKey" });
6924
+ }
6786
6925
  this._dict.set(newKey, {
6787
6926
  key: keyCbor,
6788
6927
  value: cbor(value)
@@ -7136,15 +7275,27 @@ const cbor = (value) => {
7136
7275
  value: -Infinity
7137
7276
  }
7138
7277
  };
7139
- else if (typeof value === "number" && !Number.isSafeInteger(value)) result = {
7140
- isCbor: true,
7141
- type: MajorType.Simple,
7142
- value: {
7143
- type: "Float",
7144
- value
7145
- }
7146
- };
7147
- else if (typeof value === "bigint" && (value > 18446744073709551615n || value < -18446744073709551616n)) throw new CborError({ type: "OutOfRange" });
7278
+ else if (typeof value === "number" && !Number.isSafeInteger(value)) {
7279
+ const big = BigInt(value);
7280
+ if (big >= 0n && big <= 18446744073709551615n) result = {
7281
+ isCbor: true,
7282
+ type: MajorType.Unsigned,
7283
+ value: big
7284
+ };
7285
+ else if (big < 0n && big >= -18446744073709551616n) result = {
7286
+ isCbor: true,
7287
+ type: MajorType.Negative,
7288
+ value: -big - 1n
7289
+ };
7290
+ else result = {
7291
+ isCbor: true,
7292
+ type: MajorType.Simple,
7293
+ value: {
7294
+ type: "Float",
7295
+ value
7296
+ }
7297
+ };
7298
+ } else if (typeof value === "bigint" && (value > 18446744073709551615n || value < -18446744073709551616n)) throw new CborError({ type: "OutOfRange" });
7148
7299
  else if (value < 0) if (typeof value === "bigint") result = {
7149
7300
  isCbor: true,
7150
7301
  type: MajorType.Negative,
@@ -7495,7 +7646,7 @@ const attachMethods = (obj) => {
7495
7646
  expectTag(expectedTag) {
7496
7647
  if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
7497
7648
  const expected = typeof expectedTag === "object" && "value" in expectedTag ? expectedTag : { value: expectedTag };
7498
- if (this.tag !== expected.value) throw new CborError({
7649
+ if (!tagValuesEqual(this.tag, expected.value)) throw new CborError({
7499
7650
  type: "WrongTag",
7500
7651
  expected,
7501
7652
  actual: { value: this.tag }
@@ -7508,7 +7659,7 @@ const attachMethods = (obj) => {
7508
7659
  validateTag(expectedTags) {
7509
7660
  if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
7510
7661
  const tagValue = this.tag;
7511
- const matchingTag = expectedTags.find((t) => t.value === tagValue);
7662
+ const matchingTag = expectedTags.find((t) => tagValuesEqual(t.value, tagValue));
7512
7663
  if (matchingTag === void 0) throw new CborError({
7513
7664
  type: "WrongTag",
7514
7665
  expected: expectedTags[0],
@@ -7590,807 +7741,1265 @@ const Cbor = {
7590
7741
  }
7591
7742
  };
7592
7743
  //#endregion
7593
- //#region src/cbor-tagged-encodable.ts
7594
- /**
7595
- * Copyright © 2023-2026 Blockchain Commons, LLC
7596
- * Copyright © 2025-2026 Parity Technologies
7597
- *
7598
- *
7599
- * Tagged CBOR encoding support.
7600
- *
7601
- * This module provides the `CborTaggedEncodable` interface, which enables types to
7602
- * be encoded as tagged CBOR values.
7603
- *
7604
- * CBOR tags provide semantic information about the encoded data. For example,
7605
- * tag 1 is used for dates, indicating that the value should be interpreted
7606
- * as a timestamp. The dCBOR library ensures these tags are encoded
7607
- * deterministically.
7608
- *
7609
- * This interface enables seamless encoding of TypeScript types to properly tagged CBOR
7610
- * values.
7611
- *
7612
- * @module cbor-tagged-encodable
7613
- */
7614
- /**
7615
- * Helper function to create tagged CBOR from an encodable object.
7616
- *
7617
- * Uses the first tag from cborTags().
7618
- *
7619
- * @param encodable - Object implementing CborTaggedEncodable
7620
- * @returns Tagged CBOR value
7621
- */
7622
- const createTaggedCbor = (encodable) => {
7623
- const tags = encodable.cborTags();
7624
- if (tags.length === 0) throw new CborError({
7625
- type: "Custom",
7626
- message: "No tags defined for this type"
7627
- });
7628
- const tag = tags[0];
7629
- if (tag === void 0) throw new CborError({
7630
- type: "Custom",
7631
- message: "Tag is undefined"
7632
- });
7633
- const untagged = encodable.untaggedCbor();
7634
- return attachMethods({
7635
- isCbor: true,
7636
- type: MajorType.Tagged,
7637
- tag: tag.value,
7638
- value: untagged
7639
- });
7640
- };
7641
- /**
7642
- * Default `taggedCborData()` implementation — `taggedCbor().toData()`.
7643
- *
7644
- * Mirrors Rust's default `tagged_cbor_data()` impl on
7645
- * `CBORTaggedEncodable`. TypeScript interfaces don't carry method bodies,
7646
- * so this helper plays the role of the Rust trait default; concrete types
7647
- * call it from their own `taggedCborData()` if they don't need to override.
7648
- */
7649
- const taggedCborData = (encodable) => encodable.taggedCbor().toData();
7650
- //#endregion
7651
- //#region src/cbor-tagged-decodable.ts
7652
- /**
7653
- * Copyright © 2023-2026 Blockchain Commons, LLC
7654
- * Copyright © 2025-2026 Parity Technologies
7655
- *
7656
- *
7657
- * Tagged CBOR decoding support.
7658
- *
7659
- * This module provides the `CborTaggedDecodable` interface, which enables types to
7660
- * be decoded from tagged CBOR values.
7661
- *
7662
- * Tagged CBOR values include semantic information about how to interpret the
7663
- * data. This interface allows TypeScript types to verify that incoming CBOR data has the
7664
- * expected tag(s) and to decode the data appropriately.
7665
- *
7666
- * @module cbor-tagged-decodable
7667
- */
7668
- /**
7669
- * Helper function to validate that a CBOR value has one of the expected tags.
7670
- *
7671
- * @param cbor - CBOR value to validate
7672
- * @param expectedTags - Array of valid tags
7673
- * @returns The matching tag
7674
- * @throws Error if the value is not tagged or has an unexpected tag
7675
- */
7676
- const validateTag = (cbor, expectedTags) => {
7677
- if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
7678
- const tagValue = cbor.tag;
7679
- const matchingTag = expectedTags.find((t) => t.value === tagValue);
7680
- if (matchingTag === void 0) throw new CborError({
7681
- type: "WrongTag",
7682
- expected: expectedTags[0],
7683
- actual: { value: tagValue }
7684
- });
7685
- return matchingTag;
7686
- };
7687
- /**
7688
- * Helper function to extract the content from a tagged CBOR value.
7689
- *
7690
- * @param cbor - Tagged CBOR value
7691
- * @returns The untagged content
7692
- * @throws Error if the value is not tagged
7693
- */
7694
- const extractTaggedContent = (cbor) => {
7695
- if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
7696
- return cbor.value;
7697
- };
7698
- /**
7699
- * Default `fromTaggedCborData()` implementation — `decodeCbor(data)` then
7700
- * delegate to the decodable's `fromTaggedCbor()`.
7701
- *
7702
- * Mirrors Rust's default `from_tagged_cbor_data` impl on
7703
- * `CBORTaggedDecodable`.
7704
- */
7705
- function fromTaggedCborData(decodable, data) {
7706
- return decodable.fromTaggedCbor(decodeCbor(data));
7707
- }
7708
- /**
7709
- * Default `fromUntaggedCborData()` implementation — `decodeCbor(data)`
7710
- * then delegate to the decodable's `fromUntaggedCbor()`.
7711
- *
7712
- * Mirrors Rust's default `from_untagged_cbor_data` impl on
7713
- * `CBORTaggedDecodable`.
7714
- */
7715
- function fromUntaggedCborData(decodable, data) {
7716
- return decodable.fromUntaggedCbor(decodeCbor(data));
7717
- }
7718
- //#endregion
7719
- //#region src/date.ts
7744
+ //#region src/set.ts
7720
7745
  /**
7721
7746
  * Copyright © 2023-2026 Blockchain Commons, LLC
7722
7747
  * Copyright © 2025-2026 Parity Technologies
7723
7748
  *
7724
7749
  *
7725
- * Date/time support for CBOR with tag(1) encoding.
7726
- *
7727
- * A CBOR-friendly representation of a date and time.
7728
- *
7729
- * The `CborDate` type provides a wrapper around JavaScript's native `Date` that
7730
- * supports encoding and decoding to/from CBOR with tag 1, following the CBOR
7731
- * date/time standard specified in RFC 8949.
7750
+ * Set data structure for CBOR.
7732
7751
  *
7733
- * When encoded to CBOR, dates are represented as tag 1 followed by a numeric
7734
- * value representing the number of seconds since (or before) the Unix epoch
7735
- * (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
7736
- * integer, or a floating-point value for dates with fractional seconds.
7752
+ * A Set encodes to a plain (untagged) array of unique elements in canonical
7753
+ * ascending CBOR-byte order. There's no tag-258 here: this matches Rust
7754
+ * dcbor's `From<Set> for CBOR`, which emits an untagged array.
7737
7755
  *
7738
- * @module date
7756
+ * @module set
7739
7757
  */
7740
7758
  /**
7741
- * A CBOR-friendly representation of a date and time.
7742
- *
7743
- * The `CborDate` type provides a wrapper around JavaScript's native `Date` that
7744
- * supports encoding and decoding to/from CBOR with tag 1, following the CBOR
7745
- * date/time standard specified in RFC 8949.
7746
- *
7747
- * When encoded to CBOR, dates are represented as tag 1 followed by a numeric
7748
- * value representing the number of seconds since (or before) the Unix epoch
7749
- * (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
7750
- * integer, or a floating-point value for dates with fractional seconds.
7751
- *
7752
- * # Features
7759
+ * CBOR Set type, encoded as a plain (untagged) array.
7753
7760
  *
7754
- * - Supports UTC dates with optional fractional seconds
7755
- * - Provides convenient constructors for common date creation patterns
7756
- * - Implements the `CborTagged`, `CborTaggedEncodable`, and
7757
- * `CborTaggedDecodable` interfaces
7758
- * - Supports arithmetic operations with durations and between dates
7761
+ * Internally uses a CborMap to ensure unique elements with deterministic ordering.
7762
+ * Elements are ordered by their CBOR encoding (lexicographic byte order).
7759
7763
  *
7760
7764
  * @example
7761
7765
  * ```typescript
7762
- * import { CborDate } from './date';
7763
- *
7764
- * // Create a date from a timestamp (seconds since Unix epoch)
7765
- * const date = CborDate.fromTimestamp(1675854714.0);
7766
+ * // Create set
7767
+ * const set = CborSet.fromArray([1, 2, 3]);
7768
+ * const set2 = CborSet.fromSet(new Set([1, 2, 3]));
7766
7769
  *
7767
- * // Create a date from year, month, day
7768
- * const date2 = CborDate.fromYmd(2023, 2, 8);
7770
+ * // Add elements
7771
+ * set.insert(4);
7772
+ * set.insert(2); // Duplicate, no effect
7769
7773
  *
7770
- * // Convert to CBOR
7771
- * const cborValue = date.taggedCbor();
7774
+ * // Check membership
7775
+ * console.log(set.contains(2)); // true
7776
+ * console.log(set.contains(99)); // false
7772
7777
  *
7773
- * // Decode from CBOR
7774
- * const decoded = CborDate.fromTaggedCbor(cborValue);
7778
+ * // Encode to CBOR (untagged array)
7779
+ * const c = set.toCbor();
7775
7780
  * ```
7776
7781
  */
7777
- var CborDate = class CborDate {
7778
- /**
7779
- * Canonical timestamp in seconds since the Unix epoch as a JS `number`
7780
- * (`f64`). dCBOR encodes Date (tag 1) as a numeric value in seconds, so
7781
- * keeping `_seconds` as the source of truth avoids the millisecond-only
7782
- * round-trip precision loss that going through a JS `Date` instance
7783
- * introduced in earlier versions of this port.
7784
- *
7785
- * f64 still bounds the achievable precision (~16 decimal digits, so
7786
- * roughly microseconds for current epoch values); Rust's
7787
- * `chrono::DateTime<Utc>` retains nanoseconds in memory but encodes
7788
- * to the same f64 over the wire, so the *encode/decode round-trip* is
7789
- * byte-identical.
7790
- */
7791
- _seconds;
7782
+ var CborSet = class CborSet {
7783
+ _map;
7784
+ constructor() {
7785
+ this._map = new CborMap();
7786
+ }
7792
7787
  /**
7793
- * Creates a new `CborDate` from the given JavaScript `Date`.
7794
- *
7795
- * This method creates a new `CborDate` instance by wrapping a
7796
- * JavaScript `Date`.
7788
+ * Create CborSet from array.
7797
7789
  *
7798
- * @param dateTime - A `Date` instance to wrap
7790
+ * Duplicates are automatically removed.
7799
7791
  *
7800
- * @returns A new `CborDate` instance
7792
+ * @param items - Array of items to add to the set
7793
+ * @returns New CborSet instance
7801
7794
  *
7802
7795
  * @example
7803
7796
  * ```typescript
7804
- * const datetime = new Date();
7805
- * const date = CborDate.fromDatetime(datetime);
7797
+ * const set = CborSet.fromArray([1, 2, 3, 2, 1]);
7798
+ * console.log(set.size); // 3
7806
7799
  * ```
7807
7800
  */
7808
- static fromDatetime(dateTime) {
7809
- const instance = new CborDate();
7810
- instance._seconds = dateTime.getTime() / 1e3;
7811
- return instance;
7801
+ static fromArray(items) {
7802
+ const set = new CborSet();
7803
+ for (const item of items) set.insert(item);
7804
+ return set;
7812
7805
  }
7813
7806
  /**
7814
- * Creates a new `CborDate` from year, month, and day components.
7815
- *
7816
- * This method creates a new `CborDate` with the time set to 00:00:00 UTC.
7817
- *
7818
- * @param year - The year component (e.g., 2023)
7819
- * @param month - The month component (1-12)
7820
- * @param day - The day component (1-31)
7807
+ * Create CborSet from JavaScript Set.
7821
7808
  *
7822
- * @returns A new `CborDate` instance
7809
+ * @param items - JavaScript Set of items
7810
+ * @returns New CborSet instance
7823
7811
  *
7824
7812
  * @example
7825
7813
  * ```typescript
7826
- * // Create February 8, 2023
7827
- * const date = CborDate.fromYmd(2023, 2, 8);
7814
+ * const jsSet = new Set([1, 2, 3]);
7815
+ * const cborSet = CborSet.fromSet(jsSet);
7828
7816
  * ```
7817
+ */
7818
+ static fromSet(items) {
7819
+ return CborSet.fromArray(Array.from(items));
7820
+ }
7821
+ /**
7822
+ * Create CborSet from iterable.
7829
7823
  *
7830
- * @throws Error if the provided components do not form a valid date.
7824
+ * @param items - Iterable of items
7825
+ * @returns New CborSet instance
7831
7826
  */
7832
- static fromYmd(year, month, day) {
7833
- const dt = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));
7834
- return CborDate.fromDatetime(dt);
7827
+ static fromIterable(items) {
7828
+ return CborSet.fromArray(Array.from(items));
7835
7829
  }
7836
7830
  /**
7837
- * Creates a new `CborDate` from year, month, day, hour, minute, and second
7838
- * components.
7831
+ * Insert an element into the set.
7839
7832
  *
7840
- * @param year - The year component (e.g., 2023)
7841
- * @param month - The month component (1-12)
7842
- * @param day - The day component (1-31)
7843
- * @param hour - The hour component (0-23)
7844
- * @param minute - The minute component (0-59)
7845
- * @param second - The second component (0-59)
7833
+ * If the element already exists, has no effect.
7846
7834
  *
7847
- * @returns A new `CborDate` instance
7835
+ * @param value - Value to insert
7848
7836
  *
7849
7837
  * @example
7850
7838
  * ```typescript
7851
- * // Create February 8, 2023, 15:30:45 UTC
7852
- * const date = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
7839
+ * const set = new CborSet();
7840
+ * set.insert(1);
7841
+ * set.insert(2);
7842
+ * set.insert(1); // No effect, already exists
7853
7843
  * ```
7854
- *
7855
- * @throws Error if the provided components do not form a valid date and time.
7856
7844
  */
7857
- static fromYmdHms(year, month, day, hour, minute, second) {
7858
- const dt = new Date(Date.UTC(year, month - 1, day, hour, minute, second, 0));
7859
- return CborDate.fromDatetime(dt);
7845
+ insert(value) {
7846
+ const cborValue = encodeCborValue(value);
7847
+ this._map.set(cborValue, cborValue);
7860
7848
  }
7861
7849
  /**
7862
- * Creates a new `CborDate` from seconds since (or before) the Unix epoch.
7850
+ * Insert an element that must sort strictly after every element inserted so
7851
+ * far (canonical CBOR-byte order). The decoder uses this to reject
7852
+ * misordered or duplicate elements.
7863
7853
  *
7864
- * This method creates a new `CborDate` representing the specified number of
7865
- * seconds since the Unix epoch (1970-01-01T00:00:00Z). Negative values
7866
- * represent times before the epoch.
7854
+ * Mirrors Rust `Set::insert_next` (`pub(crate)`); exposed here because
7855
+ * TypeScript has no crate-private visibility.
7867
7856
  *
7868
- * @param secondsSinceUnixEpoch - Seconds from the Unix epoch (positive or
7869
- * negative), which can include a fractional part for sub-second
7870
- * precision
7857
+ * @throws CborError of type `MisorderedMap` if `value` would not preserve
7858
+ * strict ascending CBOR-byte order, or `DuplicateMapKey` for an exact
7859
+ * repeat.
7860
+ */
7861
+ insertNext(value) {
7862
+ const cborValue = encodeCborValue(value);
7863
+ this._map.setNext(cborValue, cborValue);
7864
+ }
7865
+ /**
7866
+ * Check if set contains an element.
7871
7867
  *
7872
- * @returns A new `CborDate` instance
7868
+ * @param value - Value to check
7869
+ * @returns true if element is in the set
7873
7870
  *
7874
7871
  * @example
7875
7872
  * ```typescript
7876
- * // Create a date from a timestamp
7877
- * const date = CborDate.fromTimestamp(1675854714.0);
7878
- *
7879
- * // Create a date one second before the Unix epoch
7880
- * const beforeEpoch = CborDate.fromTimestamp(-1.0);
7881
- *
7882
- * // Create a date with fractional seconds
7883
- * const withFraction = CborDate.fromTimestamp(1675854714.5);
7873
+ * const set = CborSet.fromArray([1, 2, 3]);
7874
+ * console.log(set.contains(2)); // true
7875
+ * console.log(set.contains(99)); // false
7884
7876
  * ```
7885
7877
  */
7886
- static fromTimestamp(secondsSinceUnixEpoch) {
7887
- const instance = new CborDate();
7888
- instance._seconds = secondsSinceUnixEpoch;
7889
- return instance;
7878
+ contains(value) {
7879
+ const cborValue = encodeCborValue(value);
7880
+ return this._map.has(cborValue);
7890
7881
  }
7891
7882
  /**
7892
- * Creates a new `CborDate` from a string containing an ISO-8601 (RFC-3339)
7893
- * date (with or without time).
7894
- *
7895
- * This method parses a string representation of a date or date-time in
7896
- * ISO-8601/RFC-3339 format and creates a new `CborDate` instance. It
7897
- * supports both full date-time strings (e.g., "2023-02-08T15:30:45Z")
7898
- * and date-only strings (e.g., "2023-02-08").
7899
- *
7900
- * @param value - A string containing a date or date-time in ISO-8601/RFC-3339
7901
- * format
7902
- *
7903
- * @returns A new `CborDate` instance if parsing succeeds
7883
+ * Remove an element from the set.
7904
7884
  *
7905
- * @throws Error if the string cannot be parsed as a valid date or date-time
7885
+ * @param value - Value to remove
7886
+ * @returns true if element was removed, false if not found
7906
7887
  *
7907
7888
  * @example
7908
7889
  * ```typescript
7909
- * // Parse a date-time string
7910
- * const date = CborDate.fromString("2023-02-08T15:30:45Z");
7911
- *
7912
- * // Parse a date-only string (time will be set to 00:00:00)
7913
- * const date2 = CborDate.fromString("2023-02-08");
7890
+ * const set = CborSet.fromArray([1, 2, 3]);
7891
+ * set.delete(2); // Returns true
7892
+ * set.delete(99); // Returns false
7914
7893
  * ```
7915
7894
  */
7916
- static fromString(value) {
7917
- const dt = new Date(value);
7918
- if (isNaN(dt.getTime())) throw new CborError({
7919
- type: "InvalidDate",
7920
- message: "Invalid date string"
7921
- });
7922
- return CborDate.fromDatetime(dt);
7895
+ delete(value) {
7896
+ const cborValue = encodeCborValue(value);
7897
+ return this._map.delete(cborValue);
7923
7898
  }
7924
7899
  /**
7925
- * Creates a new `CborDate` containing the current date and time.
7926
- *
7927
- * @returns A new `CborDate` instance representing the current UTC date and time
7900
+ * Remove all elements from the set.
7901
+ */
7902
+ clear() {
7903
+ this._map.clear();
7904
+ }
7905
+ /**
7906
+ * Get the number of elements in the set.
7928
7907
  *
7929
- * @example
7930
- * ```typescript
7931
- * const now = CborDate.now();
7932
- * ```
7908
+ * @returns Number of elements
7933
7909
  */
7934
- static now() {
7935
- return CborDate.fromDatetime(/* @__PURE__ */ new Date());
7910
+ get size() {
7911
+ return this._map.size;
7936
7912
  }
7937
7913
  /**
7938
- * Creates a new `CborDate` containing the current date and time plus the given
7939
- * duration.
7914
+ * Check if the set is empty.
7940
7915
  *
7941
- * @param durationMs - The duration in milliseconds to add to the current time
7916
+ * @returns true if set has no elements
7917
+ */
7918
+ isEmpty() {
7919
+ return this._map.size === 0;
7920
+ }
7921
+ /**
7922
+ * Create a new set containing elements in this set or the other set.
7942
7923
  *
7943
- * @returns A new `CborDate` instance representing the current UTC date and time plus
7944
- * the duration
7924
+ * @param other - Other set
7925
+ * @returns New set with union of elements
7945
7926
  *
7946
7927
  * @example
7947
7928
  * ```typescript
7948
- * // Get a date 1 hour from now
7949
- * const oneHourLater = CborDate.withDurationFromNow(3600 * 1000);
7929
+ * const set1 = CborSet.fromArray([1, 2, 3]);
7930
+ * const set2 = CborSet.fromArray([3, 4, 5]);
7931
+ * const union = set1.union(set2);
7932
+ * // union contains [1, 2, 3, 4, 5]
7950
7933
  * ```
7951
7934
  */
7952
- static withDurationFromNow(durationMs) {
7953
- const future = new Date((/* @__PURE__ */ new Date()).getTime() + durationMs);
7954
- return CborDate.fromDatetime(future);
7935
+ union(other) {
7936
+ const result = new CborSet();
7937
+ for (const value of this) result.insert(extractCbor(value));
7938
+ for (const value of other) result.insert(extractCbor(value));
7939
+ return result;
7955
7940
  }
7956
7941
  /**
7957
- * Returns the underlying JavaScript `Date` object.
7958
- *
7959
- * This method provides access to the wrapped JavaScript `Date`
7960
- * instance.
7942
+ * Create a new set containing elements in both this set and the other set.
7961
7943
  *
7962
- * @returns The wrapped `Date` instance
7944
+ * @param other - Other set
7945
+ * @returns New set with intersection of elements
7963
7946
  *
7964
7947
  * @example
7965
7948
  * ```typescript
7966
- * const date = CborDate.now();
7967
- * const datetime = date.datetime();
7968
- * const year = datetime.getFullYear();
7949
+ * const set1 = CborSet.fromArray([1, 2, 3]);
7950
+ * const set2 = CborSet.fromArray([2, 3, 4]);
7951
+ * const intersection = set1.intersection(set2);
7952
+ * // intersection contains [2, 3]
7969
7953
  * ```
7970
7954
  */
7971
- datetime() {
7972
- return /* @__PURE__ */ new Date(this._seconds * 1e3);
7955
+ intersection(other) {
7956
+ const result = new CborSet();
7957
+ for (const value of this) {
7958
+ const extracted = extractCbor(value);
7959
+ if (other.contains(extracted)) result.insert(extracted);
7960
+ }
7961
+ return result;
7973
7962
  }
7974
7963
  /**
7975
- * Returns the `CborDate` as the number of seconds since the Unix epoch.
7976
- *
7977
- * This method converts the date to a floating-point number representing
7978
- * the number of seconds since the Unix epoch (1970-01-01T00:00:00Z).
7979
- * Negative values represent times before the epoch. The fractional
7980
- * part represents sub-second precision.
7964
+ * Create a new set containing elements in this set but not in the other set.
7981
7965
  *
7982
- * @returns Seconds since the Unix epoch as a `number`
7966
+ * @param other - Other set
7967
+ * @returns New set with difference of elements
7983
7968
  *
7984
7969
  * @example
7985
7970
  * ```typescript
7986
- * const date = CborDate.fromYmd(2023, 2, 8);
7987
- * const timestamp = date.timestamp();
7971
+ * const set1 = CborSet.fromArray([1, 2, 3]);
7972
+ * const set2 = CborSet.fromArray([2, 3, 4]);
7973
+ * const diff = set1.difference(set2);
7974
+ * // diff contains [1]
7988
7975
  * ```
7989
7976
  */
7990
- timestamp() {
7991
- return this._seconds;
7977
+ difference(other) {
7978
+ const result = new CborSet();
7979
+ for (const value of this) {
7980
+ const extracted = extractCbor(value);
7981
+ if (!other.contains(extracted)) result.insert(extracted);
7982
+ }
7983
+ return result;
7992
7984
  }
7993
7985
  /**
7994
- * Add seconds to this date.
7986
+ * Check if this set is a subset of another set.
7995
7987
  *
7996
- * @param seconds - Seconds to add (can be fractional)
7997
- * @returns New CborDate instance
7988
+ * @param other - Other set
7989
+ * @returns true if all elements of this set are in the other set
7990
+ */
7991
+ isSubsetOf(other) {
7992
+ for (const value of this) if (!other.contains(extractCbor(value))) return false;
7993
+ return true;
7994
+ }
7995
+ /**
7996
+ * Check if this set is a superset of another set.
7998
7997
  *
7999
- * @example
8000
- * ```typescript
8001
- * const date = CborDate.fromYmd(2022, 3, 21);
8002
- * const tomorrow = date.add(24 * 60 * 60);
8003
- * ```
7998
+ * @param other - Other set
7999
+ * @returns true if all elements of the other set are in this set
8004
8000
  */
8005
- add(seconds) {
8006
- return CborDate.fromTimestamp(this.timestamp() + seconds);
8001
+ isSupersetOf(other) {
8002
+ return other.isSubsetOf(this);
8007
8003
  }
8008
8004
  /**
8009
- * Subtract seconds from this date.
8005
+ * Iterate over elements in the set.
8010
8006
  *
8011
- * @param seconds - Seconds to subtract (can be fractional)
8012
- * @returns New CborDate instance
8007
+ * Elements are returned in deterministic order (by CBOR encoding).
8013
8008
  *
8014
8009
  * @example
8015
8010
  * ```typescript
8016
- * const date = CborDate.fromYmd(2022, 3, 21);
8017
- * const yesterday = date.subtract(24 * 60 * 60);
8011
+ * const set = CborSet.fromArray([3, 1, 2]);
8012
+ * for (const value of set) {
8013
+ * console.log(extractCbor(value));
8014
+ * }
8018
8015
  * ```
8019
8016
  */
8020
- subtract(seconds) {
8021
- return CborDate.fromTimestamp(this.timestamp() - seconds);
8017
+ *[Symbol.iterator]() {
8018
+ for (const [_, value] of this._map) yield value;
8022
8019
  }
8023
8020
  /**
8024
- * Get the difference in seconds between this date and another.
8021
+ * Get all values as an array.
8025
8022
  *
8026
- * @param other - Other CborDate to compare with
8027
- * @returns Difference in seconds (this - other)
8023
+ * @returns Array of CBOR values in deterministic order
8028
8024
  *
8029
8025
  * @example
8030
8026
  * ```typescript
8031
- * const date1 = CborDate.fromYmd(2022, 3, 22);
8032
- * const date2 = CborDate.fromYmd(2022, 3, 21);
8033
- * const diff = date1.difference(date2);
8034
- * // Returns 86400 (one day in seconds)
8027
+ * const set = CborSet.fromArray([3, 1, 2]);
8028
+ * const values = set.values();
8029
+ * // Values in deterministic order
8035
8030
  * ```
8036
8031
  */
8037
- difference(other) {
8038
- return this.timestamp() - other.timestamp();
8032
+ values() {
8033
+ return Array.from(this);
8039
8034
  }
8040
8035
  /**
8041
- * Implementation of the `CborTagged` interface for `CborDate`.
8036
+ * Execute a function for each element.
8042
8037
  *
8043
- * This implementation specifies that `CborDate` values are tagged with CBOR tag 1,
8044
- * which is the standard CBOR tag for date/time values represented as seconds
8045
- * since the Unix epoch per RFC 8949.
8038
+ * @param callback - Function to call for each element
8046
8039
  *
8047
- * @returns A vector containing tag 1
8040
+ * @example
8041
+ * ```typescript
8042
+ * set.forEach(value => {
8043
+ * console.log(extractCbor(value));
8044
+ * });
8045
+ * ```
8048
8046
  */
8049
- cborTags() {
8050
- return [createTag(1, "date")];
8047
+ forEach(callback) {
8048
+ for (const value of this) callback(value);
8051
8049
  }
8052
8050
  /**
8053
- * Implementation of the `CborTaggedEncodable` interface for `CborDate`.
8051
+ * Encode the set as an (untagged) CBOR array of its elements, in canonical
8052
+ * ascending CBOR-byte order. Matches Rust `From<Set> for CBOR`.
8054
8053
  *
8055
- * Converts this `CborDate` to an untagged CBOR value.
8056
- *
8057
- * The date is converted to a numeric value representing the number of
8058
- * seconds since the Unix epoch. This value may be an integer or a
8059
- * floating-point number, depending on whether the date has fractional
8060
- * seconds.
8061
- *
8062
- * @returns A CBOR value representing the timestamp
8054
+ * @returns CBOR array
8063
8055
  */
8064
8056
  untaggedCbor() {
8065
- return cbor(this.timestamp());
8066
- }
8067
- /**
8068
- * Converts this `CborDate` to a tagged CBOR value with tag 1.
8069
- *
8070
- * @returns Tagged CBOR value
8071
- */
8072
- taggedCbor() {
8073
- return createTaggedCbor(this);
8057
+ return cbor(this.values());
8074
8058
  }
8075
8059
  /**
8076
- * Implementation of the `CborTaggedDecodable` interface for `CborDate`.
8077
- *
8078
- * Creates a `CborDate` from an untagged CBOR value.
8079
- *
8080
- * The CBOR value must be a numeric value (integer or floating-point)
8081
- * representing the number of seconds since the Unix epoch.
8082
- *
8083
- * @param cbor - The untagged CBOR value
8060
+ * Decode a CborSet from a CBOR array into this instance.
8084
8061
  *
8085
- * @returns This CborDate instance (mutated)
8062
+ * Mirrors Rust `Set::try_from_vec`, calling `insert_next` per item, so the
8063
+ * array must already be in strict ascending CBOR-byte order with no
8064
+ * duplicates (else `MisorderedMapKey`/`DuplicateMapKey`).
8086
8065
  *
8087
- * @throws Error if the CBOR value is not a valid timestamp
8066
+ * @param c - CBOR array value
8067
+ * @returns this
8068
+ * @throws CborError of type `WrongType` if `c` is not an array.
8088
8069
  */
8089
- fromUntaggedCbor(cbor) {
8090
- let timestamp;
8091
- switch (cbor.type) {
8092
- case MajorType.Unsigned:
8093
- timestamp = typeof cbor.value === "number" ? cbor.value : Number(cbor.value);
8094
- break;
8095
- case MajorType.Negative:
8096
- if (typeof cbor.value === "bigint") timestamp = Number(-cbor.value - 1n);
8097
- else timestamp = -cbor.value - 1;
8098
- break;
8099
- case MajorType.Simple:
8100
- if (cbor.value.type === "Float") timestamp = cbor.value.value;
8101
- else throw new CborError({ type: "WrongType" });
8102
- break;
8103
- default: throw new CborError({ type: "WrongType" });
8104
- }
8105
- this._seconds = timestamp;
8070
+ fromUntaggedCbor(c) {
8071
+ if (c.type !== MajorType.Array) throw new CborError({ type: "WrongType" });
8072
+ this.clear();
8073
+ for (const value of c.value) this.insertNext(extractCbor(value));
8106
8074
  return this;
8107
8075
  }
8108
8076
  /**
8109
- * Creates a `CborDate` from a tagged CBOR value with tag 1.
8110
- *
8111
- * @param cbor - Tagged CBOR value
8077
+ * Decode a CborSet from a CBOR array.
8112
8078
  *
8113
- * @returns This CborDate instance (mutated)
8114
- *
8115
- * @throws Error if the CBOR value has the wrong tag or cannot be decoded
8079
+ * @param c - CBOR array value
8080
+ * @returns Decoded CborSet instance
8116
8081
  */
8117
- fromTaggedCbor(cbor) {
8118
- validateTag(cbor, this.cborTags());
8119
- const content = extractTaggedContent(cbor);
8120
- return this.fromUntaggedCbor(content);
8082
+ static fromCbor(c) {
8083
+ return new CborSet().fromUntaggedCbor(c);
8121
8084
  }
8122
8085
  /**
8123
- * Static method to create a CborDate from tagged CBOR.
8086
+ * Convert to CBOR array (untagged).
8124
8087
  *
8125
- * @param cbor - Tagged CBOR value
8126
- * @returns New CborDate instance
8088
+ * @returns CBOR array
8127
8089
  */
8128
- static fromTaggedCbor(cbor) {
8129
- return new CborDate().fromTaggedCbor(cbor);
8090
+ toCbor() {
8091
+ return this.untaggedCbor();
8130
8092
  }
8131
8093
  /**
8132
- * Static method to create a CborDate from untagged CBOR.
8094
+ * Convert to encoded CBOR bytes.
8133
8095
  *
8134
- * @param cbor - Untagged CBOR value
8135
- * @returns New CborDate instance
8096
+ * @returns Encoded CBOR bytes
8136
8097
  */
8137
- static fromUntaggedCbor(cbor) {
8138
- return new CborDate().fromUntaggedCbor(cbor);
8098
+ toBytes() {
8099
+ return cborData(this.untaggedCbor());
8139
8100
  }
8140
8101
  /**
8141
- * Implementation of the `toString` method for `CborDate`.
8142
- *
8143
- * This implementation provides a string representation of a `CborDate` in ISO-8601
8144
- * format. For dates with time exactly at midnight (00:00:00), only the date
8145
- * part is shown. For other times, a full date-time string is shown.
8102
+ * Convert to JavaScript Set.
8146
8103
  *
8147
- * @returns String representation in ISO-8601 format
8104
+ * @returns JavaScript Set with extracted values
8148
8105
  *
8149
8106
  * @example
8150
8107
  * ```typescript
8151
- * // A date at midnight will display as just the date
8152
- * const date = CborDate.fromYmd(2023, 2, 8);
8153
- * // Returns "2023-02-08"
8154
- * console.log(date.toString());
8155
- *
8156
- * // A date with time will display as date and time
8157
- * const date2 = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
8158
- * // Returns "2023-02-08T15:30:45.000Z"
8159
- * console.log(date2.toString());
8108
+ * const cborSet = CborSet.fromArray([1, 2, 3]);
8109
+ * const jsSet = cborSet.toSet();
8110
+ * console.log(jsSet.has(1)); // true
8160
8111
  * ```
8161
8112
  */
8162
- toString() {
8163
- const dt = /* @__PURE__ */ new Date(this._seconds * 1e3);
8164
- if (!(dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0)) {
8165
- const datePart = dt.toISOString().split("T")[0];
8166
- if (datePart === void 0) throw new CborError({
8167
- type: "Custom",
8168
- message: "Invalid ISO string format"
8169
- });
8170
- return datePart;
8171
- } else return dt.toISOString().replace(/\.\d{3}Z$/, "Z");
8113
+ toSet() {
8114
+ const result = /* @__PURE__ */ new Set();
8115
+ for (const value of this) result.add(extractCbor(value));
8116
+ return result;
8172
8117
  }
8173
8118
  /**
8174
- * Compare two dates for equality.
8119
+ * Convert to JavaScript Array.
8175
8120
  *
8176
- * @param other - Other CborDate to compare
8177
- * @returns true if dates represent the same moment in time
8121
+ * @returns Array with extracted values
8178
8122
  */
8179
- equals(other) {
8180
- return this._seconds === other._seconds;
8123
+ toArray() {
8124
+ return Array.from(this.toSet());
8181
8125
  }
8182
8126
  /**
8183
- * Compare two dates.
8127
+ * Get diagnostic notation for the set.
8184
8128
  *
8185
- * @param other - Other CborDate to compare
8186
- * @returns -1 if this < other, 0 if equal, 1 if this > other
8129
+ * @returns String representation
8130
+ *
8131
+ * @example
8132
+ * ```typescript
8133
+ * const set = CborSet.fromArray([1, 2, 3]);
8134
+ * console.log(set.diagnostic); // "[1, 2, 3]"
8135
+ * ```
8187
8136
  */
8188
- compare(other) {
8189
- if (this._seconds < other._seconds) return -1;
8190
- if (this._seconds > other._seconds) return 1;
8191
- return 0;
8137
+ get diagnostic() {
8138
+ return `[${this.values().map((v) => {
8139
+ const extracted = extractCbor(v);
8140
+ if (typeof extracted === "string") return `"${extracted}"`;
8141
+ return String(extracted);
8142
+ }).join(", ")}]`;
8192
8143
  }
8193
8144
  /**
8194
- * Convert to JSON (returns ISO 8601 string).
8145
+ * Convert to string (same as diagnostic).
8195
8146
  *
8196
- * @returns ISO 8601 string
8147
+ * @returns String representation
8197
8148
  */
8198
- toJSON() {
8199
- return this.toString();
8149
+ toString() {
8150
+ return this.diagnostic;
8200
8151
  }
8201
- constructor() {
8202
- this._seconds = Date.now() / 1e3;
8152
+ /**
8153
+ * Convert to JSON (returns array of values).
8154
+ *
8155
+ * @returns Array for JSON serialization
8156
+ */
8157
+ toJSON() {
8158
+ return this.toArray();
8203
8159
  }
8204
8160
  };
8161
+ /**
8162
+ * Convert a value to CBOR for use in set operations.
8163
+ *
8164
+ * @internal
8165
+ */
8166
+ function encodeCborValue(value) {
8167
+ if (typeof value === "object" && value !== null && "isCbor" in value && value.isCbor === true) return value;
8168
+ return cbor(value);
8169
+ }
8205
8170
  //#endregion
8206
- //#region src/bignum.ts
8171
+ //#region src/cbor-tagged-encodable.ts
8207
8172
  /**
8208
8173
  * Copyright © 2023-2026 Blockchain Commons, LLC
8209
8174
  * Copyright © 2025-2026 Parity Technologies
8210
8175
  *
8211
8176
  *
8212
- * CBOR bignum (tags 2 and 3) support.
8177
+ * Tagged CBOR encoding support.
8213
8178
  *
8214
- * This module provides conversion between CBOR and JavaScript BigInt types,
8215
- * implementing RFC 8949 §3.4.3 (Bignums) with dCBOR/CDE canonical encoding rules.
8179
+ * This module provides the `CborTaggedEncodable` interface, which enables types to
8180
+ * be encoded as tagged CBOR values.
8216
8181
  *
8217
- * Encoding:
8218
- * - `biguintToCbor` always encodes as tag 2 (positive bignum) with a byte
8219
- * string content.
8220
- * - `bigintToCbor` encodes as tag 2 for non-negative values or tag 3
8221
- * (negative bignum) for negative values.
8222
- * - No numeric reduction is performed: values are always encoded as bignums,
8223
- * even if they would fit in normal CBOR integers.
8182
+ * CBOR tags provide semantic information about the encoded data. For example,
8183
+ * tag 1 is used for dates, indicating that the value should be interpreted
8184
+ * as a timestamp. The dCBOR library ensures these tags are encoded
8185
+ * deterministically.
8224
8186
  *
8225
- * Decoding:
8226
- * - Accepts CBOR integers (major types 0 and 1) and converts them to bigints.
8227
- * - Accepts tag 2 (positive bignum) and tag 3 (negative bignum) with byte
8228
- * string content.
8229
- * - Enforces shortest-form canonical representation for bignum magnitudes.
8230
- * - Rejects floating-point values.
8187
+ * This interface enables seamless encoding of TypeScript types to properly tagged CBOR
8188
+ * values.
8231
8189
  *
8232
- * @module bignum
8190
+ * @module cbor-tagged-encodable
8233
8191
  */
8234
- const TAG_2_POSITIVE_BIGNUM = 2;
8235
- const TAG_3_NEGATIVE_BIGNUM = 3;
8236
8192
  /**
8237
- * Validates that a bignum magnitude byte string is in shortest canonical form.
8238
- *
8239
- * Matches Rust's `validate_bignum_magnitude()`.
8193
+ * Helper function to create tagged CBOR from an encodable object.
8240
8194
  *
8241
- * Rules:
8242
- * - For positive bignums (tag 2): empty byte string represents zero;
8243
- * non-empty must not have leading zero bytes.
8244
- * - For negative bignums (tag 3): byte string must not be empty
8245
- * (magnitude zero is encoded as `0x00`); must not have leading zero bytes
8246
- * except when the magnitude is zero (single `0x00`).
8195
+ * Uses the first tag from cborTags().
8247
8196
  *
8248
- * @param bytes - The magnitude byte string to validate
8249
- * @param isNegative - Whether this is for a negative bignum (tag 3)
8250
- * @throws CborError with type NonCanonicalNumeric on validation failure
8197
+ * @param encodable - Object implementing CborTaggedEncodable
8198
+ * @returns Tagged CBOR value
8251
8199
  */
8252
- function validateBignumMagnitude(bytes, isNegative) {
8253
- if (isNegative) {
8254
- if (bytes.length === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8255
- if (bytes.length > 1 && bytes[0] === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8256
- } else if (bytes.length > 0 && bytes[0] === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8257
- }
8200
+ const createTaggedCbor = (encodable) => {
8201
+ const tags = encodable.cborTags();
8202
+ if (tags.length === 0) throw new CborError({
8203
+ type: "Custom",
8204
+ message: "No tags defined for this type"
8205
+ });
8206
+ const tag = tags[0];
8207
+ if (tag === void 0) throw new CborError({
8208
+ type: "Custom",
8209
+ message: "Tag is undefined"
8210
+ });
8211
+ const untagged = encodable.untaggedCbor();
8212
+ return attachMethods({
8213
+ isCbor: true,
8214
+ type: MajorType.Tagged,
8215
+ tag: tag.value,
8216
+ value: untagged
8217
+ });
8218
+ };
8258
8219
  /**
8259
- * Strips leading zero bytes from a byte array, returning the minimal
8260
- * representation.
8261
- *
8262
- * Matches Rust's `strip_leading_zeros()`.
8220
+ * Default `taggedCborData()` implementation `taggedCbor().toData()`.
8263
8221
  *
8264
- * @param bytes - The byte array to strip
8265
- * @returns A subarray with leading zeros removed
8222
+ * Mirrors Rust's default `tagged_cbor_data()` impl on
8223
+ * `CBORTaggedEncodable`. TypeScript interfaces don't carry method bodies,
8224
+ * so this helper plays the role of the Rust trait default; concrete types
8225
+ * call it from their own `taggedCborData()` if they don't need to override.
8266
8226
  */
8267
- function stripLeadingZeros(bytes) {
8268
- let start = 0;
8269
- while (start < bytes.length && bytes[start] === 0) start++;
8270
- return bytes.subarray(start);
8271
- }
8227
+ const taggedCborData = (encodable) => encodable.taggedCbor().toData();
8228
+ //#endregion
8229
+ //#region src/cbor-tagged-decodable.ts
8272
8230
  /**
8273
- * Convert a non-negative bigint to a big-endian byte array.
8231
+ * Copyright © 2023-2026 Blockchain Commons, LLC
8232
+ * Copyright © 2025-2026 Parity Technologies
8274
8233
  *
8275
- * Zero returns an empty Uint8Array.
8276
8234
  *
8277
- * @param value - A non-negative bigint value
8278
- * @returns Big-endian byte representation
8279
- */
8280
- function bigintToBytes(value) {
8281
- if (value === 0n) return /* @__PURE__ */ new Uint8Array(0);
8282
- const hex = value.toString(16);
8283
- const padded = hex.length % 2 !== 0 ? `0${hex}` : hex;
8284
- const bytes = new Uint8Array(padded.length / 2);
8285
- for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(padded.substring(i * 2, i * 2 + 2), 16);
8286
- return bytes;
8287
- }
8288
- /**
8289
- * Convert a big-endian byte array to a bigint.
8235
+ * Tagged CBOR decoding support.
8290
8236
  *
8291
- * Empty array returns 0n.
8237
+ * This module provides the `CborTaggedDecodable` interface, which enables types to
8238
+ * be decoded from tagged CBOR values.
8292
8239
  *
8293
- * @param bytes - Big-endian byte representation
8294
- * @returns The bigint value
8240
+ * Tagged CBOR values include semantic information about how to interpret the
8241
+ * data. This interface allows TypeScript types to verify that incoming CBOR data has the
8242
+ * expected tag(s) and to decode the data appropriately.
8243
+ *
8244
+ * @module cbor-tagged-decodable
8295
8245
  */
8296
- function bytesToBigint(bytes) {
8297
- if (bytes.length === 0) return 0n;
8298
- let result = 0n;
8299
- for (const byte of bytes) result = result << 8n | BigInt(byte);
8300
- return result;
8301
- }
8302
8246
  /**
8303
- * Encode a non-negative bigint as a CBOR tag 2 (positive bignum).
8247
+ * Helper function to validate that a CBOR value has one of the expected tags.
8304
8248
  *
8305
- * Matches Rust's `From<BigUint> for CBOR`.
8249
+ * @param cbor - CBOR value to validate
8250
+ * @param expectedTags - Array of valid tags
8251
+ * @returns The matching tag
8252
+ * @throws Error if the value is not tagged or has an unexpected tag
8253
+ */
8254
+ const validateTag = (cbor, expectedTags) => {
8255
+ if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
8256
+ const tagValue = cbor.tag;
8257
+ const matchingTag = expectedTags.find((t) => tagValuesEqual(t.value, tagValue));
8258
+ if (matchingTag === void 0) throw new CborError({
8259
+ type: "WrongTag",
8260
+ expected: expectedTags[0],
8261
+ actual: { value: tagValue }
8262
+ });
8263
+ return matchingTag;
8264
+ };
8265
+ /**
8266
+ * Helper function to extract the content from a tagged CBOR value.
8306
8267
  *
8307
- * The value is always encoded as a bignum regardless of size.
8308
- * Zero is encoded as tag 2 with an empty byte string.
8268
+ * @param cbor - Tagged CBOR value
8269
+ * @returns The untagged content
8270
+ * @throws Error if the value is not tagged
8271
+ */
8272
+ const extractTaggedContent = (cbor) => {
8273
+ if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
8274
+ return cbor.value;
8275
+ };
8276
+ /**
8277
+ * Default `fromTaggedCborData()` implementation — `decodeCbor(data)` then
8278
+ * delegate to the decodable's `fromTaggedCbor()`.
8309
8279
  *
8310
- * @param value - A non-negative bigint (must be >= 0n)
8311
- * @returns CBOR tagged value
8312
- * @throws CborError with type OutOfRange if value is negative
8280
+ * Mirrors Rust's default `from_tagged_cbor_data` impl on
8281
+ * `CBORTaggedDecodable`.
8313
8282
  */
8314
- function biguintToCbor(value) {
8315
- if (value < 0n) throw new CborError({ type: "OutOfRange" });
8316
- return toTaggedValue(TAG_2_POSITIVE_BIGNUM, stripLeadingZeros(bigintToBytes(value)));
8283
+ function fromTaggedCborData(decodable, data) {
8284
+ return decodable.fromTaggedCbor(decodeCbor(data));
8317
8285
  }
8318
8286
  /**
8319
- * Encode a bigint as a CBOR tag 2 or tag 3 bignum.
8320
- *
8321
- * Matches Rust's `From<BigInt> for CBOR`.
8322
- *
8323
- * - Non-negative values use tag 2 (positive bignum).
8324
- * - Negative values use tag 3 (negative bignum), where the encoded
8325
- * magnitude is `|value| - 1` per RFC 8949.
8287
+ * Default `fromUntaggedCborData()` implementation `decodeCbor(data)`
8288
+ * then delegate to the decodable's `fromUntaggedCbor()`.
8326
8289
  *
8327
- * @param value - Any bigint value
8328
- * @returns CBOR tagged value
8290
+ * Mirrors Rust's default `from_untagged_cbor_data` impl on
8291
+ * `CBORTaggedDecodable`.
8329
8292
  */
8330
- function bigintToCbor(value) {
8331
- if (value >= 0n) return biguintToCbor(value);
8332
- const stripped = stripLeadingZeros(bigintToBytes(-value - 1n));
8333
- return toTaggedValue(TAG_3_NEGATIVE_BIGNUM, stripped.length === 0 ? new Uint8Array([0]) : stripped);
8293
+ function fromUntaggedCborData(decodable, data) {
8294
+ return decodable.fromUntaggedCbor(decodeCbor(data));
8334
8295
  }
8296
+ //#endregion
8297
+ //#region src/date.ts
8335
8298
  /**
8336
- * Decode a BigUint from an untagged CBOR byte string.
8299
+ * Copyright © 2023-2026 Blockchain Commons, LLC
8300
+ * Copyright © 2025-2026 Parity Technologies
8337
8301
  *
8338
- * Matches Rust's `biguint_from_untagged_cbor()`.
8339
8302
  *
8340
- * This function is intended for use in tag summarizers where the tag has
8341
- * already been stripped. It expects a CBOR byte string representing the
8342
- * big-endian magnitude of a positive bignum (tag 2 content).
8303
+ * Date/time support for CBOR with tag(1) encoding.
8343
8304
  *
8344
- * Enforces canonical encoding: no leading zero bytes (except empty for zero).
8305
+ * A CBOR-friendly representation of a date and time.
8345
8306
  *
8346
- * @param cbor - A CBOR value that should be a byte string
8347
- * @returns Non-negative bigint
8348
- * @throws CborError with type WrongType if not a byte string
8349
- * @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
8350
- */
8351
- function biguintFromUntaggedCbor(cbor) {
8352
- if (cbor.type !== MajorType.ByteString) throw new CborError({ type: "WrongType" });
8353
- const bytes = cbor.value;
8354
- validateBignumMagnitude(bytes, false);
8355
- return bytesToBigint(bytes);
8356
- }
8357
- /**
8358
- * Decode a BigInt from an untagged CBOR byte string for a negative bignum.
8307
+ * The `CborDate` type provides a wrapper around JavaScript's native `Date` that
8308
+ * supports encoding and decoding to/from CBOR with tag 1, following the CBOR
8309
+ * date/time standard specified in RFC 8949.
8359
8310
  *
8360
- * Matches Rust's `bigint_from_negative_untagged_cbor()`.
8311
+ * When encoded to CBOR, dates are represented as tag 1 followed by a numeric
8312
+ * value representing the number of seconds since (or before) the Unix epoch
8313
+ * (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
8314
+ * integer, or a floating-point value for dates with fractional seconds.
8361
8315
  *
8362
- * This function is intended for use in tag summarizers where the tag has
8363
- * already been stripped. It expects a CBOR byte string representing `n` where
8364
- * the actual value is `-1 - n` (tag 3 content per RFC 8949).
8316
+ * @module date
8317
+ */
8318
+ /**
8319
+ * Normalize a timestamp (seconds since the Unix epoch) to whole seconds plus a
8320
+ * non-negative, sub-second nanosecond part, matching Rust's
8321
+ * `Date::from_timestamp` so dates round-trip byte-identically with the reference.
8365
8322
  *
8366
- * Enforces canonical encoding: no leading zero bytes (except single `0x00`
8367
- * for -1).
8323
+ * The nanosecond part is computed like Rust's `as u32` cast: truncated toward
8324
+ * zero and clamped to [0, u32::MAX]. So a negative fraction floors the value
8325
+ * (`-1.5` becomes `-1.0`) and sub-nanosecond precision is dropped
8326
+ * (`1.0000000005` becomes `1.0`).
8368
8327
  *
8369
- * @param cbor - A CBOR value that should be a byte string
8370
- * @returns Negative bigint
8371
- * @throws CborError with type WrongType if not a byte string
8372
- * @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
8328
+ * @internal
8373
8329
  */
8374
- function bigintFromNegativeUntaggedCbor(cbor) {
8375
- if (cbor.type !== MajorType.ByteString) throw new CborError({ type: "WrongType" });
8376
- const bytes = cbor.value;
8377
- validateBignumMagnitude(bytes, true);
8378
- return -(bytesToBigint(bytes) + 1n);
8330
+ function normalizeTimestampSeconds(seconds) {
8331
+ if (!Number.isFinite(seconds)) throw new CborError({
8332
+ type: "InvalidDate",
8333
+ message: "non-finite timestamp"
8334
+ });
8335
+ const whole = Math.trunc(seconds);
8336
+ let nsecs = Math.trunc((seconds - whole) * 1e9);
8337
+ if (nsecs < 0) nsecs = 0;
8338
+ else if (nsecs > 4294967295) nsecs = 4294967295;
8339
+ return whole + nsecs / 1e9;
8379
8340
  }
8380
8341
  /**
8381
- * Convert CBOR to a non-negative bigint.
8342
+ * A CBOR-friendly representation of a date and time.
8382
8343
  *
8383
- * Matches Rust's `TryFrom<CBOR> for BigUint`.
8344
+ * The `CborDate` type provides a wrapper around JavaScript's native `Date` that
8345
+ * supports encoding and decoding to/from CBOR with tag 1, following the CBOR
8346
+ * date/time standard specified in RFC 8949.
8384
8347
  *
8385
- * Accepts:
8386
- * - Major type 0 (unsigned integer)
8387
- * - Tag 2 (positive bignum) with canonical byte string
8348
+ * When encoded to CBOR, dates are represented as tag 1 followed by a numeric
8349
+ * value representing the number of seconds since (or before) the Unix epoch
8350
+ * (1970-01-01T00:00:00Z). The numeric value can be a positive or negative
8351
+ * integer, or a floating-point value for dates with fractional seconds.
8388
8352
  *
8389
- * Rejects:
8390
- * - Major type 1 (negative integer) -> OutOfRange
8391
- * - Tag 3 (negative bignum) -> OutOfRange
8392
- * - Floating-point values -> WrongType
8393
- * - Non-canonical bignum encodings -> NonCanonicalNumeric
8353
+ * # Features
8354
+ *
8355
+ * - Supports UTC dates with optional fractional seconds
8356
+ * - Provides convenient constructors for common date creation patterns
8357
+ * - Implements the `CborTagged`, `CborTaggedEncodable`, and
8358
+ * `CborTaggedDecodable` interfaces
8359
+ * - Supports arithmetic operations with durations and between dates
8360
+ *
8361
+ * @example
8362
+ * ```typescript
8363
+ * import { CborDate } from './date';
8364
+ *
8365
+ * // Create a date from a timestamp (seconds since Unix epoch)
8366
+ * const date = CborDate.fromTimestamp(1675854714.0);
8367
+ *
8368
+ * // Create a date from year, month, day
8369
+ * const date2 = CborDate.fromYmd(2023, 2, 8);
8370
+ *
8371
+ * // Convert to CBOR
8372
+ * const cborValue = date.taggedCbor();
8373
+ *
8374
+ * // Decode from CBOR
8375
+ * const decoded = CborDate.fromTaggedCbor(cborValue);
8376
+ * ```
8377
+ */
8378
+ var CborDate = class CborDate {
8379
+ /**
8380
+ * Canonical timestamp in seconds since the Unix epoch as a JS `number`
8381
+ * (`f64`). dCBOR encodes Date (tag 1) as a numeric value in seconds, so
8382
+ * keeping `_seconds` as the source of truth avoids the millisecond-only
8383
+ * round-trip precision loss that going through a JS `Date` instance
8384
+ * introduced in earlier versions of this port.
8385
+ *
8386
+ * f64 still bounds the achievable precision (~16 decimal digits, so
8387
+ * roughly microseconds for current epoch values); Rust's
8388
+ * `chrono::DateTime<Utc>` retains nanoseconds in memory but encodes
8389
+ * to the same f64 over the wire, so the *encode/decode round-trip* is
8390
+ * byte-identical.
8391
+ */
8392
+ _seconds;
8393
+ /**
8394
+ * Creates a new `CborDate` from the given JavaScript `Date`.
8395
+ *
8396
+ * This method creates a new `CborDate` instance by wrapping a
8397
+ * JavaScript `Date`.
8398
+ *
8399
+ * @param dateTime - A `Date` instance to wrap
8400
+ *
8401
+ * @returns A new `CborDate` instance
8402
+ *
8403
+ * @example
8404
+ * ```typescript
8405
+ * const datetime = new Date();
8406
+ * const date = CborDate.fromDatetime(datetime);
8407
+ * ```
8408
+ */
8409
+ static fromDatetime(dateTime) {
8410
+ const instance = new CborDate();
8411
+ instance._seconds = dateTime.getTime() / 1e3;
8412
+ return instance;
8413
+ }
8414
+ /**
8415
+ * Creates a new `CborDate` from year, month, and day components.
8416
+ *
8417
+ * This method creates a new `CborDate` with the time set to 00:00:00 UTC.
8418
+ *
8419
+ * @param year - The year component (e.g., 2023)
8420
+ * @param month - The month component (1-12)
8421
+ * @param day - The day component (1-31)
8422
+ *
8423
+ * @returns A new `CborDate` instance
8424
+ *
8425
+ * @example
8426
+ * ```typescript
8427
+ * // Create February 8, 2023
8428
+ * const date = CborDate.fromYmd(2023, 2, 8);
8429
+ * ```
8430
+ *
8431
+ * @throws Error if the provided components do not form a valid date.
8432
+ */
8433
+ static fromYmd(year, month, day) {
8434
+ const dt = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));
8435
+ return CborDate.fromDatetime(dt);
8436
+ }
8437
+ /**
8438
+ * Creates a new `CborDate` from year, month, day, hour, minute, and second
8439
+ * components.
8440
+ *
8441
+ * @param year - The year component (e.g., 2023)
8442
+ * @param month - The month component (1-12)
8443
+ * @param day - The day component (1-31)
8444
+ * @param hour - The hour component (0-23)
8445
+ * @param minute - The minute component (0-59)
8446
+ * @param second - The second component (0-59)
8447
+ *
8448
+ * @returns A new `CborDate` instance
8449
+ *
8450
+ * @example
8451
+ * ```typescript
8452
+ * // Create February 8, 2023, 15:30:45 UTC
8453
+ * const date = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
8454
+ * ```
8455
+ *
8456
+ * @throws Error if the provided components do not form a valid date and time.
8457
+ */
8458
+ static fromYmdHms(year, month, day, hour, minute, second) {
8459
+ const dt = new Date(Date.UTC(year, month - 1, day, hour, minute, second, 0));
8460
+ return CborDate.fromDatetime(dt);
8461
+ }
8462
+ /**
8463
+ * Creates a new `CborDate` from seconds since (or before) the Unix epoch.
8464
+ *
8465
+ * This method creates a new `CborDate` representing the specified number of
8466
+ * seconds since the Unix epoch (1970-01-01T00:00:00Z). Negative values
8467
+ * represent times before the epoch.
8468
+ *
8469
+ * @param secondsSinceUnixEpoch - Seconds from the Unix epoch (positive or
8470
+ * negative), which can include a fractional part for sub-second
8471
+ * precision
8472
+ *
8473
+ * @returns A new `CborDate` instance
8474
+ *
8475
+ * @example
8476
+ * ```typescript
8477
+ * // Create a date from a timestamp
8478
+ * const date = CborDate.fromTimestamp(1675854714.0);
8479
+ *
8480
+ * // Create a date one second before the Unix epoch
8481
+ * const beforeEpoch = CborDate.fromTimestamp(-1.0);
8482
+ *
8483
+ * // Create a date with fractional seconds
8484
+ * const withFraction = CborDate.fromTimestamp(1675854714.5);
8485
+ * ```
8486
+ */
8487
+ static fromTimestamp(secondsSinceUnixEpoch) {
8488
+ const instance = new CborDate();
8489
+ instance._seconds = normalizeTimestampSeconds(secondsSinceUnixEpoch);
8490
+ return instance;
8491
+ }
8492
+ /**
8493
+ * Creates a new `CborDate` from a string containing an ISO-8601 (RFC-3339)
8494
+ * date (with or without time).
8495
+ *
8496
+ * This method parses a string representation of a date or date-time in
8497
+ * ISO-8601/RFC-3339 format and creates a new `CborDate` instance. It
8498
+ * supports both full date-time strings (e.g., "2023-02-08T15:30:45Z")
8499
+ * and date-only strings (e.g., "2023-02-08").
8500
+ *
8501
+ * @param value - A string containing a date or date-time in ISO-8601/RFC-3339
8502
+ * format
8503
+ *
8504
+ * @returns A new `CborDate` instance if parsing succeeds
8505
+ *
8506
+ * @throws Error if the string cannot be parsed as a valid date or date-time
8507
+ *
8508
+ * @example
8509
+ * ```typescript
8510
+ * // Parse a date-time string
8511
+ * const date = CborDate.fromString("2023-02-08T15:30:45Z");
8512
+ *
8513
+ * // Parse a date-only string (time will be set to 00:00:00)
8514
+ * const date2 = CborDate.fromString("2023-02-08");
8515
+ * ```
8516
+ */
8517
+ static fromString(value) {
8518
+ const invalidDate = new CborError({
8519
+ type: "InvalidDate",
8520
+ message: "Invalid date string"
8521
+ });
8522
+ const rfc3339 = /^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/;
8523
+ const dateOnly = /^\d{4}-\d{2}-\d{2}$/;
8524
+ let parsed;
8525
+ if (rfc3339.test(value)) parsed = new Date(value);
8526
+ else if (dateOnly.test(value)) parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
8527
+ else throw invalidDate;
8528
+ const [y, m, d] = value.slice(0, 10).split("-").map(Number);
8529
+ const probe = new Date(Date.UTC(y, m - 1, d));
8530
+ if (!(probe.getUTCFullYear() === y && probe.getUTCMonth() === m - 1 && probe.getUTCDate() === d) || isNaN(parsed.getTime())) throw invalidDate;
8531
+ return CborDate.fromDatetime(parsed);
8532
+ }
8533
+ /**
8534
+ * Creates a new `CborDate` containing the current date and time.
8535
+ *
8536
+ * @returns A new `CborDate` instance representing the current UTC date and time
8537
+ *
8538
+ * @example
8539
+ * ```typescript
8540
+ * const now = CborDate.now();
8541
+ * ```
8542
+ */
8543
+ static now() {
8544
+ return CborDate.fromDatetime(/* @__PURE__ */ new Date());
8545
+ }
8546
+ /**
8547
+ * Creates a new `CborDate` containing the current date and time plus the given
8548
+ * duration.
8549
+ *
8550
+ * @param durationMs - The duration in milliseconds to add to the current time
8551
+ *
8552
+ * @returns A new `CborDate` instance representing the current UTC date and time plus
8553
+ * the duration
8554
+ *
8555
+ * @example
8556
+ * ```typescript
8557
+ * // Get a date 1 hour from now
8558
+ * const oneHourLater = CborDate.withDurationFromNow(3600 * 1000);
8559
+ * ```
8560
+ */
8561
+ static withDurationFromNow(durationMs) {
8562
+ const future = new Date((/* @__PURE__ */ new Date()).getTime() + durationMs);
8563
+ return CborDate.fromDatetime(future);
8564
+ }
8565
+ /**
8566
+ * Returns the underlying JavaScript `Date` object.
8567
+ *
8568
+ * This method provides access to the wrapped JavaScript `Date`
8569
+ * instance.
8570
+ *
8571
+ * @returns The wrapped `Date` instance
8572
+ *
8573
+ * @example
8574
+ * ```typescript
8575
+ * const date = CborDate.now();
8576
+ * const datetime = date.datetime();
8577
+ * const year = datetime.getFullYear();
8578
+ * ```
8579
+ */
8580
+ datetime() {
8581
+ return /* @__PURE__ */ new Date(this._seconds * 1e3);
8582
+ }
8583
+ /**
8584
+ * Returns the `CborDate` as the number of seconds since the Unix epoch.
8585
+ *
8586
+ * This method converts the date to a floating-point number representing
8587
+ * the number of seconds since the Unix epoch (1970-01-01T00:00:00Z).
8588
+ * Negative values represent times before the epoch. The fractional
8589
+ * part represents sub-second precision.
8590
+ *
8591
+ * @returns Seconds since the Unix epoch as a `number`
8592
+ *
8593
+ * @example
8594
+ * ```typescript
8595
+ * const date = CborDate.fromYmd(2023, 2, 8);
8596
+ * const timestamp = date.timestamp();
8597
+ * ```
8598
+ */
8599
+ timestamp() {
8600
+ return this._seconds;
8601
+ }
8602
+ /**
8603
+ * Add seconds to this date.
8604
+ *
8605
+ * @param seconds - Seconds to add (can be fractional)
8606
+ * @returns New CborDate instance
8607
+ *
8608
+ * @example
8609
+ * ```typescript
8610
+ * const date = CborDate.fromYmd(2022, 3, 21);
8611
+ * const tomorrow = date.add(24 * 60 * 60);
8612
+ * ```
8613
+ */
8614
+ add(seconds) {
8615
+ return CborDate.fromTimestamp(this.timestamp() + seconds);
8616
+ }
8617
+ /**
8618
+ * Subtract seconds from this date.
8619
+ *
8620
+ * @param seconds - Seconds to subtract (can be fractional)
8621
+ * @returns New CborDate instance
8622
+ *
8623
+ * @example
8624
+ * ```typescript
8625
+ * const date = CborDate.fromYmd(2022, 3, 21);
8626
+ * const yesterday = date.subtract(24 * 60 * 60);
8627
+ * ```
8628
+ */
8629
+ subtract(seconds) {
8630
+ return CborDate.fromTimestamp(this.timestamp() - seconds);
8631
+ }
8632
+ /**
8633
+ * Get the difference in seconds between this date and another.
8634
+ *
8635
+ * @param other - Other CborDate to compare with
8636
+ * @returns Difference in seconds (this - other)
8637
+ *
8638
+ * @example
8639
+ * ```typescript
8640
+ * const date1 = CborDate.fromYmd(2022, 3, 22);
8641
+ * const date2 = CborDate.fromYmd(2022, 3, 21);
8642
+ * const diff = date1.difference(date2);
8643
+ * // Returns 86400 (one day in seconds)
8644
+ * ```
8645
+ */
8646
+ difference(other) {
8647
+ return this.timestamp() - other.timestamp();
8648
+ }
8649
+ /**
8650
+ * Implementation of the `CborTagged` interface for `CborDate`.
8651
+ *
8652
+ * This implementation specifies that `CborDate` values are tagged with CBOR tag 1,
8653
+ * which is the standard CBOR tag for date/time values represented as seconds
8654
+ * since the Unix epoch per RFC 8949.
8655
+ *
8656
+ * @returns A vector containing tag 1
8657
+ */
8658
+ cborTags() {
8659
+ return [createTag(1, "date")];
8660
+ }
8661
+ /**
8662
+ * Implementation of the `CborTaggedEncodable` interface for `CborDate`.
8663
+ *
8664
+ * Converts this `CborDate` to an untagged CBOR value.
8665
+ *
8666
+ * The date is converted to a numeric value representing the number of
8667
+ * seconds since the Unix epoch. This value may be an integer or a
8668
+ * floating-point number, depending on whether the date has fractional
8669
+ * seconds.
8670
+ *
8671
+ * @returns A CBOR value representing the timestamp
8672
+ */
8673
+ untaggedCbor() {
8674
+ return cbor(this.timestamp());
8675
+ }
8676
+ /**
8677
+ * Converts this `CborDate` to a tagged CBOR value with tag 1.
8678
+ *
8679
+ * @returns Tagged CBOR value
8680
+ */
8681
+ taggedCbor() {
8682
+ return createTaggedCbor(this);
8683
+ }
8684
+ /**
8685
+ * Implementation of the `CborTaggedDecodable` interface for `CborDate`.
8686
+ *
8687
+ * Creates a `CborDate` from an untagged CBOR value.
8688
+ *
8689
+ * The CBOR value must be a numeric value (integer or floating-point)
8690
+ * representing the number of seconds since the Unix epoch.
8691
+ *
8692
+ * @param cbor - The untagged CBOR value
8693
+ *
8694
+ * @returns This CborDate instance (mutated)
8695
+ *
8696
+ * @throws Error if the CBOR value is not a valid timestamp
8697
+ */
8698
+ fromUntaggedCbor(cbor) {
8699
+ let timestamp;
8700
+ switch (cbor.type) {
8701
+ case MajorType.Unsigned:
8702
+ timestamp = typeof cbor.value === "number" ? cbor.value : Number(cbor.value);
8703
+ break;
8704
+ case MajorType.Negative:
8705
+ if (typeof cbor.value === "bigint") timestamp = Number(-cbor.value - 1n);
8706
+ else timestamp = -cbor.value - 1;
8707
+ break;
8708
+ case MajorType.Simple:
8709
+ if (cbor.value.type === "Float") timestamp = cbor.value.value;
8710
+ else throw new CborError({ type: "WrongType" });
8711
+ break;
8712
+ default: throw new CborError({ type: "WrongType" });
8713
+ }
8714
+ this._seconds = normalizeTimestampSeconds(timestamp);
8715
+ return this;
8716
+ }
8717
+ /**
8718
+ * Creates a `CborDate` from a tagged CBOR value with tag 1.
8719
+ *
8720
+ * @param cbor - Tagged CBOR value
8721
+ *
8722
+ * @returns This CborDate instance (mutated)
8723
+ *
8724
+ * @throws Error if the CBOR value has the wrong tag or cannot be decoded
8725
+ */
8726
+ fromTaggedCbor(cbor) {
8727
+ validateTag(cbor, this.cborTags());
8728
+ const content = extractTaggedContent(cbor);
8729
+ return this.fromUntaggedCbor(content);
8730
+ }
8731
+ /**
8732
+ * Static method to create a CborDate from tagged CBOR.
8733
+ *
8734
+ * @param cbor - Tagged CBOR value
8735
+ * @returns New CborDate instance
8736
+ */
8737
+ static fromTaggedCbor(cbor) {
8738
+ return new CborDate().fromTaggedCbor(cbor);
8739
+ }
8740
+ /**
8741
+ * Static method to create a CborDate from untagged CBOR.
8742
+ *
8743
+ * @param cbor - Untagged CBOR value
8744
+ * @returns New CborDate instance
8745
+ */
8746
+ static fromUntaggedCbor(cbor) {
8747
+ return new CborDate().fromUntaggedCbor(cbor);
8748
+ }
8749
+ /**
8750
+ * Implementation of the `toString` method for `CborDate`.
8751
+ *
8752
+ * This implementation provides a string representation of a `CborDate` in ISO-8601
8753
+ * format. For dates with time exactly at midnight (00:00:00), only the date
8754
+ * part is shown. For other times, a full date-time string is shown.
8755
+ *
8756
+ * @returns String representation in ISO-8601 format
8757
+ *
8758
+ * @example
8759
+ * ```typescript
8760
+ * // A date at midnight will display as just the date
8761
+ * const date = CborDate.fromYmd(2023, 2, 8);
8762
+ * // Returns "2023-02-08"
8763
+ * console.log(date.toString());
8764
+ *
8765
+ * // A date with time will display as date and time
8766
+ * const date2 = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45);
8767
+ * // Returns "2023-02-08T15:30:45.000Z"
8768
+ * console.log(date2.toString());
8769
+ * ```
8770
+ */
8771
+ toString() {
8772
+ const dt = /* @__PURE__ */ new Date(this._seconds * 1e3);
8773
+ if (!(dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0)) {
8774
+ const datePart = dt.toISOString().split("T")[0];
8775
+ if (datePart === void 0) throw new CborError({
8776
+ type: "Custom",
8777
+ message: "Invalid ISO string format"
8778
+ });
8779
+ return datePart;
8780
+ } else return dt.toISOString().replace(/\.\d{3}Z$/, "Z");
8781
+ }
8782
+ /**
8783
+ * Compare two dates for equality.
8784
+ *
8785
+ * @param other - Other CborDate to compare
8786
+ * @returns true if dates represent the same moment in time
8787
+ */
8788
+ equals(other) {
8789
+ return this._seconds === other._seconds;
8790
+ }
8791
+ /**
8792
+ * Compare two dates.
8793
+ *
8794
+ * @param other - Other CborDate to compare
8795
+ * @returns -1 if this < other, 0 if equal, 1 if this > other
8796
+ */
8797
+ compare(other) {
8798
+ if (this._seconds < other._seconds) return -1;
8799
+ if (this._seconds > other._seconds) return 1;
8800
+ return 0;
8801
+ }
8802
+ /**
8803
+ * Convert to JSON (returns ISO 8601 string).
8804
+ *
8805
+ * @returns ISO 8601 string
8806
+ */
8807
+ toJSON() {
8808
+ return this.toString();
8809
+ }
8810
+ constructor() {
8811
+ this._seconds = Date.now() / 1e3;
8812
+ }
8813
+ };
8814
+ //#endregion
8815
+ //#region src/bignum.ts
8816
+ /**
8817
+ * Copyright © 2023-2026 Blockchain Commons, LLC
8818
+ * Copyright © 2025-2026 Parity Technologies
8819
+ *
8820
+ *
8821
+ * CBOR bignum (tags 2 and 3) support.
8822
+ *
8823
+ * This module provides conversion between CBOR and JavaScript BigInt types,
8824
+ * implementing RFC 8949 §3.4.3 (Bignums) with dCBOR/CDE canonical encoding rules.
8825
+ *
8826
+ * Encoding:
8827
+ * - `biguintToCbor` always encodes as tag 2 (positive bignum) with a byte
8828
+ * string content.
8829
+ * - `bigintToCbor` encodes as tag 2 for non-negative values or tag 3
8830
+ * (negative bignum) for negative values.
8831
+ * - No numeric reduction is performed: values are always encoded as bignums,
8832
+ * even if they would fit in normal CBOR integers.
8833
+ *
8834
+ * Decoding:
8835
+ * - Accepts CBOR integers (major types 0 and 1) and converts them to bigints.
8836
+ * - Accepts tag 2 (positive bignum) and tag 3 (negative bignum) with byte
8837
+ * string content.
8838
+ * - Enforces shortest-form canonical representation for bignum magnitudes.
8839
+ * - Rejects floating-point values.
8840
+ *
8841
+ * @module bignum
8842
+ */
8843
+ const TAG_2_POSITIVE_BIGNUM = 2;
8844
+ const TAG_3_NEGATIVE_BIGNUM = 3;
8845
+ /**
8846
+ * Validates that a bignum magnitude byte string is in shortest canonical form.
8847
+ *
8848
+ * Matches Rust's `validate_bignum_magnitude()`.
8849
+ *
8850
+ * Rules:
8851
+ * - For positive bignums (tag 2): empty byte string represents zero;
8852
+ * non-empty must not have leading zero bytes.
8853
+ * - For negative bignums (tag 3): byte string must not be empty
8854
+ * (magnitude zero is encoded as `0x00`); must not have leading zero bytes
8855
+ * except when the magnitude is zero (single `0x00`).
8856
+ *
8857
+ * @param bytes - The magnitude byte string to validate
8858
+ * @param isNegative - Whether this is for a negative bignum (tag 3)
8859
+ * @throws CborError with type NonCanonicalNumeric on validation failure
8860
+ */
8861
+ function validateBignumMagnitude(bytes, isNegative) {
8862
+ if (isNegative) {
8863
+ if (bytes.length === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8864
+ if (bytes.length > 1 && bytes[0] === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8865
+ } else if (bytes.length > 0 && bytes[0] === 0) throw new CborError({ type: "NonCanonicalNumeric" });
8866
+ }
8867
+ /**
8868
+ * Strips leading zero bytes from a byte array, returning the minimal
8869
+ * representation.
8870
+ *
8871
+ * Matches Rust's `strip_leading_zeros()`.
8872
+ *
8873
+ * @param bytes - The byte array to strip
8874
+ * @returns A subarray with leading zeros removed
8875
+ */
8876
+ function stripLeadingZeros(bytes) {
8877
+ let start = 0;
8878
+ while (start < bytes.length && bytes[start] === 0) start++;
8879
+ return bytes.subarray(start);
8880
+ }
8881
+ /**
8882
+ * Convert a non-negative bigint to a big-endian byte array.
8883
+ *
8884
+ * Zero returns an empty Uint8Array.
8885
+ *
8886
+ * @param value - A non-negative bigint value
8887
+ * @returns Big-endian byte representation
8888
+ */
8889
+ function bigintToBytes(value) {
8890
+ if (value === 0n) return /* @__PURE__ */ new Uint8Array(0);
8891
+ const hex = value.toString(16);
8892
+ const padded = hex.length % 2 !== 0 ? `0${hex}` : hex;
8893
+ const bytes = new Uint8Array(padded.length / 2);
8894
+ for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(padded.substring(i * 2, i * 2 + 2), 16);
8895
+ return bytes;
8896
+ }
8897
+ /**
8898
+ * Convert a big-endian byte array to a bigint.
8899
+ *
8900
+ * Empty array returns 0n.
8901
+ *
8902
+ * @param bytes - Big-endian byte representation
8903
+ * @returns The bigint value
8904
+ */
8905
+ function bytesToBigint(bytes) {
8906
+ if (bytes.length === 0) return 0n;
8907
+ let result = 0n;
8908
+ for (const byte of bytes) result = result << 8n | BigInt(byte);
8909
+ return result;
8910
+ }
8911
+ /**
8912
+ * Encode a non-negative bigint as a CBOR tag 2 (positive bignum).
8913
+ *
8914
+ * Matches Rust's `From<BigUint> for CBOR`.
8915
+ *
8916
+ * The value is always encoded as a bignum regardless of size.
8917
+ * Zero is encoded as tag 2 with an empty byte string.
8918
+ *
8919
+ * @param value - A non-negative bigint (must be >= 0n)
8920
+ * @returns CBOR tagged value
8921
+ * @throws CborError with type OutOfRange if value is negative
8922
+ */
8923
+ function biguintToCbor(value) {
8924
+ if (value < 0n) throw new CborError({ type: "OutOfRange" });
8925
+ return toTaggedValue(TAG_2_POSITIVE_BIGNUM, stripLeadingZeros(bigintToBytes(value)));
8926
+ }
8927
+ /**
8928
+ * Encode a bigint as a CBOR tag 2 or tag 3 bignum.
8929
+ *
8930
+ * Matches Rust's `From<BigInt> for CBOR`.
8931
+ *
8932
+ * - Non-negative values use tag 2 (positive bignum).
8933
+ * - Negative values use tag 3 (negative bignum), where the encoded
8934
+ * magnitude is `|value| - 1` per RFC 8949.
8935
+ *
8936
+ * @param value - Any bigint value
8937
+ * @returns CBOR tagged value
8938
+ */
8939
+ function bigintToCbor(value) {
8940
+ if (value >= 0n) return biguintToCbor(value);
8941
+ const stripped = stripLeadingZeros(bigintToBytes(-value - 1n));
8942
+ return toTaggedValue(TAG_3_NEGATIVE_BIGNUM, stripped.length === 0 ? new Uint8Array([0]) : stripped);
8943
+ }
8944
+ /**
8945
+ * Decode a BigUint from an untagged CBOR byte string.
8946
+ *
8947
+ * Matches Rust's `biguint_from_untagged_cbor()`.
8948
+ *
8949
+ * This function is intended for use in tag summarizers where the tag has
8950
+ * already been stripped. It expects a CBOR byte string representing the
8951
+ * big-endian magnitude of a positive bignum (tag 2 content).
8952
+ *
8953
+ * Enforces canonical encoding: no leading zero bytes (except empty for zero).
8954
+ *
8955
+ * @param cbor - A CBOR value that should be a byte string
8956
+ * @returns Non-negative bigint
8957
+ * @throws CborError with type WrongType if not a byte string
8958
+ * @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
8959
+ */
8960
+ function biguintFromUntaggedCbor(cbor) {
8961
+ if (cbor.type !== MajorType.ByteString) throw new CborError({ type: "WrongType" });
8962
+ const bytes = cbor.value;
8963
+ validateBignumMagnitude(bytes, false);
8964
+ return bytesToBigint(bytes);
8965
+ }
8966
+ /**
8967
+ * Decode a BigInt from an untagged CBOR byte string for a negative bignum.
8968
+ *
8969
+ * Matches Rust's `bigint_from_negative_untagged_cbor()`.
8970
+ *
8971
+ * This function is intended for use in tag summarizers where the tag has
8972
+ * already been stripped. It expects a CBOR byte string representing `n` where
8973
+ * the actual value is `-1 - n` (tag 3 content per RFC 8949).
8974
+ *
8975
+ * Enforces canonical encoding: no leading zero bytes (except single `0x00`
8976
+ * for -1).
8977
+ *
8978
+ * @param cbor - A CBOR value that should be a byte string
8979
+ * @returns Negative bigint
8980
+ * @throws CborError with type WrongType if not a byte string
8981
+ * @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
8982
+ */
8983
+ function bigintFromNegativeUntaggedCbor(cbor) {
8984
+ if (cbor.type !== MajorType.ByteString) throw new CborError({ type: "WrongType" });
8985
+ const bytes = cbor.value;
8986
+ validateBignumMagnitude(bytes, true);
8987
+ return -(bytesToBigint(bytes) + 1n);
8988
+ }
8989
+ /**
8990
+ * Convert CBOR to a non-negative bigint.
8991
+ *
8992
+ * Matches Rust's `TryFrom<CBOR> for BigUint`.
8993
+ *
8994
+ * Accepts:
8995
+ * - Major type 0 (unsigned integer)
8996
+ * - Tag 2 (positive bignum) with canonical byte string
8997
+ *
8998
+ * Rejects:
8999
+ * - Major type 1 (negative integer) -> OutOfRange
9000
+ * - Tag 3 (negative bignum) -> OutOfRange
9001
+ * - Floating-point values -> WrongType
9002
+ * - Non-canonical bignum encodings -> NonCanonicalNumeric
8394
9003
  *
8395
9004
  * @param cbor - The CBOR value to convert
8396
9005
  * @returns Non-negative bigint
@@ -8571,553 +9180,132 @@ const TAG_MIME_MESSAGE = 36;
8571
9180
  /**
8572
9181
  * Tag 37: Binary UUID
8573
9182
  */
8574
- const TAG_UUID = 37;
8575
- /**
8576
- * Tag 256: string reference (namespace)
8577
- */
8578
- const TAG_STRING_REF_NAMESPACE = 256;
8579
- /**
8580
- * Tag 257: binary UUID reference
8581
- */
8582
- const TAG_BINARY_UUID = 257;
8583
- /**
8584
- * Tag 258: Set of values (array with no duplicates)
8585
- */
8586
- const TAG_SET = 258;
8587
- /**
8588
- * Tag 55799: Self-describe CBOR (magic number 0xd9d9f7)
8589
- */
8590
- const TAG_SELF_DESCRIBE_CBOR = 55799;
8591
- const TAG_DATE = 1;
8592
- const TAG_NAME_DATE = "date";
8593
- /**
8594
- * Register standard tags in a specific tags store.
8595
- * Matches Rust's register_tags_in() function.
8596
- *
8597
- * @param tagsStore - The tags store to register tags into
8598
- */
8599
- const registerTagsIn = (tagsStore) => {
8600
- const tags = [createTag(1, TAG_NAME_DATE)];
8601
- tagsStore.insertAll(tags);
8602
- tagsStore.setSummarizer(1, (untaggedCbor, _flat) => {
8603
- try {
8604
- return {
8605
- ok: true,
8606
- value: CborDate.fromUntaggedCbor(untaggedCbor).toString()
8607
- };
8608
- } catch (e) {
8609
- return {
8610
- ok: false,
8611
- error: {
8612
- type: "Custom",
8613
- message: e instanceof Error ? e.message : String(e)
8614
- }
8615
- };
8616
- }
8617
- });
8618
- const biguintTag = createTag(2, TAG_NAME_POSITIVE_BIGNUM);
8619
- const bigintTag = createTag(3, TAG_NAME_NEGATIVE_BIGNUM);
8620
- tagsStore.insertAll([biguintTag, bigintTag]);
8621
- tagsStore.setSummarizer(2, (untaggedCbor, _flat) => {
8622
- try {
8623
- return {
8624
- ok: true,
8625
- value: `bignum(${biguintFromUntaggedCbor(untaggedCbor)})`
8626
- };
8627
- } catch (e) {
8628
- return {
8629
- ok: false,
8630
- error: {
8631
- type: "Custom",
8632
- message: e instanceof Error ? e.message : String(e)
8633
- }
8634
- };
8635
- }
8636
- });
8637
- tagsStore.setSummarizer(3, (untaggedCbor, _flat) => {
8638
- try {
8639
- return {
8640
- ok: true,
8641
- value: `bignum(${bigintFromNegativeUntaggedCbor(untaggedCbor)})`
8642
- };
8643
- } catch (e) {
8644
- return {
8645
- ok: false,
8646
- error: {
8647
- type: "Custom",
8648
- message: e instanceof Error ? e.message : String(e)
8649
- }
8650
- };
8651
- }
8652
- });
8653
- };
8654
- /**
8655
- * Register standard tags in the global tags store.
8656
- * Matches Rust's register_tags() function.
8657
- *
8658
- * This function is idempotent - calling it multiple times is safe.
8659
- */
8660
- const registerTags = () => {
8661
- registerTagsIn(getGlobalTagsStore());
8662
- };
8663
- /**
8664
- * Converts an array of tag values to their corresponding Tag objects.
8665
- * Matches Rust's tags_for_values() function.
8666
- *
8667
- * This function looks up each tag value in the global tag registry and returns
8668
- * an array of complete Tag objects. For any tag values that aren't
8669
- * registered in the global registry, it creates a basic Tag with just the
8670
- * value (no name).
8671
- *
8672
- * @param values - Array of numeric tag values to convert
8673
- * @returns Array of Tag objects corresponding to the input values
8674
- *
8675
- * @example
8676
- * ```typescript
8677
- * // Register some tags first
8678
- * registerTags();
8679
- *
8680
- * // Convert tag values to Tag objects
8681
- * const tags = tagsForValues([1, 42, 999]);
8682
- *
8683
- * // The first tag (value 1) should be registered as "date"
8684
- * console.log(tags[0].value); // 1
8685
- * console.log(tags[0].name); // "date"
8686
- *
8687
- * // Unregistered tags will have a value but no name
8688
- * console.log(tags[1].value); // 42
8689
- * console.log(tags[2].value); // 999
8690
- * ```
8691
- */
8692
- const tagsForValues = (values) => {
8693
- const globalStore = getGlobalTagsStore();
8694
- return values.map((value) => {
8695
- const tag = globalStore.tagForValue(value);
8696
- if (tag !== void 0) return tag;
8697
- return createTag(value);
8698
- });
8699
- };
8700
- //#endregion
8701
- //#region src/set.ts
9183
+ const TAG_UUID = 37;
8702
9184
  /**
8703
- * Copyright © 2023-2026 Blockchain Commons, LLC
8704
- * Copyright © 2025-2026 Parity Technologies
8705
- *
8706
- *
8707
- * Set data structure for CBOR with tag(258) encoding.
8708
- *
8709
- * A Set is encoded as an array with no duplicate elements,
8710
- * tagged with tag(258) to indicate set semantics.
8711
- *
8712
- * @module set
9185
+ * Tag 256: string reference (namespace)
8713
9186
  */
9187
+ const TAG_STRING_REF_NAMESPACE = 256;
8714
9188
  /**
8715
- * CBOR Set type with tag(258) encoding.
8716
- *
8717
- * Internally uses a CborMap to ensure unique elements with deterministic ordering.
8718
- * Elements are ordered by their CBOR encoding (lexicographic byte order).
8719
- *
8720
- * @example
8721
- * ```typescript
8722
- * // Create set
8723
- * const set = CborSet.fromArray([1, 2, 3]);
8724
- * const set2 = CborSet.fromSet(new Set([1, 2, 3]));
8725
- *
8726
- * // Add elements
8727
- * set.insert(4);
8728
- * set.insert(2); // Duplicate, no effect
8729
- *
8730
- * // Check membership
8731
- * console.log(set.contains(2)); // true
8732
- * console.log(set.contains(99)); // false
9189
+ * Tag 257: binary UUID reference
9190
+ */
9191
+ const TAG_BINARY_UUID = 257;
9192
+ /**
9193
+ * Tag 258: Set of values (array with no duplicates)
9194
+ */
9195
+ const TAG_SET = 258;
9196
+ /**
9197
+ * Tag 55799: Self-describe CBOR (magic number 0xd9d9f7)
9198
+ */
9199
+ const TAG_SELF_DESCRIBE_CBOR = 55799;
9200
+ const TAG_DATE = 1;
9201
+ const TAG_NAME_DATE = "date";
9202
+ /**
9203
+ * Register standard tags in a specific tags store.
9204
+ * Matches Rust's register_tags_in() function.
8733
9205
  *
8734
- * // Encode to CBOR
8735
- * const tagged = set.taggedCbor();
8736
- * ```
9206
+ * @param tagsStore - The tags store to register tags into
8737
9207
  */
8738
- var CborSet = class CborSet {
8739
- _map;
8740
- constructor() {
8741
- this._map = new CborMap();
8742
- }
8743
- /**
8744
- * Create CborSet from array.
8745
- *
8746
- * Duplicates are automatically removed.
8747
- *
8748
- * @param items - Array of items to add to the set
8749
- * @returns New CborSet instance
8750
- *
8751
- * @example
8752
- * ```typescript
8753
- * const set = CborSet.fromArray([1, 2, 3, 2, 1]);
8754
- * console.log(set.size); // 3
8755
- * ```
8756
- */
8757
- static fromArray(items) {
8758
- const set = new CborSet();
8759
- for (const item of items) set.insert(item);
8760
- return set;
8761
- }
8762
- /**
8763
- * Create CborSet from JavaScript Set.
8764
- *
8765
- * @param items - JavaScript Set of items
8766
- * @returns New CborSet instance
8767
- *
8768
- * @example
8769
- * ```typescript
8770
- * const jsSet = new Set([1, 2, 3]);
8771
- * const cborSet = CborSet.fromSet(jsSet);
8772
- * ```
8773
- */
8774
- static fromSet(items) {
8775
- return CborSet.fromArray(Array.from(items));
8776
- }
8777
- /**
8778
- * Create CborSet from iterable.
8779
- *
8780
- * @param items - Iterable of items
8781
- * @returns New CborSet instance
8782
- */
8783
- static fromIterable(items) {
8784
- return CborSet.fromArray(Array.from(items));
8785
- }
8786
- /**
8787
- * Insert an element into the set.
8788
- *
8789
- * If the element already exists, has no effect.
8790
- *
8791
- * @param value - Value to insert
8792
- *
8793
- * @example
8794
- * ```typescript
8795
- * const set = new CborSet();
8796
- * set.insert(1);
8797
- * set.insert(2);
8798
- * set.insert(1); // No effect, already exists
8799
- * ```
8800
- */
8801
- insert(value) {
8802
- const cborValue = encodeCborValue(value);
8803
- this._map.set(cborValue, cborValue);
8804
- }
8805
- /**
8806
- * Insert an element into the set, requiring it to be strictly greater
8807
- * (in canonical CBOR-encoded byte order) than every previously-inserted
8808
- * element. Used by the decoder to reject misordered or duplicate
8809
- * elements in tag-258 set encodings.
8810
- *
8811
- * Mirrors Rust `Set::insert_next` (`pub(crate)`); exposed here because
8812
- * TypeScript doesn't have a crate-private visibility level.
8813
- *
8814
- * @throws CborError of type `MisorderedMap` if `value` would not preserve
8815
- * strict ascending CBOR-byte order, or `DuplicateMapKey` for an exact
8816
- * repeat.
8817
- */
8818
- insertNext(value) {
8819
- const cborValue = encodeCborValue(value);
8820
- this._map.setNext(cborValue, cborValue);
8821
- }
8822
- /**
8823
- * Check if set contains an element.
8824
- *
8825
- * @param value - Value to check
8826
- * @returns true if element is in the set
8827
- *
8828
- * @example
8829
- * ```typescript
8830
- * const set = CborSet.fromArray([1, 2, 3]);
8831
- * console.log(set.contains(2)); // true
8832
- * console.log(set.contains(99)); // false
8833
- * ```
8834
- */
8835
- contains(value) {
8836
- const cborValue = encodeCborValue(value);
8837
- return this._map.has(cborValue);
8838
- }
8839
- /**
8840
- * Remove an element from the set.
8841
- *
8842
- * @param value - Value to remove
8843
- * @returns true if element was removed, false if not found
8844
- *
8845
- * @example
8846
- * ```typescript
8847
- * const set = CborSet.fromArray([1, 2, 3]);
8848
- * set.delete(2); // Returns true
8849
- * set.delete(99); // Returns false
8850
- * ```
8851
- */
8852
- delete(value) {
8853
- const cborValue = encodeCborValue(value);
8854
- return this._map.delete(cborValue);
8855
- }
8856
- /**
8857
- * Remove all elements from the set.
8858
- */
8859
- clear() {
8860
- this._map.clear();
8861
- }
8862
- /**
8863
- * Get the number of elements in the set.
8864
- *
8865
- * @returns Number of elements
8866
- */
8867
- get size() {
8868
- return this._map.size;
8869
- }
8870
- /**
8871
- * Check if the set is empty.
8872
- *
8873
- * @returns true if set has no elements
8874
- */
8875
- isEmpty() {
8876
- return this._map.size === 0;
8877
- }
8878
- /**
8879
- * Create a new set containing elements in this set or the other set.
8880
- *
8881
- * @param other - Other set
8882
- * @returns New set with union of elements
8883
- *
8884
- * @example
8885
- * ```typescript
8886
- * const set1 = CborSet.fromArray([1, 2, 3]);
8887
- * const set2 = CborSet.fromArray([3, 4, 5]);
8888
- * const union = set1.union(set2);
8889
- * // union contains [1, 2, 3, 4, 5]
8890
- * ```
8891
- */
8892
- union(other) {
8893
- const result = new CborSet();
8894
- for (const value of this) result.insert(extractCbor(value));
8895
- for (const value of other) result.insert(extractCbor(value));
8896
- return result;
8897
- }
8898
- /**
8899
- * Create a new set containing elements in both this set and the other set.
8900
- *
8901
- * @param other - Other set
8902
- * @returns New set with intersection of elements
8903
- *
8904
- * @example
8905
- * ```typescript
8906
- * const set1 = CborSet.fromArray([1, 2, 3]);
8907
- * const set2 = CborSet.fromArray([2, 3, 4]);
8908
- * const intersection = set1.intersection(set2);
8909
- * // intersection contains [2, 3]
8910
- * ```
8911
- */
8912
- intersection(other) {
8913
- const result = new CborSet();
8914
- for (const value of this) {
8915
- const extracted = extractCbor(value);
8916
- if (other.contains(extracted)) result.insert(extracted);
9208
+ const registerTagsIn = (tagsStore) => {
9209
+ const tags = [createTag(1, TAG_NAME_DATE)];
9210
+ tagsStore.insertAll(tags);
9211
+ tagsStore.setSummarizer(1, (untaggedCbor, _flat) => {
9212
+ try {
9213
+ return {
9214
+ ok: true,
9215
+ value: CborDate.fromUntaggedCbor(untaggedCbor).toString()
9216
+ };
9217
+ } catch (e) {
9218
+ return {
9219
+ ok: false,
9220
+ error: {
9221
+ type: "Custom",
9222
+ message: e instanceof Error ? e.message : String(e)
9223
+ }
9224
+ };
9225
+ }
9226
+ });
9227
+ const biguintTag = createTag(2, TAG_NAME_POSITIVE_BIGNUM);
9228
+ const bigintTag = createTag(3, TAG_NAME_NEGATIVE_BIGNUM);
9229
+ tagsStore.insertAll([biguintTag, bigintTag]);
9230
+ tagsStore.setSummarizer(2, (untaggedCbor, _flat) => {
9231
+ try {
9232
+ return {
9233
+ ok: true,
9234
+ value: `bignum(${biguintFromUntaggedCbor(untaggedCbor)})`
9235
+ };
9236
+ } catch (e) {
9237
+ return {
9238
+ ok: false,
9239
+ error: {
9240
+ type: "Custom",
9241
+ message: e instanceof Error ? e.message : String(e)
9242
+ }
9243
+ };
8917
9244
  }
8918
- return result;
8919
- }
8920
- /**
8921
- * Create a new set containing elements in this set but not in the other set.
8922
- *
8923
- * @param other - Other set
8924
- * @returns New set with difference of elements
8925
- *
8926
- * @example
8927
- * ```typescript
8928
- * const set1 = CborSet.fromArray([1, 2, 3]);
8929
- * const set2 = CborSet.fromArray([2, 3, 4]);
8930
- * const diff = set1.difference(set2);
8931
- * // diff contains [1]
8932
- * ```
8933
- */
8934
- difference(other) {
8935
- const result = new CborSet();
8936
- for (const value of this) {
8937
- const extracted = extractCbor(value);
8938
- if (!other.contains(extracted)) result.insert(extracted);
9245
+ });
9246
+ tagsStore.setSummarizer(3, (untaggedCbor, _flat) => {
9247
+ try {
9248
+ return {
9249
+ ok: true,
9250
+ value: `bignum(${bigintFromNegativeUntaggedCbor(untaggedCbor)})`
9251
+ };
9252
+ } catch (e) {
9253
+ return {
9254
+ ok: false,
9255
+ error: {
9256
+ type: "Custom",
9257
+ message: e instanceof Error ? e.message : String(e)
9258
+ }
9259
+ };
8939
9260
  }
8940
- return result;
8941
- }
8942
- /**
8943
- * Check if this set is a subset of another set.
8944
- *
8945
- * @param other - Other set
8946
- * @returns true if all elements of this set are in the other set
8947
- */
8948
- isSubsetOf(other) {
8949
- for (const value of this) if (!other.contains(extractCbor(value))) return false;
8950
- return true;
8951
- }
8952
- /**
8953
- * Check if this set is a superset of another set.
8954
- *
8955
- * @param other - Other set
8956
- * @returns true if all elements of the other set are in this set
8957
- */
8958
- isSupersetOf(other) {
8959
- return other.isSubsetOf(this);
8960
- }
8961
- /**
8962
- * Iterate over elements in the set.
8963
- *
8964
- * Elements are returned in deterministic order (by CBOR encoding).
8965
- *
8966
- * @example
8967
- * ```typescript
8968
- * const set = CborSet.fromArray([3, 1, 2]);
8969
- * for (const value of set) {
8970
- * console.log(extractCbor(value));
8971
- * }
8972
- * ```
8973
- */
8974
- *[Symbol.iterator]() {
8975
- for (const [_, value] of this._map) yield value;
8976
- }
8977
- /**
8978
- * Get all values as an array.
8979
- *
8980
- * @returns Array of CBOR values in deterministic order
8981
- *
8982
- * @example
8983
- * ```typescript
8984
- * const set = CborSet.fromArray([3, 1, 2]);
8985
- * const values = set.values();
8986
- * // Values in deterministic order
8987
- * ```
8988
- */
8989
- values() {
8990
- return Array.from(this);
8991
- }
8992
- /**
8993
- * Execute a function for each element.
8994
- *
8995
- * @param callback - Function to call for each element
8996
- *
8997
- * @example
8998
- * ```typescript
8999
- * set.forEach(value => {
9000
- * console.log(extractCbor(value));
9001
- * });
9002
- * ```
9003
- */
9004
- forEach(callback) {
9005
- for (const value of this) callback(value);
9006
- }
9007
- cborTags() {
9008
- return [createTag(258, "set")];
9009
- }
9010
- untaggedCbor() {
9011
- return cbor(this.values());
9012
- }
9013
- taggedCbor() {
9014
- return createTaggedCbor(this);
9015
- }
9016
- fromUntaggedCbor(c) {
9017
- if (c.type !== MajorType.Array) throw new CborError({ type: "WrongType" });
9018
- this.clear();
9019
- for (const value of c.value) this.insertNext(extractCbor(value));
9020
- return this;
9021
- }
9022
- fromTaggedCbor(c) {
9023
- validateTag(c, this.cborTags());
9024
- const content = extractTaggedContent(c);
9025
- return this.fromUntaggedCbor(content);
9026
- }
9027
- /**
9028
- * Decode a CborSet from tagged CBOR (static method).
9029
- *
9030
- * @param cbor - Tagged CBOR value with tag(258)
9031
- * @returns Decoded CborSet instance
9032
- */
9033
- static fromTaggedCborStatic(cbor) {
9034
- return new CborSet().fromTaggedCbor(cbor);
9035
- }
9036
- /**
9037
- * Convert to CBOR array (untagged).
9038
- *
9039
- * @returns CBOR array
9040
- */
9041
- toCbor() {
9042
- return this.untaggedCbor();
9043
- }
9044
- /**
9045
- * Convert to CBOR bytes (tagged).
9046
- *
9047
- * @returns Encoded CBOR bytes
9048
- */
9049
- toBytes() {
9050
- return cborData(this.taggedCbor());
9051
- }
9052
- /**
9053
- * Convert to JavaScript Set.
9054
- *
9055
- * @returns JavaScript Set with extracted values
9056
- *
9057
- * @example
9058
- * ```typescript
9059
- * const cborSet = CborSet.fromArray([1, 2, 3]);
9060
- * const jsSet = cborSet.toSet();
9061
- * console.log(jsSet.has(1)); // true
9062
- * ```
9063
- */
9064
- toSet() {
9065
- const result = /* @__PURE__ */ new Set();
9066
- for (const value of this) result.add(extractCbor(value));
9067
- return result;
9068
- }
9069
- /**
9070
- * Convert to JavaScript Array.
9071
- *
9072
- * @returns Array with extracted values
9073
- */
9074
- toArray() {
9075
- return Array.from(this.toSet());
9076
- }
9077
- /**
9078
- * Get diagnostic notation for the set.
9079
- *
9080
- * @returns String representation
9081
- *
9082
- * @example
9083
- * ```typescript
9084
- * const set = CborSet.fromArray([1, 2, 3]);
9085
- * console.log(set.diagnostic); // "[1, 2, 3]"
9086
- * ```
9087
- */
9088
- get diagnostic() {
9089
- return `[${this.values().map((v) => {
9090
- const extracted = extractCbor(v);
9091
- if (typeof extracted === "string") return `"${extracted}"`;
9092
- return String(extracted);
9093
- }).join(", ")}]`;
9094
- }
9095
- /**
9096
- * Convert to string (same as diagnostic).
9097
- *
9098
- * @returns String representation
9099
- */
9100
- toString() {
9101
- return this.diagnostic;
9102
- }
9103
- /**
9104
- * Convert to JSON (returns array of values).
9105
- *
9106
- * @returns Array for JSON serialization
9107
- */
9108
- toJSON() {
9109
- return this.toArray();
9110
- }
9261
+ });
9111
9262
  };
9112
9263
  /**
9113
- * Convert a value to CBOR for use in set operations.
9264
+ * Register standard tags in the global tags store.
9265
+ * Matches Rust's register_tags() function.
9114
9266
  *
9115
- * @internal
9267
+ * This function is idempotent - calling it multiple times is safe.
9116
9268
  */
9117
- function encodeCborValue(value) {
9118
- if (typeof value === "object" && value !== null && "isCbor" in value && value.isCbor === true) return value;
9119
- return cbor(value);
9120
- }
9269
+ const registerTags = () => {
9270
+ registerTagsIn(getGlobalTagsStore());
9271
+ };
9272
+ /**
9273
+ * Converts an array of tag values to their corresponding Tag objects.
9274
+ * Matches Rust's tags_for_values() function.
9275
+ *
9276
+ * This function looks up each tag value in the global tag registry and returns
9277
+ * an array of complete Tag objects. For any tag values that aren't
9278
+ * registered in the global registry, it creates a basic Tag with just the
9279
+ * value (no name).
9280
+ *
9281
+ * @param values - Array of numeric tag values to convert
9282
+ * @returns Array of Tag objects corresponding to the input values
9283
+ *
9284
+ * @example
9285
+ * ```typescript
9286
+ * // Register some tags first
9287
+ * registerTags();
9288
+ *
9289
+ * // Convert tag values to Tag objects
9290
+ * const tags = tagsForValues([1, 42, 999]);
9291
+ *
9292
+ * // The first tag (value 1) should be registered as "date"
9293
+ * console.log(tags[0].value); // 1
9294
+ * console.log(tags[0].name); // "date"
9295
+ *
9296
+ * // Unregistered tags will have a value but no name
9297
+ * console.log(tags[1].value); // 42
9298
+ * console.log(tags[2].value); // 999
9299
+ * ```
9300
+ */
9301
+ const tagsForValues = (values) => {
9302
+ const globalStore = getGlobalTagsStore();
9303
+ return values.map((value) => {
9304
+ const tag = globalStore.tagForValue(value);
9305
+ if (tag !== void 0) return tag;
9306
+ return createTag(value);
9307
+ });
9308
+ };
9121
9309
  //#endregion
9122
9310
  //#region src/sortable.ts
9123
9311
  /**
@@ -9580,6 +9768,7 @@ exports.sortArrayByCborEncoding = sortArrayByCborEncoding;
9580
9768
  exports.summary = summary;
9581
9769
  exports.tagContent = tagContent;
9582
9770
  exports.tagValue = tagValue;
9771
+ exports.tagValuesEqual = tagValuesEqual;
9583
9772
  exports.tagWithStaticName = tagWithStaticName;
9584
9773
  exports.tagWithValue = tagWithValue;
9585
9774
  exports.taggedCborData = taggedCborData;
@@ -9594,5 +9783,7 @@ exports.tryIntoByteString = expectBytes;
9594
9783
  exports.tryIntoText = expectText;
9595
9784
  exports.validateTag = validateTag;
9596
9785
  exports.walk = walk;
9786
+ exports.withTags = withTags;
9787
+ exports.withTagsMut = withTagsMut;
9597
9788
 
9598
9789
  //# sourceMappingURL=index.cjs.map