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