@lionrapid/core 0.6.1 → 0.6.2
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/browser/auto-init.d.ts +8 -3
- package/dist/browser/auto-init.d.ts.map +1 -1
- package/dist/browser/auto-init.js +34 -26
- package/dist/browser/auto-init.js.map +1 -1
- package/dist/browser/lionrapid.auto.dev.js +264 -24
- package/dist/browser/lionrapid.auto.dev.js.map +2 -2
- package/dist/browser/lionrapid.auto.js +264 -24
- package/dist/browser/lionrapid.auto.js.map +2 -2
- package/dist/browser/lionrapid.auto.min.js +4 -4
- package/dist/browser/lionrapid.auto.min.js.map +3 -3
- package/dist/browser/lionrapid.esm.js +238 -2
- package/dist/browser/lionrapid.esm.js.map +2 -2
- package/dist/browser/lionrapid.esm.min.js +3 -3
- package/dist/browser/lionrapid.esm.min.js.map +3 -3
- package/dist/browser/lionrapid.iife.dev.js +238 -2
- package/dist/browser/lionrapid.iife.dev.js.map +2 -2
- package/dist/browser/lionrapid.iife.js +238 -2
- package/dist/browser/lionrapid.iife.js.map +2 -2
- package/dist/browser/lionrapid.iife.min.js +3 -3
- package/dist/browser/lionrapid.iife.min.js.map +3 -3
- package/dist/browser/lionrapid.umd.js +238 -2
- package/dist/browser/lionrapid.umd.js.map +2 -2
- package/dist/browser/lionrapid.umd.min.js +3 -3
- package/dist/browser/lionrapid.umd.min.js.map +3 -3
- package/dist/browser/storage/cache-storage-repository.d.ts +65 -0
- package/dist/browser/storage/cache-storage-repository.d.ts.map +1 -1
- package/dist/browser/storage/cache-storage-repository.js +77 -7
- package/dist/browser/storage/cache-storage-repository.js.map +1 -1
- package/dist/browser/storage/localstorage-repository.d.ts +62 -0
- package/dist/browser/storage/localstorage-repository.d.ts.map +1 -1
- package/dist/browser/storage/localstorage-repository.js +71 -4
- package/dist/browser/storage/localstorage-repository.js.map +1 -1
- package/dist/config/repository.config.d.ts +17 -0
- package/dist/config/repository.config.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/repositories/network-repository.d.ts +42 -1
- package/dist/repositories/network-repository.d.ts.map +1 -1
- package/dist/repositories/network-repository.js +149 -1
- package/dist/repositories/network-repository.js.map +1 -1
- package/package.json +1 -1
|
@@ -3844,6 +3844,31 @@ var __lionrapidAutoExports = (() => {
|
|
|
3844
3844
|
* and payload can never desync because they live and die together.
|
|
3845
3845
|
*/
|
|
3846
3846
|
__publicField(this, "namespaceSnapshots", /* @__PURE__ */ new Map());
|
|
3847
|
+
/**
|
|
3848
|
+
* Miss-path flood protection (READINESS before-scale #1: one cold locale
|
|
3849
|
+
* switch measured ~380 requests in 10 s — every t() miss refired a key GET
|
|
3850
|
+
* and a namespace GET on every re-render, forever on animated pages).
|
|
3851
|
+
*/
|
|
3852
|
+
/** GETs currently on the wire, keyed by `url|if-none-match` — identical
|
|
3853
|
+
* concurrent requests share one fetch; each awaiter gets a clone. The
|
|
3854
|
+
* If-None-Match value is part of the key so the 304-without-snapshot
|
|
3855
|
+
* unconditional refetch never coalesces onto a conditional flight. */
|
|
3856
|
+
__publicField(this, "inflightGets", /* @__PURE__ */ new Map());
|
|
3857
|
+
/** URL → 404/423 seen recently: repeats are answered locally (same typed
|
|
3858
|
+
* error, no network) until `until`. 423 honors the server's Retry-After.
|
|
3859
|
+
* Cleared entirely by any successful write — discovery sync keeps its
|
|
3860
|
+
* miss → batch → served-back round-trip. */
|
|
3861
|
+
__publicField(this, "negativeCache", /* @__PURE__ */ new Map());
|
|
3862
|
+
/** One-way latch: a 401 anywhere (or a 403 on a READ) means the key is
|
|
3863
|
+
* wrong or unauthorized for this project, and retrying cannot heal it —
|
|
3864
|
+
* after the first one nothing touches the network again for this
|
|
3865
|
+
* instance (a page reload starts fresh). Holds the status that tripped
|
|
3866
|
+
* it so short-circuits answer honestly. */
|
|
3867
|
+
__publicField(this, "authFailedStatus", null);
|
|
3868
|
+
/** Write-only latch (auth-byok Phase 18): a 403 (scope) or 429 (quota) on
|
|
3869
|
+
* a WRITE degrades this instance to read-only — writes stop, silently
|
|
3870
|
+
* and without retries, while reads keep serving the page. */
|
|
3871
|
+
__publicField(this, "writesFailedStatus", null);
|
|
3847
3872
|
/**
|
|
3848
3873
|
* Default endpoint templates with placeholder support
|
|
3849
3874
|
* Placeholders: :key, :locale, :namespace
|
|
@@ -3851,6 +3876,7 @@ var __lionrapidAutoExports = (() => {
|
|
|
3851
3876
|
__publicField(this, "DEFAULT_ENDPOINTS", {
|
|
3852
3877
|
getTranslation: "/api/integrations/translations/:key",
|
|
3853
3878
|
getNamespace: "/api/integrations/translations/:locale/:namespace",
|
|
3879
|
+
getProjectConfig: "/api/integrations/project-config",
|
|
3854
3880
|
setTranslation: "/api/integrations/sync/:key",
|
|
3855
3881
|
setNamespace: "/api/integrations/sync/:locale/:namespace",
|
|
3856
3882
|
setBatch: "/api/integrations/sync/batch",
|
|
@@ -3962,6 +3988,40 @@ var __lionrapidAutoExports = (() => {
|
|
|
3962
3988
|
this.handleCaughtError(error);
|
|
3963
3989
|
}
|
|
3964
3990
|
}
|
|
3991
|
+
/**
|
|
3992
|
+
* Project-level config for this key — the dashboard's language list,
|
|
3993
|
+
* served under the same trust model as translation reads (docs/20,
|
|
3994
|
+
* companion track). Returns null when the server doesn't expose the
|
|
3995
|
+
* endpoint (404 — older server, feature not deployed) or the payload is
|
|
3996
|
+
* unusable: absence means "keep your local fallback", never an error.
|
|
3997
|
+
*/
|
|
3998
|
+
async getProjectConfig() {
|
|
3999
|
+
if (!this.config?.options?.baseUrl) {
|
|
4000
|
+
throw new NetworkError("API base URL is not set");
|
|
4001
|
+
}
|
|
4002
|
+
const url = this.buildUrl("getProjectConfig", {});
|
|
4003
|
+
logger.debug(`API GET ProjectConfig: ${url}`);
|
|
4004
|
+
try {
|
|
4005
|
+
const response = await this.makeRequest(url, "GET");
|
|
4006
|
+
if (response.status === 404) {
|
|
4007
|
+
return null;
|
|
4008
|
+
}
|
|
4009
|
+
if (!response.ok) {
|
|
4010
|
+
this.handleHttpError(response, "project-config");
|
|
4011
|
+
}
|
|
4012
|
+
const data = await response.json();
|
|
4013
|
+
if (!data || typeof data.defaultLocale !== "string" || !Array.isArray(data.languages)) {
|
|
4014
|
+
logger.warn("project-config payload unusable \u2014 keeping local fallback");
|
|
4015
|
+
return null;
|
|
4016
|
+
}
|
|
4017
|
+
return {
|
|
4018
|
+
defaultLocale: data.defaultLocale,
|
|
4019
|
+
languages: data.languages.map(String)
|
|
4020
|
+
};
|
|
4021
|
+
} catch (error) {
|
|
4022
|
+
this.handleCaughtError(error);
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
3965
4025
|
/**
|
|
3966
4026
|
* Shared namespace fetch with the canonical 304 contract:
|
|
3967
4027
|
* - If-None-Match is sent ONLY when a snapshot (version + payload) is in hand.
|
|
@@ -4286,7 +4346,87 @@ var __lionrapidAutoExports = (() => {
|
|
|
4286
4346
|
/**
|
|
4287
4347
|
* Make HTTP request with timeout and headers
|
|
4288
4348
|
*/
|
|
4289
|
-
|
|
4349
|
+
makeRequest(url, method, body, extraHeaders) {
|
|
4350
|
+
if (this.authFailedStatus !== null) {
|
|
4351
|
+
return Promise.resolve(
|
|
4352
|
+
new Response(null, {
|
|
4353
|
+
status: this.authFailedStatus,
|
|
4354
|
+
statusText: `auth latched off after ${this.authFailedStatus}`
|
|
4355
|
+
})
|
|
4356
|
+
);
|
|
4357
|
+
}
|
|
4358
|
+
if (method !== "GET") {
|
|
4359
|
+
if (this.writesFailedStatus !== null) {
|
|
4360
|
+
return Promise.resolve(
|
|
4361
|
+
new Response(null, {
|
|
4362
|
+
status: this.writesFailedStatus,
|
|
4363
|
+
statusText: `writes latched off after ${this.writesFailedStatus}`
|
|
4364
|
+
})
|
|
4365
|
+
);
|
|
4366
|
+
}
|
|
4367
|
+
return this.doFetch(url, method, body, extraHeaders).then(
|
|
4368
|
+
(resp) => this.recordOutcome(url, method, resp)
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
const negative = this.negativeCache.get(url);
|
|
4372
|
+
if (negative) {
|
|
4373
|
+
if (Date.now() < negative.until) {
|
|
4374
|
+
logger.debug(`Negative-cache hit (${negative.status}): ${url}`);
|
|
4375
|
+
const headers = negative.status === 423 ? { "Retry-After": String(Math.ceil((negative.until - Date.now()) / 1e3)) } : void 0;
|
|
4376
|
+
return Promise.resolve(
|
|
4377
|
+
new Response(null, { status: negative.status, statusText: "negative cache", headers })
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
this.negativeCache.delete(url);
|
|
4381
|
+
}
|
|
4382
|
+
const flightKey = `${url}|${extraHeaders?.["If-None-Match"] ?? ""}`;
|
|
4383
|
+
const existing = this.inflightGets.get(flightKey);
|
|
4384
|
+
if (existing) {
|
|
4385
|
+
return existing.then((resp) => this.cloneResponse(resp));
|
|
4386
|
+
}
|
|
4387
|
+
const flight = this.doFetch(url, method, body, extraHeaders).then((resp) => this.recordOutcome(url, method, resp)).finally(() => this.inflightGets.delete(flightKey));
|
|
4388
|
+
this.inflightGets.set(flightKey, flight);
|
|
4389
|
+
return flight.then((resp) => this.cloneResponse(resp));
|
|
4390
|
+
}
|
|
4391
|
+
/** Bookkeeping on every real (non-synthesized) response — runs once per
|
|
4392
|
+
* physical fetch, never once per coalesced awaiter. */
|
|
4393
|
+
recordOutcome(url, method, response) {
|
|
4394
|
+
const status = response.status;
|
|
4395
|
+
if (status === 401 || status === 403 && method === "GET") {
|
|
4396
|
+
if (this.authFailedStatus === null) {
|
|
4397
|
+
this.authFailedStatus = status;
|
|
4398
|
+
console.warn(
|
|
4399
|
+
`[LionRapid] API key rejected (${status}) \u2014 network translations are disabled for this session. Fix the key and reload; retrying cannot heal an auth failure.`
|
|
4400
|
+
);
|
|
4401
|
+
}
|
|
4402
|
+
return response;
|
|
4403
|
+
}
|
|
4404
|
+
if ((status === 403 || status === 429) && method !== "GET") {
|
|
4405
|
+
if (this.writesFailedStatus === null) {
|
|
4406
|
+
this.writesFailedStatus = status;
|
|
4407
|
+
logger.warn(
|
|
4408
|
+
`Write path disabled after ${status} (scope/quota) \u2014 running read-only`
|
|
4409
|
+
);
|
|
4410
|
+
}
|
|
4411
|
+
return response;
|
|
4412
|
+
}
|
|
4413
|
+
if (method === "GET" && (status === 404 || status === 423)) {
|
|
4414
|
+
const retryAfterSec = status === 423 ? Number(response.headers?.get?.("Retry-After")) : NaN;
|
|
4415
|
+
const ttl = Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? retryAfterSec * 1e3 : this.config.options?.negativeCacheTtlMs ?? _NetworkRepository.DEFAULT_NEGATIVE_TTL_MS;
|
|
4416
|
+
this.negativeCache.set(url, { status, until: Date.now() + ttl });
|
|
4417
|
+
} else if (method !== "GET" && response.ok) {
|
|
4418
|
+
this.negativeCache.clear();
|
|
4419
|
+
} else if (method === "GET" && response.ok) {
|
|
4420
|
+
this.negativeCache.delete(url);
|
|
4421
|
+
}
|
|
4422
|
+
return response;
|
|
4423
|
+
}
|
|
4424
|
+
/** Test doubles (and exotic runtimes) hand us plain objects — only real
|
|
4425
|
+
* Responses need cloning so each coalesced awaiter can read the body. */
|
|
4426
|
+
cloneResponse(response) {
|
|
4427
|
+
return typeof response.clone === "function" ? response.clone() : response;
|
|
4428
|
+
}
|
|
4429
|
+
async doFetch(url, method, body, extraHeaders) {
|
|
4290
4430
|
const controller = new AbortController();
|
|
4291
4431
|
const timeout = this.config.options?.timeout ?? 1e4;
|
|
4292
4432
|
const timeoutId = setTimeout(
|
|
@@ -4319,6 +4459,7 @@ var __lionrapidAutoExports = (() => {
|
|
|
4319
4459
|
/** Legacy bare-version prefix — a version WITHOUT its payload is exactly the
|
|
4320
4460
|
* desync the snapshot store exists to prevent; entries are deleted on sight. */
|
|
4321
4461
|
__publicField(_NetworkRepository, "LEGACY_VERSION_PREFIX", "lionrapid:v:");
|
|
4462
|
+
__publicField(_NetworkRepository, "DEFAULT_NEGATIVE_TTL_MS", 6e4);
|
|
4322
4463
|
var NetworkRepository = _NetworkRepository;
|
|
4323
4464
|
|
|
4324
4465
|
// src/browser/exclude-filter.ts
|
|
@@ -5561,9 +5702,11 @@ var __lionrapidAutoExports = (() => {
|
|
|
5561
5702
|
this.config = {
|
|
5562
5703
|
enabled: config.enabled ?? true,
|
|
5563
5704
|
priority: config.priority ?? 0,
|
|
5705
|
+
// Use build sequence by default
|
|
5564
5706
|
options: {
|
|
5565
5707
|
prefix: config.options?.prefix ?? STORAGE_PREFIX,
|
|
5566
5708
|
ttl: config.options?.ttl ?? 24 * 60 * 60 * 1e3,
|
|
5709
|
+
// 24 hours default
|
|
5567
5710
|
maxSize: config.options?.maxSize ?? 500,
|
|
5568
5711
|
...config.options
|
|
5569
5712
|
}
|
|
@@ -5576,6 +5719,10 @@ var __lionrapidAutoExports = (() => {
|
|
|
5576
5719
|
this.migrateIfNeeded();
|
|
5577
5720
|
}
|
|
5578
5721
|
}
|
|
5722
|
+
/**
|
|
5723
|
+
* Check if localStorage is available
|
|
5724
|
+
* Returns false in SSR, private browsing, or when quota is 0
|
|
5725
|
+
*/
|
|
5579
5726
|
checkAvailability() {
|
|
5580
5727
|
if (typeof window === "undefined") {
|
|
5581
5728
|
return false;
|
|
@@ -5589,6 +5736,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5589
5736
|
return false;
|
|
5590
5737
|
}
|
|
5591
5738
|
}
|
|
5739
|
+
/**
|
|
5740
|
+
* Handle version migrations - clear cache when version changes
|
|
5741
|
+
*/
|
|
5592
5742
|
migrateIfNeeded() {
|
|
5593
5743
|
try {
|
|
5594
5744
|
const storedVersion = window.localStorage.getItem(VERSION_KEY);
|
|
@@ -5599,6 +5749,10 @@ var __lionrapidAutoExports = (() => {
|
|
|
5599
5749
|
} catch {
|
|
5600
5750
|
}
|
|
5601
5751
|
}
|
|
5752
|
+
/**
|
|
5753
|
+
* Get a translation value by key
|
|
5754
|
+
* Returns null if not found or expired
|
|
5755
|
+
*/
|
|
5602
5756
|
get(key) {
|
|
5603
5757
|
if (!this.available) return null;
|
|
5604
5758
|
try {
|
|
@@ -5615,6 +5769,10 @@ var __lionrapidAutoExports = (() => {
|
|
|
5615
5769
|
return null;
|
|
5616
5770
|
}
|
|
5617
5771
|
}
|
|
5772
|
+
/**
|
|
5773
|
+
* Set a translation value
|
|
5774
|
+
* Automatically handles quota exceeded by evicting oldest entries
|
|
5775
|
+
*/
|
|
5618
5776
|
set(key, value) {
|
|
5619
5777
|
if (!this.available) return;
|
|
5620
5778
|
const fullKey = this.prefix + key;
|
|
@@ -5639,6 +5797,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5639
5797
|
}
|
|
5640
5798
|
}
|
|
5641
5799
|
}
|
|
5800
|
+
/**
|
|
5801
|
+
* Remove a translation by key
|
|
5802
|
+
*/
|
|
5642
5803
|
remove(key) {
|
|
5643
5804
|
if (!this.available) return;
|
|
5644
5805
|
try {
|
|
@@ -5646,6 +5807,10 @@ var __lionrapidAutoExports = (() => {
|
|
|
5646
5807
|
} catch {
|
|
5647
5808
|
}
|
|
5648
5809
|
}
|
|
5810
|
+
/**
|
|
5811
|
+
* Clear all LionRapid entries from localStorage
|
|
5812
|
+
* Preserves entries from other applications
|
|
5813
|
+
*/
|
|
5649
5814
|
clear() {
|
|
5650
5815
|
if (!this.available) return;
|
|
5651
5816
|
try {
|
|
@@ -5660,6 +5825,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5660
5825
|
} catch {
|
|
5661
5826
|
}
|
|
5662
5827
|
}
|
|
5828
|
+
/**
|
|
5829
|
+
* Clear all entries for a specific namespace
|
|
5830
|
+
*/
|
|
5663
5831
|
clearNamespace(locale, namespace) {
|
|
5664
5832
|
if (!this.available) return;
|
|
5665
5833
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
@@ -5678,6 +5846,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5678
5846
|
} catch {
|
|
5679
5847
|
}
|
|
5680
5848
|
}
|
|
5849
|
+
/**
|
|
5850
|
+
* Get namespace translations
|
|
5851
|
+
*/
|
|
5681
5852
|
getNamespace(locale, namespace) {
|
|
5682
5853
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
5683
5854
|
const value = this.get(namespaceCacheKey);
|
|
@@ -5689,10 +5860,16 @@ var __lionrapidAutoExports = (() => {
|
|
|
5689
5860
|
return null;
|
|
5690
5861
|
}
|
|
5691
5862
|
}
|
|
5863
|
+
/**
|
|
5864
|
+
* Set namespace translations
|
|
5865
|
+
*/
|
|
5692
5866
|
setNamespace(locale, namespace, translations) {
|
|
5693
5867
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
5694
5868
|
this.set(namespaceCacheKey, JSON.stringify(translations));
|
|
5695
5869
|
}
|
|
5870
|
+
/**
|
|
5871
|
+
* Get all cache entries for debugging
|
|
5872
|
+
*/
|
|
5696
5873
|
getEntries() {
|
|
5697
5874
|
const entries = {};
|
|
5698
5875
|
if (!this.available) return entries;
|
|
@@ -5712,12 +5889,21 @@ var __lionrapidAutoExports = (() => {
|
|
|
5712
5889
|
}
|
|
5713
5890
|
return entries;
|
|
5714
5891
|
}
|
|
5892
|
+
/**
|
|
5893
|
+
* Get repository configuration
|
|
5894
|
+
*/
|
|
5715
5895
|
getConfig() {
|
|
5716
5896
|
return this.config;
|
|
5717
5897
|
}
|
|
5898
|
+
/**
|
|
5899
|
+
* Check if localStorage is available
|
|
5900
|
+
*/
|
|
5718
5901
|
isAvailable() {
|
|
5719
5902
|
return this.available;
|
|
5720
5903
|
}
|
|
5904
|
+
/**
|
|
5905
|
+
* Get the number of entries in the cache
|
|
5906
|
+
*/
|
|
5721
5907
|
getEntryCount() {
|
|
5722
5908
|
if (!this.available) return 0;
|
|
5723
5909
|
let count = 0;
|
|
@@ -5732,12 +5918,18 @@ var __lionrapidAutoExports = (() => {
|
|
|
5732
5918
|
}
|
|
5733
5919
|
return count;
|
|
5734
5920
|
}
|
|
5921
|
+
/**
|
|
5922
|
+
* Check if error is a quota exceeded error
|
|
5923
|
+
*/
|
|
5735
5924
|
isQuotaError(error) {
|
|
5736
5925
|
if (error instanceof DOMException) {
|
|
5737
5926
|
return error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED";
|
|
5738
5927
|
}
|
|
5739
5928
|
return false;
|
|
5740
5929
|
}
|
|
5930
|
+
/**
|
|
5931
|
+
* Evict oldest 25% of entries when quota is exceeded
|
|
5932
|
+
*/
|
|
5741
5933
|
evictOldest() {
|
|
5742
5934
|
if (!this.available) return;
|
|
5743
5935
|
try {
|
|
@@ -5765,6 +5957,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5765
5957
|
} catch {
|
|
5766
5958
|
}
|
|
5767
5959
|
}
|
|
5960
|
+
/**
|
|
5961
|
+
* Get cache statistics
|
|
5962
|
+
*/
|
|
5768
5963
|
getCacheStats() {
|
|
5769
5964
|
const size = this.getEntryCount();
|
|
5770
5965
|
const usage = this.maxSize > 0 ? `${Math.round(size / this.maxSize * 100)}%` : "0%";
|
|
@@ -5778,7 +5973,7 @@ var __lionrapidAutoExports = (() => {
|
|
|
5778
5973
|
|
|
5779
5974
|
// src/browser/storage/cache-storage-repository.ts
|
|
5780
5975
|
var CACHE_NAME = "lionrapid-v1";
|
|
5781
|
-
var CACHE_PREFIX = "lionrapid
|
|
5976
|
+
var CACHE_PREFIX = "https://cache.lionrapid.internal/";
|
|
5782
5977
|
var CacheStorageRepository = class {
|
|
5783
5978
|
constructor(config = {}) {
|
|
5784
5979
|
__publicField(this, "name", "CacheStorageRepository");
|
|
@@ -5793,6 +5988,7 @@ var __lionrapidAutoExports = (() => {
|
|
|
5793
5988
|
options: {
|
|
5794
5989
|
cacheName: config.options?.cacheName ?? CACHE_NAME,
|
|
5795
5990
|
ttl: config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3,
|
|
5991
|
+
// 7 days default
|
|
5796
5992
|
...config.options
|
|
5797
5993
|
}
|
|
5798
5994
|
};
|
|
@@ -5800,9 +5996,17 @@ var __lionrapidAutoExports = (() => {
|
|
|
5800
5996
|
this.defaultTTL = this.config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3;
|
|
5801
5997
|
this.available = this.checkAvailability();
|
|
5802
5998
|
}
|
|
5999
|
+
/**
|
|
6000
|
+
* Check if Cache API is available
|
|
6001
|
+
* Returns false in SSR, old browsers, or insecure contexts
|
|
6002
|
+
*/
|
|
5803
6003
|
checkAvailability() {
|
|
5804
6004
|
return typeof caches !== "undefined";
|
|
5805
6005
|
}
|
|
6006
|
+
/**
|
|
6007
|
+
* Get a translation value by key
|
|
6008
|
+
* @throws {TranslationNotFoundError} When translation doesn't exist or is expired
|
|
6009
|
+
*/
|
|
5806
6010
|
async get(key) {
|
|
5807
6011
|
if (!this.available) {
|
|
5808
6012
|
throw new TranslationNotFoundError(key);
|
|
@@ -5826,6 +6030,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5826
6030
|
throw new TranslationNotFoundError(key);
|
|
5827
6031
|
}
|
|
5828
6032
|
}
|
|
6033
|
+
/**
|
|
6034
|
+
* Set a translation value
|
|
6035
|
+
*/
|
|
5829
6036
|
async set(key, value) {
|
|
5830
6037
|
if (!this.available) return;
|
|
5831
6038
|
try {
|
|
@@ -5844,6 +6051,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5844
6051
|
} catch {
|
|
5845
6052
|
}
|
|
5846
6053
|
}
|
|
6054
|
+
/**
|
|
6055
|
+
* Remove a translation by key
|
|
6056
|
+
*/
|
|
5847
6057
|
async remove(key) {
|
|
5848
6058
|
if (!this.available) return;
|
|
5849
6059
|
try {
|
|
@@ -5852,6 +6062,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5852
6062
|
} catch {
|
|
5853
6063
|
}
|
|
5854
6064
|
}
|
|
6065
|
+
/**
|
|
6066
|
+
* Clear all LionRapid entries from the cache
|
|
6067
|
+
*/
|
|
5855
6068
|
async clear() {
|
|
5856
6069
|
if (!this.available) return;
|
|
5857
6070
|
try {
|
|
@@ -5863,6 +6076,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5863
6076
|
} catch {
|
|
5864
6077
|
}
|
|
5865
6078
|
}
|
|
6079
|
+
/**
|
|
6080
|
+
* Clear all entries for a specific namespace
|
|
6081
|
+
*/
|
|
5866
6082
|
async clearNamespace(locale, namespace) {
|
|
5867
6083
|
if (!this.available) return;
|
|
5868
6084
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
@@ -5880,6 +6096,10 @@ var __lionrapidAutoExports = (() => {
|
|
|
5880
6096
|
} catch {
|
|
5881
6097
|
}
|
|
5882
6098
|
}
|
|
6099
|
+
/**
|
|
6100
|
+
* Get namespace translations
|
|
6101
|
+
* @throws {TranslationNotFoundError} When namespace doesn't exist
|
|
6102
|
+
*/
|
|
5883
6103
|
async getNamespace(locale, namespace) {
|
|
5884
6104
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
5885
6105
|
const value = await this.get(namespaceCacheKey);
|
|
@@ -5890,16 +6110,29 @@ var __lionrapidAutoExports = (() => {
|
|
|
5890
6110
|
throw new TranslationNotFoundError(namespaceCacheKey);
|
|
5891
6111
|
}
|
|
5892
6112
|
}
|
|
6113
|
+
/**
|
|
6114
|
+
* Set namespace translations
|
|
6115
|
+
*/
|
|
5893
6116
|
async setNamespace(locale, namespace, translations) {
|
|
5894
6117
|
const namespaceCacheKey = `@${locale}:${namespace}`;
|
|
5895
6118
|
await this.set(namespaceCacheKey, JSON.stringify(translations));
|
|
5896
6119
|
}
|
|
6120
|
+
/**
|
|
6121
|
+
* Get repository configuration
|
|
6122
|
+
*/
|
|
5897
6123
|
getConfig() {
|
|
5898
6124
|
return this.config;
|
|
5899
6125
|
}
|
|
6126
|
+
/**
|
|
6127
|
+
* Check if Cache API is available
|
|
6128
|
+
*/
|
|
5900
6129
|
isAvailable() {
|
|
5901
6130
|
return this.available;
|
|
5902
6131
|
}
|
|
6132
|
+
/**
|
|
6133
|
+
* Get all cached entries (for debugging)
|
|
6134
|
+
* Returns an object mapping keys to values
|
|
6135
|
+
*/
|
|
5903
6136
|
async getEntries() {
|
|
5904
6137
|
const entries = {};
|
|
5905
6138
|
if (!this.available) return entries;
|
|
@@ -5922,6 +6155,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5922
6155
|
}
|
|
5923
6156
|
return entries;
|
|
5924
6157
|
}
|
|
6158
|
+
/**
|
|
6159
|
+
* Get cache statistics
|
|
6160
|
+
*/
|
|
5925
6161
|
async getCacheStats() {
|
|
5926
6162
|
if (!this.available) {
|
|
5927
6163
|
return { size: 0, cacheName: this.cacheName };
|
|
@@ -5941,8 +6177,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
5941
6177
|
function resolveWritePolicy(apiKey) {
|
|
5942
6178
|
const isPublishable = apiKey.startsWith("pk_");
|
|
5943
6179
|
return {
|
|
6180
|
+
bootNetwork: isPublishable,
|
|
5944
6181
|
syncMissing: { enabled: isPublishable },
|
|
5945
|
-
|
|
6182
|
+
warnRefused: !isPublishable
|
|
5946
6183
|
};
|
|
5947
6184
|
}
|
|
5948
6185
|
function configForWindow(config) {
|
|
@@ -6091,9 +6328,9 @@ var __lionrapidAutoExports = (() => {
|
|
|
6091
6328
|
return;
|
|
6092
6329
|
}
|
|
6093
6330
|
const writePolicy = resolveWritePolicy(config.apiKey);
|
|
6094
|
-
if (writePolicy.
|
|
6331
|
+
if (writePolicy.warnRefused) {
|
|
6095
6332
|
console.error(
|
|
6096
|
-
"[LionRapid] data-api-key must be a publishable pk_ key
|
|
6333
|
+
"[LionRapid] data-api-key must be a publishable pk_ key \u2014 network translations are disabled. Copy the snippet from the integration hub to get the pk_ key for this project."
|
|
6097
6334
|
);
|
|
6098
6335
|
}
|
|
6099
6336
|
const initialLocale = resolveInitialLocale(config);
|
|
@@ -6147,25 +6384,28 @@ var __lionrapidAutoExports = (() => {
|
|
|
6147
6384
|
})
|
|
6148
6385
|
);
|
|
6149
6386
|
}
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6387
|
+
if (writePolicy.bootNetwork) {
|
|
6388
|
+
builder.use(
|
|
6389
|
+
new NetworkRepository({
|
|
6390
|
+
enabled: true,
|
|
6391
|
+
options: {
|
|
6392
|
+
baseUrl: config.baseUrl,
|
|
6393
|
+
apiKey: config.apiKey,
|
|
6394
|
+
// pk_ keys sync missing source strings (discovery) — see
|
|
6395
|
+
// resolveWritePolicy.
|
|
6396
|
+
syncMissing: writePolicy.syncMissing,
|
|
6397
|
+
preloadNamespaces: [
|
|
6398
|
+
{
|
|
6399
|
+
locale: initialLocale,
|
|
6400
|
+
namespace: config.namespace,
|
|
6401
|
+
eager: true
|
|
6402
|
+
}
|
|
6403
|
+
]
|
|
6404
|
+
}
|
|
6405
|
+
})
|
|
6406
|
+
);
|
|
6407
|
+
}
|
|
6408
|
+
const core = await builder.build();
|
|
6169
6409
|
const autoTranslator = new AutoTranslator({
|
|
6170
6410
|
excludeSelectors: config.excludeSelectors
|
|
6171
6411
|
});
|