@twin.org/core 0.0.2-next.3 → 0.0.2-next.5

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