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