@twin.org/core 0.0.1-next.51 → 0.0.1-next.53
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 +225 -75
- package/dist/esm/index.mjs +225 -76
- package/dist/types/index.d.ts +2 -0
- package/dist/types/models/II18nShared.d.ts +29 -0
- package/dist/types/utils/asyncCache.d.ts +2 -1
- package/dist/types/utils/sharedStore.d.ts +23 -0
- package/docs/changelog.md +14 -0
- package/docs/reference/classes/AlreadyExistsError.md +7 -7
- package/docs/reference/classes/ArrayHelper.md +3 -3
- package/docs/reference/classes/AsyncCache.md +21 -9
- package/docs/reference/classes/Base32.md +3 -3
- package/docs/reference/classes/Base58.md +3 -3
- package/docs/reference/classes/Base64.md +3 -3
- package/docs/reference/classes/Base64Url.md +3 -3
- package/docs/reference/classes/BaseError.md +5 -5
- package/docs/reference/classes/BitString.md +5 -5
- package/docs/reference/classes/Coerce.md +7 -5
- package/docs/reference/classes/Compression.md +3 -3
- package/docs/reference/classes/ConflictError.md +7 -7
- package/docs/reference/classes/Converter.md +6 -6
- package/docs/reference/classes/EnvHelper.md +7 -5
- package/docs/reference/classes/ErrorHelper.md +3 -3
- package/docs/reference/classes/Factory.md +17 -7
- package/docs/reference/classes/FilenameHelper.md +3 -3
- package/docs/reference/classes/GeneralError.md +7 -7
- package/docs/reference/classes/GuardError.md +7 -7
- package/docs/reference/classes/Guards.md +18 -8
- package/docs/reference/classes/HexHelper.md +3 -3
- package/docs/reference/classes/I18n.md +6 -6
- package/docs/reference/classes/Is.md +21 -9
- package/docs/reference/classes/JsonHelper.md +10 -6
- package/docs/reference/classes/NotFoundError.md +7 -7
- package/docs/reference/classes/NotImplementedError.md +7 -7
- package/docs/reference/classes/NotSupportedError.md +7 -7
- package/docs/reference/classes/ObjectHelper.md +40 -18
- package/docs/reference/classes/RandomHelper.md +3 -3
- package/docs/reference/classes/SharedStore.md +94 -0
- package/docs/reference/classes/StringHelper.md +3 -3
- package/docs/reference/classes/Uint8ArrayHelper.md +3 -3
- package/docs/reference/classes/UnauthorizedError.md +7 -7
- package/docs/reference/classes/UnprocessableError.md +7 -7
- package/docs/reference/classes/Url.md +7 -7
- package/docs/reference/classes/Urn.md +9 -9
- package/docs/reference/classes/Validation.md +36 -28
- package/docs/reference/classes/ValidationError.md +7 -7
- package/docs/reference/index.md +2 -0
- package/docs/reference/interfaces/IComponent.md +3 -3
- package/docs/reference/interfaces/IError.md +1 -1
- 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/type-aliases/CoerceType.md +1 -1
- package/docs/reference/type-aliases/CompressionType.md +1 -1
- package/package.json +2 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -1814,6 +1814,53 @@ class Guards {
|
|
|
1814
1814
|
}
|
|
1815
1815
|
}
|
|
1816
1816
|
|
|
1817
|
+
// Copyright 2024 IOTA Stiftung.
|
|
1818
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
1819
|
+
/**
|
|
1820
|
+
* Provide a store for shared objects which can be accesses through multiple
|
|
1821
|
+
* instance loads of a packages.
|
|
1822
|
+
*/
|
|
1823
|
+
class SharedStore {
|
|
1824
|
+
/**
|
|
1825
|
+
* Get a property from the shared store.
|
|
1826
|
+
* @param prop The name of the property to get.
|
|
1827
|
+
* @returns The property if it exists.
|
|
1828
|
+
*/
|
|
1829
|
+
static get(prop) {
|
|
1830
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1831
|
+
const shared = globalThis.__TWIN_SHARED__;
|
|
1832
|
+
if (Is.undefined(shared)) {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
return shared[prop];
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Set the property in the shared store.
|
|
1839
|
+
* @param prop The name of the property to set.
|
|
1840
|
+
* @param value The value to set.
|
|
1841
|
+
*/
|
|
1842
|
+
static set(prop, value) {
|
|
1843
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1844
|
+
if (Is.undefined(globalThis.__TWIN_SHARED__)) {
|
|
1845
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1846
|
+
globalThis.__TWIN_SHARED__ = {};
|
|
1847
|
+
}
|
|
1848
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1849
|
+
globalThis.__TWIN_SHARED__[prop] = value;
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Remove a property from the shared store.
|
|
1853
|
+
* @param prop The name of the property to remove.
|
|
1854
|
+
*/
|
|
1855
|
+
static remove(prop) {
|
|
1856
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1857
|
+
const shared = globalThis.__TWIN_SHARED__;
|
|
1858
|
+
if (!Is.undefined(shared)) {
|
|
1859
|
+
delete shared[prop];
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1817
1864
|
/**
|
|
1818
1865
|
* Factory for creating implementation of generic types.
|
|
1819
1866
|
*/
|
|
@@ -1823,11 +1870,6 @@ class Factory {
|
|
|
1823
1870
|
* @internal
|
|
1824
1871
|
*/
|
|
1825
1872
|
static _CLASS_NAME = "Factory";
|
|
1826
|
-
/**
|
|
1827
|
-
* Store all the created factories.
|
|
1828
|
-
* @internal
|
|
1829
|
-
*/
|
|
1830
|
-
static _factories = {};
|
|
1831
1873
|
/**
|
|
1832
1874
|
* Type name for the instances.
|
|
1833
1875
|
* @internal
|
|
@@ -1881,32 +1923,40 @@ class Factory {
|
|
|
1881
1923
|
* @returns The factory instance.
|
|
1882
1924
|
*/
|
|
1883
1925
|
static createFactory(typeName, autoInstance = false, matcher) {
|
|
1884
|
-
|
|
1885
|
-
|
|
1926
|
+
const factories = Factory.getFactories();
|
|
1927
|
+
if (Is.undefined(factories[typeName])) {
|
|
1928
|
+
factories[typeName] = new Factory(typeName, autoInstance, matcher);
|
|
1886
1929
|
}
|
|
1887
|
-
return
|
|
1930
|
+
return factories[typeName];
|
|
1888
1931
|
}
|
|
1889
1932
|
/**
|
|
1890
1933
|
* Get all the factories.
|
|
1891
1934
|
* @returns All the factories.
|
|
1892
1935
|
*/
|
|
1893
1936
|
static getFactories() {
|
|
1894
|
-
|
|
1937
|
+
let factories = SharedStore.get("factories");
|
|
1938
|
+
if (Is.undefined(factories)) {
|
|
1939
|
+
factories = {};
|
|
1940
|
+
SharedStore.set("factories", factories);
|
|
1941
|
+
}
|
|
1942
|
+
return factories;
|
|
1895
1943
|
}
|
|
1896
1944
|
/**
|
|
1897
1945
|
* Reset all the factories, which removes any created instances, but not the registrations.
|
|
1898
1946
|
*/
|
|
1899
1947
|
static resetFactories() {
|
|
1900
|
-
|
|
1901
|
-
|
|
1948
|
+
const factories = Factory.getFactories();
|
|
1949
|
+
for (const typeName in factories) {
|
|
1950
|
+
factories[typeName].reset();
|
|
1902
1951
|
}
|
|
1903
1952
|
}
|
|
1904
1953
|
/**
|
|
1905
1954
|
* Clear all the factories, which removes anything registered with the factories.
|
|
1906
1955
|
*/
|
|
1907
1956
|
static clearFactories() {
|
|
1908
|
-
|
|
1909
|
-
|
|
1957
|
+
const factories = Factory.getFactories();
|
|
1958
|
+
for (const typeName in factories) {
|
|
1959
|
+
factories[typeName].clear();
|
|
1910
1960
|
}
|
|
1911
1961
|
}
|
|
1912
1962
|
/**
|
|
@@ -2854,34 +2904,15 @@ class I18n {
|
|
|
2854
2904
|
* The default translation.
|
|
2855
2905
|
*/
|
|
2856
2906
|
static DEFAULT_LOCALE = "en";
|
|
2857
|
-
/**
|
|
2858
|
-
* Dictionaries for lookups.
|
|
2859
|
-
* @internal
|
|
2860
|
-
*/
|
|
2861
|
-
static _localeDictionaries = {};
|
|
2862
|
-
/**
|
|
2863
|
-
* The current locale.
|
|
2864
|
-
* @internal
|
|
2865
|
-
*/
|
|
2866
|
-
static _currentLocale = I18n.DEFAULT_LOCALE;
|
|
2867
|
-
/**
|
|
2868
|
-
* Change handler for the locale being updated.
|
|
2869
|
-
* @internal
|
|
2870
|
-
*/
|
|
2871
|
-
static _localeChangedHandlers = {};
|
|
2872
|
-
/**
|
|
2873
|
-
* Change handler for the dictionaries being updated.
|
|
2874
|
-
* @internal
|
|
2875
|
-
*/
|
|
2876
|
-
static _dictionaryChangedHandlers = {};
|
|
2877
2907
|
/**
|
|
2878
2908
|
* Set the locale.
|
|
2879
2909
|
* @param locale The new locale.
|
|
2880
2910
|
*/
|
|
2881
2911
|
static setLocale(locale) {
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2912
|
+
const i18nShared = I18n.getI18nShared();
|
|
2913
|
+
i18nShared.currentLocale = locale;
|
|
2914
|
+
for (const callback in i18nShared.localeChangedHandlers) {
|
|
2915
|
+
i18nShared.localeChangedHandlers[callback](i18nShared.currentLocale);
|
|
2885
2916
|
}
|
|
2886
2917
|
}
|
|
2887
2918
|
/**
|
|
@@ -2889,7 +2920,8 @@ class I18n {
|
|
|
2889
2920
|
* @returns The current locale.
|
|
2890
2921
|
*/
|
|
2891
2922
|
static getLocale() {
|
|
2892
|
-
|
|
2923
|
+
const i18nShared = I18n.getI18nShared();
|
|
2924
|
+
return i18nShared.currentLocale;
|
|
2893
2925
|
}
|
|
2894
2926
|
/**
|
|
2895
2927
|
* Add a locale dictionary.
|
|
@@ -2897,11 +2929,12 @@ class I18n {
|
|
|
2897
2929
|
* @param dictionary The dictionary to add.
|
|
2898
2930
|
*/
|
|
2899
2931
|
static addDictionary(locale, dictionary) {
|
|
2932
|
+
const i18nShared = I18n.getI18nShared();
|
|
2900
2933
|
const mergedKeys = {};
|
|
2901
2934
|
I18n.flattenTranslationKeys(dictionary, "", mergedKeys);
|
|
2902
|
-
|
|
2903
|
-
for (const callback in
|
|
2904
|
-
|
|
2935
|
+
i18nShared.localeDictionaries[locale] = mergedKeys;
|
|
2936
|
+
for (const callback in i18nShared.dictionaryChangedHandlers) {
|
|
2937
|
+
i18nShared.dictionaryChangedHandlers[callback](i18nShared.currentLocale);
|
|
2905
2938
|
}
|
|
2906
2939
|
}
|
|
2907
2940
|
/**
|
|
@@ -2910,14 +2943,16 @@ class I18n {
|
|
|
2910
2943
|
* @returns The dictionary of undefined if it does not exist.
|
|
2911
2944
|
*/
|
|
2912
2945
|
static getDictionary(locale) {
|
|
2913
|
-
|
|
2946
|
+
const i18nShared = I18n.getI18nShared();
|
|
2947
|
+
return i18nShared.localeDictionaries[locale];
|
|
2914
2948
|
}
|
|
2915
2949
|
/**
|
|
2916
2950
|
* Get all the locale dictionaries.
|
|
2917
2951
|
* @returns The dictionaries.
|
|
2918
2952
|
*/
|
|
2919
2953
|
static getAllDictionaries() {
|
|
2920
|
-
|
|
2954
|
+
const i18nShared = I18n.getI18nShared();
|
|
2955
|
+
return i18nShared.localeDictionaries;
|
|
2921
2956
|
}
|
|
2922
2957
|
/**
|
|
2923
2958
|
* Add a locale changed handler.
|
|
@@ -2925,14 +2960,16 @@ class I18n {
|
|
|
2925
2960
|
* @param handler The handler to add.
|
|
2926
2961
|
*/
|
|
2927
2962
|
static addLocaleHandler(id, handler) {
|
|
2928
|
-
|
|
2963
|
+
const i18nShared = I18n.getI18nShared();
|
|
2964
|
+
i18nShared.localeChangedHandlers[id] = handler;
|
|
2929
2965
|
}
|
|
2930
2966
|
/**
|
|
2931
2967
|
* Remove a locale changed handler.
|
|
2932
2968
|
* @param id The id of the handler.
|
|
2933
2969
|
*/
|
|
2934
2970
|
static removeLocaleHandler(id) {
|
|
2935
|
-
|
|
2971
|
+
const i18nShared = I18n.getI18nShared();
|
|
2972
|
+
delete i18nShared.localeChangedHandlers[id];
|
|
2936
2973
|
}
|
|
2937
2974
|
/**
|
|
2938
2975
|
* Add a dictionary changed handler.
|
|
@@ -2940,14 +2977,16 @@ class I18n {
|
|
|
2940
2977
|
* @param handler The handler to add.
|
|
2941
2978
|
*/
|
|
2942
2979
|
static addDictionaryHandler(id, handler) {
|
|
2943
|
-
|
|
2980
|
+
const i18nShared = I18n.getI18nShared();
|
|
2981
|
+
i18nShared.dictionaryChangedHandlers[id] = handler;
|
|
2944
2982
|
}
|
|
2945
2983
|
/**
|
|
2946
2984
|
* Remove a dictionary changed handler.
|
|
2947
2985
|
* @param id The id of the handler.
|
|
2948
2986
|
*/
|
|
2949
2987
|
static removeDictionaryHandler(id) {
|
|
2950
|
-
|
|
2988
|
+
const i18nShared = I18n.getI18nShared();
|
|
2989
|
+
delete i18nShared.dictionaryChangedHandlers[id];
|
|
2951
2990
|
}
|
|
2952
2991
|
/**
|
|
2953
2992
|
* Format a message.
|
|
@@ -2957,21 +2996,22 @@ class I18n {
|
|
|
2957
2996
|
* @returns The formatted string.
|
|
2958
2997
|
*/
|
|
2959
2998
|
static formatMessage(key, values, overrideLocale) {
|
|
2960
|
-
|
|
2999
|
+
const i18nShared = I18n.getI18nShared();
|
|
3000
|
+
let cl = overrideLocale ?? i18nShared.currentLocale;
|
|
2961
3001
|
if (cl.startsWith("debug-")) {
|
|
2962
3002
|
cl = I18n.DEFAULT_LOCALE;
|
|
2963
3003
|
}
|
|
2964
|
-
if (!
|
|
3004
|
+
if (!i18nShared.localeDictionaries[cl]) {
|
|
2965
3005
|
return `!!Missing ${cl}`;
|
|
2966
3006
|
}
|
|
2967
|
-
if (!
|
|
3007
|
+
if (!i18nShared.localeDictionaries[cl][key]) {
|
|
2968
3008
|
return `!!Missing ${cl}.${key}`;
|
|
2969
3009
|
}
|
|
2970
|
-
if (
|
|
3010
|
+
if (i18nShared.currentLocale === "debug-k") {
|
|
2971
3011
|
return key;
|
|
2972
3012
|
}
|
|
2973
|
-
let ret = new IntlMessageFormat(
|
|
2974
|
-
if (
|
|
3013
|
+
let ret = new IntlMessageFormat(i18nShared.localeDictionaries[cl][key], cl).format(values);
|
|
3014
|
+
if (i18nShared.currentLocale === "debug-x") {
|
|
2975
3015
|
ret = ret.replace(/[a-z]/g, "x").replace(/[A-Z]/g, "x").replace(/\d/g, "n");
|
|
2976
3016
|
}
|
|
2977
3017
|
return ret;
|
|
@@ -2982,7 +3022,8 @@ class I18n {
|
|
|
2982
3022
|
* @returns True if the key exists.
|
|
2983
3023
|
*/
|
|
2984
3024
|
static hasMessage(key) {
|
|
2985
|
-
|
|
3025
|
+
const i18nShared = I18n.getI18nShared();
|
|
3026
|
+
return Is.string(i18nShared.localeDictionaries[i18nShared.currentLocale]?.[key]);
|
|
2986
3027
|
}
|
|
2987
3028
|
/**
|
|
2988
3029
|
* Flatten the translation property paths for faster lookup.
|
|
@@ -3003,6 +3044,24 @@ class I18n {
|
|
|
3003
3044
|
}
|
|
3004
3045
|
}
|
|
3005
3046
|
}
|
|
3047
|
+
/**
|
|
3048
|
+
* Get the I18n shared data.
|
|
3049
|
+
* @returns The I18n shared data.
|
|
3050
|
+
* @internal
|
|
3051
|
+
*/
|
|
3052
|
+
static getI18nShared() {
|
|
3053
|
+
let i18nShared = SharedStore.get("i18n");
|
|
3054
|
+
if (Is.undefined(i18nShared)) {
|
|
3055
|
+
i18nShared = {
|
|
3056
|
+
localeDictionaries: {},
|
|
3057
|
+
currentLocale: I18n.DEFAULT_LOCALE,
|
|
3058
|
+
localeChangedHandlers: {},
|
|
3059
|
+
dictionaryChangedHandlers: {}
|
|
3060
|
+
};
|
|
3061
|
+
SharedStore.set("i18n", i18nShared);
|
|
3062
|
+
}
|
|
3063
|
+
return i18nShared;
|
|
3064
|
+
}
|
|
3006
3065
|
}
|
|
3007
3066
|
|
|
3008
3067
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -3940,29 +3999,93 @@ class Urn {
|
|
|
3940
3999
|
* Cache the results from asynchronous requests.
|
|
3941
4000
|
*/
|
|
3942
4001
|
class AsyncCache {
|
|
3943
|
-
/**
|
|
3944
|
-
* Cache for the fetch requests.
|
|
3945
|
-
* @internal
|
|
3946
|
-
*/
|
|
3947
|
-
static _cache = {};
|
|
3948
4002
|
/**
|
|
3949
4003
|
* Execute an async request and cache the result.
|
|
3950
4004
|
* @param key The key for the entry in the cache.
|
|
3951
4005
|
* @param ttlMs The TTL of the entry in the cache.
|
|
3952
4006
|
* @param requestMethod The method to call if not cached.
|
|
4007
|
+
* @param cacheFailures Cache failure results, defaults to false.
|
|
3953
4008
|
* @returns The response.
|
|
3954
4009
|
*/
|
|
3955
|
-
static exec(key, ttlMs, requestMethod) {
|
|
4010
|
+
static exec(key, ttlMs, requestMethod, cacheFailures) {
|
|
3956
4011
|
const cacheEnabled = Is.integer(ttlMs) && ttlMs >= 0;
|
|
3957
4012
|
if (cacheEnabled) {
|
|
3958
4013
|
AsyncCache.cleanupExpired();
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
4014
|
+
const cache = AsyncCache.getSharedCache();
|
|
4015
|
+
// Do we have a cache entry for the key
|
|
4016
|
+
if (cache[key]) {
|
|
4017
|
+
if (!Is.empty(cache[key].result)) {
|
|
4018
|
+
// If the cache has already resulted in a value, resolve it
|
|
4019
|
+
return Promise.resolve(cache[key].result);
|
|
4020
|
+
}
|
|
4021
|
+
else if (!Is.empty(cache[key].error)) {
|
|
4022
|
+
// If the cache has already resulted in an error, reject it
|
|
4023
|
+
return Promise.reject(cache[key].error);
|
|
4024
|
+
}
|
|
4025
|
+
// Otherwise create a promise to return and store the resolver
|
|
4026
|
+
// and rejector in the cache entry, so that we can call then
|
|
4027
|
+
// when the request is done
|
|
4028
|
+
let storedResolve;
|
|
4029
|
+
let storedReject;
|
|
4030
|
+
const wait = new Promise((resolve, reject) => {
|
|
4031
|
+
storedResolve = resolve;
|
|
4032
|
+
storedReject = reject;
|
|
4033
|
+
});
|
|
4034
|
+
if (!Is.empty(storedResolve) && !Is.empty(storedReject)) {
|
|
4035
|
+
cache[key].promiseQueue.push({
|
|
4036
|
+
requestMethod,
|
|
4037
|
+
resolve: storedResolve,
|
|
4038
|
+
reject: storedReject
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
4041
|
+
return wait;
|
|
3964
4042
|
}
|
|
3965
|
-
|
|
4043
|
+
// If we don't have a cache entry, create a new one
|
|
4044
|
+
cache[key] = {
|
|
4045
|
+
promiseQueue: [],
|
|
4046
|
+
expires: ttlMs === 0 ? 0 : Date.now() + ttlMs
|
|
4047
|
+
};
|
|
4048
|
+
// Return a promise that wraps the original request method
|
|
4049
|
+
// so that we can store any results or errors in the cache
|
|
4050
|
+
return new Promise((resolve, reject) => {
|
|
4051
|
+
// Call the request method and store the result
|
|
4052
|
+
requestMethod()
|
|
4053
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
4054
|
+
.then(res => {
|
|
4055
|
+
// If the request was successful, store the result
|
|
4056
|
+
cache[key].result = res;
|
|
4057
|
+
// and resolve both this promise and all the waiters
|
|
4058
|
+
resolve(res);
|
|
4059
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4060
|
+
wait.resolve(res);
|
|
4061
|
+
}
|
|
4062
|
+
return res;
|
|
4063
|
+
})
|
|
4064
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
4065
|
+
.catch((err) => {
|
|
4066
|
+
// Reject the promise
|
|
4067
|
+
reject(err);
|
|
4068
|
+
// Handle the waiters based on the cacheFailures flag
|
|
4069
|
+
if (cacheFailures ?? false) {
|
|
4070
|
+
// If we are caching failures, store the error and reject the waiters
|
|
4071
|
+
cache[key].error = err;
|
|
4072
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4073
|
+
wait.reject(err);
|
|
4074
|
+
}
|
|
4075
|
+
// Clear the waiters so we don't call them again
|
|
4076
|
+
cache[key].promiseQueue = [];
|
|
4077
|
+
}
|
|
4078
|
+
else {
|
|
4079
|
+
// If not caching failures for any queued requests we
|
|
4080
|
+
// have no value to either resolve or reject, so we
|
|
4081
|
+
// just resolve with the original request method
|
|
4082
|
+
for (const wait of cache[key].promiseQueue) {
|
|
4083
|
+
wait.resolve(wait.requestMethod());
|
|
4084
|
+
}
|
|
4085
|
+
delete cache[key];
|
|
4086
|
+
}
|
|
4087
|
+
});
|
|
4088
|
+
});
|
|
3966
4089
|
}
|
|
3967
4090
|
}
|
|
3968
4091
|
/**
|
|
@@ -3971,7 +4094,15 @@ class AsyncCache {
|
|
|
3971
4094
|
* @returns The item from the cache if it exists.
|
|
3972
4095
|
*/
|
|
3973
4096
|
static async get(key) {
|
|
3974
|
-
|
|
4097
|
+
const cache = AsyncCache.getSharedCache();
|
|
4098
|
+
if (!Is.empty(cache[key].result)) {
|
|
4099
|
+
// If the cache has already resulted in a value, resolve it
|
|
4100
|
+
return cache[key].result;
|
|
4101
|
+
}
|
|
4102
|
+
else if (!Is.empty(cache[key].error)) {
|
|
4103
|
+
// If the cache has already resulted in an error, reject it
|
|
4104
|
+
throw cache[key].error;
|
|
4105
|
+
}
|
|
3975
4106
|
}
|
|
3976
4107
|
/**
|
|
3977
4108
|
* Set an entry into the cache.
|
|
@@ -3981,8 +4112,10 @@ class AsyncCache {
|
|
|
3981
4112
|
* @returns Nothing.
|
|
3982
4113
|
*/
|
|
3983
4114
|
static async set(key, value, ttlMs) {
|
|
3984
|
-
|
|
3985
|
-
|
|
4115
|
+
const cache = AsyncCache.getSharedCache();
|
|
4116
|
+
cache[key] = {
|
|
4117
|
+
result: value,
|
|
4118
|
+
promiseQueue: [],
|
|
3986
4119
|
expires: Date.now() + (ttlMs ?? 1000)
|
|
3987
4120
|
};
|
|
3988
4121
|
}
|
|
@@ -3991,34 +4124,50 @@ class AsyncCache {
|
|
|
3991
4124
|
* @param key The key to remove from the cache.
|
|
3992
4125
|
*/
|
|
3993
4126
|
static remove(key) {
|
|
3994
|
-
|
|
4127
|
+
const cache = AsyncCache.getSharedCache();
|
|
4128
|
+
delete cache[key];
|
|
3995
4129
|
}
|
|
3996
4130
|
/**
|
|
3997
4131
|
* Clear the cache.
|
|
3998
4132
|
* @param prefix Optional prefix to clear only entries with that prefix.
|
|
3999
4133
|
*/
|
|
4000
4134
|
static clearCache(prefix) {
|
|
4135
|
+
const cache = AsyncCache.getSharedCache();
|
|
4001
4136
|
if (Is.stringValue(prefix)) {
|
|
4002
|
-
for (const entry in
|
|
4137
|
+
for (const entry in cache) {
|
|
4003
4138
|
if (entry.startsWith(prefix)) {
|
|
4004
|
-
delete
|
|
4139
|
+
delete cache[entry];
|
|
4005
4140
|
}
|
|
4006
4141
|
}
|
|
4007
4142
|
}
|
|
4008
4143
|
else {
|
|
4009
|
-
|
|
4144
|
+
SharedStore.set("asyncCache", {});
|
|
4010
4145
|
}
|
|
4011
4146
|
}
|
|
4012
4147
|
/**
|
|
4013
4148
|
* Perform a cleanup of the expired entries in the cache.
|
|
4014
4149
|
*/
|
|
4015
4150
|
static cleanupExpired() {
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4151
|
+
const cache = AsyncCache.getSharedCache();
|
|
4152
|
+
for (const entry in cache) {
|
|
4153
|
+
if (cache[entry].expires > 0 && cache[entry].expires < Date.now()) {
|
|
4154
|
+
delete cache[entry];
|
|
4019
4155
|
}
|
|
4020
4156
|
}
|
|
4021
4157
|
}
|
|
4158
|
+
/**
|
|
4159
|
+
* Get the shared cache.
|
|
4160
|
+
* @returns The shared cache.
|
|
4161
|
+
* @internal
|
|
4162
|
+
*/
|
|
4163
|
+
static getSharedCache() {
|
|
4164
|
+
let sharedCache = SharedStore.get("asyncCache");
|
|
4165
|
+
if (Is.undefined(sharedCache)) {
|
|
4166
|
+
sharedCache = {};
|
|
4167
|
+
SharedStore.set("asyncCache", sharedCache);
|
|
4168
|
+
}
|
|
4169
|
+
return sharedCache;
|
|
4170
|
+
}
|
|
4022
4171
|
}
|
|
4023
4172
|
|
|
4024
4173
|
/**
|
|
@@ -4842,4 +4991,4 @@ class Validation {
|
|
|
4842
4991
|
}
|
|
4843
4992
|
}
|
|
4844
4993
|
|
|
4845
|
-
export { AlreadyExistsError, ArrayHelper, AsyncCache, Base32, Base58, Base64, Base64Url, BaseError, BitString, Coerce, CoerceType, ComponentFactory, Compression, CompressionType, ConflictError, Converter, EnvHelper, ErrorHelper, Factory, FilenameHelper, GeneralError, GuardError, Guards, HexHelper, I18n, Is, JsonHelper, NotFoundError, NotImplementedError, NotSupportedError, ObjectHelper, RandomHelper, StringHelper, Uint8ArrayHelper, UnauthorizedError, UnprocessableError, Url, Urn, Validation, ValidationError };
|
|
4994
|
+
export { AlreadyExistsError, ArrayHelper, AsyncCache, Base32, Base58, Base64, Base64Url, BaseError, BitString, Coerce, CoerceType, ComponentFactory, Compression, CompressionType, ConflictError, Converter, EnvHelper, ErrorHelper, Factory, FilenameHelper, GeneralError, GuardError, Guards, HexHelper, I18n, Is, JsonHelper, NotFoundError, NotImplementedError, NotSupportedError, ObjectHelper, RandomHelper, SharedStore, StringHelper, Uint8ArrayHelper, UnauthorizedError, UnprocessableError, Url, Urn, Validation, ValidationError };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export * from "./models/coerceType";
|
|
|
29
29
|
export * from "./models/compressionType";
|
|
30
30
|
export * from "./models/IComponent";
|
|
31
31
|
export * from "./models/IError";
|
|
32
|
+
export * from "./models/II18nShared";
|
|
32
33
|
export * from "./models/IKeyValue";
|
|
33
34
|
export * from "./models/ILabelledValue";
|
|
34
35
|
export * from "./models/ILocale";
|
|
@@ -47,4 +48,5 @@ export * from "./utils/converter";
|
|
|
47
48
|
export * from "./utils/guards";
|
|
48
49
|
export * from "./utils/i18n";
|
|
49
50
|
export * from "./utils/is";
|
|
51
|
+
export * from "./utils/sharedStore";
|
|
50
52
|
export * from "./utils/validation";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared state for the I18n global.
|
|
3
|
+
*/
|
|
4
|
+
export interface II18nShared {
|
|
5
|
+
/**
|
|
6
|
+
* Dictionaries for lookups.
|
|
7
|
+
*/
|
|
8
|
+
localeDictionaries: {
|
|
9
|
+
[locale: string]: {
|
|
10
|
+
[key: string]: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The current locale.
|
|
15
|
+
*/
|
|
16
|
+
currentLocale: string;
|
|
17
|
+
/**
|
|
18
|
+
* Change handler for the locale being updated.
|
|
19
|
+
*/
|
|
20
|
+
localeChangedHandlers: {
|
|
21
|
+
[id: string]: (locale: string) => void;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Change handler for the dictionaries being updated.
|
|
25
|
+
*/
|
|
26
|
+
dictionaryChangedHandlers: {
|
|
27
|
+
[id: string]: (locale: string) => void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -7,9 +7,10 @@ export declare class AsyncCache {
|
|
|
7
7
|
* @param key The key for the entry in the cache.
|
|
8
8
|
* @param ttlMs The TTL of the entry in the cache.
|
|
9
9
|
* @param requestMethod The method to call if not cached.
|
|
10
|
+
* @param cacheFailures Cache failure results, defaults to false.
|
|
10
11
|
* @returns The response.
|
|
11
12
|
*/
|
|
12
|
-
static exec<T = unknown>(key: string, ttlMs: number | undefined, requestMethod: () => Promise<T
|
|
13
|
+
static exec<T = unknown>(key: string, ttlMs: number | undefined, requestMethod: () => Promise<T>, cacheFailures?: boolean): Promise<T> | undefined;
|
|
13
14
|
/**
|
|
14
15
|
* Get an entry from the cache.
|
|
15
16
|
* @param key The key to get from the cache.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provide a store for shared objects which can be accesses through multiple
|
|
3
|
+
* instance loads of a packages.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SharedStore {
|
|
6
|
+
/**
|
|
7
|
+
* Get a property from the shared store.
|
|
8
|
+
* @param prop The name of the property to get.
|
|
9
|
+
* @returns The property if it exists.
|
|
10
|
+
*/
|
|
11
|
+
static get<T = unknown>(prop: string): T | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Set the property in the shared store.
|
|
14
|
+
* @param prop The name of the property to set.
|
|
15
|
+
* @param value The value to set.
|
|
16
|
+
*/
|
|
17
|
+
static set<T = unknown>(prop: string, value: T): void;
|
|
18
|
+
/**
|
|
19
|
+
* Remove a property from the shared store.
|
|
20
|
+
* @param prop The name of the property to remove.
|
|
21
|
+
*/
|
|
22
|
+
static remove(prop: string): void;
|
|
23
|
+
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @twin.org/core - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.1-next.53](https://github.com/twinfoundation/framework/compare/core-v0.0.1-next.52...core-v0.0.1-next.53) (2025-05-01)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* async cache don't cache failures unless requested ([658ec4b](https://github.com/twinfoundation/framework/commit/658ec4b67a58a075de4702a3886d151e25ad3ddc))
|
|
9
|
+
|
|
10
|
+
## [0.0.1-next.52](https://github.com/twinfoundation/framework/compare/core-v0.0.1-next.51...core-v0.0.1-next.52) (2025-04-17)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* use new shared store mechanism ([#131](https://github.com/twinfoundation/framework/issues/131)) ([934385b](https://github.com/twinfoundation/framework/commit/934385b2fbaf9f5c00a505ebf9d093bd5a425f55))
|
|
16
|
+
|
|
3
17
|
## [0.0.1-next.51](https://github.com/twinfoundation/framework/compare/core-v0.0.1-next.50...core-v0.0.1-next.51) (2025-03-27)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -8,9 +8,9 @@ Class to handle errors which are triggered by data already existing.
|
|
|
8
8
|
|
|
9
9
|
## Constructors
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Constructor
|
|
12
12
|
|
|
13
|
-
> **new AlreadyExistsError**(`source`, `message`, `existingId
|
|
13
|
+
> **new AlreadyExistsError**(`source`, `message`, `existingId?`, `inner?`): `AlreadyExistsError`
|
|
14
14
|
|
|
15
15
|
Create a new instance of AlreadyExistsError.
|
|
16
16
|
|
|
@@ -42,11 +42,11 @@ The inner error if we have wrapped another error.
|
|
|
42
42
|
|
|
43
43
|
#### Returns
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
`AlreadyExistsError`
|
|
46
46
|
|
|
47
47
|
#### Overrides
|
|
48
48
|
|
|
49
|
-
[`BaseError`](BaseError.md).[`constructor`](BaseError.md#
|
|
49
|
+
[`BaseError`](BaseError.md).[`constructor`](BaseError.md#constructor)
|
|
50
50
|
|
|
51
51
|
## Properties
|
|
52
52
|
|
|
@@ -66,7 +66,7 @@ The source of the error.
|
|
|
66
66
|
|
|
67
67
|
#### Inherited from
|
|
68
68
|
|
|
69
|
-
[`BaseError`](BaseError.md).[`source`](BaseError.md#source
|
|
69
|
+
[`BaseError`](BaseError.md).[`source`](BaseError.md#source)
|
|
70
70
|
|
|
71
71
|
***
|
|
72
72
|
|
|
@@ -82,7 +82,7 @@ Any additional information for the error.
|
|
|
82
82
|
|
|
83
83
|
#### Inherited from
|
|
84
84
|
|
|
85
|
-
[`BaseError`](BaseError.md).[`properties`](BaseError.md#properties
|
|
85
|
+
[`BaseError`](BaseError.md).[`properties`](BaseError.md#properties)
|
|
86
86
|
|
|
87
87
|
***
|
|
88
88
|
|
|
@@ -94,7 +94,7 @@ The inner error if there was one.
|
|
|
94
94
|
|
|
95
95
|
#### Inherited from
|
|
96
96
|
|
|
97
|
-
[`BaseError`](BaseError.md).[`inner`](BaseError.md#inner
|
|
97
|
+
[`BaseError`](BaseError.md).[`inner`](BaseError.md#inner)
|
|
98
98
|
|
|
99
99
|
## Methods
|
|
100
100
|
|
|
@@ -4,13 +4,13 @@ Class to help with arrays.
|
|
|
4
4
|
|
|
5
5
|
## Constructors
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Constructor
|
|
8
8
|
|
|
9
|
-
> **new ArrayHelper**():
|
|
9
|
+
> **new ArrayHelper**(): `ArrayHelper`
|
|
10
10
|
|
|
11
11
|
#### Returns
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`ArrayHelper`
|
|
14
14
|
|
|
15
15
|
## Methods
|
|
16
16
|
|