@lionrapid/core 0.6.6 → 0.7.0
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/LICENSE +21 -0
- package/dist/browser/auto-init.d.ts +6 -0
- package/dist/browser/auto-init.d.ts.map +1 -1
- package/dist/browser/auto-init.js +36 -6
- package/dist/browser/auto-init.js.map +1 -1
- package/dist/browser/language-switcher.d.ts +12 -0
- package/dist/browser/language-switcher.d.ts.map +1 -1
- package/dist/browser/language-switcher.js +58 -0
- package/dist/browser/language-switcher.js.map +1 -1
- package/dist/browser/lionrapid.auto.dev.js +163 -14
- package/dist/browser/lionrapid.auto.dev.js.map +3 -3
- package/dist/browser/lionrapid.auto.js +163 -14
- package/dist/browser/lionrapid.auto.js.map +3 -3
- package/dist/browser/lionrapid.auto.min.js +5 -5
- package/dist/browser/lionrapid.auto.min.js.map +4 -4
- package/dist/browser/lionrapid.esm.js +103 -10
- package/dist/browser/lionrapid.esm.js.map +2 -2
- package/dist/browser/lionrapid.esm.min.js +4 -4
- package/dist/browser/lionrapid.esm.min.js.map +3 -3
- package/dist/browser/lionrapid.iife.dev.js +103 -10
- package/dist/browser/lionrapid.iife.dev.js.map +2 -2
- package/dist/browser/lionrapid.iife.js +103 -10
- package/dist/browser/lionrapid.iife.js.map +2 -2
- package/dist/browser/lionrapid.iife.min.js +4 -4
- package/dist/browser/lionrapid.iife.min.js.map +3 -3
- package/dist/browser/lionrapid.umd.js +103 -10
- package/dist/browser/lionrapid.umd.js.map +2 -2
- package/dist/browser/lionrapid.umd.min.js +4 -4
- package/dist/browser/lionrapid.umd.min.js.map +3 -3
- package/dist/browser/storage/cache-storage-repository.d.ts +9 -0
- package/dist/browser/storage/cache-storage-repository.d.ts.map +1 -1
- package/dist/browser/storage/cache-storage-repository.js +14 -10
- package/dist/browser/storage/cache-storage-repository.js.map +1 -1
- package/dist/browser/storage/scope.d.ts +12 -0
- package/dist/browser/storage/scope.d.ts.map +1 -0
- package/dist/browser/storage/scope.js +15 -0
- package/dist/browser/storage/scope.js.map +1 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +9 -0
- package/dist/builder.js.map +1 -1
- package/dist/handlers/async-storage-handler.d.ts +9 -0
- package/dist/handlers/async-storage-handler.d.ts.map +1 -1
- package/dist/handlers/async-storage-handler.js +42 -0
- package/dist/handlers/async-storage-handler.js.map +1 -1
- package/dist/handlers/handler-chain.d.ts +2 -0
- package/dist/handlers/handler-chain.d.ts.map +1 -1
- package/dist/handlers/handler-chain.js +29 -0
- package/dist/handlers/handler-chain.js.map +1 -1
- package/dist/handlers/sync-storage-handler.d.ts +4 -0
- package/dist/handlers/sync-storage-handler.d.ts.map +1 -1
- package/dist/handlers/sync-storage-handler.js +35 -0
- package/dist/handlers/sync-storage-handler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interfaces/handler.interface.d.ts +4 -0
- package/dist/interfaces/handler.interface.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -1246,6 +1246,24 @@ var HandlerChain = class {
|
|
|
1246
1246
|
});
|
|
1247
1247
|
await Promise.allSettled(savePromises);
|
|
1248
1248
|
}
|
|
1249
|
+
/** Forget `locale:namespace` in every memory and storage handler (a 404). */
|
|
1250
|
+
async forgetNamespaceInHandlers(context) {
|
|
1251
|
+
for (const handler of this.syncHandlers) {
|
|
1252
|
+
try {
|
|
1253
|
+
handler.forgetNamespace?.(context);
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
logger.warn(`Failed to clear namespace in ${handler.name}`, error);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
for (const handler of this.asyncHandlers) {
|
|
1259
|
+
if (handler.type !== "storage" && handler.type !== "memory") continue;
|
|
1260
|
+
try {
|
|
1261
|
+
await handler.forgetNamespace?.(context);
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
logger.warn(`Failed to clear namespace in ${handler.name}`, error);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1249
1267
|
async saveNamespaceToHandlers(translations, context) {
|
|
1250
1268
|
this.saveNamespaceToMemoryHandlers(translations, context);
|
|
1251
1269
|
await this.saveNamespaceToStorageHandlers(translations, context);
|
|
@@ -1347,6 +1365,10 @@ var HandlerChain = class {
|
|
|
1347
1365
|
});
|
|
1348
1366
|
return result.data;
|
|
1349
1367
|
}
|
|
1368
|
+
if (result && result.status === 404) {
|
|
1369
|
+
await this.forgetNamespaceInHandlers({ namespace, locale });
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1350
1372
|
} catch (error) {
|
|
1351
1373
|
logger.warn(
|
|
1352
1374
|
`Failed to load namespace: ${locale}:${namespace} from ${handler.name}`,
|
|
@@ -1730,6 +1752,7 @@ var SyncHandler = class {
|
|
|
1730
1752
|
context.locale + ":" + context.namespace,
|
|
1731
1753
|
this.name
|
|
1732
1754
|
);
|
|
1755
|
+
const previousKeys = this.storedNamespaceKeys(context.locale, context.namespace);
|
|
1733
1756
|
const namespaceCacheKey = createNamespaceCacheKey(
|
|
1734
1757
|
context.locale,
|
|
1735
1758
|
context.namespace
|
|
@@ -1741,11 +1764,38 @@ var SyncHandler = class {
|
|
|
1741
1764
|
context.locale,
|
|
1742
1765
|
context.namespace
|
|
1743
1766
|
);
|
|
1767
|
+
for (const key of previousKeys) {
|
|
1768
|
+
if (!(key in flattened)) this.removeQuietly(key);
|
|
1769
|
+
}
|
|
1744
1770
|
for (const [flatKey, flatValue] of Object.entries(flattened)) {
|
|
1745
1771
|
this.setWithTTL(flatKey, flatValue);
|
|
1746
1772
|
}
|
|
1747
1773
|
repoBus.setSuccess(JSON.stringify(translations));
|
|
1748
1774
|
}
|
|
1775
|
+
/** Forget a namespace the server says does not exist (404). See AsyncStorageHandler. */
|
|
1776
|
+
forgetNamespace(context) {
|
|
1777
|
+
if (!context.namespace) return;
|
|
1778
|
+
for (const key of this.storedNamespaceKeys(context.locale, context.namespace)) {
|
|
1779
|
+
this.removeQuietly(key);
|
|
1780
|
+
}
|
|
1781
|
+
this.clearNamespace(context.locale, context.namespace);
|
|
1782
|
+
}
|
|
1783
|
+
storedNamespaceKeys(locale, namespace) {
|
|
1784
|
+
try {
|
|
1785
|
+
const blob = this.repository.get(createNamespaceCacheKey(locale, namespace));
|
|
1786
|
+
if (!blob) return [];
|
|
1787
|
+
return Object.keys(flattenTranslations(JSON.parse(blob), "", locale, namespace));
|
|
1788
|
+
} catch {
|
|
1789
|
+
return [];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
removeQuietly(cacheKey) {
|
|
1793
|
+
this.ttlMap.delete(cacheKey);
|
|
1794
|
+
try {
|
|
1795
|
+
this.repository.remove(cacheKey);
|
|
1796
|
+
} catch {
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1749
1799
|
/**
|
|
1750
1800
|
* ✅ Strategy 1: Direct cache lookup using unified pattern
|
|
1751
1801
|
* Returns parsed ContentUnit (text + styles) or null
|
|
@@ -1999,6 +2049,7 @@ var AsyncHandler = class {
|
|
|
1999
2049
|
logger.debug(
|
|
2000
2050
|
`Saving namespace: ${context.locale}:${context.namespace} (${keyCount} keys)`
|
|
2001
2051
|
);
|
|
2052
|
+
const previousKeys = await this.storedNamespaceKeys(context.locale, context.namespace);
|
|
2002
2053
|
const namespaceCacheKey = createNamespaceCacheKey(
|
|
2003
2054
|
context.locale,
|
|
2004
2055
|
context.namespace
|
|
@@ -2010,6 +2061,9 @@ var AsyncHandler = class {
|
|
|
2010
2061
|
context.locale,
|
|
2011
2062
|
context.namespace
|
|
2012
2063
|
);
|
|
2064
|
+
for (const key of previousKeys) {
|
|
2065
|
+
if (!(key in flattened)) await this.removeQuietly(key);
|
|
2066
|
+
}
|
|
2013
2067
|
let savedCount = 0;
|
|
2014
2068
|
for (const [flatKey, flatValue] of Object.entries(flattened)) {
|
|
2015
2069
|
await this.setWithTTL(flatKey, flatValue);
|
|
@@ -2018,6 +2072,35 @@ var AsyncHandler = class {
|
|
|
2018
2072
|
logger.debug(`Saved: ${savedCount} keys + namespace blob`);
|
|
2019
2073
|
repoBus.setSuccess(JSON.stringify(translations));
|
|
2020
2074
|
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Forget a namespace the server says does not exist (404): its blob and
|
|
2077
|
+
* every per-key entry the blob listed. A network failure never gets here,
|
|
2078
|
+
* so the offline floor still serves when the server is unreachable.
|
|
2079
|
+
*/
|
|
2080
|
+
async forgetNamespace(context) {
|
|
2081
|
+
if (!context.namespace) return;
|
|
2082
|
+
for (const key of await this.storedNamespaceKeys(context.locale, context.namespace)) {
|
|
2083
|
+
await this.removeQuietly(key);
|
|
2084
|
+
}
|
|
2085
|
+
await this.removeQuietly(createNamespaceCacheKey(context.locale, context.namespace));
|
|
2086
|
+
}
|
|
2087
|
+
/** The per-key cache keys (`locale:namespace:key`) the stored blob lists. */
|
|
2088
|
+
async storedNamespaceKeys(locale, namespace) {
|
|
2089
|
+
try {
|
|
2090
|
+
const blob = await this.repository.get(createNamespaceCacheKey(locale, namespace));
|
|
2091
|
+
if (!blob) return [];
|
|
2092
|
+
return Object.keys(flattenTranslations(JSON.parse(blob), "", locale, namespace));
|
|
2093
|
+
} catch {
|
|
2094
|
+
return [];
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
async removeQuietly(cacheKey) {
|
|
2098
|
+
this.ttlMap.delete(cacheKey);
|
|
2099
|
+
try {
|
|
2100
|
+
await this.repository.remove(cacheKey);
|
|
2101
|
+
} catch {
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2021
2104
|
/**
|
|
2022
2105
|
* ✅ Strategy 1: Direct cache lookup using unified pattern
|
|
2023
2106
|
* Returns parsed ContentUnit (text + styles) or null
|
|
@@ -4245,6 +4328,12 @@ var LionRapidBuilder = class _LionRapidBuilder {
|
|
|
4245
4328
|
logger.debug(`Preloaded: ${namespaceKey}`);
|
|
4246
4329
|
return;
|
|
4247
4330
|
}
|
|
4331
|
+
if (result?.status === 404) {
|
|
4332
|
+
await handlerChain.forgetNamespaceInHandlers({
|
|
4333
|
+
locale: preloadConfig.locale,
|
|
4334
|
+
namespace: preloadConfig.namespace
|
|
4335
|
+
});
|
|
4336
|
+
}
|
|
4248
4337
|
if (result?.error) {
|
|
4249
4338
|
warnLoudlyOnce(namespaceKey, result.error);
|
|
4250
4339
|
logger.warn(`Preload failed: ${namespaceKey}`, result.error);
|
|
@@ -5621,6 +5710,8 @@ var CacheStorageRepository = class {
|
|
|
5621
5710
|
__publicField(this, "type", "storage");
|
|
5622
5711
|
__publicField(this, "config");
|
|
5623
5712
|
__publicField(this, "cacheName");
|
|
5713
|
+
/** CACHE_PREFIX, plus `<scope>/` when scoped. */
|
|
5714
|
+
__publicField(this, "entryPrefix");
|
|
5624
5715
|
__publicField(this, "defaultTTL");
|
|
5625
5716
|
__publicField(this, "available");
|
|
5626
5717
|
this.config = {
|
|
@@ -5634,6 +5725,8 @@ var CacheStorageRepository = class {
|
|
|
5634
5725
|
}
|
|
5635
5726
|
};
|
|
5636
5727
|
this.cacheName = this.config.options?.cacheName ?? CACHE_NAME;
|
|
5728
|
+
const scope = this.config.options?.scope;
|
|
5729
|
+
this.entryPrefix = scope ? `${CACHE_PREFIX}${encodeURIComponent(scope)}/` : CACHE_PREFIX;
|
|
5637
5730
|
this.defaultTTL = this.config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3;
|
|
5638
5731
|
this.available = this.checkAvailability();
|
|
5639
5732
|
}
|
|
@@ -5654,13 +5747,13 @@ var CacheStorageRepository = class {
|
|
|
5654
5747
|
}
|
|
5655
5748
|
try {
|
|
5656
5749
|
const cache = await caches.open(this.cacheName);
|
|
5657
|
-
const response = await cache.match(
|
|
5750
|
+
const response = await cache.match(this.entryPrefix + key);
|
|
5658
5751
|
if (!response) {
|
|
5659
5752
|
throw new TranslationNotFoundError(key);
|
|
5660
5753
|
}
|
|
5661
5754
|
const data = await response.json();
|
|
5662
5755
|
if (data.expiry !== null && Date.now() > data.expiry) {
|
|
5663
|
-
await cache.delete(
|
|
5756
|
+
await cache.delete(this.entryPrefix + key);
|
|
5664
5757
|
throw new TranslationNotFoundError(key);
|
|
5665
5758
|
}
|
|
5666
5759
|
return data.value;
|
|
@@ -5684,7 +5777,7 @@ var CacheStorageRepository = class {
|
|
|
5684
5777
|
timestamp: Date.now()
|
|
5685
5778
|
};
|
|
5686
5779
|
await cache.put(
|
|
5687
|
-
|
|
5780
|
+
this.entryPrefix + key,
|
|
5688
5781
|
new Response(JSON.stringify(data), {
|
|
5689
5782
|
headers: { "Content-Type": "application/json" }
|
|
5690
5783
|
})
|
|
@@ -5699,7 +5792,7 @@ var CacheStorageRepository = class {
|
|
|
5699
5792
|
if (!this.available) return;
|
|
5700
5793
|
try {
|
|
5701
5794
|
const cache = await caches.open(this.cacheName);
|
|
5702
|
-
await cache.delete(
|
|
5795
|
+
await cache.delete(this.entryPrefix + key);
|
|
5703
5796
|
} catch {
|
|
5704
5797
|
}
|
|
5705
5798
|
}
|
|
@@ -5712,7 +5805,7 @@ var CacheStorageRepository = class {
|
|
|
5712
5805
|
const cache = await caches.open(this.cacheName);
|
|
5713
5806
|
const keys = await cache.keys();
|
|
5714
5807
|
await Promise.all(
|
|
5715
|
-
keys.filter((request) => request.url.includes(
|
|
5808
|
+
keys.filter((request) => request.url.includes(this.entryPrefix)).map((request) => cache.delete(request))
|
|
5716
5809
|
);
|
|
5717
5810
|
} catch {
|
|
5718
5811
|
}
|
|
@@ -5730,7 +5823,7 @@ var CacheStorageRepository = class {
|
|
|
5730
5823
|
await Promise.all(
|
|
5731
5824
|
keys.filter((request) => {
|
|
5732
5825
|
const url = request.url;
|
|
5733
|
-
const key = url.includes(
|
|
5826
|
+
const key = url.includes(this.entryPrefix) ? url.substring(url.indexOf(this.entryPrefix) + this.entryPrefix.length) : "";
|
|
5734
5827
|
return key === namespaceCacheKey || key.startsWith(keyPrefix);
|
|
5735
5828
|
}).map((request) => cache.delete(request))
|
|
5736
5829
|
);
|
|
@@ -5782,9 +5875,9 @@ var CacheStorageRepository = class {
|
|
|
5782
5875
|
const keys = await cache.keys();
|
|
5783
5876
|
for (const request of keys) {
|
|
5784
5877
|
const url = request.url;
|
|
5785
|
-
if (!url.includes(
|
|
5878
|
+
if (!url.includes(this.entryPrefix)) continue;
|
|
5786
5879
|
const key = url.substring(
|
|
5787
|
-
url.indexOf(
|
|
5880
|
+
url.indexOf(this.entryPrefix) + this.entryPrefix.length
|
|
5788
5881
|
);
|
|
5789
5882
|
try {
|
|
5790
5883
|
const value = await this.get(key);
|
|
@@ -5806,7 +5899,7 @@ var CacheStorageRepository = class {
|
|
|
5806
5899
|
try {
|
|
5807
5900
|
const cache = await caches.open(this.cacheName);
|
|
5808
5901
|
const keys = await cache.keys();
|
|
5809
|
-
const size = keys.filter((r) => r.url.includes(
|
|
5902
|
+
const size = keys.filter((r) => r.url.includes(this.entryPrefix)).length;
|
|
5810
5903
|
return { size, cacheName: this.cacheName };
|
|
5811
5904
|
} catch {
|
|
5812
5905
|
return { size: 0, cacheName: this.cacheName };
|
|
@@ -5818,7 +5911,7 @@ var CacheStorageRepository = class {
|
|
|
5818
5911
|
var DEFAULT_API_BASE_URL = "https://app.lionrapid.com";
|
|
5819
5912
|
|
|
5820
5913
|
// src/index.ts
|
|
5821
|
-
var VERSION = "0.
|
|
5914
|
+
var VERSION = "0.7.0";
|
|
5822
5915
|
//# sourceMappingURL=lionrapid.umd.js.map
|
|
5823
5916
|
|
|
5824
5917
|
return exports;
|