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