@bcts/uniform-resources 1.0.0-alpha.21 → 1.0.0-alpha.23

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.
@@ -1,9 +1,7 @@
1
1
  var bctsUniformResources = (function(exports, _bcts_dcbor, _bcts_crypto) {
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
5
- //#region src/error.ts
6
- /**
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ //#region src/error.ts
4
+ /**
7
5
  * Copyright © 2023-2026 Blockchain Commons, LLC
8
6
  * Copyright © 2025-2026 Parity Technologies
9
7
  *
@@ -95,10 +93,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
95
93
  function isError(result) {
96
94
  return result instanceof Error;
97
95
  }
98
-
99
- //#endregion
100
- //#region src/utils.ts
101
- /**
96
+ //#endregion
97
+ //#region src/utils.ts
98
+ /**
102
99
  * Checks if a character is a valid UR type character.
103
100
  * Valid characters are lowercase letters, digits, and hyphens.
104
101
  */
@@ -653,36 +650,102 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
653
650
  "🐳"
654
651
  ];
655
652
  /**
656
- * Encodes a 4-byte slice as a string of bytewords for identification.
653
+ * Encodes an arbitrary byte slice as a string of space-separated bytewords.
654
+ *
655
+ * Mirrors `bytewords::encode_to_words` in `bc-ur-rust` (≥ v0.19.1). Does not
656
+ * add a CRC32 checksum — use {@link encodeBytewords} for UR-style encoding.
657
657
  */
658
- function encodeBytewordsIdentifier(data) {
659
- if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes");
658
+ function encodeToWords(data) {
660
659
  const words = [];
661
- for (let i = 0; i < 4; i++) {
662
- const byte = data[i];
663
- if (byte === void 0) throw new Error("Invalid byte");
660
+ for (const byte of data) {
664
661
  const word = BYTEWORDS[byte];
665
- if (word === "" || word === void 0) throw new Error("Invalid byteword mapping");
662
+ if (word === void 0) throw new Error(`Invalid byte value: ${byte}`);
666
663
  words.push(word);
667
664
  }
668
665
  return words.join(" ");
669
666
  }
670
667
  /**
671
- * Encodes a 4-byte slice as a string of bytemojis for identification.
668
+ * Encodes an arbitrary byte slice as a string of space-separated bytemojis.
669
+ *
670
+ * Mirrors `bytewords::encode_to_bytemojis` in `bc-ur-rust` (≥ v0.19.1).
672
671
  */
673
- function encodeBytemojisIdentifier(data) {
674
- if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes");
672
+ function encodeToBytemojis(data) {
675
673
  const emojis = [];
676
- for (let i = 0; i < 4; i++) {
677
- const byte = data[i];
678
- if (byte === void 0) throw new Error("Invalid byte");
674
+ for (const byte of data) {
679
675
  const emoji = BYTEMOJIS[byte];
680
- if (emoji === "" || emoji === void 0) throw new Error("Invalid bytemoji mapping");
676
+ if (emoji === void 0) throw new Error(`Invalid byte value: ${byte}`);
681
677
  emojis.push(emoji);
682
678
  }
683
679
  return emojis.join(" ");
684
680
  }
685
681
  /**
682
+ * Encodes an arbitrary byte slice as minimal bytewords (first + last letter of
683
+ * each word, concatenated with no separator).
684
+ *
685
+ * Mirrors `bytewords::encode_to_minimal_bytewords` in `bc-ur-rust`
686
+ * (≥ v0.19.1). Does not add a CRC32 checksum.
687
+ */
688
+ function encodeToMinimalBytewords(data) {
689
+ let out = "";
690
+ for (const byte of data) {
691
+ const word = BYTEWORDS[byte];
692
+ if (word === void 0) throw new Error(`Invalid byte value: ${byte}`);
693
+ out += word[0] + word[word.length - 1];
694
+ }
695
+ return out;
696
+ }
697
+ /**
698
+ * Encodes a 4-byte slice as a string of bytewords for identification.
699
+ *
700
+ * Thin wrapper over {@link encodeToWords} that enforces the 4-byte length
701
+ * contract historically used by `bc-ur-rust`'s `bytewords::identifier`.
702
+ */
703
+ function encodeBytewordsIdentifier(data) {
704
+ if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes");
705
+ return encodeToWords(data);
706
+ }
707
+ /**
708
+ * Encodes a 4-byte slice as a string of bytemojis for identification.
709
+ *
710
+ * Thin wrapper over {@link encodeToBytemojis} that enforces the 4-byte length
711
+ * contract historically used by `bc-ur-rust`'s `bytewords::bytemoji_identifier`.
712
+ */
713
+ function encodeBytemojisIdentifier(data) {
714
+ if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes");
715
+ return encodeToBytemojis(data);
716
+ }
717
+ /**
718
+ * Returns `true` if `emoji` is one of the 256 bytemojis.
719
+ *
720
+ * Mirrors `bytewords::is_valid_bytemoji` in `bc-ur-rust` (≥ v0.19.1).
721
+ */
722
+ function isValidBytemoji(emoji) {
723
+ return BYTEMOJI_SET.has(emoji);
724
+ }
725
+ /**
726
+ * Canonicalises a byteword token (2–4 ASCII letters, case-insensitive) to its
727
+ * full 4-letter lowercase form. Returns `undefined` if the token is not a
728
+ * valid byteword or any of its short forms.
729
+ *
730
+ * Mirrors `bytewords::canonicalize_byteword` in `bc-ur-rust` (≥ v0.19.1).
731
+ *
732
+ * - 2-letter tokens are matched against the first + last letter of each
733
+ * byteword (identical to the minimal bytewords encoding).
734
+ * - 3-letter tokens are matched against the first 3 and the last 3 letters of
735
+ * each byteword; if both match different entries, the first-3 match wins
736
+ * (matching rust's `or_else` priority).
737
+ * - 4-letter tokens must exactly match a full byteword (after lower-casing).
738
+ */
739
+ function canonicalizeByteword(token) {
740
+ const lower = token.toLowerCase();
741
+ switch (lower.length) {
742
+ case 4: return BYTEWORDS_MAP.has(lower) ? lower : void 0;
743
+ case 2: return BYTEWORD_FIRST_LAST_MAP.get(lower);
744
+ case 3: return BYTEWORD_FIRST_THREE_MAP.get(lower) ?? BYTEWORD_LAST_THREE_MAP.get(lower);
745
+ default: return;
746
+ }
747
+ }
748
+ /**
686
749
  * Bytewords encoding style.
687
750
  */
688
751
  let BytewordsStyle = /* @__PURE__ */ function(BytewordsStyle) {
@@ -707,6 +770,38 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
707
770
  }
708
771
  const MINIMAL_BYTEWORDS_MAP = createMinimalBytewordsMap();
709
772
  /**
773
+ * Set of all 256 bytemojis for fast membership testing. Backs
774
+ * {@link isValidBytemoji}.
775
+ */
776
+ const BYTEMOJI_SET = new Set(BYTEMOJIS);
777
+ /**
778
+ * Lookup from a 2-letter (first+last) byteword short-form to its full
779
+ * lowercase 4-letter form. Backs {@link canonicalizeByteword}.
780
+ */
781
+ const BYTEWORD_FIRST_LAST_MAP = (() => {
782
+ const map = /* @__PURE__ */ new Map();
783
+ for (const word of BYTEWORDS) map.set(word[0] + word[word.length - 1], word);
784
+ return map;
785
+ })();
786
+ /**
787
+ * Lookup from the first 3 letters of a byteword to its full lowercase 4-letter
788
+ * form. Backs {@link canonicalizeByteword}.
789
+ */
790
+ const BYTEWORD_FIRST_THREE_MAP = (() => {
791
+ const map = /* @__PURE__ */ new Map();
792
+ for (const word of BYTEWORDS) map.set(word.slice(0, 3), word);
793
+ return map;
794
+ })();
795
+ /**
796
+ * Lookup from the last 3 letters of a byteword to its full lowercase 4-letter
797
+ * form. Backs {@link canonicalizeByteword}.
798
+ */
799
+ const BYTEWORD_LAST_THREE_MAP = (() => {
800
+ const map = /* @__PURE__ */ new Map();
801
+ for (const word of BYTEWORDS) map.set(word.slice(1), word);
802
+ return map;
803
+ })();
804
+ /**
710
805
  * CRC32 lookup table (IEEE polynomial).
711
806
  */
712
807
  const CRC32_TABLE = (() => {
@@ -741,7 +836,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
741
836
  * Encode data as bytewords with the specified style.
742
837
  * Includes CRC32 checksum.
743
838
  */
744
- function encodeBytewords(data, style = BytewordsStyle.Minimal) {
839
+ function encodeBytewords(data, style = "minimal") {
745
840
  const checksumBytes = uint32ToBytes(crc32(data));
746
841
  const dataWithChecksum = new Uint8Array(data.length + 4);
747
842
  dataWithChecksum.set(data);
@@ -751,46 +846,46 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
751
846
  const word = BYTEWORDS[byte];
752
847
  if (word === void 0) throw new Error(`Invalid byte value: ${byte}`);
753
848
  switch (style) {
754
- case BytewordsStyle.Standard:
849
+ case "standard":
755
850
  words.push(word);
756
851
  break;
757
- case BytewordsStyle.Uri:
852
+ case "uri":
758
853
  words.push(word);
759
854
  break;
760
- case BytewordsStyle.Minimal:
855
+ case "minimal":
761
856
  words.push(word[0] + word[3]);
762
857
  break;
763
858
  }
764
859
  }
765
860
  switch (style) {
766
- case BytewordsStyle.Standard: return words.join(" ");
767
- case BytewordsStyle.Uri: return words.join("-");
768
- case BytewordsStyle.Minimal: return words.join("");
861
+ case "standard": return words.join(" ");
862
+ case "uri": return words.join("-");
863
+ case "minimal": return words.join("");
769
864
  }
770
865
  }
771
866
  /**
772
867
  * Decode bytewords string back to data.
773
868
  * Validates and removes CRC32 checksum.
774
869
  */
775
- function decodeBytewords(encoded, style = BytewordsStyle.Minimal) {
870
+ function decodeBytewords(encoded, style = "minimal") {
776
871
  const lowercased = encoded.toLowerCase();
777
872
  let bytes;
778
873
  switch (style) {
779
- case BytewordsStyle.Standard:
874
+ case "standard":
780
875
  bytes = lowercased.split(" ").map((word) => {
781
876
  const index = BYTEWORDS_MAP.get(word);
782
877
  if (index === void 0) throw new Error(`Invalid byteword: ${word}`);
783
878
  return index;
784
879
  });
785
880
  break;
786
- case BytewordsStyle.Uri:
881
+ case "uri":
787
882
  bytes = lowercased.split("-").map((word) => {
788
883
  const index = BYTEWORDS_MAP.get(word);
789
884
  if (index === void 0) throw new Error(`Invalid byteword: ${word}`);
790
885
  return index;
791
886
  });
792
887
  break;
793
- case BytewordsStyle.Minimal:
888
+ case "minimal":
794
889
  if (lowercased.length % 2 !== 0) throw new Error("Invalid minimal bytewords length");
795
890
  bytes = [];
796
891
  for (let i = 0; i < lowercased.length; i += 2) {
@@ -810,10 +905,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
810
905
  if (expectedChecksum !== actualChecksum) throw new Error(`Bytewords checksum mismatch: expected ${expectedChecksum.toString(16)}, got ${actualChecksum.toString(16)}`);
811
906
  return data;
812
907
  }
813
-
814
- //#endregion
815
- //#region src/ur-type.ts
816
- /**
908
+ //#endregion
909
+ //#region src/ur-type.ts
910
+ /**
817
911
  * Copyright © 2023-2026 Blockchain Commons, LLC
818
912
  * Copyright © 2025-2026 Parity Technologies
819
913
  *
@@ -894,10 +988,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
894
988
  }
895
989
  }
896
990
  };
897
-
898
- //#endregion
899
- //#region src/ur.ts
900
- /**
991
+ //#endregion
992
+ //#region src/ur.ts
993
+ /**
901
994
  * A Uniform Resource (UR) is a URI-encoded CBOR object.
902
995
  *
903
996
  * URs are defined in [BCR-2020-005: Uniform Resources](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md).
@@ -1037,7 +1130,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1037
1130
  */
1038
1131
  var URStringEncoder = class {
1039
1132
  static encode(urType, cborData) {
1040
- return `ur:${urType}/${encodeBytewords(cborData, BytewordsStyle.Minimal)}`;
1133
+ return `ur:${urType}/${encodeBytewords(cborData, "minimal")}`;
1041
1134
  }
1042
1135
  };
1043
1136
  /**
@@ -1054,44 +1147,40 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1054
1147
  try {
1055
1148
  return {
1056
1149
  urType,
1057
- cbor: (0, _bcts_dcbor.decodeCbor)(decodeBytewords(data, BytewordsStyle.Minimal))
1150
+ cbor: (0, _bcts_dcbor.decodeCbor)(decodeBytewords(data, "minimal"))
1058
1151
  };
1059
1152
  } catch (error) {
1060
1153
  throw new URError(`Failed to decode UR: ${error instanceof Error ? error.message : String(error)}`);
1061
1154
  }
1062
1155
  }
1063
1156
  };
1064
-
1065
- //#endregion
1066
- //#region src/ur-encodable.ts
1067
- /**
1157
+ //#endregion
1158
+ //#region src/ur-encodable.ts
1159
+ /**
1068
1160
  * Helper function to check if an object implements UREncodable.
1069
1161
  */
1070
1162
  function isUREncodable(obj) {
1071
1163
  return typeof obj === "object" && obj !== null && "ur" in obj && "urString" in obj && typeof obj["ur"] === "function" && typeof obj["urString"] === "function";
1072
1164
  }
1073
-
1074
- //#endregion
1075
- //#region src/ur-decodable.ts
1076
- /**
1165
+ //#endregion
1166
+ //#region src/ur-decodable.ts
1167
+ /**
1077
1168
  * Helper function to check if an object implements URDecodable.
1078
1169
  */
1079
1170
  function isURDecodable(obj) {
1080
1171
  return typeof obj === "object" && obj !== null && "fromUR" in obj && typeof obj["fromUR"] === "function";
1081
1172
  }
1082
-
1083
- //#endregion
1084
- //#region src/ur-codable.ts
1085
- /**
1173
+ //#endregion
1174
+ //#region src/ur-codable.ts
1175
+ /**
1086
1176
  * Helper function to check if an object implements URCodable.
1087
1177
  */
1088
1178
  function isURCodable(obj) {
1089
1179
  return typeof obj === "object" && obj !== null && "ur" in obj && "urString" in obj && "fromUR" in obj && typeof obj["ur"] === "function" && typeof obj["urString"] === "function" && typeof obj["fromUR"] === "function";
1090
1180
  }
1091
-
1092
- //#endregion
1093
- //#region src/xoshiro.ts
1094
- /**
1181
+ //#endregion
1182
+ //#region src/xoshiro.ts
1183
+ /**
1095
1184
  * Copyright © 2023-2026 Blockchain Commons, LLC
1096
1185
  * Copyright © 2025-2026 Parity Technologies
1097
1186
  *
@@ -1300,10 +1389,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1300
1389
  seed8[7] = checksum & 255;
1301
1390
  return (0, _bcts_crypto.sha256)(seed8);
1302
1391
  }
1303
-
1304
- //#endregion
1305
- //#region src/fountain.ts
1306
- /**
1392
+ //#endregion
1393
+ //#region src/fountain.ts
1394
+ /**
1307
1395
  * Copyright © 2023-2026 Blockchain Commons, LLC
1308
1396
  * Copyright © 2025-2026 Parity Technologies
1309
1397
  *
@@ -1553,10 +1641,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1553
1641
  this.mixedParts.clear();
1554
1642
  }
1555
1643
  };
1556
-
1557
- //#endregion
1558
- //#region src/multipart-encoder.ts
1559
- /**
1644
+ //#endregion
1645
+ //#region src/multipart-encoder.ts
1646
+ /**
1560
1647
  * Encodes a UR as multiple parts using fountain codes.
1561
1648
  *
1562
1649
  * This allows large CBOR structures to be split into multiple UR strings
@@ -1602,7 +1689,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1602
1689
  constructor(ur, maxFragmentLen) {
1603
1690
  if (maxFragmentLen < 1) throw new URError("Max fragment length must be at least 1");
1604
1691
  this._ur = ur;
1605
- this._fountainEncoder = new FountainEncoder(ur.cbor().toData(), maxFragmentLen);
1692
+ const cborData = ur.cbor().toData();
1693
+ this._fountainEncoder = new FountainEncoder(cborData, maxFragmentLen);
1606
1694
  }
1607
1695
  /**
1608
1696
  * Gets the next part of the encoding.
@@ -1628,7 +1716,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1628
1716
  */
1629
1717
  _encodePart(part) {
1630
1718
  if (part.seqLen === 1) return this._ur.string();
1631
- const encoded = encodeBytewords(this._encodePartData(part), BytewordsStyle.Minimal);
1719
+ const encoded = encodeBytewords(this._encodePartData(part), "minimal");
1632
1720
  return `ur:${this._ur.urTypeStr()}/${part.seqNum}-${part.seqLen}/${encoded}`;
1633
1721
  }
1634
1722
  /**
@@ -1660,10 +1748,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1660
1748
  return this._fountainEncoder.seqLen;
1661
1749
  }
1662
1750
  };
1663
-
1664
- //#endregion
1665
- //#region src/multipart-decoder.ts
1666
- /**
1751
+ //#endregion
1752
+ //#region src/multipart-decoder.ts
1753
+ /**
1667
1754
  * Copyright © 2023-2026 Blockchain Commons, LLC
1668
1755
  * Copyright © 2025-2026 Parity Technologies
1669
1756
  *
@@ -1749,7 +1836,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1749
1836
  * The multipart body is a CBOR array: [seqNum, seqLen, messageLen, checksum, data]
1750
1837
  */
1751
1838
  _decodeFountainPart(partInfo) {
1752
- const decoded = (0, _bcts_dcbor.decodeCbor)(decodeBytewords(partInfo.encodedData, BytewordsStyle.Minimal));
1839
+ const decoded = (0, _bcts_dcbor.decodeCbor)(decodeBytewords(partInfo.encodedData, "minimal"));
1753
1840
  if (decoded.type !== _bcts_dcbor.MajorType.Array) throw new URError("Invalid multipart data: expected CBOR array");
1754
1841
  const items = decoded.value;
1755
1842
  if (items.length !== 5) throw new URError(`Invalid multipart data: expected 5 elements, got ${items.length}`);
@@ -1782,32 +1869,37 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1782
1869
  return this._decodedMessage;
1783
1870
  }
1784
1871
  };
1785
-
1786
- //#endregion
1787
- exports.BYTEMOJIS = BYTEMOJIS;
1788
- exports.BYTEWORDS = BYTEWORDS;
1789
- exports.BytewordsError = BytewordsError;
1790
- exports.BytewordsStyle = BytewordsStyle;
1791
- exports.CBORError = CBORError;
1792
- exports.InvalidSchemeError = InvalidSchemeError;
1793
- exports.InvalidTypeError = InvalidTypeError;
1794
- exports.MultipartDecoder = MultipartDecoder;
1795
- exports.MultipartEncoder = MultipartEncoder;
1796
- exports.NotSinglePartError = NotSinglePartError;
1797
- exports.TypeUnspecifiedError = TypeUnspecifiedError;
1798
- exports.UR = UR;
1799
- exports.URDecodeError = URDecodeError;
1800
- exports.URError = URError;
1801
- exports.URType = URType;
1802
- exports.UnexpectedTypeError = UnexpectedTypeError;
1803
- exports.decodeBytewords = decodeBytewords;
1804
- exports.encodeBytemojisIdentifier = encodeBytemojisIdentifier;
1805
- exports.encodeBytewords = encodeBytewords;
1806
- exports.encodeBytewordsIdentifier = encodeBytewordsIdentifier;
1807
- exports.isError = isError;
1808
- exports.isURCodable = isURCodable;
1809
- exports.isURDecodable = isURDecodable;
1810
- exports.isUREncodable = isUREncodable;
1811
- return exports;
1872
+ //#endregion
1873
+ exports.BYTEMOJIS = BYTEMOJIS;
1874
+ exports.BYTEWORDS = BYTEWORDS;
1875
+ exports.BytewordsError = BytewordsError;
1876
+ exports.BytewordsStyle = BytewordsStyle;
1877
+ exports.CBORError = CBORError;
1878
+ exports.InvalidSchemeError = InvalidSchemeError;
1879
+ exports.InvalidTypeError = InvalidTypeError;
1880
+ exports.MultipartDecoder = MultipartDecoder;
1881
+ exports.MultipartEncoder = MultipartEncoder;
1882
+ exports.NotSinglePartError = NotSinglePartError;
1883
+ exports.TypeUnspecifiedError = TypeUnspecifiedError;
1884
+ exports.UR = UR;
1885
+ exports.URDecodeError = URDecodeError;
1886
+ exports.URError = URError;
1887
+ exports.URType = URType;
1888
+ exports.UnexpectedTypeError = UnexpectedTypeError;
1889
+ exports.canonicalizeByteword = canonicalizeByteword;
1890
+ exports.decodeBytewords = decodeBytewords;
1891
+ exports.encodeBytemojisIdentifier = encodeBytemojisIdentifier;
1892
+ exports.encodeBytewords = encodeBytewords;
1893
+ exports.encodeBytewordsIdentifier = encodeBytewordsIdentifier;
1894
+ exports.encodeToBytemojis = encodeToBytemojis;
1895
+ exports.encodeToMinimalBytewords = encodeToMinimalBytewords;
1896
+ exports.encodeToWords = encodeToWords;
1897
+ exports.isError = isError;
1898
+ exports.isURCodable = isURCodable;
1899
+ exports.isURDecodable = isURDecodable;
1900
+ exports.isUREncodable = isUREncodable;
1901
+ exports.isValidBytemoji = isValidBytemoji;
1902
+ return exports;
1812
1903
  })({}, bctsDcbor, bctsCrypto);
1904
+
1813
1905
  //# sourceMappingURL=index.iife.js.map