@twin.org/core 0.0.1-next.9 → 0.0.2-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +2266 -1470
- package/dist/esm/index.mjs +2263 -1471
- package/dist/types/errors/alreadyExistsError.d.ts +2 -2
- package/dist/types/errors/baseError.d.ts +25 -5
- package/dist/types/errors/conflictError.d.ts +2 -2
- package/dist/types/errors/generalError.d.ts +2 -2
- package/dist/types/errors/notFoundError.d.ts +2 -2
- package/dist/types/errors/notSupportedError.d.ts +2 -2
- package/dist/types/errors/unauthorizedError.d.ts +2 -2
- package/dist/types/errors/unprocessableError.d.ts +2 -2
- package/dist/types/factories/factory.d.ts +21 -2
- package/dist/types/helpers/arrayHelper.d.ts +13 -0
- package/dist/types/helpers/envHelper.d.ts +16 -0
- package/dist/types/helpers/errorHelper.d.ts +5 -4
- package/dist/types/helpers/jsonHelper.d.ts +30 -0
- package/dist/types/helpers/objectHelper.d.ts +25 -0
- package/dist/types/helpers/uint8ArrayHelper.d.ts +11 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/models/IComponent.d.ts +6 -6
- package/dist/types/models/IError.d.ts +2 -2
- package/dist/types/models/II18nShared.d.ts +29 -0
- package/dist/types/models/coerceType.d.ts +49 -0
- package/dist/types/models/compressionType.d.ts +1 -1
- package/dist/types/models/objectOrArray.d.ts +4 -0
- package/dist/types/utils/asyncCache.d.ts +10 -1
- package/dist/types/utils/coerce.d.ts +22 -0
- package/dist/types/utils/guards.d.ts +35 -0
- package/dist/types/utils/is.d.ts +18 -0
- package/dist/types/utils/sharedStore.d.ts +23 -0
- package/dist/types/utils/validation.d.ts +2 -0
- package/docs/changelog.md +442 -1
- package/docs/reference/classes/AlreadyExistsError.md +166 -32
- package/docs/reference/classes/ArrayHelper.md +71 -5
- package/docs/reference/classes/AsyncCache.md +75 -13
- package/docs/reference/classes/Base32.md +9 -5
- package/docs/reference/classes/Base58.md +9 -5
- package/docs/reference/classes/Base64.md +12 -6
- package/docs/reference/classes/Base64Url.md +9 -5
- package/docs/reference/classes/BaseError.md +160 -34
- package/docs/reference/classes/BitString.md +23 -11
- package/docs/reference/classes/Coerce.md +110 -12
- package/docs/reference/classes/Compression.md +19 -11
- package/docs/reference/classes/ConflictError.md +169 -33
- package/docs/reference/classes/Converter.md +72 -28
- package/docs/reference/classes/EnvHelper.md +45 -0
- package/docs/reference/classes/ErrorHelper.md +22 -10
- package/docs/reference/classes/Factory.md +96 -18
- package/docs/reference/classes/FilenameHelper.md +6 -4
- package/docs/reference/classes/GeneralError.md +164 -32
- package/docs/reference/classes/GuardError.md +168 -32
- package/docs/reference/classes/Guards.md +398 -80
- package/docs/reference/classes/HexHelper.md +18 -8
- package/docs/reference/classes/I18n.md +46 -20
- package/docs/reference/classes/Is.md +207 -51
- package/docs/reference/classes/JsonHelper.md +146 -10
- package/docs/reference/classes/NotFoundError.md +166 -32
- package/docs/reference/classes/NotImplementedError.md +159 -29
- package/docs/reference/classes/NotSupportedError.md +163 -31
- package/docs/reference/classes/ObjectHelper.md +197 -39
- package/docs/reference/classes/RandomHelper.md +6 -4
- package/docs/reference/classes/SharedStore.md +94 -0
- package/docs/reference/classes/StringHelper.md +54 -20
- package/docs/reference/classes/Uint8ArrayHelper.md +35 -0
- package/docs/reference/classes/UnauthorizedError.md +163 -31
- package/docs/reference/classes/UnprocessableError.md +164 -32
- package/docs/reference/classes/Url.md +37 -17
- package/docs/reference/classes/Urn.md +63 -27
- package/docs/reference/classes/Validation.md +349 -135
- package/docs/reference/classes/ValidationError.md +162 -30
- package/docs/reference/index.md +7 -0
- package/docs/reference/interfaces/IComponent.md +21 -11
- package/docs/reference/interfaces/IError.md +4 -4
- package/docs/reference/interfaces/II18nShared.md +47 -0
- package/docs/reference/interfaces/IKeyValue.md +3 -1
- package/docs/reference/interfaces/ILabelledValue.md +3 -1
- package/docs/reference/interfaces/ILocaleDictionary.md +1 -1
- package/docs/reference/interfaces/IPatchOperation.md +1 -1
- package/docs/reference/interfaces/IValidationFailure.md +1 -1
- package/docs/reference/type-aliases/CoerceType.md +5 -0
- package/docs/reference/type-aliases/CompressionType.md +1 -1
- package/docs/reference/type-aliases/ObjectOrArray.md +11 -0
- package/docs/reference/variables/CoerceType.md +67 -0
- package/docs/reference/variables/CompressionType.md +2 -2
- package/locales/en.json +14 -1
- package/package.json +7 -7
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var intlMessageformat = require('intl-messageformat');
|
|
4
3
|
var rfc6902 = require('rfc6902');
|
|
4
|
+
var intlMessageformat = require('intl-messageformat');
|
|
5
5
|
|
|
6
6
|
// Copyright 2024 IOTA Stiftung.
|
|
7
7
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -113,7 +113,12 @@ class Is {
|
|
|
113
113
|
}
|
|
114
114
|
try {
|
|
115
115
|
const json = JSON.parse(value);
|
|
116
|
-
return
|
|
116
|
+
return (Is.object(json) ||
|
|
117
|
+
Is.array(json) ||
|
|
118
|
+
Is.string(json) ||
|
|
119
|
+
Is.number(json) ||
|
|
120
|
+
Is.boolean(json) ||
|
|
121
|
+
Is.null(json));
|
|
117
122
|
}
|
|
118
123
|
catch {
|
|
119
124
|
return false;
|
|
@@ -137,7 +142,17 @@ class Is {
|
|
|
137
142
|
static stringBase64Url(value) {
|
|
138
143
|
return (Is.stringValue(value) &&
|
|
139
144
|
// eslint-disable-next-line unicorn/better-regex
|
|
140
|
-
/^(
|
|
145
|
+
/^([A-Za-z0-9-_])*$/.test(value));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Is the value a base58 string.
|
|
149
|
+
* @param value The value to test.
|
|
150
|
+
* @returns True if the value is a base58 string.
|
|
151
|
+
*/
|
|
152
|
+
static stringBase58(value) {
|
|
153
|
+
return (Is.stringValue(value) &&
|
|
154
|
+
// eslint-disable-next-line unicorn/better-regex
|
|
155
|
+
/^[A-HJ-NP-Za-km-z1-9]*$/.test(value));
|
|
141
156
|
}
|
|
142
157
|
/**
|
|
143
158
|
* Is the value a hex string.
|
|
@@ -351,6 +366,27 @@ class Is {
|
|
|
351
366
|
static promise(value) {
|
|
352
367
|
return value instanceof Promise;
|
|
353
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Is the value a regexp.
|
|
371
|
+
* @param value The value to test.
|
|
372
|
+
* @returns True if the value is a regexp.
|
|
373
|
+
*/
|
|
374
|
+
static regexp(value) {
|
|
375
|
+
return value instanceof RegExp;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Is the provided object a class constructor.
|
|
379
|
+
* @param obj The object to check.
|
|
380
|
+
* @returns True if the object is a class, false otherwise.
|
|
381
|
+
*/
|
|
382
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
383
|
+
static class(obj) {
|
|
384
|
+
if (typeof obj !== "function") {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
const str = Function.prototype.toString.call(obj);
|
|
388
|
+
return /^class\s/.test(str);
|
|
389
|
+
}
|
|
354
390
|
}
|
|
355
391
|
|
|
356
392
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -608,31 +644,33 @@ class BaseError extends Error {
|
|
|
608
644
|
*/
|
|
609
645
|
properties;
|
|
610
646
|
/**
|
|
611
|
-
* The
|
|
647
|
+
* The cause of the error.
|
|
612
648
|
*/
|
|
613
|
-
|
|
649
|
+
cause;
|
|
614
650
|
/**
|
|
615
651
|
* Create a new instance of BaseError.
|
|
616
652
|
* @param name The name of the error.
|
|
617
653
|
* @param source The source of the error.
|
|
618
654
|
* @param message The message as a code.
|
|
619
655
|
* @param properties Any additional information for the error.
|
|
620
|
-
* @param
|
|
656
|
+
* @param cause The cause of error if we have wrapped another error.
|
|
621
657
|
*/
|
|
622
|
-
constructor(name, source, message, properties,
|
|
658
|
+
constructor(name, source, message, properties, cause) {
|
|
623
659
|
super(message);
|
|
624
660
|
this.name = name;
|
|
625
661
|
this.source = source;
|
|
662
|
+
this.cause = Is.notEmpty(cause) ? BaseError.fromError(cause).toJsonObject(true) : undefined;
|
|
663
|
+
this.properties = properties;
|
|
626
664
|
// If the message is camel case but has no namespace then prefix it
|
|
627
|
-
// with the source name in camel case
|
|
665
|
+
// with the source name in camel case.
|
|
628
666
|
if (Is.stringValue(source) &&
|
|
629
667
|
Is.stringValue(message) &&
|
|
630
668
|
!message.includes(".") &&
|
|
669
|
+
// This comparison checks that it is most likely a camel case name
|
|
670
|
+
// and not a free text error with a dot in it
|
|
631
671
|
StringHelper.camelCase(message) === message) {
|
|
632
672
|
this.message = `${StringHelper.camelCase(source)}.${message}`;
|
|
633
673
|
}
|
|
634
|
-
this.properties = properties;
|
|
635
|
-
this.inner = inner ? BaseError.fromError(inner).toJsonObject() : undefined;
|
|
636
674
|
}
|
|
637
675
|
/**
|
|
638
676
|
* Construct an error from an existing one.
|
|
@@ -644,9 +682,12 @@ class BaseError extends Error {
|
|
|
644
682
|
let message;
|
|
645
683
|
let source;
|
|
646
684
|
let properties;
|
|
647
|
-
let
|
|
685
|
+
let cause;
|
|
648
686
|
let stack;
|
|
649
|
-
if (Is.object(err)) {
|
|
687
|
+
if (Is.object(err) && Is.stringValue(err.error)) {
|
|
688
|
+
message = err.error;
|
|
689
|
+
}
|
|
690
|
+
else if (Is.object(err)) {
|
|
650
691
|
if (Is.stringValue(err.name)) {
|
|
651
692
|
name = err.name;
|
|
652
693
|
}
|
|
@@ -659,23 +700,24 @@ class BaseError extends Error {
|
|
|
659
700
|
if (Is.notEmpty(err.properties)) {
|
|
660
701
|
properties = err.properties;
|
|
661
702
|
}
|
|
662
|
-
if (
|
|
663
|
-
|
|
703
|
+
if (BaseError.isAggregateError(err)) {
|
|
704
|
+
properties ??= {};
|
|
705
|
+
properties.errors = err.errors;
|
|
706
|
+
}
|
|
707
|
+
if (Is.notEmpty(err.cause)) {
|
|
708
|
+
cause = err.cause;
|
|
664
709
|
}
|
|
665
710
|
if (Is.notEmpty(err.stack)) {
|
|
666
711
|
stack = err.stack;
|
|
667
712
|
}
|
|
668
713
|
}
|
|
669
|
-
else if (Is.object(err) && Is.stringValue(err.error)) {
|
|
670
|
-
message = err.error;
|
|
671
|
-
}
|
|
672
714
|
else if (Is.stringValue(err)) {
|
|
673
715
|
message = err;
|
|
674
716
|
}
|
|
675
717
|
else {
|
|
676
718
|
message = JSON.stringify(err);
|
|
677
719
|
}
|
|
678
|
-
const baseError = new BaseError(name, source ?? "", message ?? "", properties,
|
|
720
|
+
const baseError = new BaseError(name, source ?? "", message ?? "", properties, cause);
|
|
679
721
|
baseError.stack = stack;
|
|
680
722
|
return baseError;
|
|
681
723
|
}
|
|
@@ -686,12 +728,12 @@ class BaseError extends Error {
|
|
|
686
728
|
*/
|
|
687
729
|
static flatten(err) {
|
|
688
730
|
const flattened = [];
|
|
689
|
-
let e = BaseError.fromError(err).toJsonObject();
|
|
731
|
+
let e = BaseError.fromError(err).toJsonObject(true);
|
|
690
732
|
while (e) {
|
|
691
|
-
const
|
|
692
|
-
e.
|
|
733
|
+
const cause = e.cause;
|
|
734
|
+
e.cause = undefined;
|
|
693
735
|
flattened.push(e);
|
|
694
|
-
e =
|
|
736
|
+
e = cause;
|
|
695
737
|
}
|
|
696
738
|
return flattened;
|
|
697
739
|
}
|
|
@@ -706,8 +748,8 @@ class BaseError extends Error {
|
|
|
706
748
|
first = errors[0];
|
|
707
749
|
let current = first;
|
|
708
750
|
for (let i = 1; i < errors.length; i++) {
|
|
709
|
-
current.
|
|
710
|
-
current = current.
|
|
751
|
+
current.cause = errors[i];
|
|
752
|
+
current = current.cause;
|
|
711
753
|
}
|
|
712
754
|
}
|
|
713
755
|
return first;
|
|
@@ -780,11 +822,43 @@ class BaseError extends Error {
|
|
|
780
822
|
static someErrorCode(error, code) {
|
|
781
823
|
return BaseError.flatten(error).some(e => BaseError.isErrorCode(e, code));
|
|
782
824
|
}
|
|
825
|
+
/**
|
|
826
|
+
* Is the error empty, i.e. does it have no message, source, properties, or cause?
|
|
827
|
+
* @param err The error to check for being empty.
|
|
828
|
+
* @returns True if the error is empty.
|
|
829
|
+
*/
|
|
830
|
+
static isEmpty(err) {
|
|
831
|
+
return (!Is.stringValue(err.message) &&
|
|
832
|
+
!Is.stringValue(err.source) &&
|
|
833
|
+
!Is.objectValue(err.properties) &&
|
|
834
|
+
Is.empty(err.cause));
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Is the error an aggregate error.
|
|
838
|
+
* @param err The error to check for being an aggregate error.
|
|
839
|
+
* @returns True if the error is an aggregate error.
|
|
840
|
+
*/
|
|
841
|
+
static isAggregateError(err) {
|
|
842
|
+
return err instanceof AggregateError;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Convert the aggregate error to an array of errors.
|
|
846
|
+
* @param err The error to convert.
|
|
847
|
+
* @param includeStackTrace Whether to include the error stack in the model, defaults to false.
|
|
848
|
+
* @returns The array of errors.
|
|
849
|
+
*/
|
|
850
|
+
static fromAggregate(err, includeStackTrace) {
|
|
851
|
+
if (BaseError.isAggregateError(err)) {
|
|
852
|
+
return err.errors.map(e => BaseError.fromError(e).toJsonObject(includeStackTrace));
|
|
853
|
+
}
|
|
854
|
+
return [BaseError.fromError(err).toJsonObject(includeStackTrace)];
|
|
855
|
+
}
|
|
783
856
|
/**
|
|
784
857
|
* Serialize the error to the error model.
|
|
858
|
+
* @param includeStackTrace Whether to include the error stack in the model, defaults to false.
|
|
785
859
|
* @returns The error model.
|
|
786
860
|
*/
|
|
787
|
-
toJsonObject() {
|
|
861
|
+
toJsonObject(includeStackTrace) {
|
|
788
862
|
const err = {};
|
|
789
863
|
if (Is.stringValue(this.name)) {
|
|
790
864
|
err.name = this.name;
|
|
@@ -798,11 +872,11 @@ class BaseError extends Error {
|
|
|
798
872
|
if (Is.object(this.properties)) {
|
|
799
873
|
err.properties = this.properties;
|
|
800
874
|
}
|
|
801
|
-
if (Is.stringValue(this.stack)) {
|
|
875
|
+
if ((includeStackTrace ?? false) && Is.stringValue(this.stack)) {
|
|
802
876
|
err.stack = this.stack;
|
|
803
877
|
}
|
|
804
|
-
if (Is.notEmpty(this.
|
|
805
|
-
err.
|
|
878
|
+
if (Is.notEmpty(this.cause)) {
|
|
879
|
+
err.cause = BaseError.fromError(this.cause).toJsonObject(includeStackTrace);
|
|
806
880
|
}
|
|
807
881
|
return err;
|
|
808
882
|
}
|
|
@@ -821,176 +895,614 @@ class GeneralError extends BaseError {
|
|
|
821
895
|
* @param source The source of the error.
|
|
822
896
|
* @param message The message as a code.
|
|
823
897
|
* @param properties Any additional information for the error.
|
|
824
|
-
* @param
|
|
898
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
825
899
|
*/
|
|
826
|
-
constructor(source, message, properties,
|
|
827
|
-
super(GeneralError.CLASS_NAME, source, message, properties,
|
|
900
|
+
constructor(source, message, properties, cause) {
|
|
901
|
+
super(GeneralError.CLASS_NAME, source, message, properties, cause);
|
|
828
902
|
}
|
|
829
903
|
}
|
|
830
904
|
|
|
831
|
-
// Copyright 2024 IOTA Stiftung.
|
|
832
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
833
|
-
/* eslint-disable no-bitwise */
|
|
834
905
|
/**
|
|
835
|
-
* Class to
|
|
906
|
+
* Class to handle errors which are triggered by data guards.
|
|
836
907
|
*/
|
|
837
|
-
class
|
|
908
|
+
class GuardError extends BaseError {
|
|
838
909
|
/**
|
|
839
910
|
* Runtime name for the class.
|
|
840
|
-
* @internal
|
|
841
911
|
*/
|
|
842
|
-
static
|
|
912
|
+
static CLASS_NAME = "GuardError";
|
|
843
913
|
/**
|
|
844
|
-
*
|
|
845
|
-
* @
|
|
914
|
+
* Create a new instance of GuardError.
|
|
915
|
+
* @param source The source of the error.
|
|
916
|
+
* @param message The message as a code.
|
|
917
|
+
* @param propertyName The property which triggered the guard error for the item.
|
|
918
|
+
* @param propertyValue The property value which triggered the guard error for the item.
|
|
919
|
+
* @param propertyOptions The property options which might be allowed.
|
|
846
920
|
*/
|
|
847
|
-
|
|
921
|
+
constructor(source, message, propertyName, propertyValue, propertyOptions) {
|
|
922
|
+
super(GuardError.CLASS_NAME, source, message, {
|
|
923
|
+
property: propertyName ?? "property",
|
|
924
|
+
value: Is.undefined(propertyValue) ? "undefined" : propertyValue,
|
|
925
|
+
options: propertyOptions
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Class to help with arrays.
|
|
932
|
+
*/
|
|
933
|
+
class ArrayHelper {
|
|
848
934
|
/**
|
|
849
|
-
*
|
|
850
|
-
* @param
|
|
851
|
-
* @
|
|
852
|
-
* @
|
|
935
|
+
* Do the two arrays match.
|
|
936
|
+
* @param arr1 The first array.
|
|
937
|
+
* @param arr2 The second array.
|
|
938
|
+
* @returns True if both arrays are empty of have the same values.
|
|
853
939
|
*/
|
|
854
|
-
static
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
value = (value << 5) | idx;
|
|
868
|
-
bits += 5;
|
|
869
|
-
if (bits >= 8) {
|
|
870
|
-
output[index++] = (value >>> (bits - 8)) & 255;
|
|
871
|
-
bits -= 8;
|
|
940
|
+
static matches(arr1, arr2) {
|
|
941
|
+
if (Is.empty(arr1) && Is.empty(arr2)) {
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
if (!((Is.array(arr1) && Is.array(arr2)) || (Is.typedArray(arr1) && Is.typedArray(arr2)))) {
|
|
945
|
+
return false;
|
|
946
|
+
}
|
|
947
|
+
if (arr1.length !== arr2.length) {
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
951
|
+
if (arr1[i] !== arr2[i]) {
|
|
952
|
+
return false;
|
|
872
953
|
}
|
|
873
954
|
}
|
|
874
|
-
return
|
|
955
|
+
return true;
|
|
875
956
|
}
|
|
876
957
|
/**
|
|
877
|
-
* Convert
|
|
878
|
-
* @param
|
|
879
|
-
* @returns The
|
|
958
|
+
* Convert an object or array to an array.
|
|
959
|
+
* @param value The object or array to convert.
|
|
960
|
+
* @returns The array.
|
|
880
961
|
*/
|
|
881
|
-
static
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
let output = "";
|
|
885
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
886
|
-
value = (value << 8) | bytes[i];
|
|
887
|
-
bits += 8;
|
|
888
|
-
while (bits >= 5) {
|
|
889
|
-
output += Base32._ALPHABET[(value >>> (bits - 5)) & 31];
|
|
890
|
-
bits -= 5;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
if (bits > 0) {
|
|
894
|
-
output += Base32._ALPHABET[(value << (5 - bits)) & 31];
|
|
962
|
+
static fromObjectOrArray(value) {
|
|
963
|
+
if (Is.empty(value)) {
|
|
964
|
+
return undefined;
|
|
895
965
|
}
|
|
896
|
-
|
|
897
|
-
|
|
966
|
+
if (Is.array(value)) {
|
|
967
|
+
return value;
|
|
898
968
|
}
|
|
899
|
-
return
|
|
969
|
+
return [value];
|
|
900
970
|
}
|
|
901
971
|
}
|
|
902
972
|
|
|
973
|
+
// Copyright 2024 IOTA Stiftung.
|
|
974
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
903
975
|
/**
|
|
904
|
-
* Class to
|
|
976
|
+
* Class to handle guard operations for parameters.
|
|
905
977
|
*/
|
|
906
|
-
class
|
|
907
|
-
/**
|
|
908
|
-
* Runtime name for the class.
|
|
909
|
-
* @internal
|
|
910
|
-
*/
|
|
911
|
-
static _CLASS_NAME = "Base58";
|
|
978
|
+
class Guards {
|
|
912
979
|
/**
|
|
913
|
-
*
|
|
914
|
-
* @
|
|
980
|
+
* Is the property defined.
|
|
981
|
+
* @param source The source of the error.
|
|
982
|
+
* @param property The name of the property.
|
|
983
|
+
* @param value The value to test.
|
|
984
|
+
* @throws GuardError If the value does not match the assertion.
|
|
915
985
|
*/
|
|
916
|
-
static
|
|
917
|
-
|
|
918
|
-
|
|
986
|
+
static defined(source, property, value) {
|
|
987
|
+
if (Is.undefined(value)) {
|
|
988
|
+
throw new GuardError(source, "guard.undefined", property, value);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
919
991
|
/**
|
|
920
|
-
*
|
|
921
|
-
* @
|
|
992
|
+
* Is the property a string.
|
|
993
|
+
* @param source The source of the error.
|
|
994
|
+
* @param property The name of the property.
|
|
995
|
+
* @param value The value to test.
|
|
996
|
+
* @throws GuardError If the value does not match the assertion.
|
|
922
997
|
*/
|
|
923
|
-
static
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
929
|
-
57, -1, -1, -1, -1, -1
|
|
930
|
-
];
|
|
998
|
+
static string(source, property, value) {
|
|
999
|
+
if (!Is.string(value)) {
|
|
1000
|
+
throw new GuardError(source, "guard.string", property, value);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
931
1003
|
/**
|
|
932
|
-
*
|
|
933
|
-
* @param
|
|
934
|
-
* @
|
|
935
|
-
* @
|
|
1004
|
+
* Is the property a string with a value.
|
|
1005
|
+
* @param source The source of the error.
|
|
1006
|
+
* @param property The name of the property.
|
|
1007
|
+
* @param value The value to test.
|
|
1008
|
+
* @throws GuardError If the value does not match the assertion.
|
|
936
1009
|
*/
|
|
937
|
-
static
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
if (base58[i] !== "1") {
|
|
941
|
-
break;
|
|
942
|
-
}
|
|
943
|
-
zeroes += 1;
|
|
944
|
-
}
|
|
945
|
-
const size = Math.trunc((base58.length * 733) / 1000) + 1;
|
|
946
|
-
const b256 = new Uint8Array(size).fill(0);
|
|
947
|
-
let length = 0;
|
|
948
|
-
for (let i = zeroes; i < base58.length; i++) {
|
|
949
|
-
const ch = base58.charCodeAt(i);
|
|
950
|
-
if (ch & 0xff80) {
|
|
951
|
-
throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
|
|
952
|
-
}
|
|
953
|
-
const val = Base58._ALPHABET_REVERSE[ch];
|
|
954
|
-
if (val === -1) {
|
|
955
|
-
throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
|
|
956
|
-
}
|
|
957
|
-
let carry = val;
|
|
958
|
-
let j = 0;
|
|
959
|
-
for (let k = size - 1; k >= 0; k--, j++) {
|
|
960
|
-
if (carry === 0 && j >= length) {
|
|
961
|
-
break;
|
|
962
|
-
}
|
|
963
|
-
carry += b256[k] * 58;
|
|
964
|
-
b256[k] = carry;
|
|
965
|
-
carry >>>= 8;
|
|
966
|
-
}
|
|
967
|
-
length = j;
|
|
1010
|
+
static stringValue(source, property, value) {
|
|
1011
|
+
if (!Is.string(value)) {
|
|
1012
|
+
throw new GuardError(source, "guard.string", property, value);
|
|
968
1013
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
for (j = 0; j < zeroes; j++) {
|
|
972
|
-
out[j] = 0;
|
|
1014
|
+
if (value.length === 0) {
|
|
1015
|
+
throw new GuardError(source, "guard.stringEmpty", property, value);
|
|
973
1016
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Is the property a JSON value.
|
|
1020
|
+
* @param source The source of the error.
|
|
1021
|
+
* @param property The name of the property.
|
|
1022
|
+
* @param value The value to test.
|
|
1023
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1024
|
+
*/
|
|
1025
|
+
static json(source, property, value) {
|
|
1026
|
+
if (!Is.json(value)) {
|
|
1027
|
+
throw new GuardError(source, "guard.stringJson", property, value);
|
|
977
1028
|
}
|
|
978
|
-
return out;
|
|
979
1029
|
}
|
|
980
1030
|
/**
|
|
981
|
-
*
|
|
982
|
-
* @param
|
|
983
|
-
* @
|
|
1031
|
+
* Is the property a base64 string.
|
|
1032
|
+
* @param source The source of the error.
|
|
1033
|
+
* @param property The name of the property.
|
|
1034
|
+
* @param value The value to test.
|
|
1035
|
+
* @throws GuardError If the value does not match the assertion.
|
|
984
1036
|
*/
|
|
985
|
-
static
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
if (bytes[i] !== 0) {
|
|
989
|
-
break;
|
|
990
|
-
}
|
|
991
|
-
zeroes += 1;
|
|
1037
|
+
static stringBase64(source, property, value) {
|
|
1038
|
+
if (!Is.stringBase64(value)) {
|
|
1039
|
+
throw new GuardError(source, "guard.base64", property, value);
|
|
992
1040
|
}
|
|
993
|
-
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Is the property a base64 url string.
|
|
1044
|
+
* @param source The source of the error.
|
|
1045
|
+
* @param property The name of the property.
|
|
1046
|
+
* @param value The value to test.
|
|
1047
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1048
|
+
*/
|
|
1049
|
+
static stringBase64Url(source, property, value) {
|
|
1050
|
+
if (!Is.stringBase64Url(value)) {
|
|
1051
|
+
throw new GuardError(source, "guard.base64Url", property, value);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Is the property a base58 string.
|
|
1056
|
+
* @param source The source of the error.
|
|
1057
|
+
* @param property The name of the property.
|
|
1058
|
+
* @param value The value to test.
|
|
1059
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1060
|
+
*/
|
|
1061
|
+
static stringBase58(source, property, value) {
|
|
1062
|
+
if (!Is.stringBase58(value)) {
|
|
1063
|
+
throw new GuardError(source, "guard.base58", property, value);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Is the property a string with a hex value.
|
|
1068
|
+
* @param source The source of the error.
|
|
1069
|
+
* @param property The name of the property.
|
|
1070
|
+
* @param value The value to test.
|
|
1071
|
+
* @param allowPrefix Allow the hex to have the 0x prefix.
|
|
1072
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1073
|
+
*/
|
|
1074
|
+
static stringHex(source, property, value, allowPrefix = false) {
|
|
1075
|
+
Guards.stringValue(source, property, value);
|
|
1076
|
+
if (!HexHelper.isHex(value, allowPrefix)) {
|
|
1077
|
+
throw new GuardError(source, "guard.stringHex", property, value);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Is the property a string with a hex value with fixed length.
|
|
1082
|
+
* @param source The source of the error.
|
|
1083
|
+
* @param property The name of the property.
|
|
1084
|
+
* @param value The value to test.
|
|
1085
|
+
* @param length The length of the string to match.
|
|
1086
|
+
* @param allowPrefix Allow the hex to have the 0x prefix.
|
|
1087
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1088
|
+
*/
|
|
1089
|
+
static stringHexLength(source, property, value, length, allowPrefix = false) {
|
|
1090
|
+
Guards.stringHex(source, property, value, allowPrefix);
|
|
1091
|
+
if (HexHelper.stripPrefix(value).length !== length) {
|
|
1092
|
+
throw new GuardError(source, "guard.stringHexLength", property, value.length, length.toString());
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Is the property a number.
|
|
1097
|
+
* @param source The source of the error.
|
|
1098
|
+
* @param property The name of the property.
|
|
1099
|
+
* @param value The value to test.
|
|
1100
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1101
|
+
*/
|
|
1102
|
+
static number(source, property, value) {
|
|
1103
|
+
if (!Is.number(value)) {
|
|
1104
|
+
throw new GuardError(source, "guard.number", property, value);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Is the property an integer.
|
|
1109
|
+
* @param source The source of the error.
|
|
1110
|
+
* @param property The name of the property.
|
|
1111
|
+
* @param value The value to test.
|
|
1112
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1113
|
+
*/
|
|
1114
|
+
static integer(source, property, value) {
|
|
1115
|
+
if (!Is.integer(value)) {
|
|
1116
|
+
throw new GuardError(source, "guard.integer", property, value);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Is the property a bigint.
|
|
1121
|
+
* @param source The source of the error.
|
|
1122
|
+
* @param property The name of the property.
|
|
1123
|
+
* @param value The value to test.
|
|
1124
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1125
|
+
*/
|
|
1126
|
+
static bigint(source, property, value) {
|
|
1127
|
+
if (!Is.bigint(value)) {
|
|
1128
|
+
throw new GuardError(source, "guard.bigint", property, value);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Is the property a boolean.
|
|
1133
|
+
* @param source The source of the error.
|
|
1134
|
+
* @param property The name of the property.
|
|
1135
|
+
* @param value The value to test.
|
|
1136
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1137
|
+
*/
|
|
1138
|
+
static boolean(source, property, value) {
|
|
1139
|
+
if (!Is.boolean(value)) {
|
|
1140
|
+
throw new GuardError(source, "guard.boolean", property, value);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Is the property a date.
|
|
1145
|
+
* @param source The source of the error.
|
|
1146
|
+
* @param property The name of the property.
|
|
1147
|
+
* @param value The value to test.
|
|
1148
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1149
|
+
*/
|
|
1150
|
+
static date(source, property, value) {
|
|
1151
|
+
if (!Is.date(value)) {
|
|
1152
|
+
throw new GuardError(source, "guard.date", property, value);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Is the property a timestamp in milliseconds.
|
|
1157
|
+
* @param source The source of the error.
|
|
1158
|
+
* @param property The name of the property.
|
|
1159
|
+
* @param value The value to test.
|
|
1160
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1161
|
+
*/
|
|
1162
|
+
static timestampMilliseconds(source, property, value) {
|
|
1163
|
+
if (!Is.timestampMilliseconds(value)) {
|
|
1164
|
+
throw new GuardError(source, "guard.timestampMilliseconds", property, value);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Is the property a timestamp in seconds.
|
|
1169
|
+
* @param source The source of the error.
|
|
1170
|
+
* @param property The name of the property.
|
|
1171
|
+
* @param value The value to test.
|
|
1172
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1173
|
+
*/
|
|
1174
|
+
static timestampSeconds(source, property, value) {
|
|
1175
|
+
if (!Is.timestampSeconds(value)) {
|
|
1176
|
+
throw new GuardError(source, "guard.timestampSeconds", property, value);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Is the property an object.
|
|
1181
|
+
* @param source The source of the error.
|
|
1182
|
+
* @param property The name of the property.
|
|
1183
|
+
* @param value The value to test.
|
|
1184
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1185
|
+
*/
|
|
1186
|
+
static object(source, property, value) {
|
|
1187
|
+
if (Is.undefined(value)) {
|
|
1188
|
+
throw new GuardError(source, "guard.objectUndefined", property, value);
|
|
1189
|
+
}
|
|
1190
|
+
if (!Is.object(value)) {
|
|
1191
|
+
throw new GuardError(source, "guard.object", property, value);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Is the property is an object with at least one property.
|
|
1196
|
+
* @param source The source of the error.
|
|
1197
|
+
* @param property The name of the property.
|
|
1198
|
+
* @param value The value to test.
|
|
1199
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1200
|
+
*/
|
|
1201
|
+
static objectValue(source, property, value) {
|
|
1202
|
+
if (Is.undefined(value)) {
|
|
1203
|
+
throw new GuardError(source, "guard.objectUndefined", property, value);
|
|
1204
|
+
}
|
|
1205
|
+
if (!Is.object(value)) {
|
|
1206
|
+
throw new GuardError(source, "guard.object", property, value);
|
|
1207
|
+
}
|
|
1208
|
+
if (Object.keys(value || {}).length === 0) {
|
|
1209
|
+
throw new GuardError(source, "guard.objectValue", property, value);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Is the property is an array.
|
|
1214
|
+
* @param source The source of the error.
|
|
1215
|
+
* @param property The name of the property.
|
|
1216
|
+
* @param value The value to test.
|
|
1217
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1218
|
+
*/
|
|
1219
|
+
static array(source, property, value) {
|
|
1220
|
+
if (!Is.array(value)) {
|
|
1221
|
+
throw new GuardError(source, "guard.array", property, value);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Is the property is an array with at least one item.
|
|
1226
|
+
* @param source The source of the error.
|
|
1227
|
+
* @param property The name of the property.
|
|
1228
|
+
* @param value The value to test.
|
|
1229
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1230
|
+
*/
|
|
1231
|
+
static arrayValue(source, property, value) {
|
|
1232
|
+
if (!Is.array(value)) {
|
|
1233
|
+
throw new GuardError(source, "guard.array", property, value);
|
|
1234
|
+
}
|
|
1235
|
+
if (value.length === 0) {
|
|
1236
|
+
throw new GuardError(source, "guard.arrayValue", property, value);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Is the property one of a list of items.
|
|
1241
|
+
* @param source The source of the error.
|
|
1242
|
+
* @param property The name of the property.
|
|
1243
|
+
* @param value The value to test.
|
|
1244
|
+
* @param options The options the value must be one of.
|
|
1245
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1246
|
+
*/
|
|
1247
|
+
static arrayOneOf(source, property, value, options) {
|
|
1248
|
+
if (!Is.array(options)) {
|
|
1249
|
+
throw new GuardError(source, "guard.array", property, value);
|
|
1250
|
+
}
|
|
1251
|
+
if (!options.includes(value)) {
|
|
1252
|
+
throw new GuardError(source, "guard.arrayOneOf", property, value, options.join(", "));
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Does the array start with the specified data.
|
|
1257
|
+
* @param source The source of the error.
|
|
1258
|
+
* @param property The name of the property.
|
|
1259
|
+
* @param value The value to test.
|
|
1260
|
+
* @param startValues The values that must start the array.
|
|
1261
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1262
|
+
*/
|
|
1263
|
+
static arrayStartsWith(source, property, value, startValues) {
|
|
1264
|
+
if (!Is.arrayValue(value)) {
|
|
1265
|
+
throw new GuardError(source, "guard.array", property, value);
|
|
1266
|
+
}
|
|
1267
|
+
const startValuesArray = ArrayHelper.fromObjectOrArray(startValues);
|
|
1268
|
+
if (!Is.arrayValue(startValuesArray)) {
|
|
1269
|
+
throw new GuardError(source, "guard.array", property, startValuesArray);
|
|
1270
|
+
}
|
|
1271
|
+
for (let i = 0; i < startValuesArray.length; i++) {
|
|
1272
|
+
if (value[i] !== startValuesArray[i]) {
|
|
1273
|
+
throw new GuardError(source, "guard.arrayStartsWith", property, value, startValuesArray.join(", "));
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Does the array end with the specified data.
|
|
1279
|
+
* @param source The source of the error.
|
|
1280
|
+
* @param property The name of the property.
|
|
1281
|
+
* @param value The value to test.
|
|
1282
|
+
* @param endValues The values that must end the array.
|
|
1283
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1284
|
+
*/
|
|
1285
|
+
static arrayEndsWith(source, property, value, endValues) {
|
|
1286
|
+
if (!Is.arrayValue(value)) {
|
|
1287
|
+
throw new GuardError(source, "guard.array", property, value);
|
|
1288
|
+
}
|
|
1289
|
+
const endValuesArray = ArrayHelper.fromObjectOrArray(endValues);
|
|
1290
|
+
if (!Is.arrayValue(endValuesArray)) {
|
|
1291
|
+
throw new GuardError(source, "guard.array", property, endValuesArray);
|
|
1292
|
+
}
|
|
1293
|
+
for (let i = 0; i < endValuesArray.length; i++) {
|
|
1294
|
+
if (value[value.length - i - 1] !== endValuesArray[endValuesArray.length - i - 1]) {
|
|
1295
|
+
throw new GuardError(source, "guard.arrayEndsWith", property, value, endValuesArray.join(", "));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Is the property a Uint8Array.
|
|
1301
|
+
* @param source The source of the error.
|
|
1302
|
+
* @param property The name of the property.
|
|
1303
|
+
* @param value The value to test.
|
|
1304
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1305
|
+
*/
|
|
1306
|
+
static uint8Array(source, property, value) {
|
|
1307
|
+
if (!Is.uint8Array(value)) {
|
|
1308
|
+
throw new GuardError(source, "guard.uint8Array", property, value);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Is the property a function.
|
|
1313
|
+
* @param source The source of the error.
|
|
1314
|
+
* @param property The name of the property.
|
|
1315
|
+
* @param value The value to test.
|
|
1316
|
+
* @returns True if the value is a function.
|
|
1317
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1318
|
+
*/
|
|
1319
|
+
static function(source, property, value) {
|
|
1320
|
+
if (!Is.function(value)) {
|
|
1321
|
+
throw new GuardError(source, "guard.function", property, value);
|
|
1322
|
+
}
|
|
1323
|
+
return true;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Is the property a string formatted as an email address.
|
|
1327
|
+
* @param source The source of the error.
|
|
1328
|
+
* @param property The name of the property.
|
|
1329
|
+
* @param value The value to test.
|
|
1330
|
+
* @throws GuardError If the value does not match the assertion.
|
|
1331
|
+
*/
|
|
1332
|
+
static email(source, property, value) {
|
|
1333
|
+
if (!Is.email(value)) {
|
|
1334
|
+
throw new GuardError(source, "guard.email", property, value);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1340
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1341
|
+
/* eslint-disable no-bitwise */
|
|
1342
|
+
/**
|
|
1343
|
+
* Class to help with base63 Encoding/Decoding.
|
|
1344
|
+
*/
|
|
1345
|
+
class Base32 {
|
|
1346
|
+
/**
|
|
1347
|
+
* Runtime name for the class.
|
|
1348
|
+
* @internal
|
|
1349
|
+
*/
|
|
1350
|
+
static _CLASS_NAME = "Base32";
|
|
1351
|
+
/**
|
|
1352
|
+
* Alphabet table for encoding.
|
|
1353
|
+
* @internal
|
|
1354
|
+
*/
|
|
1355
|
+
static _ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
1356
|
+
/**
|
|
1357
|
+
* Convert the base 32 string to a byte array.
|
|
1358
|
+
* @param base32 The base32 string to convert.
|
|
1359
|
+
* @returns The byte array.
|
|
1360
|
+
* @throws If the input string contains a character not in the Base32 alphabet.
|
|
1361
|
+
*/
|
|
1362
|
+
static decode(base32) {
|
|
1363
|
+
Guards.string(Base32._CLASS_NAME, "base32", base32);
|
|
1364
|
+
let bits = 0;
|
|
1365
|
+
let value = 0;
|
|
1366
|
+
base32 = base32.replace(/=+$/, "");
|
|
1367
|
+
let index = 0;
|
|
1368
|
+
const output = new Uint8Array(Math.trunc((base32.length * 5) / 8));
|
|
1369
|
+
for (let i = 0; i < base32.length; i++) {
|
|
1370
|
+
const idx = Base32._ALPHABET.indexOf(base32[i]);
|
|
1371
|
+
if (idx === -1) {
|
|
1372
|
+
throw new GeneralError(Base32._CLASS_NAME, "invalidCharacter", {
|
|
1373
|
+
invalidCharacter: base32[i]
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
value = (value << 5) | idx;
|
|
1377
|
+
bits += 5;
|
|
1378
|
+
if (bits >= 8) {
|
|
1379
|
+
output[index++] = (value >>> (bits - 8)) & 255;
|
|
1380
|
+
bits -= 8;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return output;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Convert a byte array to base 32.
|
|
1387
|
+
* @param bytes The byte array to convert.
|
|
1388
|
+
* @returns The data as base32 string.
|
|
1389
|
+
*/
|
|
1390
|
+
static encode(bytes) {
|
|
1391
|
+
Guards.uint8Array(Base32._CLASS_NAME, "bytes", bytes);
|
|
1392
|
+
let bits = 0;
|
|
1393
|
+
let value = 0;
|
|
1394
|
+
let output = "";
|
|
1395
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
1396
|
+
value = (value << 8) | bytes[i];
|
|
1397
|
+
bits += 8;
|
|
1398
|
+
while (bits >= 5) {
|
|
1399
|
+
output += Base32._ALPHABET[(value >>> (bits - 5)) & 31];
|
|
1400
|
+
bits -= 5;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (bits > 0) {
|
|
1404
|
+
output += Base32._ALPHABET[(value << (5 - bits)) & 31];
|
|
1405
|
+
}
|
|
1406
|
+
while (output.length % 8 !== 0) {
|
|
1407
|
+
output += "=";
|
|
1408
|
+
}
|
|
1409
|
+
return output;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Class to help with base58 Encoding/Decoding.
|
|
1415
|
+
*/
|
|
1416
|
+
class Base58 {
|
|
1417
|
+
/**
|
|
1418
|
+
* Runtime name for the class.
|
|
1419
|
+
* @internal
|
|
1420
|
+
*/
|
|
1421
|
+
static _CLASS_NAME = "Base58";
|
|
1422
|
+
/**
|
|
1423
|
+
* Alphabet table for encoding.
|
|
1424
|
+
* @internal
|
|
1425
|
+
*/
|
|
1426
|
+
static _ALPHABET =
|
|
1427
|
+
// cspell:disable-next-line
|
|
1428
|
+
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1429
|
+
/**
|
|
1430
|
+
* Reverse map for decoding.
|
|
1431
|
+
* @internal
|
|
1432
|
+
*/
|
|
1433
|
+
static _ALPHABET_REVERSE = [
|
|
1434
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1435
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1436
|
+
-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,
|
|
1437
|
+
17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, 33,
|
|
1438
|
+
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
1439
|
+
57, -1, -1, -1, -1, -1
|
|
1440
|
+
];
|
|
1441
|
+
/**
|
|
1442
|
+
* Convert the base 58 string to a byte array.
|
|
1443
|
+
* @param base58 The base58 string to convert.
|
|
1444
|
+
* @returns The byte array.
|
|
1445
|
+
* @throws If the input string contains a character not in the Base58 alphabet.
|
|
1446
|
+
*/
|
|
1447
|
+
static decode(base58) {
|
|
1448
|
+
Guards.string(Base58._CLASS_NAME, "base58", base58);
|
|
1449
|
+
let zeroes = 0;
|
|
1450
|
+
for (let i = 0; i < base58.length; i++) {
|
|
1451
|
+
if (base58[i] !== "1") {
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
zeroes += 1;
|
|
1455
|
+
}
|
|
1456
|
+
const size = Math.trunc((base58.length * 733) / 1000) + 1;
|
|
1457
|
+
const b256 = new Uint8Array(size).fill(0);
|
|
1458
|
+
let length = 0;
|
|
1459
|
+
for (let i = zeroes; i < base58.length; i++) {
|
|
1460
|
+
const ch = base58.charCodeAt(i);
|
|
1461
|
+
if (ch & 0xff80) {
|
|
1462
|
+
throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
|
|
1463
|
+
}
|
|
1464
|
+
const val = Base58._ALPHABET_REVERSE[ch];
|
|
1465
|
+
if (val === -1) {
|
|
1466
|
+
throw new GeneralError(Base58._CLASS_NAME, "invalidCharacter", { invalidCharacter: ch });
|
|
1467
|
+
}
|
|
1468
|
+
let carry = val;
|
|
1469
|
+
let j = 0;
|
|
1470
|
+
for (let k = size - 1; k >= 0; k--, j++) {
|
|
1471
|
+
if (carry === 0 && j >= length) {
|
|
1472
|
+
break;
|
|
1473
|
+
}
|
|
1474
|
+
carry += b256[k] * 58;
|
|
1475
|
+
b256[k] = carry;
|
|
1476
|
+
carry >>>= 8;
|
|
1477
|
+
}
|
|
1478
|
+
length = j;
|
|
1479
|
+
}
|
|
1480
|
+
const out = new Uint8Array(zeroes + length);
|
|
1481
|
+
let j;
|
|
1482
|
+
for (j = 0; j < zeroes; j++) {
|
|
1483
|
+
out[j] = 0;
|
|
1484
|
+
}
|
|
1485
|
+
let i = size - length;
|
|
1486
|
+
while (i < size) {
|
|
1487
|
+
out[j++] = b256[i++];
|
|
1488
|
+
}
|
|
1489
|
+
return out;
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Convert a byte array to base 58.
|
|
1493
|
+
* @param bytes The byte array to encode.
|
|
1494
|
+
* @returns The data as base58 string.
|
|
1495
|
+
*/
|
|
1496
|
+
static encode(bytes) {
|
|
1497
|
+
Guards.uint8Array(Base58._CLASS_NAME, "bytes", bytes);
|
|
1498
|
+
let zeroes = 0;
|
|
1499
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1500
|
+
if (bytes[i] !== 0) {
|
|
1501
|
+
break;
|
|
1502
|
+
}
|
|
1503
|
+
zeroes += 1;
|
|
1504
|
+
}
|
|
1505
|
+
const size = Math.trunc(((bytes.length - zeroes) * 138) / 100) + 1;
|
|
994
1506
|
const b58 = new Uint8Array(size).fill(0);
|
|
995
1507
|
let length = 0;
|
|
996
1508
|
for (let i = zeroes; i < bytes.length; i++) {
|
|
@@ -1127,6 +1639,7 @@ class Base64 {
|
|
|
1127
1639
|
* @returns The byte array.
|
|
1128
1640
|
*/
|
|
1129
1641
|
static decode(base64) {
|
|
1642
|
+
Guards.string(Base64._CLASS_NAME, "base64", base64);
|
|
1130
1643
|
let tmp;
|
|
1131
1644
|
const lens = Base64.getLengths(base64);
|
|
1132
1645
|
const validLen = lens[0];
|
|
@@ -1168,6 +1681,7 @@ class Base64 {
|
|
|
1168
1681
|
* @returns The data as base64 string.
|
|
1169
1682
|
*/
|
|
1170
1683
|
static encode(bytes) {
|
|
1684
|
+
Guards.uint8Array(Base64._CLASS_NAME, "bytes", bytes);
|
|
1171
1685
|
let tmp;
|
|
1172
1686
|
const len = bytes.length;
|
|
1173
1687
|
const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
|
|
@@ -1175,7 +1689,7 @@ class Base64 {
|
|
|
1175
1689
|
const maxChunkLength = 16383; // must be multiple of 3
|
|
1176
1690
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
|
1177
1691
|
for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
|
1178
|
-
parts.push(Base64.encodeChunk(bytes, i, i + maxChunkLength
|
|
1692
|
+
parts.push(Base64.encodeChunk(bytes, i, Math.min(i + maxChunkLength, len2)));
|
|
1179
1693
|
}
|
|
1180
1694
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
|
1181
1695
|
if (extraBytes === 1) {
|
|
@@ -1249,522 +1763,251 @@ class Base64 {
|
|
|
1249
1763
|
}
|
|
1250
1764
|
}
|
|
1251
1765
|
|
|
1252
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1253
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1254
1766
|
/**
|
|
1255
1767
|
* Class to help with base64 URL Encoding/Decoding.
|
|
1256
1768
|
* https://www.rfc-editor.org/rfc/rfc4648#section-5.
|
|
1257
1769
|
*/
|
|
1258
1770
|
class Base64Url {
|
|
1259
|
-
/**
|
|
1260
|
-
* Convert the base 64 string to a byte array.
|
|
1261
|
-
* @param base64Url The base64 url string to convert.
|
|
1262
|
-
* @returns The byte array.
|
|
1263
|
-
*/
|
|
1264
|
-
static decode(base64Url) {
|
|
1265
|
-
let base64 = base64Url;
|
|
1266
|
-
// Base 64 url can have padding removed, so add it back if it is missing.
|
|
1267
|
-
if (base64.length > 0 && !base64.endsWith("=")) {
|
|
1268
|
-
const placeHoldersLen = 4 - (base64.length % 4);
|
|
1269
|
-
if (placeHoldersLen > 0 && placeHoldersLen < 4) {
|
|
1270
|
-
base64 = base64.padEnd(base64.length + placeHoldersLen, "=");
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
base64 = base64.replace(/-/g, "+").replace(/_/g, "/");
|
|
1274
|
-
return Base64.decode(base64);
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
* Convert a byte array to base 64 url.
|
|
1278
|
-
* @param bytes The byte array to convert.
|
|
1279
|
-
* @returns The data as base64 url string.
|
|
1280
|
-
*/
|
|
1281
|
-
static encode(bytes) {
|
|
1282
|
-
const base64 = Base64.encode(bytes);
|
|
1283
|
-
// Base 64 url can have padding removed, so remove it.
|
|
1284
|
-
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
/**
|
|
1289
|
-
* Class to handle errors which are triggered by data already existing.
|
|
1290
|
-
*/
|
|
1291
|
-
class AlreadyExistsError extends BaseError {
|
|
1292
|
-
/**
|
|
1293
|
-
* Runtime name for the class.
|
|
1294
|
-
*/
|
|
1295
|
-
static CLASS_NAME = "AlreadyExistsError";
|
|
1296
|
-
/**
|
|
1297
|
-
* Create a new instance of AlreadyExistsError.
|
|
1298
|
-
* @param source The source of the error.
|
|
1299
|
-
* @param message The message as a code.
|
|
1300
|
-
* @param existingId The id for the item.
|
|
1301
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1302
|
-
*/
|
|
1303
|
-
constructor(source, message, existingId, inner) {
|
|
1304
|
-
super(AlreadyExistsError.CLASS_NAME, source, message, { existingId }, inner);
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
/**
|
|
1309
|
-
* Class to handle errors which are triggered by conflicting data.
|
|
1310
|
-
*/
|
|
1311
|
-
class ConflictError extends BaseError {
|
|
1312
|
-
/**
|
|
1313
|
-
* Runtime name for the class.
|
|
1314
|
-
*/
|
|
1315
|
-
static CLASS_NAME = "ConflictError";
|
|
1316
|
-
/**
|
|
1317
|
-
* Create a new instance of ConflictError.
|
|
1318
|
-
* @param source The source of the error.
|
|
1319
|
-
* @param message The message as a code.
|
|
1320
|
-
* @param conflictId The id that has conflicts.
|
|
1321
|
-
* @param conflicts The conflicts that occurred.
|
|
1322
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1323
|
-
*/
|
|
1324
|
-
constructor(source, message, conflictId, conflicts, inner) {
|
|
1325
|
-
super(ConflictError.CLASS_NAME, source, message, { conflictId, conflicts }, inner);
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* Class to handle errors which are triggered by data guards.
|
|
1331
|
-
*/
|
|
1332
|
-
class GuardError extends BaseError {
|
|
1333
|
-
/**
|
|
1334
|
-
* Runtime name for the class.
|
|
1335
|
-
*/
|
|
1336
|
-
static CLASS_NAME = "GuardError";
|
|
1337
|
-
/**
|
|
1338
|
-
* Create a new instance of GuardError.
|
|
1339
|
-
* @param source The source of the error.
|
|
1340
|
-
* @param message The message as a code.
|
|
1341
|
-
* @param propertyName The property which triggered the guard error for the item.
|
|
1342
|
-
* @param propertyValue The property value which triggered the guard error for the item.
|
|
1343
|
-
* @param propertyOptions The property options which might be allowed.
|
|
1344
|
-
*/
|
|
1345
|
-
constructor(source, message, propertyName, propertyValue, propertyOptions) {
|
|
1346
|
-
super(GuardError.CLASS_NAME, source, message, {
|
|
1347
|
-
property: propertyName ?? "property",
|
|
1348
|
-
value: Is.undefined(propertyValue) ? "undefined" : propertyValue,
|
|
1349
|
-
options: propertyOptions
|
|
1350
|
-
});
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
/**
|
|
1355
|
-
* Class to handle errors which are triggered by data not being found.
|
|
1356
|
-
*/
|
|
1357
|
-
class NotFoundError extends BaseError {
|
|
1358
|
-
/**
|
|
1359
|
-
* Runtime name for the class.
|
|
1360
|
-
*/
|
|
1361
|
-
static CLASS_NAME = "NotFoundError";
|
|
1362
|
-
/**
|
|
1363
|
-
* Create a new instance of NotFoundError.
|
|
1364
|
-
* @param source The source of the error.
|
|
1365
|
-
* @param message The message as a code.
|
|
1366
|
-
* @param notFoundId The id for the item.
|
|
1367
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1368
|
-
*/
|
|
1369
|
-
constructor(source, message, notFoundId, inner) {
|
|
1370
|
-
super(NotFoundError.CLASS_NAME, source, message, { notFoundId }, inner);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
/**
|
|
1375
|
-
* Class to handle errors.
|
|
1376
|
-
*/
|
|
1377
|
-
class NotImplementedError extends BaseError {
|
|
1378
|
-
/**
|
|
1379
|
-
* Runtime name for the class.
|
|
1380
|
-
*/
|
|
1381
|
-
static CLASS_NAME = "NotImplementedError";
|
|
1382
|
-
/**
|
|
1383
|
-
* Create a new instance of NotImplementedError.
|
|
1384
|
-
* @param source The source of the error.
|
|
1385
|
-
* @param method The method for the error.
|
|
1386
|
-
*/
|
|
1387
|
-
constructor(source, method) {
|
|
1388
|
-
super(NotImplementedError.CLASS_NAME, source, "common.notImplementedMethod", {
|
|
1389
|
-
method
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
/**
|
|
1395
|
-
* Class to handle errors when a feature is unsupported.
|
|
1396
|
-
*/
|
|
1397
|
-
class NotSupportedError extends BaseError {
|
|
1398
|
-
/**
|
|
1399
|
-
* Runtime name for the class.
|
|
1400
|
-
*/
|
|
1401
|
-
static CLASS_NAME = "NotSupportedError";
|
|
1402
|
-
/**
|
|
1403
|
-
* Create a new instance of NotSupportedError.
|
|
1404
|
-
* @param source The source of the error.
|
|
1405
|
-
* @param message The message as a code.
|
|
1406
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1407
|
-
*/
|
|
1408
|
-
constructor(source, message, inner) {
|
|
1409
|
-
super(NotSupportedError.CLASS_NAME, source, message, undefined, inner);
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
/**
|
|
1414
|
-
* Class to handle errors which are triggered by access not being unauthorized.
|
|
1415
|
-
*/
|
|
1416
|
-
class UnauthorizedError extends BaseError {
|
|
1417
|
-
/**
|
|
1418
|
-
* Runtime name for the class.
|
|
1419
|
-
*/
|
|
1420
|
-
static CLASS_NAME = "UnauthorizedError";
|
|
1421
|
-
/**
|
|
1422
|
-
* Create a new instance of UnauthorizedError.
|
|
1423
|
-
* @param source The source of the error.
|
|
1424
|
-
* @param message The message as a code.
|
|
1425
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1426
|
-
*/
|
|
1427
|
-
constructor(source, message, inner) {
|
|
1428
|
-
super(UnauthorizedError.CLASS_NAME, source, message, undefined, inner);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
/**
|
|
1433
|
-
* Class to handle errors when some data can not be processed.
|
|
1434
|
-
*/
|
|
1435
|
-
class UnprocessableError extends BaseError {
|
|
1436
1771
|
/**
|
|
1437
1772
|
* Runtime name for the class.
|
|
1773
|
+
* @internal
|
|
1438
1774
|
*/
|
|
1439
|
-
static
|
|
1440
|
-
/**
|
|
1441
|
-
* Create a new instance of UnprocessableError.
|
|
1442
|
-
* @param source The source of the error.
|
|
1443
|
-
* @param message The message as a code.
|
|
1444
|
-
* @param properties Any additional information for the error.
|
|
1445
|
-
* @param inner The inner error if we have wrapped another error.
|
|
1446
|
-
*/
|
|
1447
|
-
constructor(source, message, properties, inner) {
|
|
1448
|
-
super(UnprocessableError.CLASS_NAME, source, message, properties, inner);
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
/**
|
|
1453
|
-
* Class to handle errors which are triggered by entity validation.
|
|
1454
|
-
*/
|
|
1455
|
-
class ValidationError extends BaseError {
|
|
1456
|
-
/**
|
|
1457
|
-
* Runtime name for the class.s
|
|
1458
|
-
*/
|
|
1459
|
-
static CLASS_NAME = "ValidationError";
|
|
1460
|
-
/**
|
|
1461
|
-
* Create a new instance of ValidationError.
|
|
1462
|
-
* @param source The source of the error.
|
|
1463
|
-
* @param validationObject The object that failed validation.
|
|
1464
|
-
* @param validationFailures The validation failures.
|
|
1465
|
-
*/
|
|
1466
|
-
constructor(source, validationObject, validationFailures) {
|
|
1467
|
-
super(ValidationError.CLASS_NAME, source, "common.validation", {
|
|
1468
|
-
validationObject,
|
|
1469
|
-
validationFailures
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1475
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1476
|
-
/**
|
|
1477
|
-
* Class to handle guard operations for parameters.
|
|
1478
|
-
*/
|
|
1479
|
-
class Guards {
|
|
1480
|
-
/**
|
|
1481
|
-
* Is the property defined.
|
|
1482
|
-
* @param source The source of the error.
|
|
1483
|
-
* @param property The name of the property.
|
|
1484
|
-
* @param value The value to test.
|
|
1485
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1486
|
-
*/
|
|
1487
|
-
static defined(source, property, value) {
|
|
1488
|
-
if (Is.undefined(value)) {
|
|
1489
|
-
throw new GuardError(source, "guard.undefined", property, value);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
/**
|
|
1493
|
-
* Is the property a string.
|
|
1494
|
-
* @param source The source of the error.
|
|
1495
|
-
* @param property The name of the property.
|
|
1496
|
-
* @param value The value to test.
|
|
1497
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1498
|
-
*/
|
|
1499
|
-
static string(source, property, value) {
|
|
1500
|
-
if (!Is.string(value)) {
|
|
1501
|
-
throw new GuardError(source, "guard.string", property, value);
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
/**
|
|
1505
|
-
* Is the property a string with a value.
|
|
1506
|
-
* @param source The source of the error.
|
|
1507
|
-
* @param property The name of the property.
|
|
1508
|
-
* @param value The value to test.
|
|
1509
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1510
|
-
*/
|
|
1511
|
-
static stringValue(source, property, value) {
|
|
1512
|
-
if (!Is.string(value)) {
|
|
1513
|
-
throw new GuardError(source, "guard.string", property, value);
|
|
1514
|
-
}
|
|
1515
|
-
if (value.length === 0) {
|
|
1516
|
-
throw new GuardError(source, "guard.stringEmpty", property, value);
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1775
|
+
static _CLASS_NAME = "Base64";
|
|
1519
1776
|
/**
|
|
1520
|
-
*
|
|
1521
|
-
* @param
|
|
1522
|
-
* @
|
|
1523
|
-
* @param value The value to test.
|
|
1524
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1777
|
+
* Convert the base 64 string to a byte array.
|
|
1778
|
+
* @param base64Url The base64 url string to convert.
|
|
1779
|
+
* @returns The byte array.
|
|
1525
1780
|
*/
|
|
1526
|
-
static
|
|
1527
|
-
|
|
1528
|
-
|
|
1781
|
+
static decode(base64Url) {
|
|
1782
|
+
Guards.string(Base64Url._CLASS_NAME, "base64Url", base64Url);
|
|
1783
|
+
let base64 = base64Url;
|
|
1784
|
+
// Base 64 url can have padding removed, so add it back if it is missing.
|
|
1785
|
+
if (base64.length > 0 && !base64.endsWith("=")) {
|
|
1786
|
+
const placeHoldersLen = 4 - (base64.length % 4);
|
|
1787
|
+
if (placeHoldersLen > 0 && placeHoldersLen < 4) {
|
|
1788
|
+
base64 = base64.padEnd(base64.length + placeHoldersLen, "=");
|
|
1789
|
+
}
|
|
1529
1790
|
}
|
|
1791
|
+
base64 = base64.replace(/-/g, "+").replace(/_/g, "/");
|
|
1792
|
+
return Base64.decode(base64);
|
|
1530
1793
|
}
|
|
1531
1794
|
/**
|
|
1532
|
-
*
|
|
1533
|
-
* @param
|
|
1534
|
-
* @
|
|
1535
|
-
* @param value The value to test.
|
|
1536
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1795
|
+
* Convert a byte array to base 64 url.
|
|
1796
|
+
* @param bytes The byte array to convert.
|
|
1797
|
+
* @returns The data as base64 url string.
|
|
1537
1798
|
*/
|
|
1538
|
-
static
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1799
|
+
static encode(bytes) {
|
|
1800
|
+
Guards.uint8Array(Base64Url._CLASS_NAME, "bytes", bytes);
|
|
1801
|
+
const base64 = Base64.encode(bytes);
|
|
1802
|
+
// Base 64 url can have padding removed, so remove it.
|
|
1803
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1542
1804
|
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
/**
|
|
1808
|
+
* Class to handle errors which are triggered by data already existing.
|
|
1809
|
+
*/
|
|
1810
|
+
class AlreadyExistsError extends BaseError {
|
|
1543
1811
|
/**
|
|
1544
|
-
*
|
|
1545
|
-
* @param source The source of the error.
|
|
1546
|
-
* @param property The name of the property.
|
|
1547
|
-
* @param value The value to test.
|
|
1548
|
-
* @param allowPrefix Allow the hex to have the 0x prefix.
|
|
1549
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1812
|
+
* Runtime name for the class.
|
|
1550
1813
|
*/
|
|
1551
|
-
static
|
|
1552
|
-
Guards.stringValue(source, property, value);
|
|
1553
|
-
if (!HexHelper.isHex(value, allowPrefix)) {
|
|
1554
|
-
throw new GuardError(source, "guard.stringHex", property, value);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1814
|
+
static CLASS_NAME = "AlreadyExistsError";
|
|
1557
1815
|
/**
|
|
1558
|
-
*
|
|
1816
|
+
* Create a new instance of AlreadyExistsError.
|
|
1559
1817
|
* @param source The source of the error.
|
|
1560
|
-
* @param
|
|
1561
|
-
* @param
|
|
1562
|
-
* @param
|
|
1563
|
-
* @param allowPrefix Allow the hex to have the 0x prefix.
|
|
1564
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1818
|
+
* @param message The message as a code.
|
|
1819
|
+
* @param existingId The id for the item.
|
|
1820
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
1565
1821
|
*/
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
if (HexHelper.stripPrefix(value).length !== length) {
|
|
1569
|
-
throw new GuardError(source, "guard.stringHexLength", property, value.length, length.toString());
|
|
1570
|
-
}
|
|
1822
|
+
constructor(source, message, existingId, cause) {
|
|
1823
|
+
super(AlreadyExistsError.CLASS_NAME, source, message, { existingId });
|
|
1571
1824
|
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Class to handle errors which are triggered by conflicting data.
|
|
1829
|
+
*/
|
|
1830
|
+
class ConflictError extends BaseError {
|
|
1572
1831
|
/**
|
|
1573
|
-
*
|
|
1574
|
-
* @param source The source of the error.
|
|
1575
|
-
* @param property The name of the property.
|
|
1576
|
-
* @param value The value to test.
|
|
1577
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1832
|
+
* Runtime name for the class.
|
|
1578
1833
|
*/
|
|
1579
|
-
static
|
|
1580
|
-
if (!Is.number(value)) {
|
|
1581
|
-
throw new GuardError(source, "guard.number", property, value);
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1834
|
+
static CLASS_NAME = "ConflictError";
|
|
1584
1835
|
/**
|
|
1585
|
-
*
|
|
1836
|
+
* Create a new instance of ConflictError.
|
|
1586
1837
|
* @param source The source of the error.
|
|
1587
|
-
* @param
|
|
1588
|
-
* @param
|
|
1589
|
-
* @
|
|
1838
|
+
* @param message The message as a code.
|
|
1839
|
+
* @param conflictId The id that has conflicts.
|
|
1840
|
+
* @param conflicts The conflicts that occurred.
|
|
1841
|
+
* @param cause The cause or the error if we have wrapped another error.
|
|
1590
1842
|
*/
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
throw new GuardError(source, "guard.integer", property, value);
|
|
1594
|
-
}
|
|
1843
|
+
constructor(source, message, conflictId, conflicts, cause) {
|
|
1844
|
+
super(ConflictError.CLASS_NAME, source, message, { conflictId, conflicts }, cause);
|
|
1595
1845
|
}
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* Class to handle errors which are triggered by data not being found.
|
|
1850
|
+
*/
|
|
1851
|
+
class NotFoundError extends BaseError {
|
|
1596
1852
|
/**
|
|
1597
|
-
*
|
|
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.
|
|
1853
|
+
* Runtime name for the class.
|
|
1602
1854
|
*/
|
|
1603
|
-
static
|
|
1604
|
-
if (!Is.bigint(value)) {
|
|
1605
|
-
throw new GuardError(source, "guard.bigint", property, value);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1855
|
+
static CLASS_NAME = "NotFoundError";
|
|
1608
1856
|
/**
|
|
1609
|
-
*
|
|
1857
|
+
* Create a new instance of NotFoundError.
|
|
1610
1858
|
* @param source The source of the error.
|
|
1611
|
-
* @param
|
|
1612
|
-
* @param
|
|
1613
|
-
* @
|
|
1859
|
+
* @param message The message as a code.
|
|
1860
|
+
* @param notFoundId The id for the item.
|
|
1861
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
1614
1862
|
*/
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
throw new GuardError(source, "guard.boolean", property, value);
|
|
1618
|
-
}
|
|
1863
|
+
constructor(source, message, notFoundId, cause) {
|
|
1864
|
+
super(NotFoundError.CLASS_NAME, source, message, { notFoundId }, cause);
|
|
1619
1865
|
}
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* Class to handle errors.
|
|
1870
|
+
*/
|
|
1871
|
+
class NotImplementedError extends BaseError {
|
|
1620
1872
|
/**
|
|
1621
|
-
*
|
|
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.
|
|
1873
|
+
* Runtime name for the class.
|
|
1626
1874
|
*/
|
|
1627
|
-
static
|
|
1628
|
-
if (!Is.date(value)) {
|
|
1629
|
-
throw new GuardError(source, "guard.date", property, value);
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1875
|
+
static CLASS_NAME = "NotImplementedError";
|
|
1632
1876
|
/**
|
|
1633
|
-
*
|
|
1877
|
+
* Create a new instance of NotImplementedError.
|
|
1634
1878
|
* @param source The source of the error.
|
|
1635
|
-
* @param
|
|
1636
|
-
* @param value The value to test.
|
|
1637
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1879
|
+
* @param method The method for the error.
|
|
1638
1880
|
*/
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
}
|
|
1881
|
+
constructor(source, method) {
|
|
1882
|
+
super(NotImplementedError.CLASS_NAME, source, "common.notImplementedMethod", {
|
|
1883
|
+
method
|
|
1884
|
+
});
|
|
1643
1885
|
}
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
/**
|
|
1889
|
+
* Class to handle errors when a feature is unsupported.
|
|
1890
|
+
*/
|
|
1891
|
+
class NotSupportedError extends BaseError {
|
|
1644
1892
|
/**
|
|
1645
|
-
*
|
|
1646
|
-
* @param source The source of the error.
|
|
1647
|
-
* @param property The name of the property.
|
|
1648
|
-
* @param value The value to test.
|
|
1649
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1893
|
+
* Runtime name for the class.
|
|
1650
1894
|
*/
|
|
1651
|
-
static
|
|
1652
|
-
if (!Is.timestampSeconds(value)) {
|
|
1653
|
-
throw new GuardError(source, "guard.timestampSeconds", property, value);
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1895
|
+
static CLASS_NAME = "NotSupportedError";
|
|
1656
1896
|
/**
|
|
1657
|
-
*
|
|
1897
|
+
* Create a new instance of NotSupportedError.
|
|
1658
1898
|
* @param source The source of the error.
|
|
1659
|
-
* @param
|
|
1660
|
-
* @param
|
|
1661
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1899
|
+
* @param message The message as a code.
|
|
1900
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
1662
1901
|
*/
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
throw new GuardError(source, "guard.objectUndefined", property, value);
|
|
1666
|
-
}
|
|
1667
|
-
if (!Is.object(value)) {
|
|
1668
|
-
throw new GuardError(source, "guard.object", property, value);
|
|
1669
|
-
}
|
|
1902
|
+
constructor(source, message, cause) {
|
|
1903
|
+
super(NotSupportedError.CLASS_NAME, source, message, undefined, cause);
|
|
1670
1904
|
}
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
/**
|
|
1908
|
+
* Class to handle errors which are triggered by access not being unauthorized.
|
|
1909
|
+
*/
|
|
1910
|
+
class UnauthorizedError extends BaseError {
|
|
1671
1911
|
/**
|
|
1672
|
-
*
|
|
1673
|
-
* @param source The source of the error.
|
|
1674
|
-
* @param property The name of the property.
|
|
1675
|
-
* @param value The value to test.
|
|
1676
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1912
|
+
* Runtime name for the class.
|
|
1677
1913
|
*/
|
|
1678
|
-
static
|
|
1679
|
-
if (Is.undefined(value)) {
|
|
1680
|
-
throw new GuardError(source, "guard.objectUndefined", property, value);
|
|
1681
|
-
}
|
|
1682
|
-
if (!Is.object(value)) {
|
|
1683
|
-
throw new GuardError(source, "guard.object", property, value);
|
|
1684
|
-
}
|
|
1685
|
-
if (Object.keys(value || {}).length === 0) {
|
|
1686
|
-
throw new GuardError(source, "guard.objectValue", property, value);
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1914
|
+
static CLASS_NAME = "UnauthorizedError";
|
|
1689
1915
|
/**
|
|
1690
|
-
*
|
|
1916
|
+
* Create a new instance of UnauthorizedError.
|
|
1691
1917
|
* @param source The source of the error.
|
|
1692
|
-
* @param
|
|
1693
|
-
* @param
|
|
1694
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1918
|
+
* @param message The message as a code.
|
|
1919
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
1695
1920
|
*/
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
throw new GuardError(source, "guard.array", property, value);
|
|
1699
|
-
}
|
|
1921
|
+
constructor(source, message, cause) {
|
|
1922
|
+
super(UnauthorizedError.CLASS_NAME, source, message, undefined, cause);
|
|
1700
1923
|
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* Class to handle errors when some data can not be processed.
|
|
1928
|
+
*/
|
|
1929
|
+
class UnprocessableError extends BaseError {
|
|
1701
1930
|
/**
|
|
1702
|
-
*
|
|
1931
|
+
* Runtime name for the class.
|
|
1932
|
+
*/
|
|
1933
|
+
static CLASS_NAME = "UnprocessableError";
|
|
1934
|
+
/**
|
|
1935
|
+
* Create a new instance of UnprocessableError.
|
|
1703
1936
|
* @param source The source of the error.
|
|
1704
|
-
* @param
|
|
1705
|
-
* @param
|
|
1706
|
-
* @
|
|
1937
|
+
* @param message The message as a code.
|
|
1938
|
+
* @param properties Any additional information for the error.
|
|
1939
|
+
* @param cause The cause of the error if we have wrapped another error.
|
|
1707
1940
|
*/
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
throw new GuardError(source, "guard.array", property, value);
|
|
1711
|
-
}
|
|
1712
|
-
if (value.length === 0) {
|
|
1713
|
-
throw new GuardError(source, "guard.arrayValue", property, value);
|
|
1714
|
-
}
|
|
1941
|
+
constructor(source, message, properties, cause) {
|
|
1942
|
+
super(UnprocessableError.CLASS_NAME, source, message, properties, cause);
|
|
1715
1943
|
}
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
/**
|
|
1947
|
+
* Class to handle errors which are triggered by entity validation.
|
|
1948
|
+
*/
|
|
1949
|
+
class ValidationError extends BaseError {
|
|
1716
1950
|
/**
|
|
1717
|
-
*
|
|
1951
|
+
* Runtime name for the class.s
|
|
1952
|
+
*/
|
|
1953
|
+
static CLASS_NAME = "ValidationError";
|
|
1954
|
+
/**
|
|
1955
|
+
* Create a new instance of ValidationError.
|
|
1718
1956
|
* @param source The source of the error.
|
|
1719
|
-
* @param
|
|
1720
|
-
* @param
|
|
1721
|
-
* @param options The options the value must be one of.
|
|
1722
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1957
|
+
* @param validationObject The object that failed validation.
|
|
1958
|
+
* @param validationFailures The validation failures.
|
|
1723
1959
|
*/
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
throw new GuardError(source, "guard.arrayOneOf", property, value, options.join(", "));
|
|
1730
|
-
}
|
|
1960
|
+
constructor(source, validationObject, validationFailures) {
|
|
1961
|
+
super(ValidationError.CLASS_NAME, source, "common.validation", {
|
|
1962
|
+
validationObject,
|
|
1963
|
+
validationFailures
|
|
1964
|
+
});
|
|
1731
1965
|
}
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1969
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1970
|
+
/**
|
|
1971
|
+
* Provide a store for shared objects which can be accesses through multiple
|
|
1972
|
+
* instance loads of a packages.
|
|
1973
|
+
*/
|
|
1974
|
+
class SharedStore {
|
|
1732
1975
|
/**
|
|
1733
|
-
*
|
|
1734
|
-
* @param
|
|
1735
|
-
* @
|
|
1736
|
-
* @param value The value to test.
|
|
1737
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1976
|
+
* Get a property from the shared store.
|
|
1977
|
+
* @param prop The name of the property to get.
|
|
1978
|
+
* @returns The property if it exists.
|
|
1738
1979
|
*/
|
|
1739
|
-
static
|
|
1740
|
-
|
|
1741
|
-
|
|
1980
|
+
static get(prop) {
|
|
1981
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1982
|
+
const shared = globalThis.__TWIN_SHARED__;
|
|
1983
|
+
if (Is.undefined(shared)) {
|
|
1984
|
+
return;
|
|
1742
1985
|
}
|
|
1986
|
+
return shared[prop];
|
|
1743
1987
|
}
|
|
1744
1988
|
/**
|
|
1745
|
-
*
|
|
1746
|
-
* @param
|
|
1747
|
-
* @param
|
|
1748
|
-
* @param value The value to test.
|
|
1749
|
-
* @returns True if the value is a function.
|
|
1750
|
-
* @throws GuardError If the value does not match the assertion.
|
|
1989
|
+
* Set the property in the shared store.
|
|
1990
|
+
* @param prop The name of the property to set.
|
|
1991
|
+
* @param value The value to set.
|
|
1751
1992
|
*/
|
|
1752
|
-
static
|
|
1753
|
-
|
|
1754
|
-
|
|
1993
|
+
static set(prop, value) {
|
|
1994
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1995
|
+
if (Is.undefined(globalThis.__TWIN_SHARED__)) {
|
|
1996
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1997
|
+
globalThis.__TWIN_SHARED__ = {};
|
|
1755
1998
|
}
|
|
1756
|
-
|
|
1999
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2000
|
+
globalThis.__TWIN_SHARED__[prop] = value;
|
|
1757
2001
|
}
|
|
1758
2002
|
/**
|
|
1759
|
-
*
|
|
1760
|
-
* @param
|
|
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.
|
|
2003
|
+
* Remove a property from the shared store.
|
|
2004
|
+
* @param prop The name of the property to remove.
|
|
1764
2005
|
*/
|
|
1765
|
-
static
|
|
1766
|
-
|
|
1767
|
-
|
|
2006
|
+
static remove(prop) {
|
|
2007
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2008
|
+
const shared = globalThis.__TWIN_SHARED__;
|
|
2009
|
+
if (!Is.undefined(shared)) {
|
|
2010
|
+
delete shared[prop];
|
|
1768
2011
|
}
|
|
1769
2012
|
}
|
|
1770
2013
|
}
|
|
@@ -1778,11 +2021,6 @@ class Factory {
|
|
|
1778
2021
|
* @internal
|
|
1779
2022
|
*/
|
|
1780
2023
|
static _CLASS_NAME = "Factory";
|
|
1781
|
-
/**
|
|
1782
|
-
* Store all the created factories.
|
|
1783
|
-
* @internal
|
|
1784
|
-
*/
|
|
1785
|
-
static _factories = {};
|
|
1786
2024
|
/**
|
|
1787
2025
|
* Type name for the instances.
|
|
1788
2026
|
* @internal
|
|
@@ -1836,10 +2074,41 @@ class Factory {
|
|
|
1836
2074
|
* @returns The factory instance.
|
|
1837
2075
|
*/
|
|
1838
2076
|
static createFactory(typeName, autoInstance = false, matcher) {
|
|
1839
|
-
|
|
1840
|
-
|
|
2077
|
+
const factories = Factory.getFactories();
|
|
2078
|
+
if (Is.undefined(factories[typeName])) {
|
|
2079
|
+
factories[typeName] = new Factory(typeName, autoInstance, matcher);
|
|
2080
|
+
}
|
|
2081
|
+
return factories[typeName];
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Get all the factories.
|
|
2085
|
+
* @returns All the factories.
|
|
2086
|
+
*/
|
|
2087
|
+
static getFactories() {
|
|
2088
|
+
let factories = SharedStore.get("factories");
|
|
2089
|
+
if (Is.undefined(factories)) {
|
|
2090
|
+
factories = {};
|
|
2091
|
+
SharedStore.set("factories", factories);
|
|
2092
|
+
}
|
|
2093
|
+
return factories;
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Reset all the factories, which removes any created instances, but not the registrations.
|
|
2097
|
+
*/
|
|
2098
|
+
static resetFactories() {
|
|
2099
|
+
const factories = Factory.getFactories();
|
|
2100
|
+
for (const typeName in factories) {
|
|
2101
|
+
factories[typeName].reset();
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Clear all the factories, which removes anything registered with the factories.
|
|
2106
|
+
*/
|
|
2107
|
+
static clearFactories() {
|
|
2108
|
+
const factories = Factory.getFactories();
|
|
2109
|
+
for (const typeName in factories) {
|
|
2110
|
+
factories[typeName].clear();
|
|
1841
2111
|
}
|
|
1842
|
-
return Factory._factories[typeName];
|
|
1843
2112
|
}
|
|
1844
2113
|
/**
|
|
1845
2114
|
* Register a new generator.
|
|
@@ -1885,6 +2154,7 @@ class Factory {
|
|
|
1885
2154
|
* @throws GeneralError if no item exists to get.
|
|
1886
2155
|
*/
|
|
1887
2156
|
get(name) {
|
|
2157
|
+
Guards.stringValue(Factory._CLASS_NAME, "name", name);
|
|
1888
2158
|
const instance = this.getIfExists(name);
|
|
1889
2159
|
if (!instance) {
|
|
1890
2160
|
throw new GeneralError(Factory._CLASS_NAME, "noGet", {
|
|
@@ -1900,6 +2170,9 @@ class Factory {
|
|
|
1900
2170
|
* @returns An instance of the item or undefined if it does not exist.
|
|
1901
2171
|
*/
|
|
1902
2172
|
getIfExists(name) {
|
|
2173
|
+
if (Is.empty(name)) {
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
1903
2176
|
Guards.stringValue(Factory._CLASS_NAME, "name", name);
|
|
1904
2177
|
const matchName = this._matcher(Object.keys(this._generators), name);
|
|
1905
2178
|
if (Is.stringValue(matchName) && this._generators[matchName]) {
|
|
@@ -1912,7 +2185,7 @@ class Factory {
|
|
|
1912
2185
|
}
|
|
1913
2186
|
}
|
|
1914
2187
|
/**
|
|
1915
|
-
*
|
|
2188
|
+
* Remove all the instances and leave the generators intact.
|
|
1916
2189
|
*/
|
|
1917
2190
|
reset() {
|
|
1918
2191
|
for (const name in this._generators) {
|
|
@@ -1920,6 +2193,14 @@ class Factory {
|
|
|
1920
2193
|
}
|
|
1921
2194
|
this._instances = {};
|
|
1922
2195
|
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Remove all the instances and the generators.
|
|
2198
|
+
*/
|
|
2199
|
+
clear() {
|
|
2200
|
+
this._instances = {};
|
|
2201
|
+
this._generators = {};
|
|
2202
|
+
this._orderCounter = 0;
|
|
2203
|
+
}
|
|
1923
2204
|
/**
|
|
1924
2205
|
* Get all the instances as a map.
|
|
1925
2206
|
* @returns The instances as a map.
|
|
@@ -1953,1060 +2234,1402 @@ class Factory {
|
|
|
1953
2234
|
order: this._generators[generator].order
|
|
1954
2235
|
});
|
|
1955
2236
|
}
|
|
1956
|
-
return orderedNames.sort((a, b) => a.order - b.order).map(o => o.name);
|
|
2237
|
+
return orderedNames.sort((a, b) => a.order - b.order).map(o => o.name);
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Does the factory contain the name.
|
|
2241
|
+
* @param name The name of the instance to find.
|
|
2242
|
+
* @returns True if the factory has a matching name.
|
|
2243
|
+
*/
|
|
2244
|
+
hasName(name) {
|
|
2245
|
+
Guards.stringValue(Factory._CLASS_NAME, "name", name);
|
|
2246
|
+
return Is.stringValue(this._matcher(Object.keys(this._generators), name));
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Remove any instances of the given name.
|
|
2250
|
+
* @param name The name of the instances to remove.
|
|
2251
|
+
* @internal
|
|
2252
|
+
*/
|
|
2253
|
+
removeInstance(name) {
|
|
2254
|
+
delete this._instances[name];
|
|
2255
|
+
}
|
|
2256
|
+
/**
|
|
2257
|
+
* Match the requested name to the generator name.
|
|
2258
|
+
* @param names The list of names for all the generators.
|
|
2259
|
+
* @param name The name to match.
|
|
2260
|
+
* @returns The matched name or undefined if no match.
|
|
2261
|
+
* @internal
|
|
2262
|
+
*/
|
|
2263
|
+
defaultMatcher(names, name) {
|
|
2264
|
+
return this._generators[name] ? name : undefined;
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2269
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
2270
|
+
/**
|
|
2271
|
+
* Factory for creating implementation of component types.
|
|
2272
|
+
*/
|
|
2273
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
2274
|
+
const ComponentFactory = Factory.createFactory("component");
|
|
2275
|
+
|
|
2276
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2277
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
2278
|
+
/* eslint-disable no-bitwise */
|
|
2279
|
+
/**
|
|
2280
|
+
* Convert arrays to and from different formats.
|
|
2281
|
+
*/
|
|
2282
|
+
class Converter {
|
|
2283
|
+
/**
|
|
2284
|
+
* Lookup table for encoding.
|
|
2285
|
+
* @internal
|
|
2286
|
+
*/
|
|
2287
|
+
static _ENCODE_LOOKUP;
|
|
2288
|
+
/**
|
|
2289
|
+
* Lookup table for decoding.
|
|
2290
|
+
* @internal
|
|
2291
|
+
*/
|
|
2292
|
+
static _DECODE_LOOKUP;
|
|
2293
|
+
/**
|
|
2294
|
+
* Encode a raw array to UTF8 string.
|
|
2295
|
+
* @param array The bytes to encode.
|
|
2296
|
+
* @param startIndex The index to start in the bytes.
|
|
2297
|
+
* @param length The length of bytes to read.
|
|
2298
|
+
* @returns The array formatted as UTF8.
|
|
2299
|
+
*/
|
|
2300
|
+
static bytesToUtf8(array, startIndex, length) {
|
|
2301
|
+
const start = startIndex ?? 0;
|
|
2302
|
+
const len = length ?? array.length;
|
|
2303
|
+
let str = "";
|
|
2304
|
+
for (let i = start; i < start + len; i++) {
|
|
2305
|
+
const value = array[i];
|
|
2306
|
+
if (value < 0x80) {
|
|
2307
|
+
str += String.fromCharCode(value);
|
|
2308
|
+
}
|
|
2309
|
+
else if (value > 0xbf && value < 0xe0) {
|
|
2310
|
+
str += String.fromCharCode(((value & 0x1f) << 6) | (array[i + 1] & 0x3f));
|
|
2311
|
+
i += 1;
|
|
2312
|
+
}
|
|
2313
|
+
else if (value > 0xdf && value < 0xf0) {
|
|
2314
|
+
str += String.fromCharCode(((value & 0x0f) << 12) | ((array[i + 1] & 0x3f) << 6) | (array[i + 2] & 0x3f));
|
|
2315
|
+
i += 2;
|
|
2316
|
+
}
|
|
2317
|
+
else {
|
|
2318
|
+
// surrogate pair
|
|
2319
|
+
const charCode = (((value & 0x07) << 18) |
|
|
2320
|
+
((array[i + 1] & 0x3f) << 12) |
|
|
2321
|
+
((array[i + 2] & 0x3f) << 6) |
|
|
2322
|
+
(array[i + 3] & 0x3f)) -
|
|
2323
|
+
0x010000;
|
|
2324
|
+
str += String.fromCharCode((charCode >> 10) | 0xd800, (charCode & 0x03ff) | 0xdc00);
|
|
2325
|
+
i += 3;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
return str;
|
|
2329
|
+
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Convert a UTF8 string to raw array.
|
|
2332
|
+
* @param utf8 The text to decode.
|
|
2333
|
+
* @returns The array.
|
|
2334
|
+
*/
|
|
2335
|
+
static utf8ToBytes(utf8) {
|
|
2336
|
+
const bytes = [];
|
|
2337
|
+
for (let i = 0; i < utf8.length; i++) {
|
|
2338
|
+
let charCode = utf8.charCodeAt(i);
|
|
2339
|
+
if (charCode < 0x80) {
|
|
2340
|
+
bytes.push(charCode);
|
|
2341
|
+
}
|
|
2342
|
+
else if (charCode < 0x800) {
|
|
2343
|
+
bytes.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
|
|
2344
|
+
}
|
|
2345
|
+
else if (charCode < 0xd800 || charCode >= 0xe000) {
|
|
2346
|
+
bytes.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
|
|
2347
|
+
}
|
|
2348
|
+
else {
|
|
2349
|
+
// surrogate pair
|
|
2350
|
+
i++;
|
|
2351
|
+
// UTF-16 encodes 0x10000-0x10FFFF by
|
|
2352
|
+
// subtracting 0x10000 and splitting the
|
|
2353
|
+
// 20 bits of 0x0-0xFFFFF into two halves
|
|
2354
|
+
charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (utf8.charCodeAt(i) & 0x3ff));
|
|
2355
|
+
bytes.push(0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
return Uint8Array.from(bytes);
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Encode a raw array to hex string.
|
|
2362
|
+
* @param array The bytes to encode.
|
|
2363
|
+
* @param includePrefix Include the 0x prefix on the returned hex.
|
|
2364
|
+
* @param startIndex The index to start in the bytes.
|
|
2365
|
+
* @param length The length of bytes to read.
|
|
2366
|
+
* @param reverse Reverse the combine direction.
|
|
2367
|
+
* @returns The array formatted as hex.
|
|
2368
|
+
*/
|
|
2369
|
+
static bytesToHex(array, includePrefix = false, startIndex, length, reverse) {
|
|
2370
|
+
let hex = "";
|
|
2371
|
+
this.buildHexLookups();
|
|
2372
|
+
if (Converter._ENCODE_LOOKUP) {
|
|
2373
|
+
const len = length ?? array.length;
|
|
2374
|
+
const start = startIndex ?? 0;
|
|
2375
|
+
if (reverse) {
|
|
2376
|
+
for (let i = 0; i < len; i++) {
|
|
2377
|
+
hex = Converter._ENCODE_LOOKUP[array[start + i]] + hex;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
else {
|
|
2381
|
+
for (let i = 0; i < len; i++) {
|
|
2382
|
+
hex += Converter._ENCODE_LOOKUP[array[start + i]];
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
return includePrefix ? HexHelper.addPrefix(hex) : hex;
|
|
2387
|
+
}
|
|
2388
|
+
/**
|
|
2389
|
+
* Decode a hex string to raw array.
|
|
2390
|
+
* @param hex The hex to decode.
|
|
2391
|
+
* @param reverse Store the characters in reverse.
|
|
2392
|
+
* @returns The array.
|
|
2393
|
+
*/
|
|
2394
|
+
static hexToBytes(hex, reverse) {
|
|
2395
|
+
const strippedHex = HexHelper.stripPrefix(hex);
|
|
2396
|
+
const sizeof = strippedHex.length >> 1;
|
|
2397
|
+
const length = sizeof << 1;
|
|
2398
|
+
const array = new Uint8Array(sizeof);
|
|
2399
|
+
this.buildHexLookups();
|
|
2400
|
+
if (Converter._DECODE_LOOKUP) {
|
|
2401
|
+
let i = 0;
|
|
2402
|
+
let n = 0;
|
|
2403
|
+
while (i < length) {
|
|
2404
|
+
array[n++] =
|
|
2405
|
+
(Converter._DECODE_LOOKUP[strippedHex.charCodeAt(i++)] << 4) |
|
|
2406
|
+
Converter._DECODE_LOOKUP[strippedHex.charCodeAt(i++)];
|
|
2407
|
+
}
|
|
2408
|
+
if (reverse) {
|
|
2409
|
+
array.reverse();
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
return array;
|
|
1957
2413
|
}
|
|
1958
2414
|
/**
|
|
1959
|
-
*
|
|
1960
|
-
* @param
|
|
1961
|
-
* @
|
|
2415
|
+
* Convert the UTF8 to hex.
|
|
2416
|
+
* @param utf8 The text to convert.
|
|
2417
|
+
* @param includePrefix Include the 0x prefix on the returned hex.
|
|
2418
|
+
* @returns The hex version of the bytes.
|
|
1962
2419
|
*/
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
return
|
|
2420
|
+
static utf8ToHex(utf8, includePrefix = false) {
|
|
2421
|
+
const hex = Converter.bytesToHex(Converter.utf8ToBytes(utf8));
|
|
2422
|
+
return includePrefix ? HexHelper.addPrefix(hex) : hex;
|
|
1966
2423
|
}
|
|
1967
2424
|
/**
|
|
1968
|
-
*
|
|
1969
|
-
* @param
|
|
1970
|
-
* @
|
|
2425
|
+
* Convert the hex text to text.
|
|
2426
|
+
* @param hex The hex to convert.
|
|
2427
|
+
* @returns The UTF8 version of the bytes.
|
|
1971
2428
|
*/
|
|
1972
|
-
|
|
1973
|
-
|
|
2429
|
+
static hexToUtf8(hex) {
|
|
2430
|
+
return Converter.bytesToUtf8(Converter.hexToBytes(HexHelper.stripPrefix(hex)));
|
|
1974
2431
|
}
|
|
1975
2432
|
/**
|
|
1976
|
-
*
|
|
1977
|
-
* @param
|
|
1978
|
-
* @
|
|
1979
|
-
* @returns The matched name or undefined if no match.
|
|
1980
|
-
* @internal
|
|
2433
|
+
* Convert bytes to binary string.
|
|
2434
|
+
* @param bytes The bytes to convert.
|
|
2435
|
+
* @returns A binary string of the bytes.
|
|
1981
2436
|
*/
|
|
1982
|
-
|
|
1983
|
-
|
|
2437
|
+
static bytesToBinary(bytes) {
|
|
2438
|
+
const b = [];
|
|
2439
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2440
|
+
b.push(bytes[i].toString(2).padStart(8, "0"));
|
|
2441
|
+
}
|
|
2442
|
+
return b.join("");
|
|
1984
2443
|
}
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1988
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1989
|
-
/**
|
|
1990
|
-
* Factory for creating implementation of component types.
|
|
1991
|
-
*/
|
|
1992
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1993
|
-
const ComponentFactory = Factory.createFactory("component");
|
|
1994
|
-
|
|
1995
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1996
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1997
|
-
/**
|
|
1998
|
-
* Class to help with arrays.
|
|
1999
|
-
*/
|
|
2000
|
-
class ArrayHelper {
|
|
2001
2444
|
/**
|
|
2002
|
-
*
|
|
2003
|
-
* @param
|
|
2004
|
-
* @
|
|
2005
|
-
* @returns True if both arrays are empty of have the same values.
|
|
2445
|
+
* Convert a binary string to bytes.
|
|
2446
|
+
* @param binary The binary string.
|
|
2447
|
+
* @returns The bytes.
|
|
2006
2448
|
*/
|
|
2007
|
-
static
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
if (!((Is.array(arr1) && Is.array(arr2)) || (Is.typedArray(arr1) && Is.typedArray(arr2)))) {
|
|
2012
|
-
return false;
|
|
2013
|
-
}
|
|
2014
|
-
if (arr1.length !== arr2.length) {
|
|
2015
|
-
return false;
|
|
2016
|
-
}
|
|
2017
|
-
for (let i = 0; i < arr1.length; i++) {
|
|
2018
|
-
if (arr1[i] !== arr2[i]) {
|
|
2019
|
-
return false;
|
|
2020
|
-
}
|
|
2449
|
+
static binaryToBytes(binary) {
|
|
2450
|
+
const bytes = new Uint8Array(Math.ceil(binary.length / 8));
|
|
2451
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2452
|
+
bytes[i] = Number.parseInt(binary.slice(i * 8, (i + 1) * 8), 2);
|
|
2021
2453
|
}
|
|
2022
|
-
return
|
|
2454
|
+
return bytes;
|
|
2023
2455
|
}
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
|
-
// Copyright 2024 IOTA Stiftung.
|
|
2027
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
2028
|
-
/**
|
|
2029
|
-
* Class to perform internationalization.
|
|
2030
|
-
*/
|
|
2031
|
-
class I18n {
|
|
2032
|
-
/**
|
|
2033
|
-
* The default translation.
|
|
2034
|
-
*/
|
|
2035
|
-
static DEFAULT_LOCALE = "en";
|
|
2036
|
-
/**
|
|
2037
|
-
* Dictionaries for lookups.
|
|
2038
|
-
* @internal
|
|
2039
|
-
*/
|
|
2040
|
-
static _localeDictionaries = {};
|
|
2041
|
-
/**
|
|
2042
|
-
* The current locale.
|
|
2043
|
-
* @internal
|
|
2044
|
-
*/
|
|
2045
|
-
static _currentLocale = I18n.DEFAULT_LOCALE;
|
|
2046
|
-
/**
|
|
2047
|
-
* Change handler for the locale being updated.
|
|
2048
|
-
* @internal
|
|
2049
|
-
*/
|
|
2050
|
-
static _localeChangedHandlers = {};
|
|
2051
2456
|
/**
|
|
2052
|
-
*
|
|
2053
|
-
* @
|
|
2457
|
+
* Convert bytes to base64 string.
|
|
2458
|
+
* @param bytes The bytes to convert.
|
|
2459
|
+
* @returns A base64 string of the bytes.
|
|
2054
2460
|
*/
|
|
2055
|
-
static
|
|
2461
|
+
static bytesToBase64(bytes) {
|
|
2462
|
+
return Base64.encode(bytes);
|
|
2463
|
+
}
|
|
2056
2464
|
/**
|
|
2057
|
-
*
|
|
2058
|
-
* @param
|
|
2465
|
+
* Convert a base64 string to bytes.
|
|
2466
|
+
* @param base64 The base64 string.
|
|
2467
|
+
* @returns The bytes.
|
|
2059
2468
|
*/
|
|
2060
|
-
static
|
|
2061
|
-
|
|
2062
|
-
for (const callback in I18n._localeChangedHandlers) {
|
|
2063
|
-
I18n._localeChangedHandlers[callback](I18n._currentLocale);
|
|
2064
|
-
}
|
|
2469
|
+
static base64ToBytes(base64) {
|
|
2470
|
+
return Base64.decode(base64);
|
|
2065
2471
|
}
|
|
2066
2472
|
/**
|
|
2067
|
-
*
|
|
2068
|
-
* @
|
|
2473
|
+
* Convert bytes to base64 url string.
|
|
2474
|
+
* @param bytes The bytes to convert.
|
|
2475
|
+
* @returns A base64 url string of the bytes.
|
|
2069
2476
|
*/
|
|
2070
|
-
static
|
|
2071
|
-
return
|
|
2477
|
+
static bytesToBase64Url(bytes) {
|
|
2478
|
+
return Base64Url.encode(bytes);
|
|
2072
2479
|
}
|
|
2073
2480
|
/**
|
|
2074
|
-
*
|
|
2075
|
-
* @param
|
|
2076
|
-
* @
|
|
2481
|
+
* Convert a base64 url string to bytes.
|
|
2482
|
+
* @param base64Url The base64 url string.
|
|
2483
|
+
* @returns The bytes.
|
|
2077
2484
|
*/
|
|
2078
|
-
static
|
|
2079
|
-
|
|
2080
|
-
I18n.flattenTranslationKeys(dictionary, "", mergedKeys);
|
|
2081
|
-
I18n._localeDictionaries[locale] = mergedKeys;
|
|
2082
|
-
for (const callback in I18n._dictionaryChangedHandlers) {
|
|
2083
|
-
I18n._dictionaryChangedHandlers[callback](I18n._currentLocale);
|
|
2084
|
-
}
|
|
2485
|
+
static base64UrlToBytes(base64Url) {
|
|
2486
|
+
return Base64Url.decode(base64Url);
|
|
2085
2487
|
}
|
|
2086
2488
|
/**
|
|
2087
|
-
*
|
|
2088
|
-
* @param
|
|
2089
|
-
* @returns
|
|
2489
|
+
* Convert bytes to base58 string.
|
|
2490
|
+
* @param bytes The bytes to convert.
|
|
2491
|
+
* @returns A base58 string of the bytes.
|
|
2090
2492
|
*/
|
|
2091
|
-
static
|
|
2092
|
-
return
|
|
2493
|
+
static bytesToBase58(bytes) {
|
|
2494
|
+
return Base58.encode(bytes);
|
|
2093
2495
|
}
|
|
2094
2496
|
/**
|
|
2095
|
-
*
|
|
2096
|
-
* @
|
|
2497
|
+
* Convert a base58 string to bytes.
|
|
2498
|
+
* @param base58 The base58 string.
|
|
2499
|
+
* @returns The bytes.
|
|
2097
2500
|
*/
|
|
2098
|
-
static
|
|
2099
|
-
return
|
|
2501
|
+
static base58ToBytes(base58) {
|
|
2502
|
+
return Base58.decode(base58);
|
|
2100
2503
|
}
|
|
2101
2504
|
/**
|
|
2102
|
-
*
|
|
2103
|
-
* @
|
|
2104
|
-
* @param handler The handler to add.
|
|
2505
|
+
* Build the static lookup tables.
|
|
2506
|
+
* @internal
|
|
2105
2507
|
*/
|
|
2106
|
-
static
|
|
2107
|
-
|
|
2508
|
+
static buildHexLookups() {
|
|
2509
|
+
if (!Converter._ENCODE_LOOKUP || !Converter._DECODE_LOOKUP) {
|
|
2510
|
+
const alphabet = "0123456789abcdef";
|
|
2511
|
+
Converter._ENCODE_LOOKUP = [];
|
|
2512
|
+
Converter._DECODE_LOOKUP = [];
|
|
2513
|
+
for (let i = 0; i < 256; i++) {
|
|
2514
|
+
Converter._ENCODE_LOOKUP[i] = alphabet[(i >> 4) & 0xf] + alphabet[i & 0xf];
|
|
2515
|
+
if (i < 16) {
|
|
2516
|
+
if (i < 10) {
|
|
2517
|
+
Converter._DECODE_LOOKUP[0x30 + i] = i;
|
|
2518
|
+
}
|
|
2519
|
+
else {
|
|
2520
|
+
Converter._DECODE_LOOKUP[0x61 - 10 + i] = i;
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2108
2525
|
}
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
/**
|
|
2529
|
+
* Helpers methods for JSON objects.
|
|
2530
|
+
*/
|
|
2531
|
+
class JsonHelper {
|
|
2109
2532
|
/**
|
|
2110
|
-
*
|
|
2111
|
-
* @
|
|
2533
|
+
* Runtime name for the class.
|
|
2534
|
+
* @internal
|
|
2112
2535
|
*/
|
|
2113
|
-
static
|
|
2114
|
-
delete I18n._localeChangedHandlers[id];
|
|
2115
|
-
}
|
|
2536
|
+
static _CLASS_NAME = "JsonHelper";
|
|
2116
2537
|
/**
|
|
2117
|
-
*
|
|
2118
|
-
*
|
|
2119
|
-
* @param
|
|
2538
|
+
* Serializes in canonical format.
|
|
2539
|
+
* Based on https://www.rfc-editor.org/rfc/rfc8785.
|
|
2540
|
+
* @param object The object to be serialized.
|
|
2541
|
+
* @returns The serialized object.
|
|
2120
2542
|
*/
|
|
2121
|
-
static
|
|
2122
|
-
|
|
2543
|
+
static canonicalize(object) {
|
|
2544
|
+
const buffer = [];
|
|
2545
|
+
if (object === null ||
|
|
2546
|
+
typeof object !== "object" ||
|
|
2547
|
+
("toJSON" in object && object.toJSON instanceof Function)) {
|
|
2548
|
+
// Primitive data type
|
|
2549
|
+
buffer.push(JSON.stringify(object));
|
|
2550
|
+
}
|
|
2551
|
+
else if (Array.isArray(object)) {
|
|
2552
|
+
// Array maintain element order
|
|
2553
|
+
const parts = [];
|
|
2554
|
+
for (const element of object) {
|
|
2555
|
+
if (element === undefined) {
|
|
2556
|
+
parts.push("null");
|
|
2557
|
+
}
|
|
2558
|
+
else {
|
|
2559
|
+
parts.push(JsonHelper.canonicalize(element));
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
buffer.push(`[${parts.join(",")}]`);
|
|
2563
|
+
}
|
|
2564
|
+
else {
|
|
2565
|
+
// Object sort properties
|
|
2566
|
+
const props = [];
|
|
2567
|
+
const keys = Object.keys(object).sort();
|
|
2568
|
+
const o = object;
|
|
2569
|
+
for (const key of keys) {
|
|
2570
|
+
if (o[key] !== undefined) {
|
|
2571
|
+
props.push(`${JSON.stringify(key)}:${JsonHelper.canonicalize(o[key])}`);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
buffer.push(`{${props.join(",")}}`);
|
|
2575
|
+
}
|
|
2576
|
+
return buffer.join("");
|
|
2123
2577
|
}
|
|
2124
2578
|
/**
|
|
2125
|
-
*
|
|
2126
|
-
*
|
|
2579
|
+
* Creates a RFC 6902 diff set.
|
|
2580
|
+
* Based on https://www.rfc-editor.org/rfc/rfc6902.
|
|
2581
|
+
* @param object1 The first object.
|
|
2582
|
+
* @param object2 The second object.
|
|
2583
|
+
* @returns The list of patches.
|
|
2127
2584
|
*/
|
|
2128
|
-
static
|
|
2129
|
-
|
|
2585
|
+
static diff(object1, object2) {
|
|
2586
|
+
const operations = rfc6902.createPatch(object1, object2);
|
|
2587
|
+
return operations;
|
|
2130
2588
|
}
|
|
2131
2589
|
/**
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2134
|
-
* @param
|
|
2135
|
-
* @param
|
|
2136
|
-
* @returns The
|
|
2590
|
+
* Applies a RFC 6902 diff set to an object.
|
|
2591
|
+
* Based on https://www.rfc-editor.org/rfc/rfc6902.
|
|
2592
|
+
* @param object The object to patch.
|
|
2593
|
+
* @param patches The second object.
|
|
2594
|
+
* @returns The updated object.
|
|
2595
|
+
* @throws GeneralError if the patch fails.
|
|
2137
2596
|
*/
|
|
2138
|
-
static
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
}
|
|
2146
|
-
if (!I18n._localeDictionaries[cl][key]) {
|
|
2147
|
-
return `!!Missing ${cl}.${key}`;
|
|
2148
|
-
}
|
|
2149
|
-
if (I18n._currentLocale === "debug-k") {
|
|
2150
|
-
return key;
|
|
2151
|
-
}
|
|
2152
|
-
let ret = new intlMessageformat.IntlMessageFormat(I18n._localeDictionaries[cl][key], cl).format(values);
|
|
2153
|
-
if (I18n._currentLocale === "debug-x") {
|
|
2154
|
-
ret = ret.replace(/[a-z]/g, "x").replace(/[A-Z]/g, "x").replace(/\d/g, "n");
|
|
2597
|
+
static patch(object, patches) {
|
|
2598
|
+
const clone = ObjectHelper.clone(object);
|
|
2599
|
+
const result = rfc6902.applyPatch(clone, patches);
|
|
2600
|
+
for (let i = 0; i < result.length; i++) {
|
|
2601
|
+
if (!Is.empty(result[i])) {
|
|
2602
|
+
throw new GeneralError(JsonHelper._CLASS_NAME, "failedPatch", { index: i }, result[i]);
|
|
2603
|
+
}
|
|
2155
2604
|
}
|
|
2156
|
-
return
|
|
2605
|
+
return clone;
|
|
2157
2606
|
}
|
|
2158
2607
|
/**
|
|
2159
|
-
*
|
|
2160
|
-
* @param
|
|
2161
|
-
* @
|
|
2608
|
+
* Stringify the JSON with support for extended data types date/bigint/uint8array.
|
|
2609
|
+
* @param object The object to stringify.
|
|
2610
|
+
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
|
2611
|
+
* @returns The stringified object.
|
|
2162
2612
|
*/
|
|
2163
|
-
|
|
2164
|
-
|
|
2613
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2614
|
+
static stringifyEx(object, space) {
|
|
2615
|
+
// We want to keep the 'this' intact for the replacer
|
|
2616
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
2617
|
+
return JSON.stringify(object, JsonHelper.stringifyExReplacer, space);
|
|
2165
2618
|
}
|
|
2166
2619
|
/**
|
|
2167
|
-
*
|
|
2168
|
-
* @param
|
|
2169
|
-
* @
|
|
2170
|
-
* @param mergedKeys The merged keys dictionary to populate.
|
|
2171
|
-
* @internal
|
|
2620
|
+
* Parse the JSON string with support for extended data types date/bigint/uint8array.
|
|
2621
|
+
* @param json The object to pause.
|
|
2622
|
+
* @returns The object.
|
|
2172
2623
|
*/
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2624
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2625
|
+
static parseEx(json) {
|
|
2626
|
+
// We want to keep the 'this' intact for the reviver
|
|
2627
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
2628
|
+
return JSON.parse(json, JsonHelper.parseExReviver);
|
|
2629
|
+
}
|
|
2630
|
+
/**
|
|
2631
|
+
* Replacer function to handle extended data types.
|
|
2632
|
+
* @param this The object.
|
|
2633
|
+
* @param key The key.
|
|
2634
|
+
* @param value The value.
|
|
2635
|
+
* @returns The value.
|
|
2636
|
+
*/
|
|
2637
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2638
|
+
static stringifyExReplacer(key, value) {
|
|
2639
|
+
const rawValue = this[key];
|
|
2640
|
+
if (Is.bigint(rawValue)) {
|
|
2641
|
+
return {
|
|
2642
|
+
"@ext": "bigint",
|
|
2643
|
+
value: rawValue.toString()
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
else if (Is.date(rawValue)) {
|
|
2647
|
+
return {
|
|
2648
|
+
"@ext": "date",
|
|
2649
|
+
value: rawValue.getTime()
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
else if (Is.uint8Array(rawValue)) {
|
|
2653
|
+
return {
|
|
2654
|
+
"@ext": "uint8array",
|
|
2655
|
+
value: Converter.bytesToBase64(rawValue)
|
|
2656
|
+
};
|
|
2657
|
+
}
|
|
2658
|
+
return value;
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Reviver function to handle extended data types.
|
|
2662
|
+
* @param this The object.
|
|
2663
|
+
* @param key The key.
|
|
2664
|
+
* @param value The value.
|
|
2665
|
+
* @returns The value.
|
|
2666
|
+
*/
|
|
2667
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2668
|
+
static parseExReviver(key, value) {
|
|
2669
|
+
if (Is.object(value)) {
|
|
2670
|
+
if (value["@ext"] === "bigint") {
|
|
2671
|
+
return BigInt(value.value);
|
|
2179
2672
|
}
|
|
2180
|
-
else if (
|
|
2181
|
-
|
|
2673
|
+
else if (value["@ext"] === "date") {
|
|
2674
|
+
return new Date(value.value);
|
|
2675
|
+
}
|
|
2676
|
+
else if (value["@ext"] === "uint8array") {
|
|
2677
|
+
return Converter.base64ToBytes(value.value);
|
|
2182
2678
|
}
|
|
2183
2679
|
}
|
|
2680
|
+
return value;
|
|
2184
2681
|
}
|
|
2185
2682
|
}
|
|
2186
2683
|
|
|
2187
|
-
// Copyright 2024 IOTA Stiftung.
|
|
2188
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
2189
2684
|
/**
|
|
2190
|
-
*
|
|
2685
|
+
* Class to help with objects.
|
|
2191
2686
|
*/
|
|
2192
|
-
class
|
|
2687
|
+
class ObjectHelper {
|
|
2193
2688
|
/**
|
|
2194
|
-
*
|
|
2195
|
-
* @
|
|
2196
|
-
* @returns The error formatted including any inner errors.
|
|
2689
|
+
* Runtime name for the class.
|
|
2690
|
+
* @internal
|
|
2197
2691
|
*/
|
|
2198
|
-
static
|
|
2199
|
-
return ErrorHelper.localizeErrors(error).map(e => e.message);
|
|
2200
|
-
}
|
|
2692
|
+
static _CLASS_NAME = "ObjectHelper";
|
|
2201
2693
|
/**
|
|
2202
|
-
*
|
|
2203
|
-
* @param
|
|
2204
|
-
* @
|
|
2694
|
+
* Convert an object to bytes.
|
|
2695
|
+
* @param obj The object to convert.
|
|
2696
|
+
* @param format Format the JSON content.
|
|
2697
|
+
* @returns The object as bytes.
|
|
2205
2698
|
*/
|
|
2206
|
-
static
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
const errors = BaseError.flatten(error);
|
|
2210
|
-
for (const err of errors) {
|
|
2211
|
-
const errorNameKey = `errorNames.${StringHelper.camelCase(err.name)}`;
|
|
2212
|
-
const errorMessageKey = `error.${err.message}`;
|
|
2213
|
-
// If there is no error message then it is probably
|
|
2214
|
-
// from a 3rd party lib, so don't format it just display
|
|
2215
|
-
const hasErrorName = I18n.hasMessage(errorNameKey);
|
|
2216
|
-
const hasErrorMessage = I18n.hasMessage(errorMessageKey);
|
|
2217
|
-
const localizedError = {
|
|
2218
|
-
name: I18n.formatMessage(hasErrorName ? errorNameKey : "errorNames.error"),
|
|
2219
|
-
message: hasErrorMessage
|
|
2220
|
-
? I18n.formatMessage(errorMessageKey, err.properties)
|
|
2221
|
-
: err.message
|
|
2222
|
-
};
|
|
2223
|
-
if (Is.stringValue(err.source)) {
|
|
2224
|
-
localizedError.source = err.source;
|
|
2225
|
-
}
|
|
2226
|
-
if (Is.stringValue(err.stack)) {
|
|
2227
|
-
// Remove the first line from the stack traces as they
|
|
2228
|
-
// just have the error type and message duplicated
|
|
2229
|
-
const lines = err.stack.split("\n");
|
|
2230
|
-
lines.shift();
|
|
2231
|
-
localizedError.stack = lines.join("\n");
|
|
2232
|
-
}
|
|
2233
|
-
const additional = ErrorHelper.formatValidationErrors(err);
|
|
2234
|
-
if (Is.stringValue(additional)) {
|
|
2235
|
-
localizedError.additional = additional;
|
|
2236
|
-
}
|
|
2237
|
-
formattedErrors.push(localizedError);
|
|
2238
|
-
}
|
|
2699
|
+
static toBytes(obj, format = false) {
|
|
2700
|
+
if (obj === undefined) {
|
|
2701
|
+
return new Uint8Array();
|
|
2239
2702
|
}
|
|
2240
|
-
|
|
2703
|
+
const json = format ? JSON.stringify(obj, undefined, "\t") : JSON.stringify(obj);
|
|
2704
|
+
return Converter.utf8ToBytes(json);
|
|
2241
2705
|
}
|
|
2242
2706
|
/**
|
|
2243
|
-
*
|
|
2244
|
-
* @param
|
|
2245
|
-
* @returns The
|
|
2707
|
+
* Convert a bytes to an object.
|
|
2708
|
+
* @param bytes The bytes to convert to an object.
|
|
2709
|
+
* @returns The object.
|
|
2710
|
+
* @throws GeneralError if there was an error parsing the JSON.
|
|
2246
2711
|
*/
|
|
2247
|
-
static
|
|
2248
|
-
if (Is.
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
: errorI18n;
|
|
2258
|
-
let v = `${validationFailure.property}: ${errorMessage}`;
|
|
2259
|
-
if (Is.object(validationFailure.properties) &&
|
|
2260
|
-
Is.notEmpty(validationFailure.properties.value)) {
|
|
2261
|
-
v += ` = ${JSON.stringify(validationFailure.properties.value)}`;
|
|
2262
|
-
}
|
|
2263
|
-
validationErrors.push(v);
|
|
2264
|
-
}
|
|
2265
|
-
return validationErrors.join("\n");
|
|
2712
|
+
static fromBytes(bytes) {
|
|
2713
|
+
if (Is.empty(bytes) || bytes.length === 0) {
|
|
2714
|
+
return undefined;
|
|
2715
|
+
}
|
|
2716
|
+
try {
|
|
2717
|
+
const utf8 = Converter.bytesToUtf8(bytes);
|
|
2718
|
+
return JSON.parse(utf8);
|
|
2719
|
+
}
|
|
2720
|
+
catch (err) {
|
|
2721
|
+
throw new GeneralError(ObjectHelper._CLASS_NAME, "failedBytesToJSON", undefined, err);
|
|
2266
2722
|
}
|
|
2267
2723
|
}
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
// Copyright 2024 IOTA Stiftung.
|
|
2271
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
2272
|
-
/**
|
|
2273
|
-
* Coerce an object from one type to another.
|
|
2274
|
-
*/
|
|
2275
|
-
class Coerce {
|
|
2276
2724
|
/**
|
|
2277
|
-
*
|
|
2278
|
-
* @param
|
|
2279
|
-
* @
|
|
2280
|
-
* @returns The value if it can be coerced.
|
|
2725
|
+
* Make a deep clone of an object.
|
|
2726
|
+
* @param obj The object to clone.
|
|
2727
|
+
* @returns The objects clone.
|
|
2281
2728
|
*/
|
|
2282
|
-
static
|
|
2283
|
-
if (Is.undefined(
|
|
2284
|
-
return
|
|
2285
|
-
}
|
|
2286
|
-
if (Is.string(value)) {
|
|
2287
|
-
return value;
|
|
2729
|
+
static clone(obj) {
|
|
2730
|
+
if (Is.undefined(obj)) {
|
|
2731
|
+
return undefined;
|
|
2288
2732
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2733
|
+
return structuredClone(obj);
|
|
2734
|
+
}
|
|
2735
|
+
/**
|
|
2736
|
+
* Deep merge objects.
|
|
2737
|
+
* @param obj1 The first object to merge.
|
|
2738
|
+
* @param obj2 The second object to merge.
|
|
2739
|
+
* @returns The combined deep merge of the objects.
|
|
2740
|
+
*/
|
|
2741
|
+
static merge(obj1, obj2) {
|
|
2742
|
+
if (Is.empty(obj1)) {
|
|
2743
|
+
return ObjectHelper.clone(obj2);
|
|
2291
2744
|
}
|
|
2292
|
-
if (Is.
|
|
2293
|
-
return
|
|
2745
|
+
if (Is.empty(obj2)) {
|
|
2746
|
+
return ObjectHelper.clone(obj1);
|
|
2294
2747
|
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2748
|
+
const obj1Clone = ObjectHelper.clone(obj1);
|
|
2749
|
+
if (Is.object(obj1Clone) && Is.object(obj2)) {
|
|
2750
|
+
const keys = Object.keys(obj2);
|
|
2751
|
+
for (const key of keys) {
|
|
2752
|
+
if (Is.object(obj1Clone[key]) && Is.object(obj2[key])) {
|
|
2753
|
+
ObjectHelper.propertySet(obj1Clone, key, ObjectHelper.merge(obj1Clone[key], obj2[key]));
|
|
2754
|
+
}
|
|
2755
|
+
else {
|
|
2756
|
+
ObjectHelper.propertySet(obj1Clone, key, obj2[key]);
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2297
2759
|
}
|
|
2760
|
+
return obj1Clone;
|
|
2298
2761
|
}
|
|
2299
2762
|
/**
|
|
2300
|
-
*
|
|
2301
|
-
* @param
|
|
2302
|
-
* @
|
|
2303
|
-
* @
|
|
2763
|
+
* Does one object equal another.
|
|
2764
|
+
* @param obj1 The first object to compare.
|
|
2765
|
+
* @param obj2 The second object to compare.
|
|
2766
|
+
* @param strictPropertyOrder Should the properties be in the same order, defaults to true.
|
|
2767
|
+
* @returns True is the objects are equal.
|
|
2304
2768
|
*/
|
|
2305
|
-
static
|
|
2306
|
-
if (
|
|
2307
|
-
return
|
|
2308
|
-
}
|
|
2309
|
-
if (Is.number(value)) {
|
|
2310
|
-
return value;
|
|
2769
|
+
static equal(obj1, obj2, strictPropertyOrder) {
|
|
2770
|
+
if (strictPropertyOrder ?? true) {
|
|
2771
|
+
return JSON.stringify(obj1) === JSON.stringify(obj2);
|
|
2311
2772
|
}
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2773
|
+
return JsonHelper.canonicalize(obj1) === JsonHelper.canonicalize(obj2);
|
|
2774
|
+
}
|
|
2775
|
+
/**
|
|
2776
|
+
* Get the property of an unknown object.
|
|
2777
|
+
* @param obj The object to get the property from.
|
|
2778
|
+
* @param property The property to get, can be separated by dots for nested path.
|
|
2779
|
+
* @returns The property.
|
|
2780
|
+
*/
|
|
2781
|
+
static propertyGet(obj, property) {
|
|
2782
|
+
const pathParts = property.split(".");
|
|
2783
|
+
let pathValue = obj;
|
|
2784
|
+
for (const pathPart of pathParts) {
|
|
2785
|
+
// Is the path part numeric i.e. an array index.
|
|
2786
|
+
const arrayMatch = /^(\d+)$/.exec(pathPart);
|
|
2787
|
+
if (arrayMatch) {
|
|
2788
|
+
const arrayIndex = Number.parseInt(arrayMatch[1], 10);
|
|
2789
|
+
if (Is.arrayValue(pathValue) && arrayIndex < pathValue.length) {
|
|
2790
|
+
// There is no prop name so this is a direct array index on the current object
|
|
2791
|
+
pathValue = pathValue[arrayIndex];
|
|
2792
|
+
}
|
|
2793
|
+
else {
|
|
2794
|
+
// Array index for non array object so return
|
|
2795
|
+
return undefined;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
else if (Is.object(pathValue)) {
|
|
2799
|
+
// No array part in path so assume object sub property
|
|
2800
|
+
pathValue = pathValue[pathPart];
|
|
2801
|
+
}
|
|
2802
|
+
else {
|
|
2803
|
+
return undefined;
|
|
2316
2804
|
}
|
|
2317
2805
|
}
|
|
2318
|
-
|
|
2319
|
-
|
|
2806
|
+
return pathValue;
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Set the property of an unknown object.
|
|
2810
|
+
* @param obj The object to set the property from.
|
|
2811
|
+
* @param property The property to set.
|
|
2812
|
+
* @param value The value to set.
|
|
2813
|
+
* @throws GeneralError if the property target is not an object.
|
|
2814
|
+
*/
|
|
2815
|
+
static propertySet(obj, property, value) {
|
|
2816
|
+
const pathParts = property.split(".");
|
|
2817
|
+
let pathValue = obj;
|
|
2818
|
+
let parentObj;
|
|
2819
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
2820
|
+
const pathPart = pathParts[i];
|
|
2821
|
+
// Is the path part numeric i.e. an array index.
|
|
2822
|
+
const arrayMatch = /^(\d+)$/.exec(pathPart);
|
|
2823
|
+
const arrayIndex = arrayMatch ? Number.parseInt(arrayMatch[1], 10) : -1;
|
|
2824
|
+
if (i === pathParts.length - 1) {
|
|
2825
|
+
// Last part of path so set the value
|
|
2826
|
+
if (arrayIndex >= 0) {
|
|
2827
|
+
if (Is.array(pathValue)) {
|
|
2828
|
+
pathValue[arrayIndex] = value;
|
|
2829
|
+
}
|
|
2830
|
+
else if (Is.object(pathValue)) {
|
|
2831
|
+
pathValue[arrayIndex] = value;
|
|
2832
|
+
}
|
|
2833
|
+
else {
|
|
2834
|
+
throw new GeneralError(ObjectHelper._CLASS_NAME, "cannotSetArrayIndex", {
|
|
2835
|
+
property,
|
|
2836
|
+
index: arrayIndex
|
|
2837
|
+
});
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
else if (Is.object(pathValue)) {
|
|
2841
|
+
pathValue[pathPart] = value;
|
|
2842
|
+
}
|
|
2843
|
+
else {
|
|
2844
|
+
throw new GeneralError(ObjectHelper._CLASS_NAME, "cannotSetProperty", { property });
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
else {
|
|
2848
|
+
parentObj = pathValue;
|
|
2849
|
+
if (Is.object(pathValue)) {
|
|
2850
|
+
pathValue = pathValue[pathPart];
|
|
2851
|
+
}
|
|
2852
|
+
else if (Is.array(pathValue)) {
|
|
2853
|
+
pathValue = pathValue[arrayIndex];
|
|
2854
|
+
}
|
|
2855
|
+
if (Is.empty(pathValue)) {
|
|
2856
|
+
const nextArrayMatch = /^(\d+)$/.exec(pathParts[i + 1]);
|
|
2857
|
+
const nextArrayIndex = nextArrayMatch ? Number.parseInt(nextArrayMatch[1], 10) : -1;
|
|
2858
|
+
if (nextArrayIndex >= 0) {
|
|
2859
|
+
pathValue = [];
|
|
2860
|
+
}
|
|
2861
|
+
else {
|
|
2862
|
+
pathValue = {};
|
|
2863
|
+
}
|
|
2864
|
+
if (Is.object(parentObj)) {
|
|
2865
|
+
parentObj[pathPart] = pathValue;
|
|
2866
|
+
}
|
|
2867
|
+
else if (Is.array(parentObj)) {
|
|
2868
|
+
parentObj[arrayIndex] = pathValue;
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2320
2872
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2873
|
+
}
|
|
2874
|
+
/**
|
|
2875
|
+
* Delete the property of an unknown object.
|
|
2876
|
+
* @param obj The object to set the property from.
|
|
2877
|
+
* @param property The property to set
|
|
2878
|
+
*/
|
|
2879
|
+
static propertyDelete(obj, property) {
|
|
2880
|
+
if (Is.object(obj)) {
|
|
2881
|
+
delete obj[property];
|
|
2323
2882
|
}
|
|
2324
2883
|
}
|
|
2325
2884
|
/**
|
|
2326
|
-
*
|
|
2327
|
-
* @param
|
|
2328
|
-
* @
|
|
2329
|
-
* @
|
|
2885
|
+
* Extract a property from the object, providing alternative names.
|
|
2886
|
+
* @param obj The object to extract from.
|
|
2887
|
+
* @param propertyNames The possible names for the property.
|
|
2888
|
+
* @param removeProperties Remove the properties from the object, defaults to true.
|
|
2889
|
+
* @returns The property if available.
|
|
2330
2890
|
*/
|
|
2331
|
-
static
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
}
|
|
2341
|
-
if (Is.string(value)) {
|
|
2342
|
-
const parsed = Number.parseFloat(value);
|
|
2343
|
-
if (Is.integer(parsed)) {
|
|
2344
|
-
return BigInt(parsed);
|
|
2891
|
+
static extractProperty(obj, propertyNames, removeProperties = true) {
|
|
2892
|
+
let retVal;
|
|
2893
|
+
if (Is.object(obj)) {
|
|
2894
|
+
const names = Is.string(propertyNames) ? [propertyNames] : propertyNames;
|
|
2895
|
+
for (const prop of names) {
|
|
2896
|
+
retVal ??= ObjectHelper.propertyGet(obj, prop);
|
|
2897
|
+
if (removeProperties) {
|
|
2898
|
+
ObjectHelper.propertyDelete(obj, prop);
|
|
2899
|
+
}
|
|
2345
2900
|
}
|
|
2346
2901
|
}
|
|
2347
|
-
|
|
2348
|
-
return value ? 1n : 0n;
|
|
2349
|
-
}
|
|
2902
|
+
return retVal;
|
|
2350
2903
|
}
|
|
2351
2904
|
/**
|
|
2352
|
-
*
|
|
2353
|
-
* @param
|
|
2354
|
-
* @
|
|
2355
|
-
* @returns The
|
|
2905
|
+
* Pick a subset of properties from an object.
|
|
2906
|
+
* @param obj The object to pick the properties from.
|
|
2907
|
+
* @param keys The property keys to pick.
|
|
2908
|
+
* @returns The partial object.
|
|
2356
2909
|
*/
|
|
2357
|
-
static
|
|
2358
|
-
if (Is.
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
return value;
|
|
2363
|
-
}
|
|
2364
|
-
if (Is.number(value)) {
|
|
2365
|
-
// eslint-disable-next-line no-unneeded-ternary
|
|
2366
|
-
return value ? true : false;
|
|
2367
|
-
}
|
|
2368
|
-
if (Is.string(value)) {
|
|
2369
|
-
if (/true/i.test(value)) {
|
|
2370
|
-
return true;
|
|
2371
|
-
}
|
|
2372
|
-
if (/false/i.test(value)) {
|
|
2373
|
-
return false;
|
|
2910
|
+
static pick(obj, keys) {
|
|
2911
|
+
if (Is.object(obj) && Is.arrayValue(keys)) {
|
|
2912
|
+
const result = {};
|
|
2913
|
+
for (const key of keys) {
|
|
2914
|
+
result[key] = obj[key];
|
|
2374
2915
|
}
|
|
2916
|
+
return result;
|
|
2375
2917
|
}
|
|
2918
|
+
return obj;
|
|
2376
2919
|
}
|
|
2377
2920
|
/**
|
|
2378
|
-
*
|
|
2379
|
-
* @param
|
|
2380
|
-
* @
|
|
2381
|
-
* @returns The
|
|
2921
|
+
* Omit a subset of properties from an object.
|
|
2922
|
+
* @param obj The object to omit the properties from.
|
|
2923
|
+
* @param keys The property keys to omit.
|
|
2924
|
+
* @returns The partial object.
|
|
2382
2925
|
*/
|
|
2383
|
-
static
|
|
2384
|
-
if (Is.
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
return value;
|
|
2389
|
-
}
|
|
2390
|
-
if (Is.number(value)) {
|
|
2391
|
-
return new Date(value);
|
|
2392
|
-
}
|
|
2393
|
-
if (Is.string(value)) {
|
|
2394
|
-
const dt = new Date(value);
|
|
2395
|
-
if (!Number.isNaN(dt.getTime())) {
|
|
2396
|
-
const utc = Date.UTC(dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate());
|
|
2397
|
-
return new Date(utc);
|
|
2926
|
+
static omit(obj, keys) {
|
|
2927
|
+
if (Is.object(obj) && Is.arrayValue(keys)) {
|
|
2928
|
+
const result = { ...obj };
|
|
2929
|
+
for (const key of keys) {
|
|
2930
|
+
delete result[key];
|
|
2398
2931
|
}
|
|
2932
|
+
return result;
|
|
2399
2933
|
}
|
|
2934
|
+
return obj;
|
|
2400
2935
|
}
|
|
2401
2936
|
/**
|
|
2402
|
-
*
|
|
2403
|
-
* @param
|
|
2404
|
-
* @
|
|
2405
|
-
* @returns The value if it can be coerced.
|
|
2937
|
+
* Converter the non JSON primitives to extended types.
|
|
2938
|
+
* @param obj The object to convert.
|
|
2939
|
+
* @returns The object with extended properties.
|
|
2406
2940
|
*/
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
if (Is.date(value)) {
|
|
2412
|
-
return value;
|
|
2413
|
-
}
|
|
2414
|
-
if (Is.number(value)) {
|
|
2415
|
-
return new Date(value);
|
|
2416
|
-
}
|
|
2417
|
-
if (Is.string(value)) {
|
|
2418
|
-
const dt = new Date(value);
|
|
2419
|
-
if (!Number.isNaN(dt.getTime())) {
|
|
2420
|
-
const utc = Date.UTC(dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate(), dt.getUTCHours(), dt.getUTCMinutes(), dt.getUTCSeconds(), dt.getUTCMilliseconds());
|
|
2421
|
-
return new Date(utc);
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2941
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2942
|
+
static toExtended(obj) {
|
|
2943
|
+
const jsonExtended = JsonHelper.stringifyEx(obj);
|
|
2944
|
+
return JSON.parse(jsonExtended);
|
|
2424
2945
|
}
|
|
2425
2946
|
/**
|
|
2426
|
-
*
|
|
2427
|
-
* @param
|
|
2428
|
-
* @
|
|
2429
|
-
* @returns The value if it can be coerced.
|
|
2947
|
+
* Converter the extended types to non JSON primitives.
|
|
2948
|
+
* @param obj The object to convert.
|
|
2949
|
+
* @returns The object with regular properties.
|
|
2430
2950
|
*/
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
if (Is.date(value)) {
|
|
2436
|
-
return value;
|
|
2437
|
-
}
|
|
2438
|
-
if (Is.number(value)) {
|
|
2439
|
-
const dt = new Date(value);
|
|
2440
|
-
dt.setFullYear(1970, 0, 1);
|
|
2441
|
-
return dt;
|
|
2442
|
-
}
|
|
2443
|
-
if (Is.string(value)) {
|
|
2444
|
-
const dt = new Date(value);
|
|
2445
|
-
if (!Number.isNaN(dt.getTime())) {
|
|
2446
|
-
const utc = Date.UTC(1970, 0, 1, dt.getUTCHours(), dt.getUTCMinutes(), dt.getUTCSeconds(), dt.getUTCMilliseconds());
|
|
2447
|
-
return new Date(utc);
|
|
2448
|
-
}
|
|
2449
|
-
}
|
|
2951
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2952
|
+
static fromExtended(obj) {
|
|
2953
|
+
const jsonExtended = JsonHelper.stringifyEx(obj);
|
|
2954
|
+
return JsonHelper.parseEx(jsonExtended);
|
|
2450
2955
|
}
|
|
2451
2956
|
/**
|
|
2452
|
-
*
|
|
2453
|
-
* @param
|
|
2454
|
-
* @
|
|
2455
|
-
* @
|
|
2957
|
+
* Remove empty properties from an object.
|
|
2958
|
+
* @param obj The object to remove the empty properties from.
|
|
2959
|
+
* @param options The options for the removal.
|
|
2960
|
+
* @param options.removeUndefined Remove undefined properties, defaults to true.
|
|
2961
|
+
* @param options.removeNull Remove null properties, defaults to false.
|
|
2962
|
+
* @returns The object with empty properties removed.
|
|
2456
2963
|
*/
|
|
2457
|
-
static
|
|
2458
|
-
if (Is.
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2964
|
+
static removeEmptyProperties(obj, options) {
|
|
2965
|
+
if (Is.object(obj)) {
|
|
2966
|
+
const removeUndefined = options?.removeUndefined ?? true;
|
|
2967
|
+
const removeNull = options?.removeNull ?? false;
|
|
2968
|
+
const newObj = {};
|
|
2969
|
+
const keys = Object.keys(obj);
|
|
2970
|
+
for (const key of keys) {
|
|
2971
|
+
if (!((removeUndefined && Is.undefined(obj[key])) || (removeNull && Is.null(obj[key])))) {
|
|
2972
|
+
newObj[key] = ObjectHelper.removeEmptyProperties(obj[key], options);
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
return newObj;
|
|
2463
2976
|
}
|
|
2464
|
-
if (Is.
|
|
2465
|
-
|
|
2466
|
-
|
|
2977
|
+
else if (Is.array(obj)) {
|
|
2978
|
+
const arr = [];
|
|
2979
|
+
for (const element of obj) {
|
|
2980
|
+
arr.push(ObjectHelper.removeEmptyProperties(element, options));
|
|
2467
2981
|
}
|
|
2468
|
-
|
|
2982
|
+
return arr;
|
|
2469
2983
|
}
|
|
2984
|
+
return obj;
|
|
2470
2985
|
}
|
|
2471
2986
|
}
|
|
2472
2987
|
|
|
2473
2988
|
// Copyright 2024 IOTA Stiftung.
|
|
2474
2989
|
// SPDX-License-Identifier: Apache-2.0.
|
|
2475
2990
|
/**
|
|
2476
|
-
*
|
|
2991
|
+
* Environment variable helper.
|
|
2477
2992
|
*/
|
|
2478
|
-
class
|
|
2479
|
-
/**
|
|
2480
|
-
*
|
|
2481
|
-
* @param
|
|
2482
|
-
* @
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2993
|
+
class EnvHelper {
|
|
2994
|
+
/**
|
|
2995
|
+
* Get the environment variable as an object with camel cased names.
|
|
2996
|
+
* @param envVars The environment variables.
|
|
2997
|
+
* @param prefix The prefix of the environment variables, if not provided gets all.
|
|
2998
|
+
* @returns The object with camel cased names.
|
|
2999
|
+
*/
|
|
3000
|
+
static envToJson(envVars, prefix) {
|
|
3001
|
+
const result = {};
|
|
3002
|
+
if (!Is.empty(envVars)) {
|
|
3003
|
+
if (Is.empty(prefix)) {
|
|
3004
|
+
for (const envVar in envVars) {
|
|
3005
|
+
if (Is.stringValue(envVars[envVar])) {
|
|
3006
|
+
const camelCaseName = StringHelper.camelCase(envVar.toLowerCase());
|
|
3007
|
+
ObjectHelper.propertySet(result, camelCaseName, envVars[envVar]);
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
else {
|
|
3012
|
+
for (const envVar in envVars) {
|
|
3013
|
+
if (envVar.startsWith(prefix) && Is.stringValue(envVars[envVar])) {
|
|
3014
|
+
const camelCaseName = StringHelper.camelCase(envVar.replace(prefix, "").toLowerCase());
|
|
3015
|
+
ObjectHelper.propertySet(result, camelCaseName, envVars[envVar]);
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
2488
3019
|
}
|
|
2489
|
-
|
|
2490
|
-
safe = safe.replace(/["*/:<>?\\|]/g, "_");
|
|
2491
|
-
// Windows non filename characters
|
|
2492
|
-
safe = safe.replace(/^(con|prn|aux|nul|com\d|lpt\d)$/i, "_");
|
|
2493
|
-
// Control characters
|
|
2494
|
-
safe = safe.replace(/[\u0000-\u001F\u0080-\u009F]/g, "_");
|
|
2495
|
-
// Relative paths
|
|
2496
|
-
safe = safe.replace(/^\.+/, "_");
|
|
2497
|
-
// Trailing periods
|
|
2498
|
-
safe = safe.replace(/\.+$/, "");
|
|
2499
|
-
return safe;
|
|
3020
|
+
return result;
|
|
2500
3021
|
}
|
|
2501
3022
|
}
|
|
2502
3023
|
|
|
2503
3024
|
// Copyright 2024 IOTA Stiftung.
|
|
2504
3025
|
// SPDX-License-Identifier: Apache-2.0.
|
|
2505
3026
|
/**
|
|
2506
|
-
*
|
|
3027
|
+
* Class to perform internationalization.
|
|
2507
3028
|
*/
|
|
2508
|
-
class
|
|
3029
|
+
class I18n {
|
|
2509
3030
|
/**
|
|
2510
|
-
*
|
|
2511
|
-
* Based on https://www.rfc-editor.org/rfc/rfc8785.
|
|
2512
|
-
* @param object The object to be serialized.
|
|
2513
|
-
* @returns The serialized object.
|
|
3031
|
+
* The default translation.
|
|
2514
3032
|
*/
|
|
2515
|
-
static
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
const parts = [];
|
|
2526
|
-
for (const element of object) {
|
|
2527
|
-
if (element === undefined) {
|
|
2528
|
-
parts.push("null");
|
|
2529
|
-
}
|
|
2530
|
-
else {
|
|
2531
|
-
parts.push(JsonHelper.canonicalize(element));
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
buffer.push(`[${parts.join(",")}]`);
|
|
3033
|
+
static DEFAULT_LOCALE = "en";
|
|
3034
|
+
/**
|
|
3035
|
+
* Set the locale.
|
|
3036
|
+
* @param locale The new locale.
|
|
3037
|
+
*/
|
|
3038
|
+
static setLocale(locale) {
|
|
3039
|
+
const i18nShared = I18n.getI18nShared();
|
|
3040
|
+
i18nShared.currentLocale = locale;
|
|
3041
|
+
for (const callback in i18nShared.localeChangedHandlers) {
|
|
3042
|
+
i18nShared.localeChangedHandlers[callback](i18nShared.currentLocale);
|
|
2535
3043
|
}
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
3044
|
+
}
|
|
3045
|
+
/**
|
|
3046
|
+
* Get the locale.
|
|
3047
|
+
* @returns The current locale.
|
|
3048
|
+
*/
|
|
3049
|
+
static getLocale() {
|
|
3050
|
+
const i18nShared = I18n.getI18nShared();
|
|
3051
|
+
return i18nShared.currentLocale;
|
|
3052
|
+
}
|
|
3053
|
+
/**
|
|
3054
|
+
* Add a locale dictionary.
|
|
3055
|
+
* @param locale The locale.
|
|
3056
|
+
* @param dictionary The dictionary to add.
|
|
3057
|
+
*/
|
|
3058
|
+
static addDictionary(locale, dictionary) {
|
|
3059
|
+
const i18nShared = I18n.getI18nShared();
|
|
3060
|
+
const mergedKeys = {};
|
|
3061
|
+
I18n.flattenTranslationKeys(dictionary, "", mergedKeys);
|
|
3062
|
+
i18nShared.localeDictionaries[locale] = mergedKeys;
|
|
3063
|
+
for (const callback in i18nShared.dictionaryChangedHandlers) {
|
|
3064
|
+
i18nShared.dictionaryChangedHandlers[callback](i18nShared.currentLocale);
|
|
2547
3065
|
}
|
|
2548
|
-
return buffer.join("");
|
|
2549
3066
|
}
|
|
2550
3067
|
/**
|
|
2551
|
-
*
|
|
2552
|
-
*
|
|
2553
|
-
* @
|
|
2554
|
-
* @param object2 The second object.
|
|
2555
|
-
* @returns The list of patches.
|
|
3068
|
+
* Get a locale dictionary.
|
|
3069
|
+
* @param locale The locale.
|
|
3070
|
+
* @returns The dictionary of undefined if it does not exist.
|
|
2556
3071
|
*/
|
|
2557
|
-
static
|
|
2558
|
-
const
|
|
2559
|
-
return
|
|
3072
|
+
static getDictionary(locale) {
|
|
3073
|
+
const i18nShared = I18n.getI18nShared();
|
|
3074
|
+
return i18nShared.localeDictionaries[locale];
|
|
2560
3075
|
}
|
|
2561
3076
|
/**
|
|
2562
|
-
*
|
|
2563
|
-
*
|
|
2564
|
-
* @param object The object to patch.
|
|
2565
|
-
* @param patches The second object.
|
|
2566
|
-
* @returns The updated object.
|
|
3077
|
+
* Get all the locale dictionaries.
|
|
3078
|
+
* @returns The dictionaries.
|
|
2567
3079
|
*/
|
|
2568
|
-
static
|
|
2569
|
-
|
|
3080
|
+
static getAllDictionaries() {
|
|
3081
|
+
const i18nShared = I18n.getI18nShared();
|
|
3082
|
+
return i18nShared.localeDictionaries;
|
|
2570
3083
|
}
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
// Copyright 2024 IOTA Stiftung.
|
|
2574
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
2575
|
-
/* eslint-disable no-bitwise */
|
|
2576
|
-
/**
|
|
2577
|
-
* Convert arrays to and from different formats.
|
|
2578
|
-
*/
|
|
2579
|
-
class Converter {
|
|
2580
3084
|
/**
|
|
2581
|
-
*
|
|
2582
|
-
* @
|
|
3085
|
+
* Add a locale changed handler.
|
|
3086
|
+
* @param id The id of the handler.
|
|
3087
|
+
* @param handler The handler to add.
|
|
2583
3088
|
*/
|
|
2584
|
-
static
|
|
3089
|
+
static addLocaleHandler(id, handler) {
|
|
3090
|
+
const i18nShared = I18n.getI18nShared();
|
|
3091
|
+
i18nShared.localeChangedHandlers[id] = handler;
|
|
3092
|
+
}
|
|
2585
3093
|
/**
|
|
2586
|
-
*
|
|
2587
|
-
* @
|
|
3094
|
+
* Remove a locale changed handler.
|
|
3095
|
+
* @param id The id of the handler.
|
|
2588
3096
|
*/
|
|
2589
|
-
static
|
|
3097
|
+
static removeLocaleHandler(id) {
|
|
3098
|
+
const i18nShared = I18n.getI18nShared();
|
|
3099
|
+
delete i18nShared.localeChangedHandlers[id];
|
|
3100
|
+
}
|
|
2590
3101
|
/**
|
|
2591
|
-
*
|
|
2592
|
-
* @param
|
|
2593
|
-
* @param
|
|
2594
|
-
* @param length The length of bytes to read.
|
|
2595
|
-
* @returns The array formatted as UTF8.
|
|
3102
|
+
* Add a dictionary changed handler.
|
|
3103
|
+
* @param id The id of the handler.
|
|
3104
|
+
* @param handler The handler to add.
|
|
2596
3105
|
*/
|
|
2597
|
-
static
|
|
2598
|
-
const
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
str += String.fromCharCode((charCode >> 10) | 0xd800, (charCode & 0x03ff) | 0xdc00);
|
|
2622
|
-
i += 3;
|
|
2623
|
-
}
|
|
3106
|
+
static addDictionaryHandler(id, handler) {
|
|
3107
|
+
const i18nShared = I18n.getI18nShared();
|
|
3108
|
+
i18nShared.dictionaryChangedHandlers[id] = handler;
|
|
3109
|
+
}
|
|
3110
|
+
/**
|
|
3111
|
+
* Remove a dictionary changed handler.
|
|
3112
|
+
* @param id The id of the handler.
|
|
3113
|
+
*/
|
|
3114
|
+
static removeDictionaryHandler(id) {
|
|
3115
|
+
const i18nShared = I18n.getI18nShared();
|
|
3116
|
+
delete i18nShared.dictionaryChangedHandlers[id];
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Format a message.
|
|
3120
|
+
* @param key The key of the message to format.
|
|
3121
|
+
* @param values The values to substitute into the message.
|
|
3122
|
+
* @param overrideLocale Override the locale.
|
|
3123
|
+
* @returns The formatted string.
|
|
3124
|
+
*/
|
|
3125
|
+
static formatMessage(key, values, overrideLocale) {
|
|
3126
|
+
const i18nShared = I18n.getI18nShared();
|
|
3127
|
+
let cl = overrideLocale ?? i18nShared.currentLocale;
|
|
3128
|
+
if (cl.startsWith("debug-")) {
|
|
3129
|
+
cl = I18n.DEFAULT_LOCALE;
|
|
2624
3130
|
}
|
|
2625
|
-
|
|
3131
|
+
if (!i18nShared.localeDictionaries[cl]) {
|
|
3132
|
+
return `!!Missing ${cl}`;
|
|
3133
|
+
}
|
|
3134
|
+
if (!i18nShared.localeDictionaries[cl][key]) {
|
|
3135
|
+
return `!!Missing ${cl}.${key}`;
|
|
3136
|
+
}
|
|
3137
|
+
if (i18nShared.currentLocale === "debug-k") {
|
|
3138
|
+
return key;
|
|
3139
|
+
}
|
|
3140
|
+
let ret = new intlMessageformat.IntlMessageFormat(i18nShared.localeDictionaries[cl][key], cl).format(values);
|
|
3141
|
+
if (i18nShared.currentLocale === "debug-x") {
|
|
3142
|
+
ret = ret.replace(/[a-z]/g, "x").replace(/[A-Z]/g, "x").replace(/\d/g, "n");
|
|
3143
|
+
}
|
|
3144
|
+
return ret;
|
|
2626
3145
|
}
|
|
2627
3146
|
/**
|
|
2628
|
-
*
|
|
2629
|
-
* @param
|
|
2630
|
-
* @returns
|
|
3147
|
+
* Check if the dictionaries have a message for the given key.
|
|
3148
|
+
* @param key The key to check for existence.
|
|
3149
|
+
* @returns True if the key exists.
|
|
2631
3150
|
*/
|
|
2632
|
-
static
|
|
2633
|
-
const
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
3151
|
+
static hasMessage(key) {
|
|
3152
|
+
const i18nShared = I18n.getI18nShared();
|
|
3153
|
+
return Is.string(i18nShared.localeDictionaries[i18nShared.currentLocale]?.[key]);
|
|
3154
|
+
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Flatten the translation property paths for faster lookup.
|
|
3157
|
+
* @param translation The translation to merge.
|
|
3158
|
+
* @param propertyPath The current root path.
|
|
3159
|
+
* @param mergedKeys The merged keys dictionary to populate.
|
|
3160
|
+
* @internal
|
|
3161
|
+
*/
|
|
3162
|
+
static flattenTranslationKeys(translation, propertyPath, mergedKeys) {
|
|
3163
|
+
for (const key in translation) {
|
|
3164
|
+
const val = translation[key];
|
|
3165
|
+
const mergedPath = propertyPath.length > 0 ? `${propertyPath}.${key}` : key;
|
|
3166
|
+
if (Is.string(val)) {
|
|
3167
|
+
mergedKeys[mergedPath] = val;
|
|
2644
3168
|
}
|
|
2645
|
-
else {
|
|
2646
|
-
|
|
2647
|
-
i++;
|
|
2648
|
-
// UTF-16 encodes 0x10000-0x10FFFF by
|
|
2649
|
-
// subtracting 0x10000 and splitting the
|
|
2650
|
-
// 20 bits of 0x0-0xFFFFF into two halves
|
|
2651
|
-
charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (utf8.charCodeAt(i) & 0x3ff));
|
|
2652
|
-
bytes.push(0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
|
|
3169
|
+
else if (Is.object(val)) {
|
|
3170
|
+
I18n.flattenTranslationKeys(val, mergedPath, mergedKeys);
|
|
2653
3171
|
}
|
|
2654
3172
|
}
|
|
2655
|
-
return Uint8Array.from(bytes);
|
|
2656
3173
|
}
|
|
2657
3174
|
/**
|
|
2658
|
-
*
|
|
2659
|
-
* @
|
|
2660
|
-
* @
|
|
2661
|
-
* @param startIndex The index to start in the bytes.
|
|
2662
|
-
* @param length The length of bytes to read.
|
|
2663
|
-
* @param reverse Reverse the combine direction.
|
|
2664
|
-
* @returns The array formatted as hex.
|
|
3175
|
+
* Get the I18n shared data.
|
|
3176
|
+
* @returns The I18n shared data.
|
|
3177
|
+
* @internal
|
|
2665
3178
|
*/
|
|
2666
|
-
static
|
|
2667
|
-
let
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
3179
|
+
static getI18nShared() {
|
|
3180
|
+
let i18nShared = SharedStore.get("i18n");
|
|
3181
|
+
if (Is.undefined(i18nShared)) {
|
|
3182
|
+
i18nShared = {
|
|
3183
|
+
localeDictionaries: {},
|
|
3184
|
+
currentLocale: I18n.DEFAULT_LOCALE,
|
|
3185
|
+
localeChangedHandlers: {},
|
|
3186
|
+
dictionaryChangedHandlers: {}
|
|
3187
|
+
};
|
|
3188
|
+
SharedStore.set("i18n", i18nShared);
|
|
3189
|
+
}
|
|
3190
|
+
return i18nShared;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
// Copyright 2024 IOTA Stiftung.
|
|
3195
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3196
|
+
/**
|
|
3197
|
+
* Error helper functions.
|
|
3198
|
+
*/
|
|
3199
|
+
class ErrorHelper {
|
|
3200
|
+
/**
|
|
3201
|
+
* Format Errors and returns just their messages.
|
|
3202
|
+
* @param error The error to format.
|
|
3203
|
+
* @param includeDetails Whether to include error details, defaults to false.
|
|
3204
|
+
* @returns The error formatted including any causes errors.
|
|
3205
|
+
*/
|
|
3206
|
+
static formatErrors(error, includeDetails) {
|
|
3207
|
+
const localizedErrors = ErrorHelper.localizeErrors(error);
|
|
3208
|
+
if (includeDetails ?? false) {
|
|
3209
|
+
const output = [];
|
|
3210
|
+
for (const err of localizedErrors) {
|
|
3211
|
+
let detailedError = err.message;
|
|
3212
|
+
if (Is.stringValue(err.stack)) {
|
|
3213
|
+
detailedError += `\n${err.stack}`;
|
|
2675
3214
|
}
|
|
3215
|
+
output.push(detailedError);
|
|
2676
3216
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
3217
|
+
return output;
|
|
3218
|
+
}
|
|
3219
|
+
return localizedErrors.map(e => e.message);
|
|
3220
|
+
}
|
|
3221
|
+
/**
|
|
3222
|
+
* Localize the content of an error and any causes.
|
|
3223
|
+
* @param error The error to format.
|
|
3224
|
+
* @returns The localized version of the errors flattened.
|
|
3225
|
+
*/
|
|
3226
|
+
static localizeErrors(error) {
|
|
3227
|
+
const formattedErrors = [];
|
|
3228
|
+
if (Is.notEmpty(error)) {
|
|
3229
|
+
const errors = BaseError.flatten(error);
|
|
3230
|
+
for (const err of errors) {
|
|
3231
|
+
const errorNameKey = `errorNames.${StringHelper.camelCase(err.name)}`;
|
|
3232
|
+
const errorMessageKey = `error.${err.message}`;
|
|
3233
|
+
// If there is no error message then it is probably
|
|
3234
|
+
// from a 3rd party lib, so don't format it just display
|
|
3235
|
+
const hasErrorName = I18n.hasMessage(errorNameKey);
|
|
3236
|
+
const hasErrorMessage = I18n.hasMessage(errorMessageKey);
|
|
3237
|
+
const localizedError = {
|
|
3238
|
+
name: I18n.formatMessage(hasErrorName ? errorNameKey : "errorNames.error"),
|
|
3239
|
+
message: hasErrorMessage
|
|
3240
|
+
? I18n.formatMessage(errorMessageKey, err.properties)
|
|
3241
|
+
: err.message
|
|
3242
|
+
};
|
|
3243
|
+
if (Is.stringValue(err.source)) {
|
|
3244
|
+
localizedError.source = err.source;
|
|
3245
|
+
}
|
|
3246
|
+
if (Is.stringValue(err.stack)) {
|
|
3247
|
+
// Remove the first line from the stack traces as they
|
|
3248
|
+
// just have the error type and message duplicated
|
|
3249
|
+
const lines = err.stack.split("\n");
|
|
3250
|
+
lines.shift();
|
|
3251
|
+
localizedError.stack = lines.join("\n");
|
|
3252
|
+
}
|
|
3253
|
+
const additional = ErrorHelper.formatValidationErrors(err);
|
|
3254
|
+
if (Is.stringValue(additional)) {
|
|
3255
|
+
localizedError.additional = additional;
|
|
2680
3256
|
}
|
|
3257
|
+
formattedErrors.push(localizedError);
|
|
2681
3258
|
}
|
|
2682
3259
|
}
|
|
2683
|
-
return
|
|
3260
|
+
return formattedErrors;
|
|
2684
3261
|
}
|
|
2685
3262
|
/**
|
|
2686
|
-
*
|
|
2687
|
-
* @param
|
|
2688
|
-
* @
|
|
2689
|
-
* @returns The array.
|
|
3263
|
+
* Localize the content of an error and any causes.
|
|
3264
|
+
* @param error The error to format.
|
|
3265
|
+
* @returns The localized version of the errors flattened.
|
|
2690
3266
|
*/
|
|
2691
|
-
static
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
3267
|
+
static formatValidationErrors(error) {
|
|
3268
|
+
if (Is.object(error.properties) &&
|
|
3269
|
+
Object.keys(error.properties).length > 0 &&
|
|
3270
|
+
Is.object(error.properties) &&
|
|
3271
|
+
Is.arrayValue(error.properties.validationFailures)) {
|
|
3272
|
+
const validationErrors = [];
|
|
3273
|
+
for (const validationFailure of error.properties.validationFailures) {
|
|
3274
|
+
const errorI18n = `error.${validationFailure.reason}`;
|
|
3275
|
+
const errorMessage = I18n.hasMessage(errorI18n)
|
|
3276
|
+
? I18n.formatMessage(errorI18n, validationFailure.properties)
|
|
3277
|
+
: errorI18n;
|
|
3278
|
+
let v = `${validationFailure.property}: ${errorMessage}`;
|
|
3279
|
+
if (Is.object(validationFailure.properties) &&
|
|
3280
|
+
Is.notEmpty(validationFailure.properties.value)) {
|
|
3281
|
+
v += ` = ${JSON.stringify(validationFailure.properties.value)}`;
|
|
3282
|
+
}
|
|
3283
|
+
validationErrors.push(v);
|
|
2707
3284
|
}
|
|
3285
|
+
return validationErrors.join("\n");
|
|
2708
3286
|
}
|
|
2709
|
-
return array;
|
|
2710
|
-
}
|
|
2711
|
-
/**
|
|
2712
|
-
* Convert the UTF8 to hex.
|
|
2713
|
-
* @param utf8 The text to convert.
|
|
2714
|
-
* @param includePrefix Include the 0x prefix on the returned hex.
|
|
2715
|
-
* @returns The hex version of the bytes.
|
|
2716
|
-
*/
|
|
2717
|
-
static utf8ToHex(utf8, includePrefix = false) {
|
|
2718
|
-
const hex = Converter.bytesToHex(Converter.utf8ToBytes(utf8));
|
|
2719
|
-
return includePrefix ? HexHelper.addPrefix(hex) : hex;
|
|
2720
3287
|
}
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
// Copyright 2024 IOTA Stiftung.
|
|
3291
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3292
|
+
/**
|
|
3293
|
+
* The types the extracted data can be coerced to.
|
|
3294
|
+
*/
|
|
3295
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3296
|
+
const CoerceType = {
|
|
2721
3297
|
/**
|
|
2722
|
-
*
|
|
2723
|
-
* @param hex The hex to convert.
|
|
2724
|
-
* @returns The UTF8 version of the bytes.
|
|
3298
|
+
* String.
|
|
2725
3299
|
*/
|
|
2726
|
-
|
|
2727
|
-
return Converter.bytesToUtf8(Converter.hexToBytes(HexHelper.stripPrefix(hex)));
|
|
2728
|
-
}
|
|
3300
|
+
String: "string",
|
|
2729
3301
|
/**
|
|
2730
|
-
*
|
|
2731
|
-
* @param bytes The bytes to convert.
|
|
2732
|
-
* @returns A binary string of the bytes.
|
|
3302
|
+
* Number.
|
|
2733
3303
|
*/
|
|
2734
|
-
|
|
2735
|
-
const b = [];
|
|
2736
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
2737
|
-
b.push(bytes[i].toString(2).padStart(8, "0"));
|
|
2738
|
-
}
|
|
2739
|
-
return b.join("");
|
|
2740
|
-
}
|
|
3304
|
+
Number: "number",
|
|
2741
3305
|
/**
|
|
2742
|
-
*
|
|
2743
|
-
* @param binary The binary string.
|
|
2744
|
-
* @returns The bytes.
|
|
3306
|
+
* Integer.
|
|
2745
3307
|
*/
|
|
2746
|
-
|
|
2747
|
-
const bytes = new Uint8Array(Math.ceil(binary.length / 8));
|
|
2748
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
2749
|
-
bytes[i] = Number.parseInt(binary.slice(i * 8, (i + 1) * 8), 2);
|
|
2750
|
-
}
|
|
2751
|
-
return bytes;
|
|
2752
|
-
}
|
|
3308
|
+
Integer: "integer",
|
|
2753
3309
|
/**
|
|
2754
|
-
*
|
|
2755
|
-
* @param bytes The bytes to convert.
|
|
2756
|
-
* @returns A base64 string of the bytes.
|
|
3310
|
+
* Boolean.
|
|
2757
3311
|
*/
|
|
2758
|
-
|
|
2759
|
-
return Base64.encode(bytes);
|
|
2760
|
-
}
|
|
3312
|
+
Boolean: "boolean",
|
|
2761
3313
|
/**
|
|
2762
|
-
*
|
|
2763
|
-
* @param base64 The base64 string.
|
|
2764
|
-
* @returns The bytes.
|
|
3314
|
+
* Big Integer.
|
|
2765
3315
|
*/
|
|
2766
|
-
|
|
2767
|
-
return Base64.decode(base64);
|
|
2768
|
-
}
|
|
3316
|
+
BigInt: "bigint",
|
|
2769
3317
|
/**
|
|
2770
|
-
*
|
|
2771
|
-
* @param bytes The bytes to convert.
|
|
2772
|
-
* @returns A base64 url string of the bytes.
|
|
3318
|
+
* Date.
|
|
2773
3319
|
*/
|
|
2774
|
-
|
|
2775
|
-
return Base64Url.encode(bytes);
|
|
2776
|
-
}
|
|
3320
|
+
Date: "date",
|
|
2777
3321
|
/**
|
|
2778
|
-
*
|
|
2779
|
-
* @param base64Url The base64 url string.
|
|
2780
|
-
* @returns The bytes.
|
|
3322
|
+
* Date Time.
|
|
2781
3323
|
*/
|
|
2782
|
-
|
|
2783
|
-
return Base64Url.decode(base64Url);
|
|
2784
|
-
}
|
|
3324
|
+
DateTime: "datetime",
|
|
2785
3325
|
/**
|
|
2786
|
-
*
|
|
2787
|
-
* @param bytes The bytes to convert.
|
|
2788
|
-
* @returns A base58 string of the bytes.
|
|
3326
|
+
* Time.
|
|
2789
3327
|
*/
|
|
2790
|
-
|
|
2791
|
-
return Base58.encode(bytes);
|
|
2792
|
-
}
|
|
3328
|
+
Time: "time",
|
|
2793
3329
|
/**
|
|
2794
|
-
*
|
|
2795
|
-
* @param base58 The base58 string.
|
|
2796
|
-
* @returns The bytes.
|
|
3330
|
+
* Object.
|
|
2797
3331
|
*/
|
|
2798
|
-
|
|
2799
|
-
return Base58.decode(base58);
|
|
2800
|
-
}
|
|
3332
|
+
Object: "object",
|
|
2801
3333
|
/**
|
|
2802
|
-
*
|
|
2803
|
-
* @internal
|
|
3334
|
+
* Uint8Array.
|
|
2804
3335
|
*/
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
const alphabet = "0123456789abcdef";
|
|
2808
|
-
Converter._ENCODE_LOOKUP = [];
|
|
2809
|
-
Converter._DECODE_LOOKUP = [];
|
|
2810
|
-
for (let i = 0; i < 256; i++) {
|
|
2811
|
-
Converter._ENCODE_LOOKUP[i] = alphabet[(i >> 4) & 0xf] + alphabet[i & 0xf];
|
|
2812
|
-
if (i < 16) {
|
|
2813
|
-
if (i < 10) {
|
|
2814
|
-
Converter._DECODE_LOOKUP[0x30 + i] = i;
|
|
2815
|
-
}
|
|
2816
|
-
else {
|
|
2817
|
-
Converter._DECODE_LOOKUP[0x61 - 10 + i] = i;
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
3336
|
+
Uint8Array: "uint8array"
|
|
3337
|
+
};
|
|
2824
3338
|
|
|
3339
|
+
// Copyright 2024 IOTA Stiftung.
|
|
3340
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
2825
3341
|
/**
|
|
2826
|
-
*
|
|
3342
|
+
* Coerce an object from one type to another.
|
|
2827
3343
|
*/
|
|
2828
|
-
class
|
|
2829
|
-
/**
|
|
2830
|
-
* Runtime name for the class.
|
|
2831
|
-
* @internal
|
|
2832
|
-
*/
|
|
2833
|
-
static _CLASS_NAME = "ObjectHelper";
|
|
3344
|
+
class Coerce {
|
|
2834
3345
|
/**
|
|
2835
|
-
*
|
|
2836
|
-
* @param
|
|
2837
|
-
* @
|
|
2838
|
-
* @returns The
|
|
3346
|
+
* Coerce the value to a string.
|
|
3347
|
+
* @param value The value to coerce.
|
|
3348
|
+
* @throws TypeError If the value can not be coerced.
|
|
3349
|
+
* @returns The value if it can be coerced.
|
|
2839
3350
|
*/
|
|
2840
|
-
static
|
|
2841
|
-
if (
|
|
2842
|
-
return
|
|
3351
|
+
static string(value) {
|
|
3352
|
+
if (Is.undefined(value)) {
|
|
3353
|
+
return value;
|
|
3354
|
+
}
|
|
3355
|
+
if (Is.string(value)) {
|
|
3356
|
+
return value;
|
|
3357
|
+
}
|
|
3358
|
+
if (Is.number(value)) {
|
|
3359
|
+
return value.toString();
|
|
3360
|
+
}
|
|
3361
|
+
if (Is.boolean(value)) {
|
|
3362
|
+
return value ? "true" : "false";
|
|
3363
|
+
}
|
|
3364
|
+
if (Is.date(value)) {
|
|
3365
|
+
return value.toISOString();
|
|
2843
3366
|
}
|
|
2844
|
-
const json = format ? JSON.stringify(obj, undefined, "\t") : JSON.stringify(obj);
|
|
2845
|
-
return Converter.utf8ToBytes(json);
|
|
2846
3367
|
}
|
|
2847
3368
|
/**
|
|
2848
|
-
*
|
|
2849
|
-
* @param
|
|
2850
|
-
* @
|
|
2851
|
-
* @
|
|
3369
|
+
* Coerce the value to a number.
|
|
3370
|
+
* @param value The value to coerce.
|
|
3371
|
+
* @throws TypeError If the value can not be coerced.
|
|
3372
|
+
* @returns The value if it can be coerced.
|
|
2852
3373
|
*/
|
|
2853
|
-
static
|
|
2854
|
-
if (Is.
|
|
2855
|
-
return
|
|
3374
|
+
static number(value) {
|
|
3375
|
+
if (Is.undefined(value)) {
|
|
3376
|
+
return value;
|
|
2856
3377
|
}
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
return JSON.parse(utf8);
|
|
3378
|
+
if (Is.number(value)) {
|
|
3379
|
+
return value;
|
|
2860
3380
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
3381
|
+
if (Is.string(value)) {
|
|
3382
|
+
const parsed = Number.parseFloat(value);
|
|
3383
|
+
if (Is.number(parsed)) {
|
|
3384
|
+
return parsed;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
if (Is.boolean(value)) {
|
|
3388
|
+
return value ? 1 : 0;
|
|
3389
|
+
}
|
|
3390
|
+
if (Is.date(value)) {
|
|
3391
|
+
return value.getTime();
|
|
2863
3392
|
}
|
|
2864
3393
|
}
|
|
2865
3394
|
/**
|
|
2866
|
-
*
|
|
2867
|
-
* @param
|
|
2868
|
-
* @
|
|
3395
|
+
* Coerce the value to an integer.
|
|
3396
|
+
* @param value The value to coerce.
|
|
3397
|
+
* @throws TypeError If the value can not be coerced.
|
|
3398
|
+
* @returns The value if it can be coerced.
|
|
2869
3399
|
*/
|
|
2870
|
-
static
|
|
2871
|
-
|
|
2872
|
-
|
|
3400
|
+
static integer(value) {
|
|
3401
|
+
const num = Coerce.number(value);
|
|
3402
|
+
if (!Is.undefined(num)) {
|
|
3403
|
+
return Math.trunc(num);
|
|
2873
3404
|
}
|
|
2874
|
-
return structuredClone(obj);
|
|
2875
3405
|
}
|
|
2876
3406
|
/**
|
|
2877
|
-
*
|
|
2878
|
-
* @param
|
|
2879
|
-
* @
|
|
2880
|
-
* @returns The
|
|
3407
|
+
* Coerce the value to a bigint.
|
|
3408
|
+
* @param value The value to coerce.
|
|
3409
|
+
* @throws TypeError If the value can not be coerced.
|
|
3410
|
+
* @returns The value if it can be coerced.
|
|
2881
3411
|
*/
|
|
2882
|
-
static
|
|
2883
|
-
if (Is.
|
|
2884
|
-
return
|
|
3412
|
+
static bigint(value) {
|
|
3413
|
+
if (Is.undefined(value)) {
|
|
3414
|
+
return value;
|
|
2885
3415
|
}
|
|
2886
|
-
if (Is.
|
|
2887
|
-
return
|
|
3416
|
+
if (Is.bigint(value)) {
|
|
3417
|
+
return value;
|
|
2888
3418
|
}
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
3419
|
+
if (Is.number(value)) {
|
|
3420
|
+
return BigInt(value);
|
|
3421
|
+
}
|
|
3422
|
+
if (Is.string(value)) {
|
|
3423
|
+
const parsed = Number.parseFloat(value);
|
|
3424
|
+
if (Is.integer(parsed)) {
|
|
3425
|
+
return BigInt(parsed);
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
if (Is.boolean(value)) {
|
|
3429
|
+
return value ? 1n : 0n;
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
/**
|
|
3433
|
+
* Coerce the value to a boolean.
|
|
3434
|
+
* @param value The value to coerce.
|
|
3435
|
+
* @throws TypeError If the value can not be coerced.
|
|
3436
|
+
* @returns The value if it can be coerced.
|
|
3437
|
+
*/
|
|
3438
|
+
static boolean(value) {
|
|
3439
|
+
if (Is.undefined(value)) {
|
|
3440
|
+
return value;
|
|
3441
|
+
}
|
|
3442
|
+
if (Is.boolean(value)) {
|
|
3443
|
+
return value;
|
|
3444
|
+
}
|
|
3445
|
+
if (Is.number(value)) {
|
|
3446
|
+
// eslint-disable-next-line no-unneeded-ternary
|
|
3447
|
+
return value ? true : false;
|
|
3448
|
+
}
|
|
3449
|
+
if (Is.string(value)) {
|
|
3450
|
+
if (/true/i.test(value)) {
|
|
3451
|
+
return true;
|
|
3452
|
+
}
|
|
3453
|
+
if (/false/i.test(value)) {
|
|
3454
|
+
return false;
|
|
2899
3455
|
}
|
|
2900
3456
|
}
|
|
2901
|
-
return obj1Clone;
|
|
2902
3457
|
}
|
|
2903
3458
|
/**
|
|
2904
|
-
*
|
|
2905
|
-
* @param
|
|
2906
|
-
* @
|
|
2907
|
-
* @
|
|
2908
|
-
* @returns True is the objects are equal.
|
|
3459
|
+
* Coerce the value to a date.
|
|
3460
|
+
* @param value The value to coerce.
|
|
3461
|
+
* @throws TypeError If the value can not be coerced.
|
|
3462
|
+
* @returns The value if it can be coerced.
|
|
2909
3463
|
*/
|
|
2910
|
-
static
|
|
2911
|
-
if (
|
|
2912
|
-
return
|
|
3464
|
+
static date(value) {
|
|
3465
|
+
if (Is.undefined(value)) {
|
|
3466
|
+
return value;
|
|
3467
|
+
}
|
|
3468
|
+
if (Is.date(value)) {
|
|
3469
|
+
return value;
|
|
3470
|
+
}
|
|
3471
|
+
if (Is.number(value)) {
|
|
3472
|
+
return new Date(value);
|
|
3473
|
+
}
|
|
3474
|
+
if (Is.string(value)) {
|
|
3475
|
+
const dt = new Date(value);
|
|
3476
|
+
if (!Number.isNaN(dt.getTime())) {
|
|
3477
|
+
const utc = Date.UTC(dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate());
|
|
3478
|
+
return new Date(utc);
|
|
3479
|
+
}
|
|
2913
3480
|
}
|
|
2914
|
-
return JsonHelper.canonicalize(obj1) === JsonHelper.canonicalize(obj2);
|
|
2915
3481
|
}
|
|
2916
3482
|
/**
|
|
2917
|
-
*
|
|
2918
|
-
* @param
|
|
2919
|
-
* @
|
|
2920
|
-
* @returns The
|
|
3483
|
+
* Coerce the value to a date/time.
|
|
3484
|
+
* @param value The value to coerce.
|
|
3485
|
+
* @throws TypeError If the value can not be coerced.
|
|
3486
|
+
* @returns The value if it can be coerced.
|
|
2921
3487
|
*/
|
|
2922
|
-
static
|
|
2923
|
-
if (
|
|
2924
|
-
const parts = property.split(".");
|
|
2925
|
-
let value = obj;
|
|
2926
|
-
for (const part of parts) {
|
|
2927
|
-
if (Is.object(value)) {
|
|
2928
|
-
value = value[part];
|
|
2929
|
-
}
|
|
2930
|
-
else {
|
|
2931
|
-
return undefined;
|
|
2932
|
-
}
|
|
2933
|
-
}
|
|
3488
|
+
static dateTime(value) {
|
|
3489
|
+
if (Is.undefined(value)) {
|
|
2934
3490
|
return value;
|
|
2935
3491
|
}
|
|
2936
|
-
|
|
3492
|
+
if (Is.date(value)) {
|
|
3493
|
+
return value;
|
|
3494
|
+
}
|
|
3495
|
+
if (Is.number(value)) {
|
|
3496
|
+
return new Date(value);
|
|
3497
|
+
}
|
|
3498
|
+
if (Is.string(value)) {
|
|
3499
|
+
const dt = new Date(value);
|
|
3500
|
+
if (!Number.isNaN(dt.getTime())) {
|
|
3501
|
+
const utc = Date.UTC(dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate(), dt.getUTCHours(), dt.getUTCMinutes(), dt.getUTCSeconds(), dt.getUTCMilliseconds());
|
|
3502
|
+
return new Date(utc);
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
2937
3505
|
}
|
|
2938
3506
|
/**
|
|
2939
|
-
*
|
|
2940
|
-
* @param
|
|
2941
|
-
* @
|
|
2942
|
-
* @
|
|
3507
|
+
* Coerce the value to a time.
|
|
3508
|
+
* @param value The value to coerce.
|
|
3509
|
+
* @throws TypeError If the value can not be coerced.
|
|
3510
|
+
* @returns The value if it can be coerced.
|
|
2943
3511
|
*/
|
|
2944
|
-
static
|
|
2945
|
-
if (Is.
|
|
2946
|
-
|
|
3512
|
+
static time(value) {
|
|
3513
|
+
if (Is.undefined(value)) {
|
|
3514
|
+
return value;
|
|
3515
|
+
}
|
|
3516
|
+
if (Is.date(value)) {
|
|
3517
|
+
return value;
|
|
3518
|
+
}
|
|
3519
|
+
if (Is.number(value)) {
|
|
3520
|
+
const dt = new Date(value);
|
|
3521
|
+
dt.setFullYear(1970, 0, 1);
|
|
3522
|
+
return dt;
|
|
3523
|
+
}
|
|
3524
|
+
if (Is.string(value)) {
|
|
3525
|
+
const dt = new Date(value);
|
|
3526
|
+
if (!Number.isNaN(dt.getTime())) {
|
|
3527
|
+
const utc = Date.UTC(1970, 0, 1, dt.getUTCHours(), dt.getUTCMinutes(), dt.getUTCSeconds(), dt.getUTCMilliseconds());
|
|
3528
|
+
return new Date(utc);
|
|
3529
|
+
}
|
|
2947
3530
|
}
|
|
2948
3531
|
}
|
|
2949
3532
|
/**
|
|
2950
|
-
*
|
|
2951
|
-
* @param
|
|
2952
|
-
* @
|
|
3533
|
+
* Coerce the value to an object.
|
|
3534
|
+
* @param value The value to coerce.
|
|
3535
|
+
* @throws TypeError If the value can not be coerced.
|
|
3536
|
+
* @returns The value if it can be coerced.
|
|
2953
3537
|
*/
|
|
2954
|
-
static
|
|
2955
|
-
if (Is.
|
|
2956
|
-
|
|
3538
|
+
static object(value) {
|
|
3539
|
+
if (Is.undefined(value)) {
|
|
3540
|
+
return value;
|
|
3541
|
+
}
|
|
3542
|
+
if (Is.object(value)) {
|
|
3543
|
+
return value;
|
|
3544
|
+
}
|
|
3545
|
+
if (Is.stringValue(value)) {
|
|
3546
|
+
try {
|
|
3547
|
+
return JSON.parse(value);
|
|
3548
|
+
}
|
|
3549
|
+
catch { }
|
|
2957
3550
|
}
|
|
2958
3551
|
}
|
|
2959
3552
|
/**
|
|
2960
|
-
*
|
|
2961
|
-
* @param
|
|
2962
|
-
* @
|
|
2963
|
-
* @
|
|
2964
|
-
* @returns The property if available.
|
|
3553
|
+
* Coerce the value to a Uint8Array.
|
|
3554
|
+
* @param value The value to coerce.
|
|
3555
|
+
* @throws TypeError If the value can not be coerced.
|
|
3556
|
+
* @returns The value if it can be coerced.
|
|
2965
3557
|
*/
|
|
2966
|
-
static
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3558
|
+
static uint8Array(value) {
|
|
3559
|
+
if (Is.undefined(value)) {
|
|
3560
|
+
return value;
|
|
3561
|
+
}
|
|
3562
|
+
if (Is.string(value)) {
|
|
3563
|
+
if (Is.stringHex(value.toLowerCase(), true)) {
|
|
3564
|
+
return Converter.hexToBytes(value.toLowerCase());
|
|
3565
|
+
}
|
|
3566
|
+
if (Is.stringBase64(value)) {
|
|
3567
|
+
return Converter.base64ToBytes(value);
|
|
2975
3568
|
}
|
|
2976
3569
|
}
|
|
2977
|
-
return retVal;
|
|
2978
3570
|
}
|
|
2979
3571
|
/**
|
|
2980
|
-
*
|
|
2981
|
-
* @param
|
|
2982
|
-
* @param
|
|
2983
|
-
* @returns The
|
|
2984
|
-
*/
|
|
2985
|
-
static
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3572
|
+
* Coerces a value based on the coercion type.
|
|
3573
|
+
* @param value The value to coerce.
|
|
3574
|
+
* @param type The coercion type to perform.
|
|
3575
|
+
* @returns The coerced value.
|
|
3576
|
+
*/
|
|
3577
|
+
static byType(value, type) {
|
|
3578
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
3579
|
+
switch (type) {
|
|
3580
|
+
case CoerceType.String:
|
|
3581
|
+
return Coerce.string(value);
|
|
3582
|
+
case CoerceType.Number:
|
|
3583
|
+
return Coerce.number(value);
|
|
3584
|
+
case CoerceType.Integer:
|
|
3585
|
+
return Coerce.integer(value);
|
|
3586
|
+
case CoerceType.BigInt:
|
|
3587
|
+
return Coerce.bigint(value);
|
|
3588
|
+
case CoerceType.Boolean:
|
|
3589
|
+
return Coerce.boolean(value);
|
|
3590
|
+
case CoerceType.Date:
|
|
3591
|
+
return Coerce.date(value);
|
|
3592
|
+
case CoerceType.DateTime:
|
|
3593
|
+
return Coerce.dateTime(value);
|
|
3594
|
+
case CoerceType.Time:
|
|
3595
|
+
return Coerce.time(value);
|
|
3596
|
+
case CoerceType.Object:
|
|
3597
|
+
return Coerce.object(value);
|
|
3598
|
+
case CoerceType.Uint8Array:
|
|
3599
|
+
return Coerce.uint8Array(value);
|
|
3600
|
+
default:
|
|
3601
|
+
return value;
|
|
2992
3602
|
}
|
|
2993
|
-
return obj;
|
|
2994
3603
|
}
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3606
|
+
// Copyright 2024 IOTA Stiftung.
|
|
3607
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3608
|
+
/**
|
|
3609
|
+
* Class to help with filenames.
|
|
3610
|
+
*/
|
|
3611
|
+
class FilenameHelper {
|
|
2995
3612
|
/**
|
|
2996
|
-
*
|
|
2997
|
-
* @param
|
|
2998
|
-
* @
|
|
2999
|
-
* @returns The partial object.
|
|
3613
|
+
* Replaces any unsafe characters in the filename.
|
|
3614
|
+
* @param filename The filename to make safe.
|
|
3615
|
+
* @returns The safe filename.
|
|
3000
3616
|
*/
|
|
3001
|
-
static
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
delete result[key];
|
|
3006
|
-
}
|
|
3007
|
-
return result;
|
|
3617
|
+
static safeFilename(filename) {
|
|
3618
|
+
let safe = Coerce.string(filename);
|
|
3619
|
+
if (Is.empty(safe)) {
|
|
3620
|
+
return "";
|
|
3008
3621
|
}
|
|
3009
|
-
|
|
3622
|
+
// Common non filename characters
|
|
3623
|
+
safe = safe.replace(/["*/:<>?\\|]/g, "_");
|
|
3624
|
+
// Windows non filename characters
|
|
3625
|
+
safe = safe.replace(/^(con|prn|aux|nul|com\d|lpt\d)$/i, "_");
|
|
3626
|
+
// Control characters
|
|
3627
|
+
safe = safe.replace(/[\u0000-\u001F\u0080-\u009F]/g, "_");
|
|
3628
|
+
// Relative paths
|
|
3629
|
+
safe = safe.replace(/^\.+/, "_");
|
|
3630
|
+
// Trailing periods
|
|
3631
|
+
safe = safe.replace(/\.+$/, "");
|
|
3632
|
+
return safe;
|
|
3010
3633
|
}
|
|
3011
3634
|
}
|
|
3012
3635
|
|
|
@@ -3028,6 +3651,32 @@ class RandomHelper {
|
|
|
3028
3651
|
}
|
|
3029
3652
|
}
|
|
3030
3653
|
|
|
3654
|
+
// Copyright 2024 IOTA Stiftung.
|
|
3655
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3656
|
+
/**
|
|
3657
|
+
* Class to help with uint8 arrays.
|
|
3658
|
+
*/
|
|
3659
|
+
class Uint8ArrayHelper {
|
|
3660
|
+
/**
|
|
3661
|
+
* Concatenate multiple arrays.
|
|
3662
|
+
* @param arrays The array to concatenate.
|
|
3663
|
+
* @returns The combined array.
|
|
3664
|
+
*/
|
|
3665
|
+
static concat(arrays) {
|
|
3666
|
+
let totalLength = 0;
|
|
3667
|
+
for (const array of arrays) {
|
|
3668
|
+
totalLength += array.length;
|
|
3669
|
+
}
|
|
3670
|
+
const concatBytes = new Uint8Array(totalLength);
|
|
3671
|
+
let offset = 0;
|
|
3672
|
+
for (const array of arrays) {
|
|
3673
|
+
concatBytes.set(array, offset);
|
|
3674
|
+
offset += array.length;
|
|
3675
|
+
}
|
|
3676
|
+
return concatBytes;
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3031
3680
|
// Copyright 2024 IOTA Stiftung.
|
|
3032
3681
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3033
3682
|
/**
|
|
@@ -3040,7 +3689,7 @@ const CompressionType = {
|
|
|
3040
3689
|
*/
|
|
3041
3690
|
Gzip: "gzip",
|
|
3042
3691
|
/**
|
|
3043
|
-
*
|
|
3692
|
+
* Deflate.
|
|
3044
3693
|
*/
|
|
3045
3694
|
Deflate: "deflate"
|
|
3046
3695
|
};
|
|
@@ -3491,29 +4140,93 @@ class Urn {
|
|
|
3491
4140
|
* Cache the results from asynchronous requests.
|
|
3492
4141
|
*/
|
|
3493
4142
|
class AsyncCache {
|
|
3494
|
-
/**
|
|
3495
|
-
* Cache for the fetch requests.
|
|
3496
|
-
* @internal
|
|
3497
|
-
*/
|
|
3498
|
-
static _cache = {};
|
|
3499
4143
|
/**
|
|
3500
4144
|
* Execute an async request and cache the result.
|
|
3501
4145
|
* @param key The key for the entry in the cache.
|
|
3502
4146
|
* @param ttlMs The TTL of the entry in the cache.
|
|
3503
4147
|
* @param requestMethod The method to call if not cached.
|
|
4148
|
+
* @param cacheFailures Cache failure results, defaults to false.
|
|
3504
4149
|
* @returns The response.
|
|
3505
4150
|
*/
|
|
3506
|
-
static exec(key, ttlMs, requestMethod) {
|
|
4151
|
+
static exec(key, ttlMs, requestMethod, cacheFailures) {
|
|
3507
4152
|
const cacheEnabled = Is.integer(ttlMs) && ttlMs >= 0;
|
|
3508
4153
|
if (cacheEnabled) {
|
|
3509
4154
|
AsyncCache.cleanupExpired();
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
4155
|
+
const cache = AsyncCache.getSharedCache();
|
|
4156
|
+
// Do we have a cache entry for the key
|
|
4157
|
+
if (cache[key]) {
|
|
4158
|
+
if (!Is.empty(cache[key].result)) {
|
|
4159
|
+
// If the cache has already resulted in a value, resolve it
|
|
4160
|
+
return Promise.resolve(cache[key].result);
|
|
4161
|
+
}
|
|
4162
|
+
else if (!Is.empty(cache[key].error)) {
|
|
4163
|
+
// If the cache has already resulted in an error, reject it
|
|
4164
|
+
return Promise.reject(cache[key].error);
|
|
4165
|
+
}
|
|
4166
|
+
// Otherwise create a promise to return and store the resolver
|
|
4167
|
+
// and rejector in the cache entry, so that we can call then
|
|
4168
|
+
// when the request is done
|
|
4169
|
+
let storedResolve;
|
|
4170
|
+
let storedReject;
|
|
4171
|
+
const wait = new Promise((resolve, reject) => {
|
|
4172
|
+
storedResolve = resolve;
|
|
4173
|
+
storedReject = reject;
|
|
4174
|
+
});
|
|
4175
|
+
if (!Is.empty(storedResolve) && !Is.empty(storedReject)) {
|
|
4176
|
+
cache[key].promiseQueue.push({
|
|
4177
|
+
requestMethod,
|
|
4178
|
+
resolve: storedResolve,
|
|
4179
|
+
reject: storedReject
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
return wait;
|
|
3515
4183
|
}
|
|
3516
|
-
|
|
4184
|
+
// If we don't have a cache entry, create a new one
|
|
4185
|
+
cache[key] = {
|
|
4186
|
+
promiseQueue: [],
|
|
4187
|
+
expires: ttlMs === 0 ? 0 : Date.now() + ttlMs
|
|
4188
|
+
};
|
|
4189
|
+
// Return a promise that wraps the original request method
|
|
4190
|
+
// so that we can store any results or errors in the cache
|
|
4191
|
+
return new Promise((resolve, reject) => {
|
|
4192
|
+
// Call the request method and store the result
|
|
4193
|
+
requestMethod()
|
|
4194
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
4195
|
+
.then(res => {
|
|
4196
|
+
// If the request was successful, store the result
|
|
4197
|
+
cache[key].result = res;
|
|
4198
|
+
// and resolve both this promise and all the waiters
|
|
4199
|
+
resolve(res);
|
|
4200
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4201
|
+
wait.resolve(res);
|
|
4202
|
+
}
|
|
4203
|
+
return res;
|
|
4204
|
+
})
|
|
4205
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
4206
|
+
.catch((err) => {
|
|
4207
|
+
// Reject the promise
|
|
4208
|
+
reject(err);
|
|
4209
|
+
// Handle the waiters based on the cacheFailures flag
|
|
4210
|
+
if (cacheFailures ?? false) {
|
|
4211
|
+
// If we are caching failures, store the error and reject the waiters
|
|
4212
|
+
cache[key].error = err;
|
|
4213
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4214
|
+
wait.reject(err);
|
|
4215
|
+
}
|
|
4216
|
+
// Clear the waiters so we don't call them again
|
|
4217
|
+
cache[key].promiseQueue = [];
|
|
4218
|
+
}
|
|
4219
|
+
else {
|
|
4220
|
+
// If not caching failures for any queued requests we
|
|
4221
|
+
// have no value to either resolve or reject, so we
|
|
4222
|
+
// just resolve with the original request method
|
|
4223
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4224
|
+
wait.resolve(wait.requestMethod());
|
|
4225
|
+
}
|
|
4226
|
+
delete cache[key];
|
|
4227
|
+
}
|
|
4228
|
+
});
|
|
4229
|
+
});
|
|
3517
4230
|
}
|
|
3518
4231
|
}
|
|
3519
4232
|
/**
|
|
@@ -3522,41 +4235,80 @@ class AsyncCache {
|
|
|
3522
4235
|
* @returns The item from the cache if it exists.
|
|
3523
4236
|
*/
|
|
3524
4237
|
static async get(key) {
|
|
3525
|
-
|
|
4238
|
+
const cache = AsyncCache.getSharedCache();
|
|
4239
|
+
if (!Is.empty(cache[key].result)) {
|
|
4240
|
+
// If the cache has already resulted in a value, resolve it
|
|
4241
|
+
return cache[key].result;
|
|
4242
|
+
}
|
|
4243
|
+
else if (!Is.empty(cache[key].error)) {
|
|
4244
|
+
// If the cache has already resulted in an error, reject it
|
|
4245
|
+
throw cache[key].error;
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
/**
|
|
4249
|
+
* Set an entry into the cache.
|
|
4250
|
+
* @param key The key to set in the cache.
|
|
4251
|
+
* @param value The value to set in the cache.
|
|
4252
|
+
* @param ttlMs The TTL of the entry in the cache in ms, defaults to 1s.
|
|
4253
|
+
* @returns Nothing.
|
|
4254
|
+
*/
|
|
4255
|
+
static async set(key, value, ttlMs) {
|
|
4256
|
+
const cache = AsyncCache.getSharedCache();
|
|
4257
|
+
cache[key] = {
|
|
4258
|
+
result: value,
|
|
4259
|
+
promiseQueue: [],
|
|
4260
|
+
expires: Date.now() + (ttlMs ?? 1000)
|
|
4261
|
+
};
|
|
3526
4262
|
}
|
|
3527
4263
|
/**
|
|
3528
4264
|
* Remove an entry from the cache.
|
|
3529
4265
|
* @param key The key to remove from the cache.
|
|
3530
4266
|
*/
|
|
3531
4267
|
static remove(key) {
|
|
3532
|
-
|
|
4268
|
+
const cache = AsyncCache.getSharedCache();
|
|
4269
|
+
delete cache[key];
|
|
3533
4270
|
}
|
|
3534
4271
|
/**
|
|
3535
4272
|
* Clear the cache.
|
|
3536
4273
|
* @param prefix Optional prefix to clear only entries with that prefix.
|
|
3537
4274
|
*/
|
|
3538
4275
|
static clearCache(prefix) {
|
|
4276
|
+
const cache = AsyncCache.getSharedCache();
|
|
3539
4277
|
if (Is.stringValue(prefix)) {
|
|
3540
|
-
for (const entry in
|
|
4278
|
+
for (const entry in cache) {
|
|
3541
4279
|
if (entry.startsWith(prefix)) {
|
|
3542
|
-
delete
|
|
4280
|
+
delete cache[entry];
|
|
3543
4281
|
}
|
|
3544
4282
|
}
|
|
3545
4283
|
}
|
|
3546
4284
|
else {
|
|
3547
|
-
|
|
4285
|
+
SharedStore.set("asyncCache", {});
|
|
3548
4286
|
}
|
|
3549
4287
|
}
|
|
3550
4288
|
/**
|
|
3551
4289
|
* Perform a cleanup of the expired entries in the cache.
|
|
3552
4290
|
*/
|
|
3553
4291
|
static cleanupExpired() {
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
4292
|
+
const cache = AsyncCache.getSharedCache();
|
|
4293
|
+
for (const entry in cache) {
|
|
4294
|
+
if (cache[entry].expires > 0 && cache[entry].expires < Date.now()) {
|
|
4295
|
+
delete cache[entry];
|
|
3557
4296
|
}
|
|
3558
4297
|
}
|
|
3559
4298
|
}
|
|
4299
|
+
/**
|
|
4300
|
+
* Get the shared cache.
|
|
4301
|
+
* @returns The shared cache.
|
|
4302
|
+
* @internal
|
|
4303
|
+
*/
|
|
4304
|
+
static getSharedCache() {
|
|
4305
|
+
let sharedCache = SharedStore.get("asyncCache");
|
|
4306
|
+
if (Is.undefined(sharedCache)) {
|
|
4307
|
+
sharedCache = {};
|
|
4308
|
+
SharedStore.set("asyncCache", sharedCache);
|
|
4309
|
+
}
|
|
4310
|
+
return sharedCache;
|
|
4311
|
+
}
|
|
3560
4312
|
}
|
|
3561
4313
|
|
|
3562
4314
|
/**
|
|
@@ -3577,16 +4329,15 @@ class Compression {
|
|
|
3577
4329
|
static async compress(bytes, type) {
|
|
3578
4330
|
Guards.uint8Array(Compression._CLASS_NAME, "bytes", bytes);
|
|
3579
4331
|
Guards.arrayOneOf(Compression._CLASS_NAME, "type", type, Object.values(CompressionType));
|
|
3580
|
-
const blob = new Blob([bytes]);
|
|
3581
|
-
const
|
|
3582
|
-
const
|
|
3583
|
-
const compressedBlob = await new Response(
|
|
3584
|
-
const
|
|
3585
|
-
const compressedBytes = new Uint8Array(ab);
|
|
4332
|
+
const blob = new Blob([new Uint8Array(bytes)]);
|
|
4333
|
+
const compressionStream = new CompressionStream(type);
|
|
4334
|
+
const compressionPipe = blob.stream().pipeThrough(compressionStream);
|
|
4335
|
+
const compressedBlob = await new Response(compressionPipe).blob();
|
|
4336
|
+
const compressedBytes = new Uint8Array(await compressedBlob.arrayBuffer());
|
|
3586
4337
|
// GZIP header contains a byte which specifies the OS the
|
|
3587
4338
|
// compression was performed on. We set this to 3 (Unix) to ensure
|
|
3588
4339
|
// that we produce consistent results.
|
|
3589
|
-
if (type ===
|
|
4340
|
+
if (type === CompressionType.Gzip && compressedBytes.length >= 10) {
|
|
3590
4341
|
compressedBytes[9] = 3;
|
|
3591
4342
|
}
|
|
3592
4343
|
return compressedBytes;
|
|
@@ -3600,12 +4351,11 @@ class Compression {
|
|
|
3600
4351
|
static async decompress(compressedBytes, type) {
|
|
3601
4352
|
Guards.uint8Array(Compression._CLASS_NAME, "compressedBytes", compressedBytes);
|
|
3602
4353
|
Guards.arrayOneOf(Compression._CLASS_NAME, "type", type, Object.values(CompressionType));
|
|
3603
|
-
const blob = new Blob([compressedBytes]);
|
|
3604
|
-
const
|
|
3605
|
-
const
|
|
3606
|
-
const decompressedBlob = await new Response(
|
|
3607
|
-
|
|
3608
|
-
return new Uint8Array(ab);
|
|
4354
|
+
const blob = new Blob([new Uint8Array(compressedBytes)]);
|
|
4355
|
+
const decompressionStream = new DecompressionStream(type);
|
|
4356
|
+
const decompressionPipe = blob.stream().pipeThrough(decompressionStream);
|
|
4357
|
+
const decompressedBlob = await new Response(decompressionPipe).blob();
|
|
4358
|
+
return new Uint8Array(await decompressedBlob.bytes());
|
|
3609
4359
|
}
|
|
3610
4360
|
}
|
|
3611
4361
|
|
|
@@ -3663,6 +4413,7 @@ class Validation {
|
|
|
3663
4413
|
* @param options Additional options for the validation.
|
|
3664
4414
|
* @param options.minLength The minimum length of the string.
|
|
3665
4415
|
* @param options.maxLength The maximum length of the string.
|
|
4416
|
+
* @param options.format Specific format to check.
|
|
3666
4417
|
* @returns True if the value is a valid string.
|
|
3667
4418
|
*/
|
|
3668
4419
|
static string(property, value, failures, fieldNameResource, options) {
|
|
@@ -3681,6 +4432,47 @@ class Validation {
|
|
|
3681
4432
|
const maxLimitDefined = Is.integer(maxLength);
|
|
3682
4433
|
const belowMin = minLimitDefined && value.length < minLength;
|
|
3683
4434
|
const aboveMax = maxLimitDefined && value.length > maxLength;
|
|
4435
|
+
if (options?.format === "base58" && !Is.stringBase58(value)) {
|
|
4436
|
+
failures.push({
|
|
4437
|
+
property,
|
|
4438
|
+
reason: "validation.beTextBase58",
|
|
4439
|
+
properties: {
|
|
4440
|
+
fieldName: fieldNameResource ?? "validation.defaultFieldName",
|
|
4441
|
+
value
|
|
4442
|
+
}
|
|
4443
|
+
});
|
|
4444
|
+
}
|
|
4445
|
+
else if (options?.format === "base64" && !Is.stringBase64(value)) {
|
|
4446
|
+
failures.push({
|
|
4447
|
+
property,
|
|
4448
|
+
reason: "validation.beTextBase64",
|
|
4449
|
+
properties: {
|
|
4450
|
+
fieldName: fieldNameResource ?? "validation.defaultFieldName",
|
|
4451
|
+
value
|
|
4452
|
+
}
|
|
4453
|
+
});
|
|
4454
|
+
}
|
|
4455
|
+
else if (options?.format === "hex" && !Is.stringHex(value)) {
|
|
4456
|
+
failures.push({
|
|
4457
|
+
property,
|
|
4458
|
+
reason: "validation.beTextHex",
|
|
4459
|
+
properties: {
|
|
4460
|
+
fieldName: fieldNameResource ?? "validation.defaultFieldName",
|
|
4461
|
+
value
|
|
4462
|
+
}
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
else if (Is.regexp(options?.format) && !options.format.test(value)) {
|
|
4466
|
+
failures.push({
|
|
4467
|
+
property,
|
|
4468
|
+
reason: "validation.beTextRegExp",
|
|
4469
|
+
properties: {
|
|
4470
|
+
fieldName: fieldNameResource ?? "validation.defaultFieldName",
|
|
4471
|
+
value,
|
|
4472
|
+
format: options?.format
|
|
4473
|
+
}
|
|
4474
|
+
});
|
|
4475
|
+
}
|
|
3684
4476
|
if (minLimitDefined && maxLimitDefined && (belowMin || aboveMax)) {
|
|
3685
4477
|
failures.push({
|
|
3686
4478
|
property,
|
|
@@ -4350,11 +5142,13 @@ exports.Base64Url = Base64Url;
|
|
|
4350
5142
|
exports.BaseError = BaseError;
|
|
4351
5143
|
exports.BitString = BitString;
|
|
4352
5144
|
exports.Coerce = Coerce;
|
|
5145
|
+
exports.CoerceType = CoerceType;
|
|
4353
5146
|
exports.ComponentFactory = ComponentFactory;
|
|
4354
5147
|
exports.Compression = Compression;
|
|
4355
5148
|
exports.CompressionType = CompressionType;
|
|
4356
5149
|
exports.ConflictError = ConflictError;
|
|
4357
5150
|
exports.Converter = Converter;
|
|
5151
|
+
exports.EnvHelper = EnvHelper;
|
|
4358
5152
|
exports.ErrorHelper = ErrorHelper;
|
|
4359
5153
|
exports.Factory = Factory;
|
|
4360
5154
|
exports.FilenameHelper = FilenameHelper;
|
|
@@ -4370,7 +5164,9 @@ exports.NotImplementedError = NotImplementedError;
|
|
|
4370
5164
|
exports.NotSupportedError = NotSupportedError;
|
|
4371
5165
|
exports.ObjectHelper = ObjectHelper;
|
|
4372
5166
|
exports.RandomHelper = RandomHelper;
|
|
5167
|
+
exports.SharedStore = SharedStore;
|
|
4373
5168
|
exports.StringHelper = StringHelper;
|
|
5169
|
+
exports.Uint8ArrayHelper = Uint8ArrayHelper;
|
|
4374
5170
|
exports.UnauthorizedError = UnauthorizedError;
|
|
4375
5171
|
exports.UnprocessableError = UnprocessableError;
|
|
4376
5172
|
exports.Url = Url;
|