@twin.org/core 0.0.1 → 0.0.2-next.11

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.
Files changed (40) hide show
  1. package/dist/cjs/index.cjs +915 -849
  2. package/dist/esm/index.mjs +915 -849
  3. package/dist/types/errors/alreadyExistsError.d.ts +2 -2
  4. package/dist/types/errors/baseError.d.ts +23 -4
  5. package/dist/types/errors/conflictError.d.ts +2 -2
  6. package/dist/types/errors/generalError.d.ts +2 -2
  7. package/dist/types/errors/notFoundError.d.ts +2 -2
  8. package/dist/types/errors/notSupportedError.d.ts +2 -2
  9. package/dist/types/errors/unauthorizedError.d.ts +2 -2
  10. package/dist/types/errors/unprocessableError.d.ts +2 -2
  11. package/dist/types/factories/factory.d.ts +1 -1
  12. package/dist/types/helpers/errorHelper.d.ts +3 -3
  13. package/dist/types/models/IComponent.d.ts +6 -15
  14. package/dist/types/models/IError.d.ts +2 -2
  15. package/dist/types/utils/is.d.ts +6 -0
  16. package/docs/changelog.md +229 -0
  17. package/docs/reference/classes/AlreadyExistsError.md +91 -7
  18. package/docs/reference/classes/ArrayHelper.md +0 -8
  19. package/docs/reference/classes/BaseError.md +83 -7
  20. package/docs/reference/classes/ConflictError.md +91 -7
  21. package/docs/reference/classes/EnvHelper.md +1 -1
  22. package/docs/reference/classes/ErrorHelper.md +3 -3
  23. package/docs/reference/classes/Factory.md +2 -2
  24. package/docs/reference/classes/GeneralError.md +91 -7
  25. package/docs/reference/classes/GuardError.md +88 -4
  26. package/docs/reference/classes/Guards.md +2 -2
  27. package/docs/reference/classes/I18n.md +2 -2
  28. package/docs/reference/classes/Is.md +30 -2
  29. package/docs/reference/classes/NotFoundError.md +91 -7
  30. package/docs/reference/classes/NotImplementedError.md +88 -4
  31. package/docs/reference/classes/NotSupportedError.md +91 -7
  32. package/docs/reference/classes/UnauthorizedError.md +91 -7
  33. package/docs/reference/classes/UnprocessableError.md +91 -7
  34. package/docs/reference/classes/Validation.md +1 -1
  35. package/docs/reference/classes/ValidationError.md +88 -4
  36. package/docs/reference/interfaces/IComponent.md +9 -21
  37. package/docs/reference/interfaces/IError.md +3 -3
  38. package/docs/reference/variables/CoerceType.md +1 -1
  39. package/docs/reference/variables/CompressionType.md +1 -1
  40. package/package.json +2 -2
@@ -372,6 +372,19 @@ class Is {
372
372
  static regexp(value) {
373
373
  return value instanceof RegExp;
374
374
  }
375
+ /**
376
+ * Is the provided object a class constructor.
377
+ * @param obj The object to check.
378
+ * @returns True if the object is a class, false otherwise.
379
+ */
380
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
381
+ static class(obj) {
382
+ if (typeof obj !== "function") {
383
+ return false;
384
+ }
385
+ const str = Function.prototype.toString.call(obj);
386
+ return /^class\s/.test(str);
387
+ }
375
388
  }
376
389
 
377
390
  // Copyright 2024 IOTA Stiftung.
