@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
|
@@ -1149,6 +1149,24 @@ var HandlerChain = class {
|
|
|
1149
1149
|
});
|
|
1150
1150
|
await Promise.allSettled(savePromises);
|
|
1151
1151
|
}
|
|
1152
|
+
/** Forget `locale:namespace` in every memory and storage handler (a 404). */
|
|
1153
|
+
async forgetNamespaceInHandlers(context) {
|
|
1154
|
+
for (const handler of this.syncHandlers) {
|
|
1155
|
+
try {
|
|
1156
|
+
handler.forgetNamespace?.(context);
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
logger.warn(`Failed to clear namespace in ${handler.name}`, error);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
for (const handler of this.asyncHandlers) {
|
|
1162
|
+
if (handler.type !== "storage" && handler.type !== "memory") continue;
|
|
1163
|
+
try {
|
|
1164
|
+
await handler.forgetNamespace?.(context);
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
logger.warn(`Failed to clear namespace in ${handler.name}`, error);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1152
1170
|
async saveNamespaceToHandlers(translations, context) {
|
|
1153
1171
|
this.saveNamespaceToMemoryHandlers(translations, context);
|
|
1154
1172
|
await this.saveNamespaceToStorageHandlers(translations, context);
|
|
@@ -1250,6 +1268,10 @@ var HandlerChain = class {
|
|
|
1250
1268
|
});
|
|
1251
1269
|
return result.data;
|
|
1252
1270
|
}
|
|
1271
|
+
if (result && result.status === 404) {
|
|
1272
|
+
await this.forgetNamespaceInHandlers({ namespace, locale });
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1253
1275
|
} catch (error) {
|
|
1254
1276
|
logger.warn(
|
|
1255
1277
|
`Failed to load namespace: ${locale}:${namespace} from ${handler.name}`,
|
|
@@ -1633,6 +1655,7 @@ var SyncHandler = class {
|
|
|
1633
1655
|
context.locale + ":" + context.namespace,
|
|
1634
1656
|
this.name
|
|
1635
1657
|
);
|
|
1658
|
+
const previousKeys = this.storedNamespaceKeys(context.locale, context.namespace);
|
|
1636
1659
|
const namespaceCacheKey = createNamespaceCacheKey(
|
|
1637
1660
|
context.locale,
|
|
1638
1661
|
context.namespace
|
|
@@ -1644,11 +1667,38 @@ var SyncHandler = class {
|
|
|
1644
1667
|
context.locale,
|
|
1645
1668
|
context.namespace
|
|
1646
1669
|
);
|
|
1670
|
+
for (const key of previousKeys) {
|
|
1671
|
+
if (!(key in flattened)) this.removeQuietly(key);
|
|
1672
|
+
}
|
|
1647
1673
|
for (const [flatKey, flatValue] of Object.entries(flattened)) {
|
|
1648
1674
|
this.setWithTTL(flatKey, flatValue);
|
|
1649
1675
|
}
|
|
1650
1676
|
repoBus.setSuccess(JSON.stringify(translations));
|
|
1651
1677
|
}
|
|
1678
|
+
/** Forget a namespace the server says does not exist (404). See AsyncStorageHandler. */
|
|
1679
|
+
forgetNamespace(context) {
|
|
1680
|
+
if (!context.namespace) return;
|
|
1681
|
+
for (const key of this.storedNamespaceKeys(context.locale, context.namespace)) {
|
|
1682
|
+
this.removeQuietly(key);
|
|
1683
|
+
}
|
|
1684
|
+
this.clearNamespace(context.locale, context.namespace);
|
|
1685
|
+
}
|
|
1686
|
+
storedNamespaceKeys(locale, namespace) {
|
|
1687
|
+
try {
|
|
1688
|
+
const blob = this.repository.get(createNamespaceCacheKey(locale, namespace));
|
|
1689
|
+
if (!blob) return [];
|
|
1690
|
+
return Object.keys(flattenTranslations(JSON.parse(blob), "", locale, namespace));
|
|
1691
|
+
} catch {
|
|
1692
|
+
return [];
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
removeQuietly(cacheKey) {
|
|
1696
|
+
this.ttlMap.delete(cacheKey);
|
|
1697
|
+
try {
|
|
1698
|
+
this.repository.remove(cacheKey);
|
|
1699
|
+
} catch {
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1652
1702
|
/**
|
|
1653
1703
|
* ✅ Strategy 1: Direct cache lookup using unified pattern
|
|
1654
1704
|
* Returns parsed ContentUnit (text + styles) or null
|
|
@@ -1902,6 +1952,7 @@ var AsyncHandler = class {
|
|
|
1902
1952
|
logger.debug(
|
|
1903
1953
|
`Saving namespace: ${context.locale}:${context.namespace} (${keyCount} keys)`
|
|
1904
1954
|
);
|
|
1955
|
+
const previousKeys = await this.storedNamespaceKeys(context.locale, context.namespace);
|
|
1905
1956
|
const namespaceCacheKey = createNamespaceCacheKey(
|
|
1906
1957
|
context.locale,
|
|
1907
1958
|
context.namespace
|
|
@@ -1913,6 +1964,9 @@ var AsyncHandler = class {
|
|
|
1913
1964
|
context.locale,
|
|
1914
1965
|
context.namespace
|
|
1915
1966
|
);
|
|
1967
|
+
for (const key of previousKeys) {
|
|
1968
|
+
if (!(key in flattened)) await this.removeQuietly(key);
|
|
1969
|
+
}
|
|
1916
1970
|
let savedCount = 0;
|
|
1917
1971
|
for (const [flatKey, flatValue] of Object.entries(flattened)) {
|
|
1918
1972
|
await this.setWithTTL(flatKey, flatValue);
|
|
@@ -1921,6 +1975,35 @@ var AsyncHandler = class {
|
|
|
1921
1975
|
logger.debug(`Saved: ${savedCount} keys + namespace blob`);
|
|
1922
1976
|
repoBus.setSuccess(JSON.stringify(translations));
|
|
1923
1977
|
}
|
|
1978
|
+
/**
|
|
1979
|
+
* Forget a namespace the server says does not exist (404): its blob and
|
|
1980
|
+
* every per-key entry the blob listed. A network failure never gets here,
|
|
1981
|
+
* so the offline floor still serves when the server is unreachable.
|
|
1982
|
+
*/
|
|
1983
|
+
async forgetNamespace(context) {
|
|
1984
|
+
if (!context.namespace) return;
|
|
1985
|
+
for (const key of await this.storedNamespaceKeys(context.locale, context.namespace)) {
|
|
1986
|
+
await this.removeQuietly(key);
|
|
1987
|
+
}
|
|
1988
|
+
await this.removeQuietly(createNamespaceCacheKey(context.locale, context.namespace));
|
|
1989
|
+
}
|
|
1990
|
+
/** The per-key cache keys (`locale:namespace:key`) the stored blob lists. */
|
|
1991
|
+
async storedNamespaceKeys(locale, namespace) {
|
|
1992
|
+
try {
|
|
1993
|
+
const blob = await this.repository.get(createNamespaceCacheKey(locale, namespace));
|
|
1994
|
+
if (!blob) return [];
|
|
1995
|
+
return Object.keys(flattenTranslations(JSON.parse(blob), "", locale, namespace));
|
|
1996
|
+
} catch {
|
|
1997
|
+
return [];
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
async removeQuietly(cacheKey) {
|
|
2001
|
+
this.ttlMap.delete(cacheKey);
|
|
2002
|
+
try {
|
|
2003
|
+
await this.repository.remove(cacheKey);
|
|
2004
|
+
} catch {
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
1924
2007
|
/**
|
|
1925
2008
|
* ✅ Strategy 1: Direct cache lookup using unified pattern
|
|
1926
2009
|
* Returns parsed ContentUnit (text + styles) or null
|
|
@@ -4148,6 +4231,12 @@ var LionRapidBuilder = class _LionRapidBuilder {
|
|
|
4148
4231
|
logger.debug(`Preloaded: ${namespaceKey}`);
|
|
4149
4232
|
return;
|
|
4150
4233
|
}
|
|
4234
|
+
if (result?.status === 404) {
|
|
4235
|
+
await handlerChain.forgetNamespaceInHandlers({
|
|
4236
|
+
locale: preloadConfig.locale,
|
|
4237
|
+
namespace: preloadConfig.namespace
|
|
4238
|
+
});
|
|
4239
|
+
}
|
|
4151
4240
|
if (result?.error) {
|
|
4152
4241
|
warnLoudlyOnce(namespaceKey, result.error);
|
|
4153
4242
|
logger.warn(`Preload failed: ${namespaceKey}`, result.error);
|
|
@@ -5524,6 +5613,8 @@ var CacheStorageRepository = class {
|
|
|
5524
5613
|
__publicField(this, "type", "storage");
|
|
5525
5614
|
__publicField(this, "config");
|
|
5526
5615
|
__publicField(this, "cacheName");
|
|
5616
|
+
/** CACHE_PREFIX, plus `<scope>/` when scoped. */
|
|
5617
|
+
__publicField(this, "entryPrefix");
|
|
5527
5618
|
__publicField(this, "defaultTTL");
|
|
5528
5619
|
__publicField(this, "available");
|
|
5529
5620
|
this.config = {
|
|
@@ -5537,6 +5628,8 @@ var CacheStorageRepository = class {
|
|
|
5537
5628
|
}
|
|
5538
5629
|
};
|
|
5539
5630
|
this.cacheName = this.config.options?.cacheName ?? CACHE_NAME;
|
|
5631
|
+
const scope = this.config.options?.scope;
|
|
5632
|
+
this.entryPrefix = scope ? `${CACHE_PREFIX}${encodeURIComponent(scope)}/` : CACHE_PREFIX;
|
|
5540
5633
|
this.defaultTTL = this.config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3;
|
|
5541
5634
|
this.available = this.checkAvailability();
|
|
5542
5635
|
}
|
|
@@ -5557,13 +5650,13 @@ var CacheStorageRepository = class {
|
|
|
5557
5650
|
}
|
|
5558
5651
|
try {
|
|
5559
5652
|
const cache = await caches.open(this.cacheName);
|
|
5560
|
-
const response = await cache.match(
|
|
5653
|
+
const response = await cache.match(this.entryPrefix + key);
|
|
5561
5654
|
if (!response) {
|
|
5562
5655
|
throw new TranslationNotFoundError(key);
|
|
5563
5656
|
}
|
|
5564
5657
|
const data = await response.json();
|
|
5565
5658
|
if (data.expiry !== null && Date.now() > data.expiry) {
|
|
5566
|
-
await cache.delete(
|
|
5659
|
+
await cache.delete(this.entryPrefix + key);
|
|
5567
5660
|
throw new TranslationNotFoundError(key);
|
|
5568
5661
|
}
|
|
5569
5662
|
return data.value;
|
|
@@ -5587,7 +5680,7 @@ var CacheStorageRepository = class {
|
|
|
5587
5680
|
timestamp: Date.now()
|
|
5588
5681
|
};
|
|
5589
5682
|
await cache.put(
|
|
5590
|
-
|
|
5683
|
+
this.entryPrefix + key,
|
|
5591
5684
|
new Response(JSON.stringify(data), {
|
|
5592
5685
|
headers: { "Content-Type": "application/json" }
|
|
5593
5686
|
})
|
|
@@ -5602,7 +5695,7 @@ var CacheStorageRepository = class {
|
|
|
5602
5695
|
if (!this.available) return;
|
|
5603
5696
|
try {
|
|
5604
5697
|
const cache = await caches.open(this.cacheName);
|
|
5605
|
-
await cache.delete(
|
|
5698
|
+
await cache.delete(this.entryPrefix + key);
|
|
5606
5699
|
} catch {
|
|
5607
5700
|
}
|
|
5608
5701
|
}
|
|
@@ -5615,7 +5708,7 @@ var CacheStorageRepository = class {
|
|
|
5615
5708
|
const cache = await caches.open(this.cacheName);
|
|
5616
5709
|
const keys = await cache.keys();
|
|
5617
5710
|
await Promise.all(
|
|
5618
|
-
keys.filter((request) => request.url.includes(
|
|
5711
|
+
keys.filter((request) => request.url.includes(this.entryPrefix)).map((request) => cache.delete(request))
|
|
5619
5712
|
);
|
|
5620
5713
|
} catch {
|
|
5621
5714
|
}
|
|
@@ -5633,7 +5726,7 @@ var CacheStorageRepository = class {
|
|
|
5633
5726
|
await Promise.all(
|
|
5634
5727
|
keys.filter((request) => {
|
|
5635
5728
|
const url = request.url;
|
|
5636
|
-
const key = url.includes(
|
|
5729
|
+
const key = url.includes(this.entryPrefix) ? url.substring(url.indexOf(this.entryPrefix) + this.entryPrefix.length) : "";
|
|
5637
5730
|
return key === namespaceCacheKey || key.startsWith(keyPrefix);
|
|
5638
5731
|
}).map((request) => cache.delete(request))
|
|
5639
5732
|
);
|
|
@@ -5685,9 +5778,9 @@ var CacheStorageRepository = class {
|
|
|
5685
5778
|
const keys = await cache.keys();
|
|
5686
5779
|
for (const request of keys) {
|
|
5687
5780
|
const url = request.url;
|
|
5688
|
-
if (!url.includes(
|
|
5781
|
+
if (!url.includes(this.entryPrefix)) continue;
|
|
5689
5782
|
const key = url.substring(
|
|
5690
|
-
url.indexOf(
|
|
5783
|
+
url.indexOf(this.entryPrefix) + this.entryPrefix.length
|
|
5691
5784
|
);
|
|
5692
5785
|
try {
|
|
5693
5786
|
const value = await this.get(key);
|
|
@@ -5709,7 +5802,7 @@ var CacheStorageRepository = class {
|
|
|
5709
5802
|
try {
|
|
5710
5803
|
const cache = await caches.open(this.cacheName);
|
|
5711
5804
|
const keys = await cache.keys();
|
|
5712
|
-
const size = keys.filter((r) => r.url.includes(
|
|
5805
|
+
const size = keys.filter((r) => r.url.includes(this.entryPrefix)).length;
|
|
5713
5806
|
return { size, cacheName: this.cacheName };
|
|
5714
5807
|
} catch {
|
|
5715
5808
|
return { size: 0, cacheName: this.cacheName };
|
|
@@ -5721,7 +5814,7 @@ var CacheStorageRepository = class {
|
|
|
5721
5814
|
var DEFAULT_API_BASE_URL = "https://app.lionrapid.com";
|
|
5722
5815
|
|
|
5723
5816
|
// src/index.ts
|
|
5724
|
-
var VERSION = "0.
|
|
5817
|
+
var VERSION = "0.7.0";
|
|
5725
5818
|
export {
|
|
5726
5819
|
CORE_CACHE_ENTRY_PREFIX,
|
|
5727
5820
|
CORE_CACHE_NAMES,
|