@twin.org/core 0.0.3-next.44 → 0.0.3-next.46

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.
@@ -11,23 +11,27 @@ export class ErrorHelper {
11
11
  /**
12
12
  * Format Errors and returns just their messages.
13
13
  * @param error The error to format.
14
- * @param includeDetails Whether to include error details, defaults to false.
14
+ * @param options Options for formatting the error.
15
+ * @param options.includeStack Whether to include the stack trace in the output, defaults to false.
16
+ * @param options.includeAdditional Whether to include additional error information in the output, defaults to false.
15
17
  * @returns The error formatted including any causes errors.
16
18
  */
17
- static formatErrors(error, includeDetails) {
19
+ static formatErrors(error, options) {
18
20
  const localizedErrors = ErrorHelper.localizeErrors(error);
19
- if (includeDetails ?? false) {
20
- const output = [];
21
- for (const err of localizedErrors) {
22
- let detailedError = err.message;
23
- if (Is.stringValue(err.stack)) {
24
- detailedError += `\n${err.stack}`;
25
- }
26
- output.push(detailedError);
21
+ const output = [];
22
+ const includeAdditional = options?.includeAdditional ?? false;
23
+ const includeStack = options?.includeStack ?? false;
24
+ for (const err of localizedErrors) {
25
+ let detailedError = err.message;
26
+ if (includeAdditional && Is.arrayValue(err.additional)) {
27
+ detailedError += `\n${err.additional.join("\n")}`;
28
+ }
29
+ if (includeStack && Is.stringValue(err.stack)) {
30
+ detailedError += `\n${err.stack}`;
27
31
  }
28
- return output;
32
+ output.push(detailedError);
29
33
  }
30
- return localizedErrors.map(e => e.message);
34
+ return output;
31
35
  }
32
36
  /**
33
37
  * Localize the content of an error and any causes.
@@ -62,7 +66,7 @@ export class ErrorHelper {
62
66
  localizedError.stack = lines.join("\n");
63
67
  }
64
68
  const additional = ErrorHelper.formatValidationErrors(err);
65
- if (Is.stringValue(additional)) {
69
+ if (Is.arrayValue(additional)) {
66
70
  localizedError.additional = additional;
67
71
  }
68
72
  formattedErrors.push(localizedError);
@@ -93,7 +97,7 @@ export class ErrorHelper {
93
97
  }
94
98
  validationErrors.push(v);
95
99
  }
96
- return validationErrors.join("\n");
100
+ return validationErrors;
97
101
  }
98
102
  }
99
103
  }
@@ -1 +1 @@
1
- {"version":3,"file":"errorHelper.js","sourceRoot":"","sources":["../../../src/helpers/errorHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { StringHelper } from \"./stringHelper.js\";\nimport { BaseError } from \"../errors/baseError.js\";\nimport type { IError } from \"../models/IError.js\";\nimport type { IValidationFailure } from \"../models/IValidationFailure.js\";\nimport { I18n } from \"../utils/i18n.js\";\nimport { Is } from \"../utils/is.js\";\n\n/**\n * Error helper functions.\n */\nexport class ErrorHelper {\n\t/**\n\t * Format Errors and returns just their messages.\n\t * @param error The error to format.\n\t * @param includeDetails Whether to include error details, defaults to false.\n\t * @returns The error formatted including any causes errors.\n\t */\n\tpublic static formatErrors(error: unknown, includeDetails?: boolean): string[] {\n\t\tconst localizedErrors = ErrorHelper.localizeErrors(error);\n\t\tif (includeDetails ?? false) {\n\t\t\tconst output: string[] = [];\n\t\t\tfor (const err of localizedErrors) {\n\t\t\t\tlet detailedError = err.message;\n\t\t\t\tif (Is.stringValue(err.stack)) {\n\t\t\t\t\tdetailedError += `\\n${err.stack}`;\n\t\t\t\t}\n\t\t\t\toutput.push(detailedError);\n\t\t\t}\n\t\t\treturn output;\n\t\t}\n\t\treturn localizedErrors.map(e => e.message);\n\t}\n\n\t/**\n\t * Localize the content of an error and any causes.\n\t * @param error The error to format.\n\t * @returns The localized version of the errors flattened.\n\t */\n\tpublic static localizeErrors(error: unknown): IError[] {\n\t\tconst formattedErrors: IError[] = [];\n\n\t\tif (Is.notEmpty(error)) {\n\t\t\tconst errors = BaseError.flatten(error);\n\n\t\t\tfor (const err of errors) {\n\t\t\t\tconst errorNameKey = `errorNames.${StringHelper.camelCase(err.name)}`;\n\t\t\t\tconst errorMessageKey = `error.${err.message}`;\n\n\t\t\t\t// If there is no error message then it is probably\n\t\t\t\t// from a 3rd party lib, so don't format it just display\n\t\t\t\tconst hasErrorName = I18n.hasMessage(errorNameKey);\n\t\t\t\tconst hasErrorMessage = I18n.hasMessage(errorMessageKey);\n\n\t\t\t\tconst localizedError: IError & { additional?: string } = {\n\t\t\t\t\tname: I18n.formatMessage(hasErrorName ? errorNameKey : \"errorNames.error\"),\n\t\t\t\t\tmessage: hasErrorMessage\n\t\t\t\t\t\t? I18n.formatMessage(errorMessageKey, err.properties)\n\t\t\t\t\t\t: err.message\n\t\t\t\t};\n\n\t\t\t\tif (Is.stringValue(err.source)) {\n\t\t\t\t\tlocalizedError.source = err.source;\n\t\t\t\t}\n\t\t\t\tif (Is.stringValue(err.stack)) {\n\t\t\t\t\t// Remove the first line from the stack traces as they\n\t\t\t\t\t// just have the error type and message duplicated\n\t\t\t\t\tconst lines = err.stack.split(\"\\n\");\n\t\t\t\t\tlines.shift();\n\t\t\t\t\tlocalizedError.stack = lines.join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\tconst additional = ErrorHelper.formatValidationErrors(err);\n\t\t\t\tif (Is.stringValue(additional)) {\n\t\t\t\t\tlocalizedError.additional = additional;\n\t\t\t\t}\n\n\t\t\t\tformattedErrors.push(localizedError);\n\t\t\t}\n\t\t}\n\n\t\treturn formattedErrors;\n\t}\n\n\t/**\n\t * Localize the content of an error and any causes.\n\t * @param error The error to format.\n\t * @returns The localized version of the errors flattened.\n\t */\n\tpublic static formatValidationErrors(error: IError): string | undefined {\n\t\tif (\n\t\t\tIs.object(error.properties) &&\n\t\t\tObject.keys(error.properties).length > 0 &&\n\t\t\tIs.object<{ validationFailures: IValidationFailure[] }>(error.properties) &&\n\t\t\tIs.arrayValue(error.properties.validationFailures)\n\t\t) {\n\t\t\tconst validationErrors = [];\n\t\t\tfor (const validationFailure of error.properties.validationFailures) {\n\t\t\t\tconst errorI18n = `error.${validationFailure.reason}`;\n\t\t\t\tconst errorMessage = I18n.hasMessage(errorI18n)\n\t\t\t\t\t? I18n.formatMessage(errorI18n, validationFailure.properties)\n\t\t\t\t\t: errorI18n;\n\n\t\t\t\tlet v = `${validationFailure.property}: ${errorMessage}`;\n\t\t\t\tif (\n\t\t\t\t\tIs.object<{ value: unknown }>(validationFailure.properties) &&\n\t\t\t\t\tIs.notEmpty(validationFailure.properties.value)\n\t\t\t\t) {\n\t\t\t\t\tv += ` = ${JSON.stringify(validationFailure.properties.value)}`;\n\t\t\t\t}\n\t\t\t\tvalidationErrors.push(v);\n\t\t\t}\n\t\t\treturn validationErrors.join(\"\\n\");\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"errorHelper.js","sourceRoot":"","sources":["../../../src/helpers/errorHelper.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { StringHelper } from \"./stringHelper.js\";\nimport { BaseError } from \"../errors/baseError.js\";\nimport type { IError } from \"../models/IError.js\";\nimport type { IValidationFailure } from \"../models/IValidationFailure.js\";\nimport { I18n } from \"../utils/i18n.js\";\nimport { Is } from \"../utils/is.js\";\n\n/**\n * Error helper functions.\n */\nexport class ErrorHelper {\n\t/**\n\t * Format Errors and returns just their messages.\n\t * @param error The error to format.\n\t * @param options Options for formatting the error.\n\t * @param options.includeStack Whether to include the stack trace in the output, defaults to false.\n\t * @param options.includeAdditional Whether to include additional error information in the output, defaults to false.\n\t * @returns The error formatted including any causes errors.\n\t */\n\tpublic static formatErrors(\n\t\terror: unknown,\n\t\toptions?: {\n\t\t\tincludeStack?: boolean;\n\t\t\tincludeAdditional?: boolean;\n\t\t}\n\t): string[] {\n\t\tconst localizedErrors = ErrorHelper.localizeErrors(error);\n\n\t\tconst output: string[] = [];\n\n\t\tconst includeAdditional = options?.includeAdditional ?? false;\n\t\tconst includeStack = options?.includeStack ?? false;\n\n\t\tfor (const err of localizedErrors) {\n\t\t\tlet detailedError = err.message;\n\t\t\tif (includeAdditional && Is.arrayValue(err.additional)) {\n\t\t\t\tdetailedError += `\\n${err.additional.join(\"\\n\")}`;\n\t\t\t}\n\t\t\tif (includeStack && Is.stringValue(err.stack)) {\n\t\t\t\tdetailedError += `\\n${err.stack}`;\n\t\t\t}\n\t\t\toutput.push(detailedError);\n\t\t}\n\n\t\treturn output;\n\t}\n\n\t/**\n\t * Localize the content of an error and any causes.\n\t * @param error The error to format.\n\t * @returns The localized version of the errors flattened.\n\t */\n\tpublic static localizeErrors(error: unknown): (IError & { additional?: string[] })[] {\n\t\tconst formattedErrors: (IError & { additional?: string[] })[] = [];\n\n\t\tif (Is.notEmpty(error)) {\n\t\t\tconst errors = BaseError.flatten(error);\n\n\t\t\tfor (const err of errors) {\n\t\t\t\tconst errorNameKey = `errorNames.${StringHelper.camelCase(err.name)}`;\n\t\t\t\tconst errorMessageKey = `error.${err.message}`;\n\n\t\t\t\t// If there is no error message then it is probably\n\t\t\t\t// from a 3rd party lib, so don't format it just display\n\t\t\t\tconst hasErrorName = I18n.hasMessage(errorNameKey);\n\t\t\t\tconst hasErrorMessage = I18n.hasMessage(errorMessageKey);\n\n\t\t\t\tconst localizedError: IError & { additional?: string[] } = {\n\t\t\t\t\tname: I18n.formatMessage(hasErrorName ? errorNameKey : \"errorNames.error\"),\n\t\t\t\t\tmessage: hasErrorMessage\n\t\t\t\t\t\t? I18n.formatMessage(errorMessageKey, err.properties)\n\t\t\t\t\t\t: err.message\n\t\t\t\t};\n\n\t\t\t\tif (Is.stringValue(err.source)) {\n\t\t\t\t\tlocalizedError.source = err.source;\n\t\t\t\t}\n\t\t\t\tif (Is.stringValue(err.stack)) {\n\t\t\t\t\t// Remove the first line from the stack traces as they\n\t\t\t\t\t// just have the error type and message duplicated\n\t\t\t\t\tconst lines = err.stack.split(\"\\n\");\n\t\t\t\t\tlines.shift();\n\t\t\t\t\tlocalizedError.stack = lines.join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\tconst additional = ErrorHelper.formatValidationErrors(err);\n\t\t\t\tif (Is.arrayValue(additional)) {\n\t\t\t\t\tlocalizedError.additional = additional;\n\t\t\t\t}\n\n\t\t\t\tformattedErrors.push(localizedError);\n\t\t\t}\n\t\t}\n\n\t\treturn formattedErrors;\n\t}\n\n\t/**\n\t * Localize the content of an error and any causes.\n\t * @param error The error to format.\n\t * @returns The localized version of the errors flattened.\n\t */\n\tpublic static formatValidationErrors(error: IError): string[] | undefined {\n\t\tif (\n\t\t\tIs.object(error.properties) &&\n\t\t\tObject.keys(error.properties).length > 0 &&\n\t\t\tIs.object<{ validationFailures: IValidationFailure[] }>(error.properties) &&\n\t\t\tIs.arrayValue(error.properties.validationFailures)\n\t\t) {\n\t\t\tconst validationErrors: string[] = [];\n\t\t\tfor (const validationFailure of error.properties.validationFailures) {\n\t\t\t\tconst errorI18n = `error.${validationFailure.reason}`;\n\t\t\t\tconst errorMessage = I18n.hasMessage(errorI18n)\n\t\t\t\t\t? I18n.formatMessage(errorI18n, validationFailure.properties)\n\t\t\t\t\t: errorI18n;\n\n\t\t\t\tlet v = `${validationFailure.property}: ${errorMessage}`;\n\t\t\t\tif (\n\t\t\t\t\tIs.object<{ value: unknown }>(validationFailure.properties) &&\n\t\t\t\t\tIs.notEmpty(validationFailure.properties.value)\n\t\t\t\t) {\n\t\t\t\t\tv += ` = ${JSON.stringify(validationFailure.properties.value)}`;\n\t\t\t\t}\n\t\t\t\tvalidationErrors.push(v);\n\t\t\t}\n\t\t\treturn validationErrors;\n\t\t}\n\t}\n}\n"]}
package/dist/es/index.js CHANGED
@@ -46,6 +46,7 @@ export * from "./models/IValidationFailure.js";
46
46
  export * from "./types/bitString.js";
47
47
  export * from "./types/objectOrArray.js";
48
48
  export * from "./types/singleOccurrenceArray.js";
49
+ export * from "./types/singleOccurrenceArrayDepthHelper.js";
49
50
  export * from "./types/url.js";
50
51
  export * from "./types/urn.js";
51
52
  export * from "./utils/asyncCache.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./encoding/base32.js\";\nexport * from \"./encoding/base58.js\";\nexport * from \"./encoding/base64.js\";\nexport * from \"./encoding/base64Url.js\";\nexport * from \"./errors/alreadyExistsError.js\";\nexport * from \"./errors/baseError.js\";\nexport * from \"./errors/conflictError.js\";\nexport * from \"./errors/generalError.js\";\nexport * from \"./errors/guardError.js\";\nexport * from \"./errors/notFoundError.js\";\nexport * from \"./errors/notImplementedError.js\";\nexport * from \"./errors/notSupportedError.js\";\nexport * from \"./errors/unauthorizedError.js\";\nexport * from \"./errors/unprocessableError.js\";\nexport * from \"./errors/validationError.js\";\nexport * from \"./factories/componentFactory.js\";\nexport * from \"./factories/factory.js\";\nexport * from \"./helpers/arrayHelper.js\";\nexport * from \"./helpers/envHelper.js\";\nexport * from \"./helpers/errorHelper.js\";\nexport * from \"./helpers/filenameHelper.js\";\nexport * from \"./helpers/hexHelper.js\";\nexport * from \"./helpers/jsonHelper.js\";\nexport * from \"./helpers/numberHelper.js\";\nexport * from \"./helpers/objectHelper.js\";\nexport * from \"./helpers/randomHelper.js\";\nexport * from \"./helpers/stringHelper.js\";\nexport * from \"./helpers/uint8ArrayHelper.js\";\nexport * from \"./models/coerceType.js\";\nexport * from \"./models/compressionType.js\";\nexport * from \"./models/healthStatus.js\";\nexport * from \"./models/IComponent.js\";\nexport * from \"./models/IError.js\";\nexport * from \"./models/IHealth.js\";\nexport * from \"./models/II18nShared.js\";\nexport * from \"./models/IKeyValue.js\";\nexport * from \"./models/ILabelledValue.js\";\nexport * from \"./models/ILocale.js\";\nexport * from \"./models/ILocaleDictionary.js\";\nexport * from \"./models/ILocalesIndex.js\";\nexport * from \"./models/IPatchOperation.js\";\nexport * from \"./models/IUrlParts.js\";\nexport * from \"./models/IValidationFailure.js\";\nexport * from \"./types/bitString.js\";\nexport * from \"./types/objectOrArray.js\";\nexport * from \"./types/singleOccurrenceArray.js\";\nexport * from \"./types/url.js\";\nexport * from \"./types/urn.js\";\nexport * from \"./utils/asyncCache.js\";\nexport * from \"./utils/coerce.js\";\nexport * from \"./utils/compression.js\";\nexport * from \"./utils/converter.js\";\nexport * from \"./utils/guards.js\";\nexport * from \"./utils/i18n.js\";\nexport * from \"./utils/is.js\";\nexport * from \"./utils/sharedStore.js\";\nexport * from \"./utils/validation.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./encoding/base32.js\";\nexport * from \"./encoding/base58.js\";\nexport * from \"./encoding/base64.js\";\nexport * from \"./encoding/base64Url.js\";\nexport * from \"./errors/alreadyExistsError.js\";\nexport * from \"./errors/baseError.js\";\nexport * from \"./errors/conflictError.js\";\nexport * from \"./errors/generalError.js\";\nexport * from \"./errors/guardError.js\";\nexport * from \"./errors/notFoundError.js\";\nexport * from \"./errors/notImplementedError.js\";\nexport * from \"./errors/notSupportedError.js\";\nexport * from \"./errors/unauthorizedError.js\";\nexport * from \"./errors/unprocessableError.js\";\nexport * from \"./errors/validationError.js\";\nexport * from \"./factories/componentFactory.js\";\nexport * from \"./factories/factory.js\";\nexport * from \"./helpers/arrayHelper.js\";\nexport * from \"./helpers/envHelper.js\";\nexport * from \"./helpers/errorHelper.js\";\nexport * from \"./helpers/filenameHelper.js\";\nexport * from \"./helpers/hexHelper.js\";\nexport * from \"./helpers/jsonHelper.js\";\nexport * from \"./helpers/numberHelper.js\";\nexport * from \"./helpers/objectHelper.js\";\nexport * from \"./helpers/randomHelper.js\";\nexport * from \"./helpers/stringHelper.js\";\nexport * from \"./helpers/uint8ArrayHelper.js\";\nexport * from \"./models/coerceType.js\";\nexport * from \"./models/compressionType.js\";\nexport * from \"./models/healthStatus.js\";\nexport * from \"./models/IComponent.js\";\nexport * from \"./models/IError.js\";\nexport * from \"./models/IHealth.js\";\nexport * from \"./models/II18nShared.js\";\nexport * from \"./models/IKeyValue.js\";\nexport * from \"./models/ILabelledValue.js\";\nexport * from \"./models/ILocale.js\";\nexport * from \"./models/ILocaleDictionary.js\";\nexport * from \"./models/ILocalesIndex.js\";\nexport * from \"./models/IPatchOperation.js\";\nexport * from \"./models/IUrlParts.js\";\nexport * from \"./models/IValidationFailure.js\";\nexport * from \"./types/bitString.js\";\nexport * from \"./types/objectOrArray.js\";\nexport * from \"./types/singleOccurrenceArray.js\";\nexport * from \"./types/singleOccurrenceArrayDepthHelper.js\";\nexport * from \"./types/url.js\";\nexport * from \"./types/urn.js\";\nexport * from \"./utils/asyncCache.js\";\nexport * from \"./utils/coerce.js\";\nexport * from \"./utils/compression.js\";\nexport * from \"./utils/converter.js\";\nexport * from \"./utils/guards.js\";\nexport * from \"./utils/i18n.js\";\nexport * from \"./utils/is.js\";\nexport * from \"./utils/sharedStore.js\";\nexport * from \"./utils/validation.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"singleOccurrenceArray.js","sourceRoot":"","sources":["../../../src/types/singleOccurrenceArray.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/**\n * Helper with bounded recursion depth to keep type instantiation tractable.\n */\nexport type SingleOccurrenceArrayDepthHelper<T, U, Depth extends 0[]> = Depth[\"length\"] extends 16\n\t? [U, ...T[]]\n\t: [U, ...T[]] | [T, ...SingleOccurrenceArrayDepthHelper<T, U, [0, ...Depth]>];\n\n/**\n * Utility type to create a non-empty array with values of type T and exactly one value of type U.\n */\nexport type SingleOccurrenceArray<T = unknown, U = never> = SingleOccurrenceArrayDepthHelper<\n\tT,\n\tU,\n\t[]\n>;\n"]}
1
+ {"version":3,"file":"singleOccurrenceArray.js","sourceRoot":"","sources":["../../../src/types/singleOccurrenceArray.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { SingleOccurrenceArrayDepthHelper } from \"./singleOccurrenceArrayDepthHelper.js\";\n\n/**\n * Utility type to create a non-empty array with values of type T and exactly one value of type U.\n */\nexport type SingleOccurrenceArray<T = unknown, U = never> = SingleOccurrenceArrayDepthHelper<\n\tT,\n\tU,\n\t[]\n>;\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=singleOccurrenceArrayDepthHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleOccurrenceArrayDepthHelper.js","sourceRoot":"","sources":["../../../src/types/singleOccurrenceArrayDepthHelper.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n/**\n * Helper with bounded recursion depth to keep type instantiation tractable.\n */\nexport type SingleOccurrenceArrayDepthHelper<T, U, Depth extends 0[]> = Depth[\"length\"] extends 16\n\t? [U, ...T[]]\n\t: [U, ...T[]] | [T, ...SingleOccurrenceArrayDepthHelper<T, U, [0, ...Depth]>];\n"]}
@@ -14,7 +14,7 @@ export class AsyncCache {
14
14
  * @param cacheFailures Cache failure results, defaults to false.
15
15
  * @returns The response.
16
16
  */
17
- static exec(key, ttlMs, requestMethod, cacheFailures) {
17
+ static async exec(key, ttlMs, requestMethod, cacheFailures) {
18
18
  const cacheEnabled = Is.integer(ttlMs) && ttlMs > 0;
19
19
  if (!cacheEnabled) {
20
20
  // No caching, just execute the request method
@@ -1 +1 @@
1
- {"version":3,"file":"asyncCache.js","sourceRoot":"","sources":["../../../src/utils/asyncCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"./is.js\";\nimport { SharedStore } from \"./sharedStore.js\";\n\n/**\n * Cache the results from asynchronous requests.\n */\nexport class AsyncCache {\n\t/**\n\t * Execute an async request and cache the result.\n\t * @param key The key for the entry in the cache.\n\t * @param ttlMs The TTL of the entry in the cache.\n\t * @param requestMethod The method to call if not cached.\n\t * @param cacheFailures Cache failure results, defaults to false.\n\t * @returns The response.\n\t */\n\tpublic static exec<T = unknown>(\n\t\tkey: string,\n\t\tttlMs: number | undefined,\n\t\trequestMethod: () => Promise<T>,\n\t\tcacheFailures?: boolean\n\t): Promise<T> | undefined {\n\t\tconst cacheEnabled = Is.integer(ttlMs) && ttlMs > 0;\n\t\tif (!cacheEnabled) {\n\t\t\t// No caching, just execute the request method\n\t\t\treturn requestMethod();\n\t\t}\n\n\t\tAsyncCache.cleanupExpired();\n\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tconst cachedEntry = cache[key];\n\n\t\t// Do we have a cache entry for the key\n\t\tif (cachedEntry) {\n\t\t\tif (!Is.empty(cachedEntry.result)) {\n\t\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\t\treturn Promise.resolve(cachedEntry.result);\n\t\t\t} else if (!Is.empty(cachedEntry.error)) {\n\t\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\t\treturn Promise.reject(cachedEntry.error);\n\t\t\t}\n\n\t\t\t// Otherwise create a promise to return and store the resolver\n\t\t\t// and rejector in the cache entry, so that we can call then\n\t\t\t// when the request is done\n\n\t\t\tlet storedResolve: ((value: T | PromiseLike<T>) => void) | undefined;\n\t\t\tlet storedReject: ((reason?: unknown) => void) | undefined;\n\t\t\tconst wait = new Promise<T>((resolve, reject) => {\n\t\t\t\tstoredResolve = resolve;\n\t\t\t\tstoredReject = reject;\n\t\t\t});\n\t\t\tif (!Is.empty(storedResolve) && !Is.empty(storedReject)) {\n\t\t\t\tcachedEntry.promiseQueue.push({\n\t\t\t\t\trequestMethod,\n\t\t\t\t\tresolve: storedResolve,\n\t\t\t\t\treject: storedReject\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn wait;\n\t\t}\n\n\t\t// If we don't have a cache entry, create a new one\n\t\tconst cacheEntry: {\n\t\t\tresult?: T;\n\t\t\terror?: unknown;\n\t\t\tinProgress?: boolean;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t} = {\n\t\t\tinProgress: true,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + ttlMs\n\t\t};\n\t\tcache[key] = cacheEntry;\n\n\t\t// Return a promise that wraps the original request method\n\t\t// so that we can store any results or errors in the cache\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Call the request method and store the result\n\t\t\trequestMethod()\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.then(res => {\n\t\t\t\t\t// If the request was successful, store the result\n\t\t\t\t\tcacheEntry.inProgress = false;\n\t\t\t\t\tcacheEntry.result = res;\n\n\t\t\t\t\t// and resolve both this promise and all the waiters\n\t\t\t\t\tresolve(res);\n\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\twait.resolve(res);\n\t\t\t\t\t}\n\t\t\t\t\tcacheEntry.promiseQueue = [];\n\t\t\t\t\treturn res;\n\t\t\t\t})\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\t// Reject the promise\n\t\t\t\t\treject(err);\n\t\t\t\t\tcacheEntry.inProgress = false;\n\n\t\t\t\t\t// Handle the waiters based on the cacheFailures flag\n\t\t\t\t\tif (cacheFailures ?? false) {\n\t\t\t\t\t\t// If we are caching failures, store the error and reject the waiters\n\t\t\t\t\t\tcacheEntry.error = err;\n\t\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\t\twait.reject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clear the waiters so we don't call them again\n\t\t\t\t\t\tcacheEntry.promiseQueue = [];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If not caching failures for any queued requests we\n\t\t\t\t\t\t// have no value to either resolve or reject, so we\n\t\t\t\t\t\t// just resolve with the original request method\n\t\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\t\t\t\t\t\tAsyncCache.resolveWaiter(wait.requestMethod, wait.resolve, wait.reject);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cache[key] === cacheEntry) {\n\t\t\t\t\t\t\tdelete cache[key];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key The key to get from the cache.\n\t * @returns The item from the cache if it exists.\n\t */\n\tpublic static async get<T = unknown>(key: string): Promise<T | undefined> {\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tif (!Is.empty(cache[key]?.result)) {\n\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\treturn cache[key].result;\n\t\t}\n\n\t\tif (!Is.empty(cache[key]?.error)) {\n\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\tthrow cache[key].error as Error;\n\t\t}\n\t}\n\n\t/**\n\t * Set an entry into the cache.\n\t * @param key The key to set in the cache.\n\t * @param value The value to set in the cache.\n\t * @param ttlMs The TTL of the entry in the cache in ms, defaults to 1s.\n\t * @returns Nothing.\n\t */\n\tpublic static async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tcache[key] = {\n\t\t\tresult: value,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + (ttlMs ?? 1000)\n\t\t};\n\t}\n\n\t/**\n\t * Remove an entry from the cache.\n\t * @param key The key to remove from the cache.\n\t */\n\tpublic static remove(key: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tdelete cache[key];\n\t}\n\n\t/**\n\t * Clear the cache.\n\t * @param prefix Optional prefix to clear only entries with that prefix.\n\t */\n\tpublic static clearCache(prefix?: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tif (Is.stringValue(prefix)) {\n\t\t\tfor (const entry in cache) {\n\t\t\t\tif (entry.startsWith(prefix)) {\n\t\t\t\t\tdelete cache[entry];\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tSharedStore.set(\"asyncCache\", {});\n\t\t}\n\t}\n\n\t/**\n\t * Perform a cleanup of the expired entries in the cache.\n\t */\n\tpublic static cleanupExpired(): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tfor (const entry in cache) {\n\t\t\tif (\n\t\t\t\tcache[entry].expires > 0 &&\n\t\t\t\tcache[entry].expires < Date.now() &&\n\t\t\t\tcache[entry].inProgress !== true\n\t\t\t) {\n\t\t\t\tdelete cache[entry];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the shared cache.\n\t * @returns The shared cache.\n\t * @internal\n\t */\n\tprivate static getSharedCache<T = unknown>(): {\n\t\t[url: string]: {\n\t\t\tresult?: T;\n\t\t\terror?: unknown;\n\t\t\tinProgress?: boolean;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t};\n\t} {\n\t\tlet sharedCache = SharedStore.get<{\n\t\t\t[url: string]: {\n\t\t\t\tresult?: T;\n\t\t\t\terror?: unknown;\n\t\t\t\tinProgress?: boolean;\n\t\t\t\tpromiseQueue: {\n\t\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t\t}[];\n\t\t\t\texpires: number;\n\t\t\t};\n\t\t}>(\"asyncCache\");\n\n\t\tif (Is.undefined(sharedCache)) {\n\t\t\tsharedCache = {};\n\t\t\tSharedStore.set(\"asyncCache\", sharedCache);\n\t\t}\n\n\t\treturn sharedCache;\n\t}\n\n\t/**\n\t * Resolve a waiter by re-running its request method safely.\n\t * @param requestMethod The method to execute.\n\t * @param resolve The resolver for the waiter.\n\t * @param reject The rejector for the waiter.\n\t */\n\tprivate static async resolveWaiter<T>(\n\t\trequestMethod: () => Promise<T>,\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: unknown) => void\n\t): Promise<void> {\n\t\ttry {\n\t\t\tresolve(await requestMethod());\n\t\t} catch (waitErr) {\n\t\t\treject(waitErr);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"asyncCache.js","sourceRoot":"","sources":["../../../src/utils/asyncCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"./is.js\";\nimport { SharedStore } from \"./sharedStore.js\";\n\n/**\n * Cache the results from asynchronous requests.\n */\nexport class AsyncCache {\n\t/**\n\t * Execute an async request and cache the result.\n\t * @param key The key for the entry in the cache.\n\t * @param ttlMs The TTL of the entry in the cache.\n\t * @param requestMethod The method to call if not cached.\n\t * @param cacheFailures Cache failure results, defaults to false.\n\t * @returns The response.\n\t */\n\tpublic static async exec<T = unknown>(\n\t\tkey: string,\n\t\tttlMs: number | undefined,\n\t\trequestMethod: () => Promise<T>,\n\t\tcacheFailures?: boolean\n\t): Promise<T> {\n\t\tconst cacheEnabled = Is.integer(ttlMs) && ttlMs > 0;\n\t\tif (!cacheEnabled) {\n\t\t\t// No caching, just execute the request method\n\t\t\treturn requestMethod();\n\t\t}\n\n\t\tAsyncCache.cleanupExpired();\n\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tconst cachedEntry = cache[key];\n\n\t\t// Do we have a cache entry for the key\n\t\tif (cachedEntry) {\n\t\t\tif (!Is.empty(cachedEntry.result)) {\n\t\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\t\treturn Promise.resolve(cachedEntry.result);\n\t\t\t} else if (!Is.empty(cachedEntry.error)) {\n\t\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\t\treturn Promise.reject(cachedEntry.error);\n\t\t\t}\n\n\t\t\t// Otherwise create a promise to return and store the resolver\n\t\t\t// and rejector in the cache entry, so that we can call then\n\t\t\t// when the request is done\n\n\t\t\tlet storedResolve: ((value: T | PromiseLike<T>) => void) | undefined;\n\t\t\tlet storedReject: ((reason?: unknown) => void) | undefined;\n\t\t\tconst wait = new Promise<T>((resolve, reject) => {\n\t\t\t\tstoredResolve = resolve;\n\t\t\t\tstoredReject = reject;\n\t\t\t});\n\t\t\tif (!Is.empty(storedResolve) && !Is.empty(storedReject)) {\n\t\t\t\tcachedEntry.promiseQueue.push({\n\t\t\t\t\trequestMethod,\n\t\t\t\t\tresolve: storedResolve,\n\t\t\t\t\treject: storedReject\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn wait;\n\t\t}\n\n\t\t// If we don't have a cache entry, create a new one\n\t\tconst cacheEntry: {\n\t\t\tresult?: T;\n\t\t\terror?: unknown;\n\t\t\tinProgress?: boolean;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t} = {\n\t\t\tinProgress: true,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + ttlMs\n\t\t};\n\t\tcache[key] = cacheEntry;\n\n\t\t// Return a promise that wraps the original request method\n\t\t// so that we can store any results or errors in the cache\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Call the request method and store the result\n\t\t\trequestMethod()\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.then(res => {\n\t\t\t\t\t// If the request was successful, store the result\n\t\t\t\t\tcacheEntry.inProgress = false;\n\t\t\t\t\tcacheEntry.result = res;\n\n\t\t\t\t\t// and resolve both this promise and all the waiters\n\t\t\t\t\tresolve(res);\n\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\twait.resolve(res);\n\t\t\t\t\t}\n\t\t\t\t\tcacheEntry.promiseQueue = [];\n\t\t\t\t\treturn res;\n\t\t\t\t})\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\t// Reject the promise\n\t\t\t\t\treject(err);\n\t\t\t\t\tcacheEntry.inProgress = false;\n\n\t\t\t\t\t// Handle the waiters based on the cacheFailures flag\n\t\t\t\t\tif (cacheFailures ?? false) {\n\t\t\t\t\t\t// If we are caching failures, store the error and reject the waiters\n\t\t\t\t\t\tcacheEntry.error = err;\n\t\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\t\twait.reject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clear the waiters so we don't call them again\n\t\t\t\t\t\tcacheEntry.promiseQueue = [];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If not caching failures for any queued requests we\n\t\t\t\t\t\t// have no value to either resolve or reject, so we\n\t\t\t\t\t\t// just resolve with the original request method\n\t\t\t\t\t\tfor (const wait of cacheEntry.promiseQueue) {\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\t\t\t\t\t\tAsyncCache.resolveWaiter(wait.requestMethod, wait.resolve, wait.reject);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (cache[key] === cacheEntry) {\n\t\t\t\t\t\t\tdelete cache[key];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key The key to get from the cache.\n\t * @returns The item from the cache if it exists.\n\t */\n\tpublic static async get<T = unknown>(key: string): Promise<T | undefined> {\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tif (!Is.empty(cache[key]?.result)) {\n\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\treturn cache[key].result;\n\t\t}\n\n\t\tif (!Is.empty(cache[key]?.error)) {\n\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\tthrow cache[key].error as Error;\n\t\t}\n\t}\n\n\t/**\n\t * Set an entry into the cache.\n\t * @param key The key to set in the cache.\n\t * @param value The value to set in the cache.\n\t * @param ttlMs The TTL of the entry in the cache in ms, defaults to 1s.\n\t * @returns Nothing.\n\t */\n\tpublic static async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tcache[key] = {\n\t\t\tresult: value,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + (ttlMs ?? 1000)\n\t\t};\n\t}\n\n\t/**\n\t * Remove an entry from the cache.\n\t * @param key The key to remove from the cache.\n\t */\n\tpublic static remove(key: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tdelete cache[key];\n\t}\n\n\t/**\n\t * Clear the cache.\n\t * @param prefix Optional prefix to clear only entries with that prefix.\n\t */\n\tpublic static clearCache(prefix?: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tif (Is.stringValue(prefix)) {\n\t\t\tfor (const entry in cache) {\n\t\t\t\tif (entry.startsWith(prefix)) {\n\t\t\t\t\tdelete cache[entry];\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tSharedStore.set(\"asyncCache\", {});\n\t\t}\n\t}\n\n\t/**\n\t * Perform a cleanup of the expired entries in the cache.\n\t */\n\tpublic static cleanupExpired(): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tfor (const entry in cache) {\n\t\t\tif (\n\t\t\t\tcache[entry].expires > 0 &&\n\t\t\t\tcache[entry].expires < Date.now() &&\n\t\t\t\tcache[entry].inProgress !== true\n\t\t\t) {\n\t\t\t\tdelete cache[entry];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the shared cache.\n\t * @returns The shared cache.\n\t * @internal\n\t */\n\tprivate static getSharedCache<T = unknown>(): {\n\t\t[url: string]: {\n\t\t\tresult?: T;\n\t\t\terror?: unknown;\n\t\t\tinProgress?: boolean;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t};\n\t} {\n\t\tlet sharedCache = SharedStore.get<{\n\t\t\t[url: string]: {\n\t\t\t\tresult?: T;\n\t\t\t\terror?: unknown;\n\t\t\t\tinProgress?: boolean;\n\t\t\t\tpromiseQueue: {\n\t\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t\t}[];\n\t\t\t\texpires: number;\n\t\t\t};\n\t\t}>(\"asyncCache\");\n\n\t\tif (Is.undefined(sharedCache)) {\n\t\t\tsharedCache = {};\n\t\t\tSharedStore.set(\"asyncCache\", sharedCache);\n\t\t}\n\n\t\treturn sharedCache;\n\t}\n\n\t/**\n\t * Resolve a waiter by re-running its request method safely.\n\t * @param requestMethod The method to execute.\n\t * @param resolve The resolver for the waiter.\n\t * @param reject The rejector for the waiter.\n\t */\n\tprivate static async resolveWaiter<T>(\n\t\trequestMethod: () => Promise<T>,\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: unknown) => void\n\t): Promise<void> {\n\t\ttry {\n\t\t\tresolve(await requestMethod());\n\t\t} catch (waitErr) {\n\t\t\treject(waitErr);\n\t\t}\n\t}\n}\n"]}
@@ -6,20 +6,27 @@ export declare class ErrorHelper {
6
6
  /**
7
7
  * Format Errors and returns just their messages.
8
8
  * @param error The error to format.
9
- * @param includeDetails Whether to include error details, defaults to false.
9
+ * @param options Options for formatting the error.
10
+ * @param options.includeStack Whether to include the stack trace in the output, defaults to false.
11
+ * @param options.includeAdditional Whether to include additional error information in the output, defaults to false.
10
12
  * @returns The error formatted including any causes errors.
11
13
  */
12
- static formatErrors(error: unknown, includeDetails?: boolean): string[];
14
+ static formatErrors(error: unknown, options?: {
15
+ includeStack?: boolean;
16
+ includeAdditional?: boolean;
17
+ }): string[];
13
18
  /**
14
19
  * Localize the content of an error and any causes.
15
20
  * @param error The error to format.
16
21
  * @returns The localized version of the errors flattened.
17
22
  */
18
- static localizeErrors(error: unknown): IError[];
23
+ static localizeErrors(error: unknown): (IError & {
24
+ additional?: string[];
25
+ })[];
19
26
  /**
20
27
  * Localize the content of an error and any causes.
21
28
  * @param error The error to format.
22
29
  * @returns The localized version of the errors flattened.
23
30
  */
24
- static formatValidationErrors(error: IError): string | undefined;
31
+ static formatValidationErrors(error: IError): string[] | undefined;
25
32
  }
@@ -44,6 +44,7 @@ export * from "./models/IValidationFailure.js";
44
44
  export * from "./types/bitString.js";
45
45
  export * from "./types/objectOrArray.js";
46
46
  export * from "./types/singleOccurrenceArray.js";
47
+ export * from "./types/singleOccurrenceArrayDepthHelper.js";
47
48
  export * from "./types/url.js";
48
49
  export * from "./types/urn.js";
49
50
  export * from "./utils/asyncCache.js";
@@ -1,7 +1,4 @@
1
- /**
2
- * Helper with bounded recursion depth to keep type instantiation tractable.
3
- */
4
- export type SingleOccurrenceArrayDepthHelper<T, U, Depth extends 0[]> = Depth["length"] extends 16 ? [U, ...T[]] : [U, ...T[]] | [T, ...SingleOccurrenceArrayDepthHelper<T, U, [0, ...Depth]>];
1
+ import type { SingleOccurrenceArrayDepthHelper } from "./singleOccurrenceArrayDepthHelper.js";
5
2
  /**
6
3
  * Utility type to create a non-empty array with values of type T and exactly one value of type U.
7
4
  */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Helper with bounded recursion depth to keep type instantiation tractable.
3
+ */
4
+ export type SingleOccurrenceArrayDepthHelper<T, U, Depth extends 0[]> = Depth["length"] extends 16 ? [U, ...T[]] : [U, ...T[]] | [T, ...SingleOccurrenceArrayDepthHelper<T, U, [0, ...Depth]>];
@@ -10,7 +10,7 @@ export declare class AsyncCache {
10
10
  * @param cacheFailures Cache failure results, defaults to false.
11
11
  * @returns The response.
12
12
  */
13
- static exec<T = unknown>(key: string, ttlMs: number | undefined, requestMethod: () => Promise<T>, cacheFailures?: boolean): Promise<T> | undefined;
13
+ static exec<T = unknown>(key: string, ttlMs: number | undefined, requestMethod: () => Promise<T>, cacheFailures?: boolean): Promise<T>;
14
14
  /**
15
15
  * Get an entry from the cache.
16
16
  * @param key The key to get from the cache.
package/docs/changelog.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.3-next.46](https://github.com/iotaledger/twin-framework/compare/core-v0.0.3-next.45...core-v0.0.3-next.46) (2026-05-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * improve error formatting ([#313](https://github.com/iotaledger/twin-framework/issues/313)) ([5a19623](https://github.com/iotaledger/twin-framework/commit/5a196231bcbf088bf9ba92a93b7478d3b8c5593f))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/nameof bumped from 0.0.3-next.45 to 0.0.3-next.46
16
+ * devDependencies
17
+ * @twin.org/nameof-transformer bumped from 0.0.3-next.45 to 0.0.3-next.46
18
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.45 to 0.0.3-next.46
19
+
20
+ ## [0.0.3-next.45](https://github.com/iotaledger/twin-framework/compare/core-v0.0.3-next.44...core-v0.0.3-next.45) (2026-05-21)
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * remove misleading undefined from AsyncCache return type ([05b3291](https://github.com/iotaledger/twin-framework/commit/05b32914e03a63c7daf7b77952a2ebedb7ca7f6b))
26
+
27
+
28
+ ### Dependencies
29
+
30
+ * The following workspace dependencies were updated
31
+ * dependencies
32
+ * @twin.org/nameof bumped from 0.0.3-next.44 to 0.0.3-next.45
33
+ * devDependencies
34
+ * @twin.org/nameof-transformer bumped from 0.0.3-next.44 to 0.0.3-next.45
35
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.44 to 0.0.3-next.45
36
+
3
37
  ## [0.0.3-next.44](https://github.com/iotaledger/twin-framework/compare/core-v0.0.3-next.43...core-v0.0.3-next.44) (2026-05-19)
4
38
 
5
39
 
@@ -16,7 +16,7 @@ Cache the results from asynchronous requests.
16
16
 
17
17
  ### exec() {#exec}
18
18
 
19
- > `static` **exec**\<`T`\>(`key`, `ttlMs`, `requestMethod`, `cacheFailures?`): `Promise`\<`T`\> \| `undefined`
19
+ > `static` **exec**\<`T`\>(`key`, `ttlMs`, `requestMethod`, `cacheFailures?`): `Promise`\<`T`\>
20
20
 
21
21
  Execute an async request and cache the result.
22
22
 
@@ -54,7 +54,7 @@ Cache failure results, defaults to false.
54
54
 
55
55
  #### Returns
56
56
 
57
- `Promise`\<`T`\> \| `undefined`
57
+ `Promise`\<`T`\>
58
58
 
59
59
  The response.
60
60
 
@@ -16,7 +16,7 @@ Error helper functions.
16
16
 
17
17
  ### formatErrors() {#formaterrors}
18
18
 
19
- > `static` **formatErrors**(`error`, `includeDetails?`): `string`[]
19
+ > `static` **formatErrors**(`error`, `options?`): `string`[]
20
20
 
21
21
  Format Errors and returns just their messages.
22
22
 
@@ -28,11 +28,21 @@ Format Errors and returns just their messages.
28
28
 
29
29
  The error to format.
30
30
 
31
- ##### includeDetails?
31
+ ##### options?
32
+
33
+ Options for formatting the error.
34
+
35
+ ###### includeStack?
36
+
37
+ `boolean`
38
+
39
+ Whether to include the stack trace in the output, defaults to false.
40
+
41
+ ###### includeAdditional?
32
42
 
33
43
  `boolean`
34
44
 
35
- Whether to include error details, defaults to false.
45
+ Whether to include additional error information in the output, defaults to false.
36
46
 
37
47
  #### Returns
38
48
 
@@ -44,7 +54,7 @@ The error formatted including any causes errors.
44
54
 
45
55
  ### localizeErrors() {#localizeerrors}
46
56
 
47
- > `static` **localizeErrors**(`error`): [`IError`](../interfaces/IError.md)[]
57
+ > `static` **localizeErrors**(`error`): [`IError`](../interfaces/IError.md) & `object`[]
48
58
 
49
59
  Localize the content of an error and any causes.
50
60
 
@@ -58,7 +68,7 @@ The error to format.
58
68
 
59
69
  #### Returns
60
70
 
61
- [`IError`](../interfaces/IError.md)[]
71
+ [`IError`](../interfaces/IError.md) & `object`[]
62
72
 
63
73
  The localized version of the errors flattened.
64
74
 
@@ -66,7 +76,7 @@ The localized version of the errors flattened.
66
76
 
67
77
  ### formatValidationErrors() {#formatvalidationerrors}
68
78
 
69
- > `static` **formatValidationErrors**(`error`): `string` \| `undefined`
79
+ > `static` **formatValidationErrors**(`error`): `string`[] \| `undefined`
70
80
 
71
81
  Localize the content of an error and any causes.
72
82
 
@@ -80,6 +90,6 @@ The error to format.
80
90
 
81
91
  #### Returns
82
92
 
83
- `string` \| `undefined`
93
+ `string`[] \| `undefined`
84
94
 
85
95
  The localized version of the errors flattened.
@@ -63,8 +63,8 @@
63
63
  - [CompressionType](type-aliases/CompressionType.md)
64
64
  - [HealthStatus](type-aliases/HealthStatus.md)
65
65
  - [ObjectOrArray](type-aliases/ObjectOrArray.md)
66
- - [SingleOccurrenceArrayDepthHelper](type-aliases/SingleOccurrenceArrayDepthHelper.md)
67
66
  - [SingleOccurrenceArray](type-aliases/SingleOccurrenceArray.md)
67
+ - [SingleOccurrenceArrayDepthHelper](type-aliases/SingleOccurrenceArrayDepthHelper.md)
68
68
 
69
69
  ## Variables
70
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/core",
3
- "version": "0.0.3-next.44",
3
+ "version": "0.0.3-next.46",
4
4
  "description": "Helper methods/classes for data type checking/validation/guarding/error handling",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/nameof": "0.0.3-next.44",
17
+ "@twin.org/nameof": "0.0.3-next.46",
18
18
  "intl-messageformat": "11.2.6",
19
19
  "rfc6902": "5.2.0"
20
20
  },