@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.
Files changed (55) hide show
  1. package/dist/cjs/index.cjs +225 -75
  2. package/dist/esm/index.mjs +225 -76
  3. package/dist/types/index.d.ts +2 -0
  4. package/dist/types/models/II18nShared.d.ts +29 -0
  5. package/dist/types/utils/asyncCache.d.ts +2 -1
  6. package/dist/types/utils/sharedStore.d.ts +23 -0
  7. package/docs/changelog.md +14 -0
  8. package/docs/reference/classes/AlreadyExistsError.md +7 -7
  9. package/docs/reference/classes/ArrayHelper.md +3 -3
  10. package/docs/reference/classes/AsyncCache.md +21 -9
  11. package/docs/reference/classes/Base32.md +3 -3
  12. package/docs/reference/classes/Base58.md +3 -3
  13. package/docs/reference/classes/Base64.md +3 -3
  14. package/docs/reference/classes/Base64Url.md +3 -3
  15. package/docs/reference/classes/BaseError.md +5 -5
  16. package/docs/reference/classes/BitString.md +5 -5
  17. package/docs/reference/classes/Coerce.md +7 -5
  18. package/docs/reference/classes/Compression.md +3 -3
  19. package/docs/reference/classes/ConflictError.md +7 -7
  20. package/docs/reference/classes/Converter.md +6 -6
  21. package/docs/reference/classes/EnvHelper.md +7 -5
  22. package/docs/reference/classes/ErrorHelper.md +3 -3
  23. package/docs/reference/classes/Factory.md +17 -7
  24. package/docs/reference/classes/FilenameHelper.md +3 -3
  25. package/docs/reference/classes/GeneralError.md +7 -7
  26. package/docs/reference/classes/GuardError.md +7 -7
  27. package/docs/reference/classes/Guards.md +18 -8
  28. package/docs/reference/classes/HexHelper.md +3 -3
  29. package/docs/reference/classes/I18n.md +6 -6
  30. package/docs/reference/classes/Is.md +21 -9
  31. package/docs/reference/classes/JsonHelper.md +10 -6
  32. package/docs/reference/classes/NotFoundError.md +7 -7
  33. package/docs/reference/classes/NotImplementedError.md +7 -7
  34. package/docs/reference/classes/NotSupportedError.md +7 -7
  35. package/docs/reference/classes/ObjectHelper.md +40 -18
  36. package/docs/reference/classes/RandomHelper.md +3 -3
  37. package/docs/reference/classes/SharedStore.md +94 -0
  38. package/docs/reference/classes/StringHelper.md +3 -3
  39. package/docs/reference/classes/Uint8ArrayHelper.md +3 -3
  40. package/docs/reference/classes/UnauthorizedError.md +7 -7
  41. package/docs/reference/classes/UnprocessableError.md +7 -7
  42. package/docs/reference/classes/Url.md +7 -7
  43. package/docs/reference/classes/Urn.md +9 -9
  44. package/docs/reference/classes/Validation.md +36 -28
  45. package/docs/reference/classes/ValidationError.md +7 -7
  46. package/docs/reference/index.md +2 -0
  47. package/docs/reference/interfaces/IComponent.md +3 -3
  48. package/docs/reference/interfaces/IError.md +1 -1
  49. package/docs/reference/interfaces/II18nShared.md +47 -0
  50. package/docs/reference/interfaces/IKeyValue.md +3 -1
  51. package/docs/reference/interfaces/ILabelledValue.md +3 -1
  52. package/docs/reference/interfaces/ILocaleDictionary.md +1 -1
  53. package/docs/reference/type-aliases/CoerceType.md +1 -1
  54. package/docs/reference/type-aliases/CompressionType.md +1 -1
  55. package/package.json +2 -2