@@ -629,31 +642,33 @@ class BaseError extends Error {
629
642
  */
630
643
  properties;
631
644
  /**
632
- * The inner error if there was one.
645
+ * The cause of the error.
633
646
  */
634
- inner;
647
+ cause;
635
648
  /**
636
649
  * Create a new instance of BaseError.
637
650
  * @param name The name of the error.
638
651
  * @param source The source of the error.
639
652
  * @param message The message as a code.
640
653
  * @param properties Any additional information for the error.
641
- * @param inner The inner error if we have wrapped another error.
654
+ * @param cause The cause of error if we have wrapped another error.
642
655
  */
643
- constructor(name, source, message, properties, inner) {
656
+ constructor(name, source, message, properties, cause) {
644
657
  super(message);
645
658
  this.name = name;
646
659
  this.source = source;
660
+ this.cause = Is.notEmpty(cause) ? BaseError.fromError(cause).toJsonObject(true) : undefined;
661
+ this.properties = properties;
647
662
  // If the message is camel case but has no namespace then prefix it
648
- // with the source name in camel case
663
+ // with the source name in camel case.
649
664
  if (Is.stringValue(source) &&
650
665
  Is.stringValue(message) &&
651
666
  !message.includes(".") &&
667
+ // This comparison checks that it is most likely a camel case name
668
+ // and not a free text error with a dot in it
652
669
  StringHelper.camelCase(message) === message) {
653
670
  this.message = `${StringHelper.camelCase(source)}.${message}`;
654
671
  }
655
- this.properties = properties;
656
- this.inner = inner ? BaseError.fromError(inner).toJsonObject() : undefined;
657
672
  }
658
673
  /**
659
674
  * Construct an error from an existing one.
@@ -665,7 +680,7 @@ class BaseError extends Error {
665
680
  let message;
666
681
  let source;
667
682
  let properties;
668
- let inner;
683
+ let cause;
669
684
  let stack;
670
685
  if (Is.object(err) && Is.stringValue(err.error)) {
671
686
  message = err.error;
@@ -683,8 +698,12 @@ class BaseError extends Error {
683
698
  if (Is.notEmpty(err.properties)) {
684
699
  properties = err.properties;
685
700
  }
686
- if (Is.notEmpty(err.inner)) {
687
- inner = err.inner;
701
+ if (BaseError.isAggregateError(err)) {
702
+ properties ??= {};
703
+ properties.errors = err.errors;
704
+ }
705
+ if (Is.notEmpty(err.cause)) {
706
+ cause = err.cause;
688
707
  }
689
708
  if (Is.notEmpty(err.stack)) {
690
709
  stack = err.stack;
@@ -696,7 +715,7 @@ class BaseError extends Error {
696
715
  else {
697
716
  message = JSON.stringify(err);
698
717
  }
699
- const baseError = new BaseError(name, source ?? "", message ?? "", properties, inner);
718
+ const baseError = new BaseError(name, source ?? "", message ?? "", properties, cause);
700
719
  baseError.stack = stack;
701
720
  return baseError;
702
721
  }
@@ -709,10 +728,10 @@ class BaseError extends Error {
709
728
  const flattened = [];
710
729
  let e = BaseError.fromError(err).toJsonObject(true);
711
730
  while (e) {
712
- const inner = e.inner;
713
- e.inner = undefined;
731
+ const cause = e.cause;
732
+ e.cause = undefined;
714
733
  flattened.push(e);
715
- e = inner;
734
+ e = cause;
716
735
  }
717
736
  return flattened;
718
737
  }
@@ -727,8 +746,8 @@ class BaseError extends Error {
727
746
  first = errors[0];
728
747
  let current = first;
729
748
  for (let i = 1; i < errors.length; i++) {
730
- current.inner = errors[i];
731
- current = current.inner;
749
+ current.cause = errors[i];
750
+ current = current.cause;
732
751
  }
733
752
  }
734
753
  return first;
@@ -801,6 +820,37 @@ class BaseError extends Error {
801
820
  static someErrorCode(error, code) {
802
821
  return BaseError.flatten(error).some(e => BaseError.isErrorCode(e, code));
803
822
  }
823
+ /**
824
+ * Is the error empty, i.e. does it have no message, source, properties, or cause?
825
+ * @param err The error to check for being empty.
826
+ * @returns True if the error is empty.
827
+ */
828
+ static isEmpty(err) {
829
+ return (!Is.stringValue(err.message) &&
830
+ !Is.stringValue(err.source) &&
831
+ !Is.objectValue(err.properties) &&
832
+ Is.empty(err.cause));
833
+ }
834
+ /**
835
+ * Is the error an aggregate error.
836
+ * @param err The error to check for being an aggregate error.
837
+ * @returns True if the error is an aggregate error.
838
+ */
839
+ static isAggregateError(err) {
840
+ return err instanceof AggregateError;
841
+ }
842
+ /**
843
+ * Convert the aggregate error to an array of errors.
844
+ * @param err The error to convert.
845
+ * @param includeStackTrace Whether to include the error stack in the model, defaults to false.
846
+ * @returns The array of errors.
847
+ */
848
+ static fromAggregate(err, includeStackTrace) {
849
+ if (BaseError.isAggregateError(err)) {
850
+ return err.errors.map(e => BaseError.fromError(e).toJsonObject(includeStackTrace));
851
+ }
852
+ return [BaseError.fromError(err).toJsonObject(includeStackTrace)];
853
+ }
804
854
  /**
805
855
  * Serialize the error to the error model.
806
856
  * @param includeStackTrace Whether to include the error stack in the model, defaults to false.
@@ -823,8 +873,8 @@ class BaseError extends Error {
823
873
  if ((includeStackTrace ?? false) && Is.stringValue(this.stack)) {
824
874
  err.stack = this.stack;
825
875
  }
826
- if (Is.notEmpty(this.inner)) {
827
- err.inner = BaseError.fromError(this.inner).toJsonObject(includeStackTrace);
876
+ if (Is.notEmpty(this.cause)) {
877
+ err.cause = BaseError.fromError(this.cause).toJsonObject(includeStackTrace);
828
878
  }
829
879
  return err;
830
880
  }
@@ -843,1062 +893,1073 @@ class GeneralError extends BaseError {
843
893
  * @param source The source of the error.
844
894
  * @param message The message as a code.
845
895
  * @param properties Any additional information for the error.
846
- * @param inner The inner error if we have wrapped another error.
896
+ * @param cause The cause of the error if we have wrapped another error.
847
897
  */
848
- constructor(source, message, properties, inner) {
849
- super(GeneralError.CLASS_NAME, source, message, properties, inner);
898
+ constructor(source, message, properties, cause) {
899
+ super(GeneralError.CLASS_NAME, source, message, properties, cause);
850
900
  }
851
901
  }
852
902
 
853
- // Copyright 2024 IOTA Stiftung.
854
- // SPDX-License-Identifier: Apache-2.0.
855
- /* eslint-disable no-bitwise */
856
903
  /**
857
- * Class to help with base63 Encoding/Decoding.
904
+ * Class to handle errors which are triggered by data guards.
858
905
  */
859
- class Base32 {
906
+ class GuardError extends BaseError {
860
907
  /**
861
908
  * Runtime name for the class.
862
- * @internal
863
- */
864
- static _CLASS_NAME = "Base32";
865
- /**
866
- * Alphabet table for encoding.
867
- * @internal
868
- */
869
- static _ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
870
- /**
871
- * Convert the base 32 string to a byte array.
872
- * @param base32 The base32 string to convert.
873
- * @returns The byte array.
874
- * @throws If the input string contains a character not in the Base32 alphabet.
875
909
  */
876
- static decode(base32) {
877
- let bits = 0;
878
- let value = 0;
879
- base32 = base32.replace(/=+$/, "");
880
- let index = 0;
881
- const output = new Uint8Array(Math.trunc((base32.length * 5) / 8));
882
- for (let i = 0; i < base32.length; i++) {
883
- const idx = Base32._ALPHABET.indexOf(base32[i]);
884
- if (idx === -1) {
885
- throw new GeneralError(Base32._CLASS_NAME, "invalidCharacter", {
886
- invalidCharacter: base32[i]
887
- });
888
- }
889
- value = (value << 5) | idx;
890
- bits += 5;
891
- if (bits >= 8) {
892
- output[index++] = (value >>> (bits - 8)) & 255;
893
- bits -= 8;
894
- }
895
- }
896
- return output;
897
- }
910
+ static CLASS_NAME = "GuardError";
898
911
  /**
899
- * Convert a byte array to base 32.
900
- * @param bytes The byte array to convert.
901
- * @returns The data as base32 string.
912
+ * Create a new instance of GuardError.
913
+ * @param source The source of the error.
914
+ * @param message The message as a code.
915
+ * @param propertyName The property which triggered the guard error for the item.
916
+ * @param propertyValue The property value which triggered the guard error for the item.
917
+ * @param propertyOptions The property options which might be allowed.
902
918
  */
903
- static encode(bytes) {
904
- let bits = 0;
905
- let value = 0;
906
- let output = "";
907
- for (let i = 0; i < bytes.byteLength; i++) {
908
- value = (value << 8) | bytes[i];
909
- bits += 8;
910
- while (bits >= 5) {
911
- output += Base32._ALPHABET[(value >>> (bits - 5)) & 31];
912
- bits -= 5;
913
- }
914
- }
915
- if (bits > 0) {
916
- output += Base32._ALPHABET[(value << (5 - bits)) & 31];
917
- }
918
- while (output.length % 8 !== 0) {
919
- output += "=";
920
- }
921
- return output;
919
+ constructor(source, message, propertyName, propertyValue, propertyOptions) {
920
+ super(GuardError.CLASS_NAME, source, message, {
921
+ property: propertyName ?? "property",
922
+ value: Is.undefined(propertyValue) ? "undefined" : propertyValue,
923
+ options: propertyOptions
924
+ });
922
925
  }
923
926
  }
924
927
 
925
928
  /**
926
- * Class to help with base58 Encoding/Decoding.
929
+ * Class to help with arrays.
927
930
  */
928
- class Base58 {
929
- /**
930
- * Runtime name for the class.
931
- * @internal
932
- */
933
- static _CLASS_NAME = "Base58";
934
- /**
935
- * Alphabet table for encoding.
936
- * @internal
937
- */
938
- static _ALPHABET =
939
- // cspell:disable-next-line
940
- "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
941
- /**
942
- * Reverse map for decoding.
943
- * @internal
944
- */
945
- static _ALPHABET_REVERSE = [
946
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
947
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
948
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1,
949
- 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, 33,
950
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
951
- 57, -1, -1, -1, -1, -1
952
- ];
931
+ class ArrayHelper {
953
932
  /**
954
- * Convert the base 58 string to a byte array.
955
- * @param base58 The base58 string to convert.
956
- * @returns The byte array.
957
- * @throws If the input string contains a character not in the Base58 alphabet.
933
+ * Do the two arrays match.
934
+ * @param arr1 The first array.
935
+ * @param arr2 The second array.
936
+ * @returns True if both arrays are empty of have the same values.
958
937
  */
959
- static decode(base58) {
960
- let zeroes = 0;
961
- for (let i = 0; i < base58.length; i++) {
962
- if (base58[i] !== "1") {
963
- break;
964
- }
965
- zeroes += 1;
938
+ static matches(arr1, arr2) {
939
+ if (Is.empty(arr1) && Is.empty(arr2)) {
940
+ return true;
966
941
  }
967
- const size = Math.trunc((base58.length * 733) / 1000) + 1;
968
- const b256 = new Uint8Array(size).fill(0);
969
- let length = 0;
970
- for (let i = zeroes; i < base58.length; i++) {
971
- const ch = base58.charCodeAt(i);
972
- if (ch & 0xff80) {
973
- throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
974
- }
975
- const val = Base58._ALPHABET_REVERSE[ch];
976
- if (val === -1) {
977
- throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
978
- }
979
- let carry = val;
980
- let j = 0;
981
- for (let k = size - 1; k >= 0; k--, j++) {
982
- if (carry === 0 && j >= length) {
983
- break;
984
- }
985
- carry += b256[k] * 58;
986
- b256[k] = carry;
987
- carry >>>= 8;
988
- }
989
- length = j;
942
+ if (!((Is.array(arr1) && Is.array(arr2)) || (Is.typedArray(arr1) && Is.typedArray(arr2)))) {
943
+ return false;
990
944
  }
991
- const out = new Uint8Array(zeroes + length);
992
- let j;
993
- for (j = 0; j < zeroes; j++) {
994
- out[j] = 0;
945
+ if (arr1.length !== arr2.length) {
946
+ return false;
995
947
  }
996
- let i = size - length;
997
- while (i < size) {
998
- out[j++] = b256[i++];
948
+ for (let i = 0; i < arr1.length; i++) {
949
+ if (arr1[i] !== arr2[i]) {
950
+ return false;
951
+ }
999
952
  }
1000
- return out;
953
+ return true;
1001
954
  }
1002
955
  /**
1003
- * Convert a byte array to base 58.
1004
- * @param bytes The byte array to encode.
1005
- * @returns The data as base58 string.
956
+ * Convert an object or array to an array.
957
+ * @param value The object or array to convert.
958
+ * @returns The array.
1006
959
  */
1007
- static encode(bytes) {
1008
- let zeroes = 0;
1009
- for (let i = 0; i < bytes.length; i++) {
1010
- if (bytes[i] !== 0) {
1011
- break;
1012
- }
1013
- zeroes += 1;
1014
- }
1015
- const size = Math.trunc(((bytes.length - zeroes) * 138) / 100) + 1;
1016
- const b58 = new Uint8Array(size).fill(0);
1017
- let length = 0;
1018
- for (let i = zeroes; i < bytes.length; i++) {
1019
- let carry = bytes[i];
1020
- let j = 0;
1021
- for (let k = size - 1; k >= 0; k--, j++) {
1022
- if (carry === 0 && j >= length) {
1023
- break;
1024
- }
1025
- carry += b58[k] * 256;
1026
- b58[k] = carry % 58;
1027
- carry = Math.trunc(carry / 58);
1028
- }
1029
- length = j;
1030
- }
1031
- let i = size - length;
1032
- while (i < size && b58[i] === 0) {
1033
- i += 1;
1034
- }
1035
- let str = "";
1036
- for (let j = 0; j < zeroes; j++) {
1037
- str += "1";
960
+ static fromObjectOrArray(value) {
961
+ if (Is.empty(value)) {
962
+ return undefined;
1038
963
  }
1039
- while (i < size) {
1040
- str += Base58._ALPHABET[b58[i++]];
964
+ if (Is.array(value)) {
965
+ return value;
1041
966
  }
1042
- return str;
967
+ return [value];
1043
968
  }
1044
969
  }
1045
970
 
1046
971
  // Copyright 2024 IOTA Stiftung.
1047
972
  // SPDX-License-Identifier: Apache-2.0.
1048
- /* eslint-disable no-bitwise */
1049
- /* eslint-disable no-mixed-operators */
1050
973
  /**
1051
- * Class to help with base64 Encoding/Decoding.
1052
- * Sourced from https://github.com/beatgammit/base64-js.
974
+ * Class to handle guard operations for parameters.
1053
975
  */
1054
- class Base64 {
976
+ class Guards {
1055
977
  /**
1056
- * Runtime name for the class.
1057
- * @internal
978
+ * Is the property defined.
979
+ * @param source The source of the error.
980
+ * @param property The name of the property.
981
+ * @param value The value to test.
982
+ * @throws GuardError If the value does not match the assertion.
1058
983
  */
1059
- static _CLASS_NAME = "Base64";
984
+ static defined(source, property, value) {
985
+ if (Is.undefined(value)) {
986
+ throw new GuardError(source, "guard.undefined", property, value);
987
+ }
988
+ }
1060
989
  /**
1061
- * Alphabet table for encoding.
1062
- * @internal
990
+ * Is the property a string.
991
+ * @param source The source of the error.
992
+ * @param property The name of the property.
993
+ * @param value The value to test.
994
+ * @throws GuardError If the value does not match the assertion.
1063
995
  */
1064
- static _LOOKUP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
996
+ static string(source, property, value) {
997
+ if (!Is.string(value)) {
998
+ throw new GuardError(source, "guard.string", property, value);
999
+ }
1000
+ }
1065
1001
  /**
1066
- * Alphabet table for decoding.
1067
- * @internal
1002
+ * Is the property a string with a value.
1003
+ * @param source The source of the error.
1004
+ * @param property The name of the property.
1005
+ * @param value The value to test.
1006
+ * @throws GuardError If the value does not match the assertion.
1068
1007
  */
1069
- static _REVERSE_LOOKUP = {
1070
- "43": 62,
1071
- "45": 62,
1072
- "47": 63,
1073
- "48": 52,
1074
- "49": 53,
1075
- "50": 54,
1076
- "51": 55,
1077
- "52": 56,
1078
- "53": 57,
1079
- "54": 58,
1080
- "55": 59,
1081
- "56": 60,
1082
- "57": 61,
1083
- "65": 0,
1084
- "66": 1,
1085
- "67": 2,
1086
- "68": 3,
1087
- "69": 4,
1088
- "70": 5,
1089
- "71": 6,
1090
- "72": 7,
1091
- "73": 8,
1092
- "74": 9,
1093
- "75": 10,
1094
- "76": 11,
1095
- "77": 12,
1096
- "78": 13,
1097
- "79": 14,
1098
- "80": 15,
1099
- "81": 16,
1100
- "82": 17,
1101
- "83": 18,
1102
- "84": 19,
1103
- "85": 20,
1104
- "86": 21,
1105
- "87": 22,
1106
- "88": 23,
1107
- "89": 24,
1108
- "90": 25,
1109
- "95": 63,
1110
- "97": 26,
1111
- "98": 27,
1112
- "99": 28,
1113
- "100": 29,
1114
- "101": 30,
1115
- "102": 31,
1116
- "103": 32,
1117
- "104": 33,
1118
- "105": 34,
1119
- "106": 35,
1120
- "107": 36,
1121
- "108": 37,
1122
- "109": 38,
1123
- "110": 39,
1124
- "111": 40,
1125
- "112": 41,
1126
- "113": 42,
1127
- "114": 43,
1128
- "115": 44,
1129
- "116": 45,
1130
- "117": 46,
1131
- "118": 47,
1132
- "119": 48,
1133
- "120": 49,
1134
- "121": 50,
1135
- "122": 51
1136
- };
1008
+ static stringValue(source, property, value) {
1009
+ if (!Is.string(value)) {
1010
+ throw new GuardError(source, "guard.string", property, value);
1011
+ }
1012
+ if (value.length === 0) {
1013
+ throw new GuardError(source, "guard.stringEmpty", property, value);
1014
+ }
1015
+ }
1137
1016
  /**
1138
- * Get the byte length of the data.
1139
- * @param base64 The base64 string.
1140
- * @returns The byte length of the data.
1017
+ * Is the property a JSON value.
1018
+ * @param source The source of the error.
1019
+ * @param property The name of the property.
1020
+ * @param value The value to test.
1021
+ * @throws GuardError If the value does not match the assertion.
1141
1022
  */
1142
- static byteLength(base64) {
1143
- const lens = Base64.getLengths(base64);
1144
- return Base64.calcByteLength(lens[0], lens[1]);
1023
+ static json(source, property, value) {
1024
+ if (!Is.json(value)) {
1025
+ throw new GuardError(source, "guard.stringJson", property, value);
1026
+ }
1145
1027
  }
1146
1028
  /**
1147
- * Convert the base 64 string to a byte array.
1148
- * @param base64 The base64 string to convert.
1149
- * @returns The byte array.
1029
+ * Is the property a base64 string.
1030
+ * @param source The source of the error.
1031
+ * @param property The name of the property.
1032
+ * @param value The value to test.
1033
+ * @throws GuardError If the value does not match the assertion.
1150
1034
  */
1151
- static decode(base64) {
1152
- let tmp;
1153
- const lens = Base64.getLengths(base64);
1154
- const validLen = lens[0];
1155
- const placeHoldersLen = lens[1];
1156
- const arr = new Uint8Array(Base64.calcByteLength(validLen, placeHoldersLen));
1157
- let curByte = 0;
1158
- // if there are placeholders, only get up to the last complete 4 chars
1159
- const len = placeHoldersLen > 0 ? validLen - 4 : validLen;
1160
- let i;
1161
- for (i = 0; i < len; i += 4) {
1162
- tmp =
1163
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 18) |
1164
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] << 12) |
1165
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 2)] << 6) |
1166
- Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 3)];
1167
- arr[curByte++] = (tmp >> 16) & 0xff;
1168
- arr[curByte++] = (tmp >> 8) & 0xff;
1169
- arr[curByte++] = tmp & 0xff;
1170
- }
1171
- if (placeHoldersLen === 2) {
1172
- tmp =
1173
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 2) |
1174
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] >> 4);
1175
- arr[curByte++] = tmp & 0xff;
1035
+ static stringBase64(source, property, value) {
1036
+ if (!Is.stringBase64(value)) {
1037
+ throw new GuardError(source, "guard.base64", property, value);
1176
1038
  }
1177
- if (placeHoldersLen === 1) {
1178
- tmp =
1179
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 10) |
1180
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] << 4) |
1181
- (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 2)] >> 2);
1182
- arr[curByte++] = (tmp >> 8) & 0xff;
1183
- arr[curByte++] = tmp & 0xff;
1039
+ }
1040
+ /**
1041
+ * Is the property a base64 url string.
1042
+ * @param source The source of the error.
1043
+ * @param property The name of the property.
1044
+ * @param value The value to test.
1045
+ * @throws GuardError If the value does not match the assertion.
1046
+ */
1047
+ static stringBase64Url(source, property, value) {
1048
+ if (!Is.stringBase64Url(value)) {
1049
+ throw new GuardError(source, "guard.base64Url", property, value);
1184
1050
  }
1185
- return arr;
1186
1051
  }
1187
1052
  /**
1188
- * Convert a byte array to base 64.
1189
- * @param bytes The byte array to convert.
1190
- * @returns The data as base64 string.
1053
+ * Is the property a base58 string.
1054
+ * @param source The source of the error.
1055
+ * @param property The name of the property.
1056
+ * @param value The value to test.
1057
+ * @throws GuardError If the value does not match the assertion.
1191
1058
  */
1192
- static encode(bytes) {
1193
- let tmp;
1194
- const len = bytes.length;
1195
- const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
1196
- const parts = [];
1197
- const maxChunkLength = 16383; // must be multiple of 3
1198
- // go through the array every three bytes, we'll deal with trailing stuff later
1199
- for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
1200
- parts.push(Base64.encodeChunk(bytes, i, Math.min(i + maxChunkLength, len2)));
1059
+ static stringBase58(source, property, value) {
1060
+ if (!Is.stringBase58(value)) {
1061
+ throw new GuardError(source, "guard.base58", property, value);
1201
1062
  }
1202
- // pad the end with zeros, but make sure to not forget the extra bytes
1203
- if (extraBytes === 1) {
1204
- tmp = bytes[len - 1];
1205
- parts.push(`${Base64._LOOKUP[tmp >> 2] + Base64._LOOKUP[(tmp << 4) & 0x3f]}==`);
1063
+ }
1064
+ /**
1065
+ * Is the property a string with a hex value.
1066
+ * @param source The source of the error.
1067
+ * @param property The name of the property.
1068
+ * @param value The value to test.
1069
+ * @param allowPrefix Allow the hex to have the 0x prefix.
1070
+ * @throws GuardError If the value does not match the assertion.
1071
+ */
1072
+ static stringHex(source, property, value, allowPrefix = false) {
1073
+ Guards.stringValue(source, property, value);
1074
+ if (!HexHelper.isHex(value, allowPrefix)) {
1075
+ throw new GuardError(source, "guard.stringHex", property, value);
1206
1076
  }
1207
- else if (extraBytes === 2) {
1208
- tmp = (bytes[len - 2] << 8) + bytes[len - 1];
1209
- parts.push(`${Base64._LOOKUP[tmp >> 10] + Base64._LOOKUP[(tmp >> 4) & 0x3f] + Base64._LOOKUP[(tmp << 2) & 0x3f]}=`);
1077
+ }
1078
+ /**
1079
+ * Is the property a string with a hex value with fixed length.
1080
+ * @param source The source of the error.
1081
+ * @param property The name of the property.
1082
+ * @param value The value to test.
1083
+ * @param length The length of the string to match.
1084
+ * @param allowPrefix Allow the hex to have the 0x prefix.
1085
+ * @throws GuardError If the value does not match the assertion.
1086
+ */
1087
+ static stringHexLength(source, property, value, length, allowPrefix = false) {
1088
+ Guards.stringHex(source, property, value, allowPrefix);
1089
+ if (HexHelper.stripPrefix(value).length !== length) {
1090
+ throw new GuardError(source, "guard.stringHexLength", property, value.length, length.toString());
1210
1091
  }
1211
- return parts.join("");
1212
1092
  }
1213
1093
  /**
1214
- * Calculate the byte length.
1215
- * @param validLen The valid length.
1216
- * @param placeHoldersLen The placeholder length.
1217
- * @returns The length.
1218
- * @internal
1094
+ * Is the property a number.
1095
+ * @param source The source of the error.
1096
+ * @param property The name of the property.
1097
+ * @param value The value to test.
1098
+ * @throws GuardError If the value does not match the assertion.
1219
1099
  */
1220
- static calcByteLength(validLen, placeHoldersLen) {
1221
- return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
1100
+ static number(source, property, value) {
1101
+ if (!Is.number(value)) {
1102
+ throw new GuardError(source, "guard.number", property, value);
1103
+ }
1222
1104
  }
1223
1105
  /**
1224
- * Get the valid and placeholder lengths from a bas64 string.
1225
- * @param base64 The base64 string.
1226
- * @returns The lengths.
1227
- * @internal
1106
+ * Is the property an integer.
1107
+ * @param source The source of the error.
1108
+ * @param property The name of the property.
1109
+ * @param value The value to test.
1110
+ * @throws GuardError If the value does not match the assertion.
1228
1111
  */
1229
- static getLengths(base64) {
1230
- const len = base64.length;
1231
- if (len % 4 > 0) {
1232
- throw new GeneralError(Base64._CLASS_NAME, "length4Multiple", { value: len });
1112
+ static integer(source, property, value) {
1113
+ if (!Is.integer(value)) {
1114
+ throw new GuardError(source, "guard.integer", property, value);
1233
1115
  }
1234
- // Trim off extra bytes after placeholder bytes are found
1235
- // See: https://github.com/beatgammit/base64-js/issues/42
1236
- let validLen = base64.indexOf("=");
1237
- if (validLen === -1) {
1238
- validLen = len;
1116
+ }
1117
+ /**
1118
+ * Is the property a bigint.
1119
+ * @param source The source of the error.
1120
+ * @param property The name of the property.
1121
+ * @param value The value to test.
1122
+ * @throws GuardError If the value does not match the assertion.
1123
+ */
1124
+ static bigint(source, property, value) {
1125
+ if (!Is.bigint(value)) {
1126
+ throw new GuardError(source, "guard.bigint", property, value);
1239
1127
  }
1240
- const placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);
1241
- return [validLen, placeHoldersLen];
1242
1128
  }
1243
1129
  /**
1244
- * Convert the triplet to base 64.
1245
- * @param num The number to convert.
1246
- * @returns The base64 encoding.
1247
- * @internal
1130
+ * Is the property a boolean.
1131
+ * @param source The source of the error.
1132
+ * @param property The name of the property.
1133
+ * @param value The value to test.
1134
+ * @throws GuardError If the value does not match the assertion.
1248
1135
  */
1249
- static tripletToBase64(num) {
1250
- return (Base64._LOOKUP[(num >> 18) & 0x3f] +
1251
- Base64._LOOKUP[(num >> 12) & 0x3f] +
1252
- Base64._LOOKUP[(num >> 6) & 0x3f] +
1253
- Base64._LOOKUP[num & 0x3f]);
1136
+ static boolean(source, property, value) {
1137
+ if (!Is.boolean(value)) {
1138
+ throw new GuardError(source, "guard.boolean", property, value);
1139
+ }
1254
1140
  }
1255
1141
  /**
1256
- * Encode a chunk.
1257
- * @param bytes The byte array.
1258
- * @param start The start index in the buffer.
1259
- * @param end The end index in the buffer.
1260
- * @returns The encoded chunk.
1261
- * @internal
1142
+ * Is the property a date.
1143
+ * @param source The source of the error.
1144
+ * @param property The name of the property.
1145
+ * @param value The value to test.
1146
+ * @throws GuardError If the value does not match the assertion.
1262
1147
  */
1263
- static encodeChunk(bytes, start, end) {
1264
- let tmp;
1265
- const output = [];
1266
- for (let i = start; i < end; i += 3) {
1267
- tmp = ((bytes[i] << 16) & 0xff0000) + ((bytes[i + 1] << 8) & 0xff00) + (bytes[i + 2] & 0xff);
1268
- output.push(Base64.tripletToBase64(tmp));
1148
+ static date(source, property, value) {
1149
+ if (!Is.date(value)) {
1150
+ throw new GuardError(source, "guard.date", property, value);
1269
1151
  }
1270
- return output.join("");
1271
1152
  }
1272
- }
1273
-
1274
- // Copyright 2024 IOTA Stiftung.
1275
- // SPDX-License-Identifier: Apache-2.0.
1276
- /**
1277
- * Class to help with base64 URL Encoding/Decoding.
1278
- * https://www.rfc-editor.org/rfc/rfc4648#section-5.
1279
- */
1280
- class Base64Url {
1281
1153
  /**
1282
- * Convert the base 64 string to a byte array.
1283
- * @param base64Url The base64 url string to convert.
1284
- * @returns The byte array.
1154
+ * Is the property a timestamp in milliseconds.
1155
+ * @param source The source of the error.
1156
+ * @param property The name of the property.
1157
+ * @param value The value to test.
1158
+ * @throws GuardError If the value does not match the assertion.
1285
1159
  */
1286
- static decode(base64Url) {
1287
- let base64 = base64Url;
1288
- // Base 64 url can have padding removed, so add it back if it is missing.
1289
- if (base64.length > 0 && !base64.endsWith("=")) {
1290
- const placeHoldersLen = 4 - (base64.length % 4);
1291
- if (placeHoldersLen > 0 && placeHoldersLen < 4) {
1292
- base64 = base64.padEnd(base64.length + placeHoldersLen, "=");
1293
- }
1160
+ static timestampMilliseconds(source, property, value) {
1161
+ if (!Is.timestampMilliseconds(value)) {
1162
+ throw new GuardError(source, "guard.timestampMilliseconds", property, value);
1294
1163
  }
1295
- base64 = base64.replace(/-/g, "+").replace(/_/g, "/");
1296
- return Base64.decode(base64);
1297
1164
  }
1298
1165
  /**
1299
- * Convert a byte array to base 64 url.
1300
- * @param bytes The byte array to convert.
1301
- * @returns The data as base64 url string.
1166
+ * Is the property a timestamp in seconds.
1167
+ * @param source The source of the error.
1168
+ * @param property The name of the property.
1169
+ * @param value The value to test.
1170
+ * @throws GuardError If the value does not match the assertion.
1302
1171
  */
1303
- static encode(bytes) {
1304
- const base64 = Base64.encode(bytes);
1305
- // Base 64 url can have padding removed, so remove it.
1306
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1172
+ static timestampSeconds(source, property, value) {
1173
+ if (!Is.timestampSeconds(value)) {
1174
+ throw new GuardError(source, "guard.timestampSeconds", property, value);
1175
+ }
1307
1176
  }
1308
- }
1309
-
1310
- /**
1311
- * Class to handle errors which are triggered by data already existing.
1312
- */
1313
- class AlreadyExistsError extends BaseError {
1314
1177
  /**
1315
- * Runtime name for the class.
1178
+ * Is the property an object.
1179
+ * @param source The source of the error.
1180
+ * @param property The name of the property.
1181
+ * @param value The value to test.
1182
+ * @throws GuardError If the value does not match the assertion.
1316
1183
  */
1317
- static CLASS_NAME = "AlreadyExistsError";
1184
+ static object(source, property, value) {
1185
+ if (Is.undefined(value)) {
1186
+ throw new GuardError(source, "guard.objectUndefined", property, value);
1187
+ }
1188
+ if (!Is.object(value)) {
1189
+ throw new GuardError(source, "guard.object", property, value);
1190
+ }
1191
+ }
1318
1192
  /**
1319
- * Create a new instance of AlreadyExistsError.
1193
+ * Is the property is an object with at least one property.
1320
1194
  * @param source The source of the error.
1321
- * @param message The message as a code.
1322
- * @param existingId The id for the item.
1323
- * @param inner The inner error if we have wrapped another error.
1195
+ * @param property The name of the property.
1196
+ * @param value The value to test.
1197
+ * @throws GuardError If the value does not match the assertion.
1324
1198
  */
1325
- constructor(source, message, existingId, inner) {
1326
- super(AlreadyExistsError.CLASS_NAME, source, message, { existingId }, inner);
1199
+ static objectValue(source, property, value) {
1200
+ if (Is.undefined(value)) {
1201
+ throw new GuardError(source, "guard.objectUndefined", property, value);
1202
+ }
1203
+ if (!Is.object(value)) {
1204
+ throw new GuardError(source, "guard.object", property, value);
1205
+ }
1206
+ if (Object.keys(value || {}).length === 0) {
1207
+ throw new GuardError(source, "guard.objectValue", property, value);
1208
+ }
1327
1209
  }
1328
- }
1329
-
1330
- /**
1331
- * Class to handle errors which are triggered by conflicting data.
1332
- */
1333
- class ConflictError extends BaseError {
1334
1210
  /**
1335
- * Runtime name for the class.
1211
+ * Is the property is an array.
1212
+ * @param source The source of the error.
1213
+ * @param property The name of the property.
1214
+ * @param value The value to test.
1215
+ * @throws GuardError If the value does not match the assertion.
1336
1216
  */
1337
- static CLASS_NAME = "ConflictError";
1217
+ static array(source, property, value) {
1218
+ if (!Is.array(value)) {
1219
+ throw new GuardError(source, "guard.array", property, value);
1220
+ }
1221
+ }
1338
1222
  /**
1339
- * Create a new instance of ConflictError.
1223
+ * Is the property is an array with at least one item.
1340
1224
  * @param source The source of the error.
1341
- * @param message The message as a code.
1342
- * @param conflictId The id that has conflicts.
1343
- * @param conflicts The conflicts that occurred.
1344
- * @param inner The inner error if we have wrapped another error.
1225
+ * @param property The name of the property.
1226
+ * @param value The value to test.
1227
+ * @throws GuardError If the value does not match the assertion.
1345
1228
  */
1346
- constructor(source, message, conflictId, conflicts, inner) {
1347
- super(ConflictError.CLASS_NAME, source, message, { conflictId, conflicts }, inner);
1229
+ static arrayValue(source, property, value) {
1230
+ if (!Is.array(value)) {
1231
+ throw new GuardError(source, "guard.array", property, value);
1232
+ }
1233
+ if (value.length === 0) {
1234
+ throw new GuardError(source, "guard.arrayValue", property, value);
1235
+ }
1348
1236
  }
1349
- }
1350
-
1351
- /**
1352
- * Class to handle errors which are triggered by data guards.
1353
- */
1354
- class GuardError extends BaseError {
1355
1237
  /**
1356
- * Runtime name for the class.
1238
+ * Is the property one of a list of items.
1239
+ * @param source The source of the error.
1240
+ * @param property The name of the property.
1241
+ * @param value The value to test.
1242
+ * @param options The options the value must be one of.
1243
+ * @throws GuardError If the value does not match the assertion.
1357
1244
  */
1358
- static CLASS_NAME = "GuardError";
1245
+ static arrayOneOf(source, property, value, options) {
1246
+ if (!Is.array(options)) {
1247
+ throw new GuardError(source, "guard.array", property, value);
1248
+ }
1249
+ if (!options.includes(value)) {
1250
+ throw new GuardError(source, "guard.arrayOneOf", property, value, options.join(", "));
1251
+ }
1252
+ }
1359
1253
  /**
1360
- * Create a new instance of GuardError.
1254
+ * Does the array start with the specified data.
1361
1255
  * @param source The source of the error.
1362
- * @param message The message as a code.
1363
- * @param propertyName The property which triggered the guard error for the item.
1364
- * @param propertyValue The property value which triggered the guard error for the item.
1365
- * @param propertyOptions The property options which might be allowed.
1256
+ * @param property The name of the property.
1257
+ * @param value The value to test.
1258
+ * @param startValues The values that must start the array.
1259
+ * @throws GuardError If the value does not match the assertion.
1366
1260
  */
1367
- constructor(source, message, propertyName, propertyValue, propertyOptions) {
1368
- super(GuardError.CLASS_NAME, source, message, {
1369
- property: propertyName ?? "property",
1370
- value: Is.undefined(propertyValue) ? "undefined" : propertyValue,
1371
- options: propertyOptions
1372
- });
1261
+ static arrayStartsWith(source, property, value, startValues) {
1262
+ if (!Is.arrayValue(value)) {
1263
+ throw new GuardError(source, "guard.array", property, value);
1264
+ }
1265
+ const startValuesArray = ArrayHelper.fromObjectOrArray(startValues);
1266
+ if (!Is.arrayValue(startValuesArray)) {
1267
+ throw new GuardError(source, "guard.array", property, startValuesArray);
1268
+ }
1269
+ for (let i = 0; i < startValuesArray.length; i++) {
1270
+ if (value[i] !== startValuesArray[i]) {
1271
+ throw new GuardError(source, "guard.arrayStartsWith", property, value, startValuesArray.join(", "));
1272
+ }
1273
+ }
1373
1274
  }
1374
- }
1375
-
1376
- /**
1377
- * Class to handle errors which are triggered by data not being found.
1378
- */
1379
- class NotFoundError extends BaseError {
1380
1275
  /**
1381
- * Runtime name for the class.
1276
+ * Does the array end with the specified data.
1277
+ * @param source The source of the error.
1278
+ * @param property The name of the property.
1279
+ * @param value The value to test.
1280
+ * @param endValues The values that must end the array.
1281
+ * @throws GuardError If the value does not match the assertion.
1382
1282
  */
1383
- static CLASS_NAME = "NotFoundError";
1283
+ static arrayEndsWith(source, property, value, endValues) {
1284
+ if (!Is.arrayValue(value)) {
1285
+ throw new GuardError(source, "guard.array", property, value);
1286
+ }
1287
+ const endValuesArray = ArrayHelper.fromObjectOrArray(endValues);
1288
+ if (!Is.arrayValue(endValuesArray)) {
1289
+ throw new GuardError(source, "guard.array", property, endValuesArray);
1290
+ }
1291
+ for (let i = 0; i < endValuesArray.length; i++) {
1292
+ if (value[value.length - i - 1] !== endValuesArray[endValuesArray.length - i - 1]) {
1293
+ throw new GuardError(source, "guard.arrayEndsWith", property, value, endValuesArray.join(", "));
1294
+ }
1295
+ }
1296
+ }
1384
1297
  /**
1385
- * Create a new instance of NotFoundError.
1298
+ * Is the property a Uint8Array.
1386
1299
  * @param source The source of the error.
1387
- * @param message The message as a code.
1388
- * @param notFoundId The id for the item.
1389
- * @param inner The inner error if we have wrapped another error.
1300
+ * @param property The name of the property.
1301
+ * @param value The value to test.
1302
+ * @throws GuardError If the value does not match the assertion.
1390
1303
  */
1391
- constructor(source, message, notFoundId, inner) {
1392
- super(NotFoundError.CLASS_NAME, source, message, { notFoundId }, inner);
1304
+ static uint8Array(source, property, value) {
1305
+ if (!Is.uint8Array(value)) {
1306
+ throw new GuardError(source, "guard.uint8Array", property, value);
1307
+ }
1393
1308
  }
1394
- }
1395
-
1396
- /**
1397
- * Class to handle errors.
1398
- */
1399
- class NotImplementedError extends BaseError {
1400
1309
  /**
1401
- * Runtime name for the class.
1310
+ * Is the property a function.
1311
+ * @param source The source of the error.
1312
+ * @param property The name of the property.
1313
+ * @param value The value to test.
1314
+ * @returns True if the value is a function.
1315
+ * @throws GuardError If the value does not match the assertion.
1402
1316
  */
1403
- static CLASS_NAME = "NotImplementedError";
1317
+ static function(source, property, value) {
1318
+ if (!Is.function(value)) {
1319
+ throw new GuardError(source, "guard.function", property, value);
1320
+ }
1321
+ return true;
1322
+ }
1404
1323
  /**
1405
- * Create a new instance of NotImplementedError.
1324
+ * Is the property a string formatted as an email address.
1406
1325
  * @param source The source of the error.
1407
- * @param method The method for the error.
1326
+ * @param property The name of the property.
1327
+ * @param value The value to test.
1328
+ * @throws GuardError If the value does not match the assertion.
1408
1329
  */
1409
- constructor(source, method) {
1410
- super(NotImplementedError.CLASS_NAME, source, "common.notImplementedMethod", {
1411
- method
1412
- });
1330
+ static email(source, property, value) {
1331
+ if (!Is.email(value)) {
1332
+ throw new GuardError(source, "guard.email", property, value);
1333
+ }
1413
1334
  }
1414
1335
  }
1415
1336
 
1337
+ // Copyright 2024 IOTA Stiftung.
1338
+ // SPDX-License-Identifier: Apache-2.0.
1339
+ /* eslint-disable no-bitwise */
1416
1340
  /**
1417
- * Class to handle errors when a feature is unsupported.
1341
+ * Class to help with base63 Encoding/Decoding.
1418
1342
  */
1419
- class NotSupportedError extends BaseError {
1343
+ class Base32 {
1420
1344
  /**
1421
1345
  * Runtime name for the class.
1346
+ * @internal
1422
1347
  */
1423
- static CLASS_NAME = "NotSupportedError";
1348
+ static _CLASS_NAME = "Base32";
1424
1349
  /**
1425
- * Create a new instance of NotSupportedError.
1426
- * @param source The source of the error.
1427
- * @param message The message as a code.
1428
- * @param inner The inner error if we have wrapped another error.
1350
+ * Alphabet table for encoding.
1351
+ * @internal
1429
1352
  */
1430
- constructor(source, message, inner) {
1431
- super(NotSupportedError.CLASS_NAME, source, message, undefined, inner);
1432
- }
1433
- }
1434
-
1435
- /**
1436
- * Class to handle errors which are triggered by access not being unauthorized.
1437
- */
1438
- class UnauthorizedError extends BaseError {
1353
+ static _ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
1439
1354
  /**
1440
- * Runtime name for the class.
1355
+ * Convert the base 32 string to a byte array.
1356
+ * @param base32 The base32 string to convert.
1357
+ * @returns The byte array.
1358
+ * @throws If the input string contains a character not in the Base32 alphabet.
1441
1359
  */
1442
- static CLASS_NAME = "UnauthorizedError";
1360
+ static decode(base32) {
1361
+ Guards.string(Base32._CLASS_NAME, "base32", base32);
1362
+ let bits = 0;
1363
+ let value = 0;
1364
+ base32 = base32.replace(/=+$/, "");
1365
+ let index = 0;
1366
+ const output = new Uint8Array(Math.trunc((base32.length * 5) / 8));
1367
+ for (let i = 0; i < base32.length; i++) {
1368
+ const idx = Base32._ALPHABET.indexOf(base32[i]);
1369
+ if (idx === -1) {
1370
+ throw new GeneralError(Base32._CLASS_NAME, "invalidCharacter", {
1371
+ invalidCharacter: base32[i]
1372
+ });
1373
+ }
1374
+ value = (value << 5) | idx;
1375
+ bits += 5;
1376
+ if (bits >= 8) {
1377
+ output[index++] = (value >>> (bits - 8)) & 255;
1378
+ bits -= 8;
1379
+ }
1380
+ }
1381
+ return output;
1382
+ }
1443
1383
  /**
1444
- * Create a new instance of UnauthorizedError.
1445
- * @param source The source of the error.
1446
- * @param message The message as a code.
1447
- * @param inner The inner error if we have wrapped another error.
1384
+ * Convert a byte array to base 32.
1385
+ * @param bytes The byte array to convert.
1386
+ * @returns The data as base32 string.
1448
1387
  */
1449
- constructor(source, message, inner) {
1450
- super(UnauthorizedError.CLASS_NAME, source, message, undefined, inner);
1388
+ static encode(bytes) {
1389
+ Guards.uint8Array(Base32._CLASS_NAME, "bytes", bytes);
1390
+ let bits = 0;
1391
+ let value = 0;
1392
+ let output = "";
1393
+ for (let i = 0; i < bytes.byteLength; i++) {
1394
+ value = (value << 8) | bytes[i];
1395
+ bits += 8;
1396
+ while (bits >= 5) {
1397
+ output += Base32._ALPHABET[(value >>> (bits - 5)) & 31];
1398
+ bits -= 5;
1399
+ }
1400
+ }
1401
+ if (bits > 0) {
1402
+ output += Base32._ALPHABET[(value << (5 - bits)) & 31];
1403
+ }
1404
+ while (output.length % 8 !== 0) {
1405
+ output += "=";
1406
+ }
1407
+ return output;
1451
1408
  }
1452
1409
  }
1453
1410
 
1454
1411
  /**
1455
- * Class to handle errors when some data can not be processed.
1412
+ * Class to help with base58 Encoding/Decoding.
1456
1413
  */
1457
- class UnprocessableError extends BaseError {
1414
+ class Base58 {
1458
1415
  /**
1459
1416
  * Runtime name for the class.
1417
+ * @internal
1460
1418
  */
1461
- static CLASS_NAME = "UnprocessableError";
1462
- /**
1463
- * Create a new instance of UnprocessableError.
1464
- * @param source The source of the error.
1465
- * @param message The message as a code.
1466
- * @param properties Any additional information for the error.
1467
- * @param inner The inner error if we have wrapped another error.
1468
- */
1469
- constructor(source, message, properties, inner) {
1470
- super(UnprocessableError.CLASS_NAME, source, message, properties, inner);
1471
- }
1472
- }
1473
-
1474
- /**
1475
- * Class to handle errors which are triggered by entity validation.
1476
- */
1477
- class ValidationError extends BaseError {
1419
+ static _CLASS_NAME = "Base58";
1478
1420
  /**
1479
- * Runtime name for the class.s
1421
+ * Alphabet table for encoding.
1422
+ * @internal
1480
1423
  */
1481
- static CLASS_NAME = "ValidationError";
1424
+ static _ALPHABET =
1425
+ // cspell:disable-next-line
1426
+ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
1482
1427
  /**
1483
- * Create a new instance of ValidationError.
1484
- * @param source The source of the error.
1485
- * @param validationObject The object that failed validation.
1486
- * @param validationFailures The validation failures.
1428
+ * Reverse map for decoding.
1429
+ * @internal
1487
1430
  */
1488
- constructor(source, validationObject, validationFailures) {
1489
- super(ValidationError.CLASS_NAME, source, "common.validation", {
1490
- validationObject,
1491
- validationFailures
1492
- });
1493
- }
1494
- }
1495
-
1496
- /**
1497
- * Class to help with arrays.
1498
- */
1499
- class ArrayHelper {
1431
+ static _ALPHABET_REVERSE = [
1432
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1433
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1434
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1,
1435
+ 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, 33,
1436
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
1437
+ 57, -1, -1, -1, -1, -1
1438
+ ];
1500
1439
  /**
1501
- * Do the two arrays match.
1502
- * @param arr1 The first array.
1503
- * @param arr2 The second array.
1504
- * @returns True if both arrays are empty of have the same values.
1440
+ * Convert the base 58 string to a byte array.
1441
+ * @param base58 The base58 string to convert.
1442
+ * @returns The byte array.
1443
+ * @throws If the input string contains a character not in the Base58 alphabet.
1505
1444
  */
1506
- static matches(arr1, arr2) {
1507
- if (Is.empty(arr1) && Is.empty(arr2)) {
1508
- return true;
1445
+ static decode(base58) {
1446
+ Guards.string(Base58._CLASS_NAME, "base58", base58);
1447
+ let zeroes = 0;
1448
+ for (let i = 0; i < base58.length; i++) {
1449
+ if (base58[i] !== "1") {
1450
+ break;
1451
+ }
1452
+ zeroes += 1;
1509
1453
  }
1510
- if (!((Is.array(arr1) && Is.array(arr2)) || (Is.typedArray(arr1) && Is.typedArray(arr2)))) {
1511
- return false;
1454
+ const size = Math.trunc((base58.length * 733) / 1000) + 1;
1455
+ const b256 = new Uint8Array(size).fill(0);
1456
+ let length = 0;
1457
+ for (let i = zeroes; i < base58.length; i++) {
1458
+ const ch = base58.charCodeAt(i);
1459
+ if (ch & 0xff80) {
1460
+ throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
1461
+ }
1462
+ const val = Base58._ALPHABET_REVERSE[ch];
1463
+ if (val === -1) {
1464
+ throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
1465
+ }
1466
+ let carry = val;
1467
+ let j = 0;
1468
+ for (let k = size - 1; k >= 0; k--, j++) {
1469
+ if (carry === 0 && j >= length) {
1470
+ break;
1471
+ }
1472
+ carry += b256[k] * 58;
1473
+ b256[k] = carry;
1474
+ carry >>>= 8;
1475
+ }
1476
+ length = j;
1512
1477
  }
1513
- if (arr1.length !== arr2.length) {
1514
- return false;
1478
+ const out = new Uint8Array(zeroes + length);
1479
+ let j;
1480
+ for (j = 0; j < zeroes; j++) {
1481
+ out[j] = 0;
1515
1482
  }
1516
- for (let i = 0; i < arr1.length; i++) {
1517
- if (arr1[i] !== arr2[i]) {
1518
- return false;
1519
- }
1483
+ let i = size - length;
1484
+ while (i < size) {
1485
+ out[j++] = b256[i++];
1520
1486
  }
1521
- return true;
1487
+ return out;
1522
1488
  }
1523
1489
  /**
1524
- * Convert an object or array to an array.
1525
- * @param value The object or array to convert.
1526
- * @returns The array.
1490
+ * Convert a byte array to base 58.
1491
+ * @param bytes The byte array to encode.
1492
+ * @returns The data as base58 string.
1527
1493
  */
1528
- static fromObjectOrArray(value) {
1529
- if (Is.empty(value)) {
1530
- return undefined;
1494
+ static encode(bytes) {
1495
+ Guards.uint8Array(Base58._CLASS_NAME, "bytes", bytes);
1496
+ let zeroes = 0;
1497
+ for (let i = 0; i < bytes.length; i++) {
1498
+ if (bytes[i] !== 0) {
1499
+ break;
1500
+ }
1501
+ zeroes += 1;
1531
1502
  }
1532
- if (Is.array(value)) {
1533
- return value;
1503
+ const size = Math.trunc(((bytes.length - zeroes) * 138) / 100) + 1;
1504
+ const b58 = new Uint8Array(size).fill(0);
1505
+ let length = 0;
1506
+ for (let i = zeroes; i < bytes.length; i++) {
1507
+ let carry = bytes[i];
1508
+ let j = 0;
1509
+ for (let k = size - 1; k >= 0; k--, j++) {
1510
+ if (carry === 0 && j >= length) {
1511
+ break;
1512
+ }
1513
+ carry += b58[k] * 256;
1514
+ b58[k] = carry % 58;
1515
+ carry = Math.trunc(carry / 58);
1516
+ }
1517
+ length = j;
1534
1518
  }
1535
- return [value];
1519
+ let i = size - length;
1520
+ while (i < size && b58[i] === 0) {
1521
+ i += 1;
1522
+ }
1523
+ let str = "";
1524
+ for (let j = 0; j < zeroes; j++) {
1525
+ str += "1";
1526
+ }
1527
+ while (i < size) {
1528
+ str += Base58._ALPHABET[b58[i++]];
1529
+ }
1530
+ return str;
1536
1531
  }
1537
1532
  }
1538
1533
 
1539
1534
  // Copyright 2024 IOTA Stiftung.
1540
1535
  // SPDX-License-Identifier: Apache-2.0.
1536
+ /* eslint-disable no-bitwise */
1537
+ /* eslint-disable no-mixed-operators */
1541
1538
  /**
1542
- * Class to handle guard operations for parameters.
1539
+ * Class to help with base64 Encoding/Decoding.
1540
+ * Sourced from https://github.com/beatgammit/base64-js.
1543
1541
  */
1544
- class Guards {
1542
+ class Base64 {
1545
1543
  /**
1546
- * Is the property defined.
1547
- * @param source The source of the error.
1548
- * @param property The name of the property.
1549
- * @param value The value to test.
1550
- * @throws GuardError If the value does not match the assertion.
1544
+ * Runtime name for the class.
1545
+ * @internal
1551
1546
  */
1552
- static defined(source, property, value) {
1553
- if (Is.undefined(value)) {
1554
- throw new GuardError(source, "guard.undefined", property, value);
1555
- }
1556
- }
1547
+ static _CLASS_NAME = "Base64";
1548
+ /**
1549
+ * Alphabet table for encoding.
1550
+ * @internal
1551
+ */
1552
+ static _LOOKUP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1553
+ /**
1554
+ * Alphabet table for decoding.
1555
+ * @internal
1556
+ */
1557
+ static _REVERSE_LOOKUP = {
1558
+ "43": 62,
1559
+ "45": 62,
1560
+ "47": 63,
1561
+ "48": 52,
1562
+ "49": 53,
1563
+ "50": 54,
1564
+ "51": 55,
1565
+ "52": 56,
1566
+ "53": 57,
1567
+ "54": 58,
1568
+ "55": 59,
1569
+ "56": 60,
1570
+ "57": 61,
1571
+ "65": 0,
1572
+ "66": 1,
1573
+ "67": 2,
1574
+ "68": 3,
1575
+ "69": 4,
1576
+ "70": 5,
1577
+ "71": 6,
1578
+ "72": 7,
1579
+ "73": 8,
1580
+ "74": 9,
1581
+ "75": 10,
1582
+ "76": 11,
1583
+ "77": 12,
1584
+ "78": 13,
1585
+ "79": 14,
1586
+ "80": 15,
1587
+ "81": 16,
1588
+ "82": 17,
1589
+ "83": 18,
1590
+ "84": 19,
1591
+ "85": 20,
1592
+ "86": 21,
1593
+ "87": 22,
1594
+ "88": 23,
1595
+ "89": 24,
1596
+ "90": 25,
1597
+ "95": 63,
1598
+ "97": 26,
1599
+ "98": 27,
1600
+ "99": 28,
1601
+ "100": 29,
1602
+ "101": 30,
1603
+ "102": 31,
1604
+ "103": 32,
1605
+ "104": 33,
1606
+ "105": 34,
1607
+ "106": 35,
1608
+ "107": 36,
1609
+ "108": 37,
1610
+ "109": 38,
1611
+ "110": 39,
1612
+ "111": 40,
1613
+ "112": 41,
1614
+ "113": 42,
1615
+ "114": 43,
1616
+ "115": 44,
1617
+ "116": 45,
1618
+ "117": 46,
1619
+ "118": 47,
1620
+ "119": 48,
1621
+ "120": 49,
1622
+ "121": 50,
1623
+ "122": 51
1624
+ };
1557
1625
  /**
1558
- * Is the property a string.
1559
- * @param source The source of the error.
1560
- * @param property The name of the property.
1561
- * @param value The value to test.
1562
- * @throws GuardError If the value does not match the assertion.
1626
+ * Get the byte length of the data.
1627
+ * @param base64 The base64 string.
1628
+ * @returns The byte length of the data.
1563
1629
  */
1564
- static string(source, property, value) {
1565
- if (!Is.string(value)) {
1566
- throw new GuardError(source, "guard.string", property, value);
1567
- }
1630
+ static byteLength(base64) {
1631
+ const lens = Base64.getLengths(base64);
1632
+ return Base64.calcByteLength(lens[0], lens[1]);
1568
1633
  }
1569
1634
  /**
1570
- * Is the property a string with a value.
1571
- * @param source The source of the error.
1572
- * @param property The name of the property.
1573
- * @param value The value to test.
1574
- * @throws GuardError If the value does not match the assertion.
1635
+ * Convert the base 64 string to a byte array.
1636
+ * @param base64 The base64 string to convert.
1637
+ * @returns The byte array.
1575
1638
  */
1576
- static stringValue(source, property, value) {
1577
- if (!Is.string(value)) {
1578
- throw new GuardError(source, "guard.string", property, value);
1639
+ static decode(base64) {
1640
+ Guards.string(Base64._CLASS_NAME, "base64", base64);
1641
+ let tmp;
1642
+ const lens = Base64.getLengths(base64);
1643
+ const validLen = lens[0];
1644
+ const placeHoldersLen = lens[1];
1645
+ const arr = new Uint8Array(Base64.calcByteLength(validLen, placeHoldersLen));
1646
+ let curByte = 0;
1647
+ // if there are placeholders, only get up to the last complete 4 chars
1648
+ const len = placeHoldersLen > 0 ? validLen - 4 : validLen;
1649
+ let i;
1650
+ for (i = 0; i < len; i += 4) {
1651
+ tmp =
1652
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 18) |
1653
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] << 12) |
1654
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 2)] << 6) |
1655
+ Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 3)];
1656
+ arr[curByte++] = (tmp >> 16) & 0xff;
1657
+ arr[curByte++] = (tmp >> 8) & 0xff;
1658
+ arr[curByte++] = tmp & 0xff;
1579
1659
  }
1580
- if (value.length === 0) {
1581
- throw new GuardError(source, "guard.stringEmpty", property, value);
1660
+ if (placeHoldersLen === 2) {
1661
+ tmp =
1662
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 2) |
1663
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] >> 4);
1664
+ arr[curByte++] = tmp & 0xff;
1582
1665
  }
1583
- }
1584
- /**
1585
- * Is the property a JSON value.
1586
- * @param source The source of the error.
1587
- * @param property The name of the property.
1588
- * @param value The value to test.
1589
- * @throws GuardError If the value does not match the assertion.
1590
- */
1591
- static json(source, property, value) {
1592
- if (!Is.json(value)) {
1593
- throw new GuardError(source, "guard.stringJson", property, value);
1666
+ if (placeHoldersLen === 1) {
1667
+ tmp =
1668
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i)] << 10) |
1669
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 1)] << 4) |
1670
+ (Base64._REVERSE_LOOKUP[base64.charCodeAt(i + 2)] >> 2);
1671
+ arr[curByte++] = (tmp >> 8) & 0xff;
1672
+ arr[curByte++] = tmp & 0xff;
1594
1673
  }
1674
+ return arr;
1595
1675
  }
1596
1676
  /**
1597
- * Is the property a base64 string.
1598
- * @param source The source of the error.
1599
- * @param property The name of the property.
1600
- * @param value The value to test.
1601
- * @throws GuardError If the value does not match the assertion.
1677
+ * Convert a byte array to base 64.
1678
+ * @param bytes The byte array to convert.
1679
+ * @returns The data as base64 string.
1602
1680
  */
1603
- static stringBase64(source, property, value) {
1604
- if (!Is.stringBase64(value)) {
1605
- throw new GuardError(source, "guard.base64", property, value);
1681
+ static encode(bytes) {
1682
+ Guards.uint8Array(Base64._CLASS_NAME, "bytes", bytes);
1683
+ let tmp;
1684
+ const len = bytes.length;
1685
+ const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
1686
+ const parts = [];
1687
+ const maxChunkLength = 16383; // must be multiple of 3
1688
+ // go through the array every three bytes, we'll deal with trailing stuff later
1689
+ for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
1690
+ parts.push(Base64.encodeChunk(bytes, i, Math.min(i + maxChunkLength, len2)));
1691
+ }
1692
+ // pad the end with zeros, but make sure to not forget the extra bytes
1693
+ if (extraBytes === 1) {
1694
+ tmp = bytes[len - 1];
1695
+ parts.push(`${Base64._LOOKUP[tmp >> 2] + Base64._LOOKUP[(tmp << 4) & 0x3f]}==`);
1696
+ }
1697
+ else if (extraBytes === 2) {
1698
+ tmp = (bytes[len - 2] << 8) + bytes[len - 1];
1699
+ parts.push(`${Base64._LOOKUP[tmp >> 10] + Base64._LOOKUP[(tmp >> 4) & 0x3f] + Base64._LOOKUP[(tmp << 2) & 0x3f]}=`);
1606
1700
  }
1701
+ return parts.join("");
1607
1702
  }
1608
1703
  /**
1609
- * Is the property a base64 url string.
1610
- * @param source The source of the error.
1611
- * @param property The name of the property.
1612
- * @param value The value to test.
1613
- * @throws GuardError If the value does not match the assertion.
1704
+ * Calculate the byte length.
1705
+ * @param validLen The valid length.
1706
+ * @param placeHoldersLen The placeholder length.
1707
+ * @returns The length.
1708
+ * @internal
1614
1709
  */
1615
- static stringBase64Url(source, property, value) {
1616
- if (!Is.stringBase64Url(value)) {
1617
- throw new GuardError(source, "guard.base64Url", property, value);
1618
- }
1710
+ static calcByteLength(validLen, placeHoldersLen) {
1711
+ return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;
1619
1712
  }
1620
1713
  /**
1621
- * Is the property a base58 string.
1622
- * @param source The source of the error.
1623
- * @param property The name of the property.
1624
- * @param value The value to test.
1625
- * @throws GuardError If the value does not match the assertion.
1714
+ * Get the valid and placeholder lengths from a bas64 string.
1715
+ * @param base64 The base64 string.
1716
+ * @returns The lengths.
1717
+ * @internal
1626
1718
  */
1627
- static stringBase58(source, property, value) {
1628
- if (!Is.stringBase58(value)) {
1629
- throw new GuardError(source, "guard.base58", property, value);
1719
+ static getLengths(base64) {
1720
+ const len = base64.length;
1721
+ if (len % 4 > 0) {
1722
+ throw new GeneralError(Base64._CLASS_NAME, "length4Multiple", { value: len });
1723
+ }
1724
+ // Trim off extra bytes after placeholder bytes are found
1725
+ // See: https://github.com/beatgammit/base64-js/issues/42
1726
+ let validLen = base64.indexOf("=");
1727
+ if (validLen === -1) {
1728
+ validLen = len;
1630
1729
  }
1730
+ const placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);
1731
+ return [validLen, placeHoldersLen];
1631
1732
  }
1632
1733
  /**
1633
- * Is the property a string with a hex value.
1634
- * @param source The source of the error.
1635
- * @param property The name of the property.
1636
- * @param value The value to test.
1637
- * @param allowPrefix Allow the hex to have the 0x prefix.
1638
- * @throws GuardError If the value does not match the assertion.
1734
+ * Convert the triplet to base 64.
1735
+ * @param num The number to convert.
1736
+ * @returns The base64 encoding.
1737
+ * @internal
1639
1738
  */
1640
- static stringHex(source, property, value, allowPrefix = false) {
1641
- Guards.stringValue(source, property, value);
1642
- if (!HexHelper.isHex(value, allowPrefix)) {
1643
- throw new GuardError(source, "guard.stringHex", property, value);
1644
- }
1739
+ static tripletToBase64(num) {
1740
+ return (Base64._LOOKUP[(num >> 18) & 0x3f] +
1741
+ Base64._LOOKUP[(num >> 12) & 0x3f] +
1742
+ Base64._LOOKUP[(num >> 6) & 0x3f] +
1743
+ Base64._LOOKUP[num & 0x3f]);
1645
1744
  }
1646
1745
  /**
1647
- * Is the property a string with a hex value with fixed length.
1648
- * @param source The source of the error.
1649
- * @param property The name of the property.
1650
- * @param value The value to test.
1651
- * @param length The length of the string to match.
1652
- * @param allowPrefix Allow the hex to have the 0x prefix.
1653
- * @throws GuardError If the value does not match the assertion.
1746
+ * Encode a chunk.
1747
+ * @param bytes The byte array.
1748
+ * @param start The start index in the buffer.
1749
+ * @param end The end index in the buffer.
1750
+ * @returns The encoded chunk.
1751
+ * @internal
1654
1752
  */
1655
- static stringHexLength(source, property, value, length, allowPrefix = false) {
1656
- Guards.stringHex(source, property, value, allowPrefix);
1657
- if (HexHelper.stripPrefix(value).length !== length) {
1658
- throw new GuardError(source, "guard.stringHexLength", property, value.length, length.toString());
1753
+ static encodeChunk(bytes, start, end) {
1754
+ let tmp;
1755
+ const output = [];
1756
+ for (let i = start; i < end; i += 3) {
1757
+ tmp = ((bytes[i] << 16) & 0xff0000) + ((bytes[i + 1] << 8) & 0xff00) + (bytes[i + 2] & 0xff);
1758
+ output.push(Base64.tripletToBase64(tmp));
1659
1759
  }
1760
+ return output.join("");
1660
1761
  }
1762
+ }
1763
+
1764
+ /**
1765
+ * Class to help with base64 URL Encoding/Decoding.
1766
+ * https://www.rfc-editor.org/rfc/rfc4648#section-5.
1767
+ */
1768
+ class Base64Url {
1661
1769
  /**
1662
- * Is the property a number.
1663
- * @param source The source of the error.
1664
- * @param property The name of the property.
1665
- * @param value The value to test.
1666
- * @throws GuardError If the value does not match the assertion.
1770
+ * Runtime name for the class.
1771
+ * @internal
1667
1772
  */
1668
- static number(source, property, value) {
1669
- if (!Is.number(value)) {
1670
- throw new GuardError(source, "guard.number", property, value);
1671
- }
1672
- }
1773
+ static _CLASS_NAME = "Base64";
1673
1774
  /**
1674
- * Is the property an integer.
1675
- * @param source The source of the error.
1676
- * @param property The name of the property.
1677
- * @param value The value to test.
1678
- * @throws GuardError If the value does not match the assertion.
1775
+ * Convert the base 64 string to a byte array.
1776
+ * @param base64Url The base64 url string to convert.
1777
+ * @returns The byte array.
1679
1778
  */
1680
- static integer(source, property, value) {
1681
- if (!Is.integer(value)) {
1682
- throw new GuardError(source, "guard.integer", property, value);
1779
+ static decode(base64Url) {
1780
+ Guards.string(Base64Url._CLASS_NAME, "base64Url", base64Url);
1781
+ let base64 = base64Url;
1782
+ // Base 64 url can have padding removed, so add it back if it is missing.
1783
+ if (base64.length > 0 && !base64.endsWith("=")) {
1784
+ const placeHoldersLen = 4 - (base64.length % 4);
1785
+ if (placeHoldersLen > 0 && placeHoldersLen < 4) {
1786
+ base64 = base64.padEnd(base64.length + placeHoldersLen, "=");
1787
+ }
1683
1788
  }
1789
+ base64 = base64.replace(/-/g, "+").replace(/_/g, "/");
1790
+ return Base64.decode(base64);
1684
1791
  }
1685
1792
  /**
1686
- * Is the property a bigint.
1687
- * @param source The source of the error.
1688
- * @param property The name of the property.
1689
- * @param value The value to test.
1690
- * @throws GuardError If the value does not match the assertion.
1793
+ * Convert a byte array to base 64 url.
1794
+ * @param bytes The byte array to convert.
1795
+ * @returns The data as base64 url string.
1691
1796
  */
1692
- static bigint(source, property, value) {
1693
- if (!Is.bigint(value)) {
1694
- throw new GuardError(source, "guard.bigint", property, value);
1695
- }
1797
+ static encode(bytes) {
1798
+ Guards.uint8Array(Base64Url._CLASS_NAME, "bytes", bytes);
1799
+ const base64 = Base64.encode(bytes);
1800
+ // Base 64 url can have padding removed, so remove it.
1801
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
1696
1802
  }
1803
+ }
1804
+
1805
+ /**
1806
+ * Class to handle errors which are triggered by data already existing.
1807
+ */
1808
+ class AlreadyExistsError extends BaseError {
1809
+ /**
1810
+ * Runtime name for the class.
1811
+ */
1812
+ static CLASS_NAME = "AlreadyExistsError";
1697
1813
  /**
1698
- * Is the property a boolean.
1814
+ * Create a new instance of AlreadyExistsError.
1699
1815
  * @param source The source of the error.
1700
- * @param property The name of the property.
1701
- * @param value The value to test.
1702
- * @throws GuardError If the value does not match the assertion.
1816
+ * @param message The message as a code.
1817
+ * @param existingId The id for the item.
1818
+ * @param cause The cause of the error if we have wrapped another error.
1703
1819
  */
1704
- static boolean(source, property, value) {
1705
- if (!Is.boolean(value)) {
1706
- throw new GuardError(source, "guard.boolean", property, value);
1707
- }
1820
+ constructor(source, message, existingId, cause) {
1821
+ super(AlreadyExistsError.CLASS_NAME, source, message, { existingId });
1708
1822
  }
1823
+ }
1824
+
1825
+ /**
1826
+ * Class to handle errors which are triggered by conflicting data.
1827
+ */
1828
+ class ConflictError extends BaseError {
1709
1829
  /**
1710
- * Is the property a date.
1711
- * @param source The source of the error.
1712
- * @param property The name of the property.
1713
- * @param value The value to test.
1714
- * @throws GuardError If the value does not match the assertion.
1830
+ * Runtime name for the class.
1715
1831
  */
1716
- static date(source, property, value) {
1717
- if (!Is.date(value)) {
1718
- throw new GuardError(source, "guard.date", property, value);
1719
- }
1720
- }
1832
+ static CLASS_NAME = "ConflictError";
1721
1833
  /**
1722
- * Is the property a timestamp in milliseconds.
1834
+ * Create a new instance of ConflictError.
1723
1835
  * @param source The source of the error.
1724
- * @param property The name of the property.
1725
- * @param value The value to test.
1726
- * @throws GuardError If the value does not match the assertion.
1836
+ * @param message The message as a code.
1837
+ * @param conflictId The id that has conflicts.
1838
+ * @param conflicts The conflicts that occurred.
1839
+ * @param cause The cause or the error if we have wrapped another error.
1727
1840
  */
1728
- static timestampMilliseconds(source, property, value) {
1729
- if (!Is.timestampMilliseconds(value)) {
1730
- throw new GuardError(source, "guard.timestampMilliseconds", property, value);
1731
- }
1841
+ constructor(source, message, conflictId, conflicts, cause) {
1842
+ super(ConflictError.CLASS_NAME, source, message, { conflictId, conflicts }, cause);
1732
1843
  }
1844
+ }
1845
+
1846
+ /**
1847
+ * Class to handle errors which are triggered by data not being found.
1848
+ */
1849
+ class NotFoundError extends BaseError {
1733
1850
  /**
1734
- * Is the property a timestamp in seconds.
1735
- * @param source The source of the error.
1736
- * @param property The name of the property.
1737
- * @param value The value to test.
1738
- * @throws GuardError If the value does not match the assertion.
1851
+ * Runtime name for the class.
1739
1852
  */
1740
- static timestampSeconds(source, property, value) {
1741
- if (!Is.timestampSeconds(value)) {
1742
- throw new GuardError(source, "guard.timestampSeconds", property, value);
1743
- }
1744
- }
1853
+ static CLASS_NAME = "NotFoundError";
1745
1854
  /**
1746
- * Is the property an object.
1855
+ * Create a new instance of NotFoundError.
1747
1856
  * @param source The source of the error.
1748
- * @param property The name of the property.
1749
- * @param value The value to test.
1750
- * @throws GuardError If the value does not match the assertion.
1857
+ * @param message The message as a code.
1858
+ * @param notFoundId The id for the item.
1859
+ * @param cause The cause of the error if we have wrapped another error.
1751
1860
  */
1752
- static object(source, property, value) {
1753
- if (Is.undefined(value)) {
1754
- throw new GuardError(source, "guard.objectUndefined", property, value);
1755
- }
1756
- if (!Is.object(value)) {
1757
- throw new GuardError(source, "guard.object", property, value);
1758
- }
1861
+ constructor(source, message, notFoundId, cause) {
1862
+ super(NotFoundError.CLASS_NAME, source, message, { notFoundId }, cause);
1759
1863
  }
1864
+ }
1865
+
1866
+ /**
1867
+ * Class to handle errors.
1868
+ */
1869
+ class NotImplementedError extends BaseError {
1760
1870
  /**
1761
- * Is the property is an object with at least one property.
1762
- * @param source The source of the error.
1763
- * @param property The name of the property.
1764
- * @param value The value to test.
1765
- * @throws GuardError If the value does not match the assertion.
1871
+ * Runtime name for the class.
1766
1872
  */
1767
- static objectValue(source, property, value) {
1768
- if (Is.undefined(value)) {
1769
- throw new GuardError(source, "guard.objectUndefined", property, value);
1770
- }
1771
- if (!Is.object(value)) {
1772
- throw new GuardError(source, "guard.object", property, value);
1773
- }
1774
- if (Object.keys(value || {}).length === 0) {
1775
- throw new GuardError(source, "guard.objectValue", property, value);
1776
- }
1777
- }
1873
+ static CLASS_NAME = "NotImplementedError";
1778
1874
  /**
1779
- * Is the property is an array.
1875
+ * Create a new instance of NotImplementedError.
1780
1876
  * @param source The source of the error.
1781
- * @param property The name of the property.
1782
- * @param value The value to test.
1783
- * @throws GuardError If the value does not match the assertion.
1877
+ * @param method The method for the error.
1784
1878
  */
1785
- static array(source, property, value) {
1786
- if (!Is.array(value)) {
1787
- throw new GuardError(source, "guard.array", property, value);
1788
- }
1879
+ constructor(source, method) {
1880
+ super(NotImplementedError.CLASS_NAME, source, "common.notImplementedMethod", {
1881
+ method
1882
+ });
1789
1883
  }
1884
+ }
1885
+
1886
+ /**
1887
+ * Class to handle errors when a feature is unsupported.
1888
+ */
1889
+ class NotSupportedError extends BaseError {
1790
1890
  /**
1791
- * Is the property is an array with at least one item.
1792
- * @param source The source of the error.
1793
- * @param property The name of the property.
1794
- * @param value The value to test.
1795
- * @throws GuardError If the value does not match the assertion.
1891
+ * Runtime name for the class.
1796
1892
  */
1797
- static arrayValue(source, property, value) {
1798
- if (!Is.array(value)) {
1799
- throw new GuardError(source, "guard.array", property, value);
1800
- }
1801
- if (value.length === 0) {
1802
- throw new GuardError(source, "guard.arrayValue", property, value);
1803
- }
1804
- }
1893
+ static CLASS_NAME = "NotSupportedError";
1805
1894
  /**
1806
- * Is the property one of a list of items.
1895
+ * Create a new instance of NotSupportedError.
1807
1896
  * @param source The source of the error.
1808
- * @param property The name of the property.
1809
- * @param value The value to test.
1810
- * @param options The options the value must be one of.
1811
- * @throws GuardError If the value does not match the assertion.
1897
+ * @param message The message as a code.
1898
+ * @param cause The cause of the error if we have wrapped another error.
1812
1899
  */
1813
- static arrayOneOf(source, property, value, options) {
1814
- if (!Is.array(options)) {
1815
- throw new GuardError(source, "guard.array", property, value);
1816
- }
1817
- if (!options.includes(value)) {
1818
- throw new GuardError(source, "guard.arrayOneOf", property, value, options.join(", "));
1819
- }
1900
+ constructor(source, message, cause) {
1901
+ super(NotSupportedError.CLASS_NAME, source, message, undefined, cause);
1820
1902
  }
1903
+ }
1904
+
1905
+ /**
1906
+ * Class to handle errors which are triggered by access not being unauthorized.
1907
+ */
1908
+ class UnauthorizedError extends BaseError {
1821
1909
  /**
1822
- * Does the array start with the specified data.
1823
- * @param source The source of the error.
1824
- * @param property The name of the property.
1825
- * @param value The value to test.
1826
- * @param startValues The values that must start the array.
1827
- * @throws GuardError If the value does not match the assertion.
1910
+ * Runtime name for the class.
1828
1911
  */
1829
- static arrayStartsWith(source, property, value, startValues) {
1830
- if (!Is.arrayValue(value)) {
1831
- throw new GuardError(source, "guard.array", property, value);
1832
- }
1833
- const startValuesArray = ArrayHelper.fromObjectOrArray(startValues);
1834
- if (!Is.arrayValue(startValuesArray)) {
1835
- throw new GuardError(source, "guard.array", property, startValuesArray);
1836
- }
1837
- for (let i = 0; i < startValuesArray.length; i++) {
1838
- if (value[i] !== startValuesArray[i]) {
1839
- throw new GuardError(source, "guard.arrayStartsWith", property, value, startValuesArray.join(", "));
1840
- }
1841
- }
1842
- }
1912
+ static CLASS_NAME = "UnauthorizedError";
1843
1913
  /**
1844
- * Does the array end with the specified data.
1914
+ * Create a new instance of UnauthorizedError.
1845
1915
  * @param source The source of the error.
1846
- * @param property The name of the property.
1847
- * @param value The value to test.
1848
- * @param endValues The values that must end the array.
1849
- * @throws GuardError If the value does not match the assertion.
1916
+ * @param message The message as a code.
1917
+ * @param cause The cause of the error if we have wrapped another error.
1850
1918
  */
1851
- static arrayEndsWith(source, property, value, endValues) {
1852
- if (!Is.arrayValue(value)) {
1853
- throw new GuardError(source, "guard.array", property, value);
1854
- }
1855
- const endValuesArray = ArrayHelper.fromObjectOrArray(endValues);
1856
- if (!Is.arrayValue(endValuesArray)) {
1857
- throw new GuardError(source, "guard.array", property, endValuesArray);
1858
- }
1859
- for (let i = 0; i < endValuesArray.length; i++) {
1860
- if (value[value.length - i - 1] !== endValuesArray[endValuesArray.length - i - 1]) {
1861
- throw new GuardError(source, "guard.arrayEndsWith", property, value, endValuesArray.join(", "));
1862
- }
1863
- }
1919
+ constructor(source, message, cause) {
1920
+ super(UnauthorizedError.CLASS_NAME, source, message, undefined, cause);
1864
1921
  }
1922
+ }
1923
+
1924
+ /**
1925
+ * Class to handle errors when some data can not be processed.
1926
+ */
1927
+ class UnprocessableError extends BaseError {
1865
1928
  /**
1866
- * Is the property a Uint8Array.
1867
- * @param source The source of the error.
1868
- * @param property The name of the property.
1869
- * @param value The value to test.
1870
- * @throws GuardError If the value does not match the assertion.
1929
+ * Runtime name for the class.
1871
1930
  */
1872
- static uint8Array(source, property, value) {
1873
- if (!Is.uint8Array(value)) {
1874
- throw new GuardError(source, "guard.uint8Array", property, value);
1875
- }
1876
- }
1931
+ static CLASS_NAME = "UnprocessableError";
1877
1932
  /**
1878
- * Is the property a function.
1933
+ * Create a new instance of UnprocessableError.
1879
1934
  * @param source The source of the error.
1880
- * @param property The name of the property.
1881
- * @param value The value to test.
1882
- * @returns True if the value is a function.
1883
- * @throws GuardError If the value does not match the assertion.
1935
+ * @param message The message as a code.
1936
+ * @param properties Any additional information for the error.
1937
+ * @param cause The cause of the error if we have wrapped another error.
1884
1938
  */
1885
- static function(source, property, value) {
1886
- if (!Is.function(value)) {
1887
- throw new GuardError(source, "guard.function", property, value);
1888
- }
1889
- return true;
1939
+ constructor(source, message, properties, cause) {
1940
+ super(UnprocessableError.CLASS_NAME, source, message, properties, cause);
1890
1941
  }
1942
+ }
1943
+
1944
+ /**
1945
+ * Class to handle errors which are triggered by entity validation.
1946
+ */
1947
+ class ValidationError extends BaseError {
1891
1948
  /**
1892
- * Is the property a string formatted as an email address.
1949
+ * Runtime name for the class.s
1950
+ */
1951
+ static CLASS_NAME = "ValidationError";
1952
+ /**
1953
+ * Create a new instance of ValidationError.
1893
1954
  * @param source The source of the error.
1894
- * @param property The name of the property.
1895
- * @param value The value to test.
1896
- * @throws GuardError If the value does not match the assertion.
1955
+ * @param validationObject The object that failed validation.
1956
+ * @param validationFailures The validation failures.
1897
1957
  */
1898
- static email(source, property, value) {
1899
- if (!Is.email(value)) {
1900
- throw new GuardError(source, "guard.email", property, value);
1901
- }
1958
+ constructor(source, validationObject, validationFailures) {
1959
+ super(ValidationError.CLASS_NAME, source, "common.validation", {
1960
+ validationObject,
1961
+ validationFailures
1962
+ });
1902
1963
  }
1903
1964
  }
1904
1965
 
@@ -2091,6 +2152,7 @@ class Factory {
2091
2152
  * @throws GeneralError if no item exists to get.
2092
2153
  */
2093
2154
  get(name) {
2155
+ Guards.stringValue(Factory._CLASS_NAME, "name", name);
2094
2156
  const instance = this.getIfExists(name);
2095
2157
  if (!instance) {
2096
2158
  throw new GeneralError(Factory._CLASS_NAME, "noGet", {
@@ -2106,6 +2168,9 @@ class Factory {
2106
2168
  * @returns An instance of the item or undefined if it does not exist.
2107
2169
  */
2108
2170
  getIfExists(name) {
2171
+ if (Is.empty(name)) {
2172
+ return;
2173
+ }
2109
2174
  Guards.stringValue(Factory._CLASS_NAME, "name", name);
2110
2175
  const matchName = this._matcher(Object.keys(this._generators), name);
2111
2176
  if (Is.stringValue(matchName) && this._generators[matchName]) {
@@ -3134,7 +3199,7 @@ class ErrorHelper {
3134
3199
  * Format Errors and returns just their messages.
3135
3200
  * @param error The error to format.
3136
3201
  * @param includeDetails Whether to include error details, defaults to false.
3137
- * @returns The error formatted including any inner errors.
3202
+ * @returns The error formatted including any causes errors.
3138
3203
  */
3139
3204
  static formatErrors(error, includeDetails) {
3140
3205
  const localizedErrors = ErrorHelper.localizeErrors(error);
@@ -3152,7 +3217,7 @@ class ErrorHelper {
3152
3217
  return localizedErrors.map(e => e.message);
3153
3218
  }
3154
3219
  /**
3155
- * Localize the content of an error and any inner errors.
3220
+ * Localize the content of an error and any causes.
3156
3221
  * @param error The error to format.
3157
3222
  * @returns The localized version of the errors flattened.
3158
3223
  */
@@ -3193,7 +3258,7 @@ class ErrorHelper {
3193
3258
  return formattedErrors;
3194
3259
  }
3195
3260
  /**
3196
- * Localize the content of an error and any inner errors.
3261
+ * Localize the content of an error and any causes.
3197
3262
  * @param error The error to format.
3198
3263
  * @returns The localized version of the errors flattened.
3199
3264
  */
@@ -3508,6 +3573,7 @@ class Coerce {
3508
3573
  * @returns The coerced value.
3509
3574
  */
3510
3575
  static byType(value, type) {
3576
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
3511
3577
  switch (type) {
3512
3578
  case CoerceType.String:
3513
3579
  return Coerce.string(value);
@@ -4261,7 +4327,7 @@ class Compression {
4261
4327
  static async compress(bytes, type) {
4262
4328
  Guards.uint8Array(Compression._CLASS_NAME, "bytes", bytes);
4263
4329
  Guards.arrayOneOf(Compression._CLASS_NAME, "type", type, Object.values(CompressionType));
4264
- const blob = new Blob([bytes]);
4330
+ const blob = new Blob([new Uint8Array(bytes)]);
4265
4331
  const compressionStream = new CompressionStream(type);
4266
4332
  const compressionPipe = blob.stream().pipeThrough(compressionStream);
4267
4333
  const compressedBlob = await new Response(compressionPipe).blob();
@@ -4283,7 +4349,7 @@ class Compression {
4283
4349
  static async decompress(compressedBytes, type) {
4284
4350
  Guards.uint8Array(Compression._CLASS_NAME, "compressedBytes", compressedBytes);
4285
4351
  Guards.arrayOneOf(Compression._CLASS_NAME, "type", type, Object.values(CompressionType));
4286
- const blob = new Blob([compressedBytes]);
4352
+ const blob = new Blob([new Uint8Array(compressedBytes)]);
4287
4353
  const decompressionStream = new DecompressionStream(type);
4288
4354
  const decompressionPipe = blob.stream().pipeThrough(decompressionStream);
4289
4355
  const decompressedBlob = await new Response(decompressionPipe).blob();