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