@@ -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
- if (Is.undefined(Factory._factories[typeName])) {
1885
- Factory._factories[typeName] = new Factory(typeName, autoInstance, matcher);
1926
+ const factories = Factory.getFactories();
1927
+ if (Is.undefined(factories[typeName])) {
1928
+ factories[typeName] = new Factory(typeName, autoInstance, matcher);
1886
1929
  }
1887
- return Factory._factories[typeName];
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
- return Factory._factories;
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
- for (const typeName in Factory._factories) {
1901
- Factory._factories[typeName].reset();
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
- for (const typeName in Factory._factories) {
1909
- Factory._factories[typeName].clear();
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
- I18n._currentLocale = locale;
2883
- for (const callback in I18n._localeChangedHandlers) {
2884
- I18n._localeChangedHandlers[callback](I18n._currentLocale);
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
- return I18n._currentLocale;
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
- I18n._localeDictionaries[locale] = mergedKeys;
2903
- for (const callback in I18n._dictionaryChangedHandlers) {
2904
- I18n._dictionaryChangedHandlers[callback](I18n._currentLocale);
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
- return I18n._localeDictionaries[locale];
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
- return I18n._localeDictionaries;
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
- I18n._localeChangedHandlers[id] = handler;
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
- delete I18n._localeChangedHandlers[id];
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
- I18n._dictionaryChangedHandlers[id] = handler;
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
- delete I18n._dictionaryChangedHandlers[id];
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
- let cl = overrideLocale ?? I18n._currentLocale;
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 (!I18n._localeDictionaries[cl]) {
3004
+ if (!i18nShared.localeDictionaries[cl]) {
2965
3005
  return `!!Missing ${cl}`;
2966
3006
  }
2967
- if (!I18n._localeDictionaries[cl][key]) {
3007
+ if (!i18nShared.localeDictionaries[cl][key]) {
2968
3008
  return `!!Missing ${cl}.${key}`;
2969
3009
  }
2970
- if (I18n._currentLocale === "debug-k") {
3010
+ if (i18nShared.currentLocale === "debug-k") {
2971
3011
  return key;
2972
3012
  }
2973
- let ret = new IntlMessageFormat(I18n._localeDictionaries[cl][key], cl).format(values);
2974
- if (I18n._currentLocale === "debug-x") {
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
- return Is.string(I18n._localeDictionaries[I18n._currentLocale]?.[key]);
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
- if (!this._cache[key]) {
3960
- this._cache[key] = {
3961
- response: requestMethod(),
3962
- expires: ttlMs === 0 ? 0 : Date.now() + ttlMs
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
- return this._cache[key].response;
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
- return AsyncCache._cache[key]?.response;
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
- AsyncCache._cache[key] = {
3985
- response: Promise.resolve(value),
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
- delete AsyncCache._cache[key];
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 this._cache) {
4137
+ for (const entry in cache) {
4003
4138
  if (entry.startsWith(prefix)) {
4004
- delete this._cache[entry];
4139
+ delete cache[entry];
4005
4140
  }
4006
4141
  }
4007
4142
  }
4008
4143
  else {
4009
- AsyncCache._cache = {};
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
- for (const entry in this._cache) {
4017
- if (AsyncCache._cache[entry].expires > 0 && AsyncCache._cache[entry].expires < Date.now()) {
4018
- delete this._cache[entry];
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 };
@@ -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>): Promise<T> | undefined;
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
- ### new AlreadyExistsError()
11
+ ### Constructor
12
12
 
13
- > **new AlreadyExistsError**(`source`, `message`, `existingId`?, `inner`?): [`AlreadyExistsError`](AlreadyExistsError.md)
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
- [`AlreadyExistsError`](AlreadyExistsError.md)
45
+ `AlreadyExistsError`
46
46
 
47
47
  #### Overrides
48
48
 
49
- [`BaseError`](BaseError.md).[`constructor`](BaseError.md#constructors)
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-1)
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-1)
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-1)
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
- ### new ArrayHelper()
7
+ ### Constructor
8
8
 
9
- > **new ArrayHelper**(): [`ArrayHelper`](ArrayHelper.md)
9
+ > **new ArrayHelper**(): `ArrayHelper`
10
10
 
11
11
  #### Returns
12
12
 
13
- [`ArrayHelper`](ArrayHelper.md)
13
+ `ArrayHelper`
14
14
 
15
15
  ## Methods
16
16