@lionrapid/core 0.6.0 → 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.
Files changed (46) hide show
  1. package/dist/browser/auto-init.d.ts +17 -3
  2. package/dist/browser/auto-init.d.ts.map +1 -1
  3. package/dist/browser/auto-init.js +57 -30
  4. package/dist/browser/auto-init.js.map +1 -1
  5. package/dist/browser/lionrapid.auto.dev.js +285 -27
  6. package/dist/browser/lionrapid.auto.dev.js.map +2 -2
  7. package/dist/browser/lionrapid.auto.js +285 -27
  8. package/dist/browser/lionrapid.auto.js.map +2 -2
  9. package/dist/browser/lionrapid.auto.min.js +4 -4
  10. package/dist/browser/lionrapid.auto.min.js.map +3 -3
  11. package/dist/browser/lionrapid.esm.js +244 -2
  12. package/dist/browser/lionrapid.esm.js.map +2 -2
  13. package/dist/browser/lionrapid.esm.min.js +3 -3
  14. package/dist/browser/lionrapid.esm.min.js.map +3 -3
  15. package/dist/browser/lionrapid.iife.dev.js +244 -2
  16. package/dist/browser/lionrapid.iife.dev.js.map +2 -2
  17. package/dist/browser/lionrapid.iife.js +244 -2
  18. package/dist/browser/lionrapid.iife.js.map +2 -2
  19. package/dist/browser/lionrapid.iife.min.js +3 -3
  20. package/dist/browser/lionrapid.iife.min.js.map +3 -3
  21. package/dist/browser/lionrapid.umd.js +244 -2
  22. package/dist/browser/lionrapid.umd.js.map +2 -2
  23. package/dist/browser/lionrapid.umd.min.js +3 -3
  24. package/dist/browser/lionrapid.umd.min.js.map +3 -3
  25. package/dist/browser/storage/cache-storage-repository.d.ts +65 -0
  26. package/dist/browser/storage/cache-storage-repository.d.ts.map +1 -1
  27. package/dist/browser/storage/cache-storage-repository.js +77 -7
  28. package/dist/browser/storage/cache-storage-repository.js.map +1 -1
  29. package/dist/browser/storage/localstorage-repository.d.ts +62 -0
  30. package/dist/browser/storage/localstorage-repository.d.ts.map +1 -1
  31. package/dist/browser/storage/localstorage-repository.js +71 -4
  32. package/dist/browser/storage/localstorage-repository.js.map +1 -1
  33. package/dist/config/repository.config.d.ts +17 -0
  34. package/dist/config/repository.config.d.ts.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/lionRapid.d.ts +1 -0
  39. package/dist/lionRapid.d.ts.map +1 -1
  40. package/dist/lionRapid.js +14 -0
  41. package/dist/lionRapid.js.map +1 -1
  42. package/dist/repositories/network-repository.d.ts +42 -1
  43. package/dist/repositories/network-repository.d.ts.map +1 -1
  44. package/dist/repositories/network-repository.js +149 -1
  45. package/dist/repositories/network-repository.js.map +1 -1
  46. package/package.json +1 -1
@@ -2819,6 +2819,7 @@ var LionRapidCore = class {
2819
2819
  // 🔥 EMBEDDED: Core integration maps
2820
2820
  __publicField(this, "formatters", /* @__PURE__ */ new Map());
2821
2821
  __publicField(this, "processors", /* @__PURE__ */ new Map());
2822
+ __publicField(this, "warnedNoInterpolate", false);
2822
2823
  // 📡 EVENT-DRIVEN: Just track for cleanup
2823
2824
  __publicField(this, "eventPlugins", /* @__PURE__ */ new Set());
2824
2825
  // 📦 CONTENT: Parser and serializer for ContentUnit processing
@@ -3111,6 +3112,11 @@ var LionRapidCore = class {
3111
3112
  resolvedLocale,
3112
3113
  resolvedKey
3113
3114
  );
3115
+ } else if (!this.warnedNoInterpolate && params && Object.keys(params).length > 0 && processedValue.includes("{")) {
3116
+ this.warnedNoInterpolate = true;
3117
+ console.warn(
3118
+ "[LionRapid] Translation params were passed but no interpolate formatter is registered \u2014 {placeholders} render literally. Install @lionrapid/formatters and add .use(coreFormattersPlugin) to the builder."
3119
+ );
3114
3120
  }
3115
3121
  if (this.processors.size > 0) {
3116
3122
  for (const [name, processor] of this.processors.entries()) {
@@ -3891,6 +3897,31 @@ var _NetworkRepository = class _NetworkRepository {
3891
3897
  * and payload can never desync because they live and die together.
3892
3898
  */
3893
3899
  __publicField(this, "namespaceSnapshots", /* @__PURE__ */ new Map());
3900
+ /**
3901
+ * Miss-path flood protection (READINESS before-scale #1: one cold locale
3902
+ * switch measured ~380 requests in 10 s — every t() miss refired a key GET
3903
+ * and a namespace GET on every re-render, forever on animated pages).
3904
+ */
3905
+ /** GETs currently on the wire, keyed by `url|if-none-match` — identical
3906
+ * concurrent requests share one fetch; each awaiter gets a clone. The
3907
+ * If-None-Match value is part of the key so the 304-without-snapshot
3908
+ * unconditional refetch never coalesces onto a conditional flight. */
3909
+ __publicField(this, "inflightGets", /* @__PURE__ */ new Map());
3910
+ /** URL → 404/423 seen recently: repeats are answered locally (same typed
3911
+ * error, no network) until `until`. 423 honors the server's Retry-After.
3912
+ * Cleared entirely by any successful write — discovery sync keeps its
3913
+ * miss → batch → served-back round-trip. */
3914
+ __publicField(this, "negativeCache", /* @__PURE__ */ new Map());
3915
+ /** One-way latch: a 401 anywhere (or a 403 on a READ) means the key is
3916
+ * wrong or unauthorized for this project, and retrying cannot heal it —
3917
+ * after the first one nothing touches the network again for this
3918
+ * instance (a page reload starts fresh). Holds the status that tripped
3919
+ * it so short-circuits answer honestly. */
3920
+ __publicField(this, "authFailedStatus", null);
3921
+ /** Write-only latch (auth-byok Phase 18): a 403 (scope) or 429 (quota) on
3922
+ * a WRITE degrades this instance to read-only — writes stop, silently
3923
+ * and without retries, while reads keep serving the page. */
3924
+ __publicField(this, "writesFailedStatus", null);
3894
3925
  /**
3895
3926
  * Default endpoint templates with placeholder support
3896
3927
  * Placeholders: :key, :locale, :namespace
@@ -3898,6 +3929,7 @@ var _NetworkRepository = class _NetworkRepository {
3898
3929
  __publicField(this, "DEFAULT_ENDPOINTS", {
3899
3930
  getTranslation: "/api/integrations/translations/:key",
3900
3931
  getNamespace: "/api/integrations/translations/:locale/:namespace",
3932
+ getProjectConfig: "/api/integrations/project-config",
3901
3933
  setTranslation: "/api/integrations/sync/:key",
3902
3934
  setNamespace: "/api/integrations/sync/:locale/:namespace",
3903
3935
  setBatch: "/api/integrations/sync/batch",
@@ -4009,6 +4041,40 @@ var _NetworkRepository = class _NetworkRepository {
4009
4041
  this.handleCaughtError(error);
4010
4042
  }
4011
4043
  }
4044
+ /**
4045
+ * Project-level config for this key — the dashboard's language list,
4046
+ * served under the same trust model as translation reads (docs/20,
4047
+ * companion track). Returns null when the server doesn't expose the
4048
+ * endpoint (404 — older server, feature not deployed) or the payload is
4049
+ * unusable: absence means "keep your local fallback", never an error.
4050
+ */
4051
+ async getProjectConfig() {
4052
+ if (!this.config?.options?.baseUrl) {
4053
+ throw new NetworkError("API base URL is not set");
4054
+ }
4055
+ const url = this.buildUrl("getProjectConfig", {});
4056
+ logger.debug(`API GET ProjectConfig: ${url}`);
4057
+ try {
4058
+ const response = await this.makeRequest(url, "GET");
4059
+ if (response.status === 404) {
4060
+ return null;
4061
+ }
4062
+ if (!response.ok) {
4063
+ this.handleHttpError(response, "project-config");
4064
+ }
4065
+ const data = await response.json();
4066
+ if (!data || typeof data.defaultLocale !== "string" || !Array.isArray(data.languages)) {
4067
+ logger.warn("project-config payload unusable \u2014 keeping local fallback");
4068
+ return null;
4069
+ }
4070
+ return {
4071
+ defaultLocale: data.defaultLocale,
4072
+ languages: data.languages.map(String)
4073
+ };
4074
+ } catch (error) {
4075
+ this.handleCaughtError(error);
4076
+ }
4077
+ }
4012
4078
  /**
4013
4079
  * Shared namespace fetch with the canonical 304 contract:
4014
4080
  * - If-None-Match is sent ONLY when a snapshot (version + payload) is in hand.
@@ -4333,7 +4399,87 @@ var _NetworkRepository = class _NetworkRepository {
4333
4399
  /**
4334
4400
  * Make HTTP request with timeout and headers
4335
4401
  */
4336
- async makeRequest(url, method, body, extraHeaders) {
4402
+ makeRequest(url, method, body, extraHeaders) {
4403
+ if (this.authFailedStatus !== null) {
4404
+ return Promise.resolve(
4405
+ new Response(null, {
4406
+ status: this.authFailedStatus,
4407
+ statusText: `auth latched off after ${this.authFailedStatus}`
4408
+ })
4409
+ );
4410
+ }
4411
+ if (method !== "GET") {
4412
+ if (this.writesFailedStatus !== null) {
4413
+ return Promise.resolve(
4414
+ new Response(null, {
4415
+ status: this.writesFailedStatus,
4416
+ statusText: `writes latched off after ${this.writesFailedStatus}`
4417
+ })
4418
+ );
4419
+ }
4420
+ return this.doFetch(url, method, body, extraHeaders).then(
4421
+ (resp) => this.recordOutcome(url, method, resp)
4422
+ );
4423
+ }
4424
+ const negative = this.negativeCache.get(url);
4425
+ if (negative) {
4426
+ if (Date.now() < negative.until) {
4427
+ logger.debug(`Negative-cache hit (${negative.status}): ${url}`);
4428
+ const headers = negative.status === 423 ? { "Retry-After": String(Math.ceil((negative.until - Date.now()) / 1e3)) } : void 0;
4429
+ return Promise.resolve(
4430
+ new Response(null, { status: negative.status, statusText: "negative cache", headers })
4431
+ );
4432
+ }
4433
+ this.negativeCache.delete(url);
4434
+ }
4435
+ const flightKey = `${url}|${extraHeaders?.["If-None-Match"] ?? ""}`;
4436
+ const existing = this.inflightGets.get(flightKey);
4437
+ if (existing) {
4438
+ return existing.then((resp) => this.cloneResponse(resp));
4439
+ }
4440
+ const flight = this.doFetch(url, method, body, extraHeaders).then((resp) => this.recordOutcome(url, method, resp)).finally(() => this.inflightGets.delete(flightKey));
4441
+ this.inflightGets.set(flightKey, flight);
4442
+ return flight.then((resp) => this.cloneResponse(resp));
4443
+ }
4444
+ /** Bookkeeping on every real (non-synthesized) response — runs once per
4445
+ * physical fetch, never once per coalesced awaiter. */
4446
+ recordOutcome(url, method, response) {
4447
+ const status = response.status;
4448
+ if (status === 401 || status === 403 && method === "GET") {
4449
+ if (this.authFailedStatus === null) {
4450
+ this.authFailedStatus = status;
4451
+ console.warn(
4452
+ `[LionRapid] API key rejected (${status}) \u2014 network translations are disabled for this session. Fix the key and reload; retrying cannot heal an auth failure.`
4453
+ );
4454
+ }
4455
+ return response;
4456
+ }
4457
+ if ((status === 403 || status === 429) && method !== "GET") {
4458
+ if (this.writesFailedStatus === null) {
4459
+ this.writesFailedStatus = status;
4460
+ logger.warn(
4461
+ `Write path disabled after ${status} (scope/quota) \u2014 running read-only`
4462
+ );
4463
+ }
4464
+ return response;
4465
+ }
4466
+ if (method === "GET" && (status === 404 || status === 423)) {
4467
+ const retryAfterSec = status === 423 ? Number(response.headers?.get?.("Retry-After")) : NaN;
4468
+ const ttl = Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? retryAfterSec * 1e3 : this.config.options?.negativeCacheTtlMs ?? _NetworkRepository.DEFAULT_NEGATIVE_TTL_MS;
4469
+ this.negativeCache.set(url, { status, until: Date.now() + ttl });
4470
+ } else if (method !== "GET" && response.ok) {
4471
+ this.negativeCache.clear();
4472
+ } else if (method === "GET" && response.ok) {
4473
+ this.negativeCache.delete(url);
4474
+ }
4475
+ return response;
4476
+ }
4477
+ /** Test doubles (and exotic runtimes) hand us plain objects — only real
4478
+ * Responses need cloning so each coalesced awaiter can read the body. */
4479
+ cloneResponse(response) {
4480
+ return typeof response.clone === "function" ? response.clone() : response;
4481
+ }
4482
+ async doFetch(url, method, body, extraHeaders) {
4337
4483
  const controller = new AbortController();
4338
4484
  const timeout = this.config.options?.timeout ?? 1e4;
4339
4485
  const timeoutId = setTimeout(
@@ -4366,6 +4512,7 @@ __publicField(_NetworkRepository, "SNAPSHOT_PREFIX", "lionrapid:ns:");
4366
4512
  /** Legacy bare-version prefix — a version WITHOUT its payload is exactly the
4367
4513
  * desync the snapshot store exists to prevent; entries are deleted on sight. */
4368
4514
  __publicField(_NetworkRepository, "LEGACY_VERSION_PREFIX", "lionrapid:v:");
4515
+ __publicField(_NetworkRepository, "DEFAULT_NEGATIVE_TTL_MS", 6e4);
4369
4516
  var NetworkRepository = _NetworkRepository;
4370
4517
 
4371
4518
  // src/content/validator/ContentValidator.ts
@@ -4964,9 +5111,11 @@ var LocalStorageRepository = class {
4964
5111
  this.config = {
4965
5112
  enabled: config.enabled ?? true,
4966
5113
  priority: config.priority ?? 0,
5114
+ // Use build sequence by default
4967
5115
  options: {
4968
5116
  prefix: config.options?.prefix ?? STORAGE_PREFIX,
4969
5117
  ttl: config.options?.ttl ?? 24 * 60 * 60 * 1e3,
5118
+ // 24 hours default
4970
5119
  maxSize: config.options?.maxSize ?? 500,
4971
5120
  ...config.options
4972
5121
  }
@@ -4979,6 +5128,10 @@ var LocalStorageRepository = class {
4979
5128
  this.migrateIfNeeded();
4980
5129
  }
4981
5130
  }
5131
+ /**
5132
+ * Check if localStorage is available
5133
+ * Returns false in SSR, private browsing, or when quota is 0
5134
+ */
4982
5135
  checkAvailability() {
4983
5136
  if (typeof window === "undefined") {
4984
5137
  return false;
@@ -4992,6 +5145,9 @@ var LocalStorageRepository = class {
4992
5145
  return false;
4993
5146
  }
4994
5147
  }
5148
+ /**
5149
+ * Handle version migrations - clear cache when version changes
5150
+ */
4995
5151
  migrateIfNeeded() {
4996
5152
  try {
4997
5153
  const storedVersion = window.localStorage.getItem(VERSION_KEY);
@@ -5002,6 +5158,10 @@ var LocalStorageRepository = class {
5002
5158
  } catch {
5003
5159
  }
5004
5160
  }
5161
+ /**
5162
+ * Get a translation value by key
5163
+ * Returns null if not found or expired
5164
+ */
5005
5165
  get(key) {
5006
5166
  if (!this.available) return null;
5007
5167
  try {
@@ -5018,6 +5178,10 @@ var LocalStorageRepository = class {
5018
5178
  return null;
5019
5179
  }
5020
5180
  }
5181
+ /**
5182
+ * Set a translation value
5183
+ * Automatically handles quota exceeded by evicting oldest entries
5184
+ */
5021
5185
  set(key, value) {
5022
5186
  if (!this.available) return;
5023
5187
  const fullKey = this.prefix + key;
@@ -5042,6 +5206,9 @@ var LocalStorageRepository = class {
5042
5206
  }
5043
5207
  }
5044
5208
  }
5209
+ /**
5210
+ * Remove a translation by key
5211
+ */
5045
5212
  remove(key) {
5046
5213
  if (!this.available) return;
5047
5214
  try {
@@ -5049,6 +5216,10 @@ var LocalStorageRepository = class {
5049
5216
  } catch {
5050
5217
  }
5051
5218
  }
5219
+ /**
5220
+ * Clear all LionRapid entries from localStorage
5221
+ * Preserves entries from other applications
5222
+ */
5052
5223
  clear() {
5053
5224
  if (!this.available) return;
5054
5225
  try {
@@ -5063,6 +5234,9 @@ var LocalStorageRepository = class {
5063
5234
  } catch {
5064
5235
  }
5065
5236
  }
5237
+ /**
5238
+ * Clear all entries for a specific namespace
5239
+ */
5066
5240
  clearNamespace(locale, namespace) {
5067
5241
  if (!this.available) return;
5068
5242
  const namespaceCacheKey = `@${locale}:${namespace}`;
@@ -5081,6 +5255,9 @@ var LocalStorageRepository = class {
5081
5255
  } catch {
5082
5256
  }
5083
5257
  }
5258
+ /**
5259
+ * Get namespace translations
5260
+ */
5084
5261
  getNamespace(locale, namespace) {
5085
5262
  const namespaceCacheKey = `@${locale}:${namespace}`;
5086
5263
  const value = this.get(namespaceCacheKey);
@@ -5092,10 +5269,16 @@ var LocalStorageRepository = class {
5092
5269
  return null;
5093
5270
  }
5094
5271
  }
5272
+ /**
5273
+ * Set namespace translations
5274
+ */
5095
5275
  setNamespace(locale, namespace, translations) {
5096
5276
  const namespaceCacheKey = `@${locale}:${namespace}`;
5097
5277
  this.set(namespaceCacheKey, JSON.stringify(translations));
5098
5278
  }
5279
+ /**
5280
+ * Get all cache entries for debugging
5281
+ */
5099
5282
  getEntries() {
5100
5283
  const entries = {};
5101
5284
  if (!this.available) return entries;
@@ -5115,12 +5298,21 @@ var LocalStorageRepository = class {
5115
5298
  }
5116
5299
  return entries;
5117
5300
  }
5301
+ /**
5302
+ * Get repository configuration
5303
+ */
5118
5304
  getConfig() {
5119
5305
  return this.config;
5120
5306
  }
5307
+ /**
5308
+ * Check if localStorage is available
5309
+ */
5121
5310
  isAvailable() {
5122
5311
  return this.available;
5123
5312
  }
5313
+ /**
5314
+ * Get the number of entries in the cache
5315
+ */
5124
5316
  getEntryCount() {
5125
5317
  if (!this.available) return 0;
5126
5318
  let count = 0;
@@ -5135,12 +5327,18 @@ var LocalStorageRepository = class {
5135
5327
  }
5136
5328
  return count;
5137
5329
  }
5330
+ /**
5331
+ * Check if error is a quota exceeded error
5332
+ */
5138
5333
  isQuotaError(error) {
5139
5334
  if (error instanceof DOMException) {
5140
5335
  return error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED";
5141
5336
  }
5142
5337
  return false;
5143
5338
  }
5339
+ /**
5340
+ * Evict oldest 25% of entries when quota is exceeded
5341
+ */
5144
5342
  evictOldest() {
5145
5343
  if (!this.available) return;
5146
5344
  try {
@@ -5168,6 +5366,9 @@ var LocalStorageRepository = class {
5168
5366
  } catch {
5169
5367
  }
5170
5368
  }
5369
+ /**
5370
+ * Get cache statistics
5371
+ */
5171
5372
  getCacheStats() {
5172
5373
  const size = this.getEntryCount();
5173
5374
  const usage = this.maxSize > 0 ? `${Math.round(size / this.maxSize * 100)}%` : "0%";
@@ -5181,7 +5382,7 @@ var LocalStorageRepository = class {
5181
5382
 
5182
5383
  // src/browser/storage/cache-storage-repository.ts
5183
5384
  var CACHE_NAME = "lionrapid-v1";
5184
- var CACHE_PREFIX = "lionrapid:";
5385
+ var CACHE_PREFIX = "https://cache.lionrapid.internal/";
5185
5386
  var CacheStorageRepository = class {
5186
5387
  constructor(config = {}) {
5187
5388
  __publicField(this, "name", "CacheStorageRepository");
@@ -5196,6 +5397,7 @@ var CacheStorageRepository = class {
5196
5397
  options: {
5197
5398
  cacheName: config.options?.cacheName ?? CACHE_NAME,
5198
5399
  ttl: config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3,
5400
+ // 7 days default
5199
5401
  ...config.options
5200
5402
  }
5201
5403
  };
@@ -5203,9 +5405,17 @@ var CacheStorageRepository = class {
5203
5405
  this.defaultTTL = this.config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3;
5204
5406
  this.available = this.checkAvailability();
5205
5407
  }
5408
+ /**
5409
+ * Check if Cache API is available
5410
+ * Returns false in SSR, old browsers, or insecure contexts
5411
+ */
5206
5412
  checkAvailability() {
5207
5413
  return typeof caches !== "undefined";
5208
5414
  }
5415
+ /**
5416
+ * Get a translation value by key
5417
+ * @throws {TranslationNotFoundError} When translation doesn't exist or is expired
5418
+ */
5209
5419
  async get(key) {
5210
5420
  if (!this.available) {
5211
5421
  throw new TranslationNotFoundError(key);
@@ -5229,6 +5439,9 @@ var CacheStorageRepository = class {
5229
5439
  throw new TranslationNotFoundError(key);
5230
5440
  }
5231
5441
  }
5442
+ /**
5443
+ * Set a translation value
5444
+ */
5232
5445
  async set(key, value) {
5233
5446
  if (!this.available) return;
5234
5447
  try {
@@ -5247,6 +5460,9 @@ var CacheStorageRepository = class {
5247
5460
  } catch {
5248
5461
  }
5249
5462
  }
5463
+ /**
5464
+ * Remove a translation by key
5465
+ */
5250
5466
  async remove(key) {
5251
5467
  if (!this.available) return;
5252
5468
  try {
@@ -5255,6 +5471,9 @@ var CacheStorageRepository = class {
5255
5471
  } catch {
5256
5472
  }
5257
5473
  }
5474
+ /**
5475
+ * Clear all LionRapid entries from the cache
5476
+ */
5258
5477
  async clear() {
5259
5478
  if (!this.available) return;
5260
5479
  try {
@@ -5266,6 +5485,9 @@ var CacheStorageRepository = class {
5266
5485
  } catch {
5267
5486
  }
5268
5487
  }
5488
+ /**
5489
+ * Clear all entries for a specific namespace
5490
+ */
5269
5491
  async clearNamespace(locale, namespace) {
5270
5492
  if (!this.available) return;
5271
5493
  const namespaceCacheKey = `@${locale}:${namespace}`;
@@ -5283,6 +5505,10 @@ var CacheStorageRepository = class {
5283
5505
  } catch {
5284
5506
  }
5285
5507
  }
5508
+ /**
5509
+ * Get namespace translations
5510
+ * @throws {TranslationNotFoundError} When namespace doesn't exist
5511
+ */
5286
5512
  async getNamespace(locale, namespace) {
5287
5513
  const namespaceCacheKey = `@${locale}:${namespace}`;
5288
5514
  const value = await this.get(namespaceCacheKey);
@@ -5293,16 +5519,29 @@ var CacheStorageRepository = class {
5293
5519
  throw new TranslationNotFoundError(namespaceCacheKey);
5294
5520
  }
5295
5521
  }
5522
+ /**
5523
+ * Set namespace translations
5524
+ */
5296
5525
  async setNamespace(locale, namespace, translations) {
5297
5526
  const namespaceCacheKey = `@${locale}:${namespace}`;
5298
5527
  await this.set(namespaceCacheKey, JSON.stringify(translations));
5299
5528
  }
5529
+ /**
5530
+ * Get repository configuration
5531
+ */
5300
5532
  getConfig() {
5301
5533
  return this.config;
5302
5534
  }
5535
+ /**
5536
+ * Check if Cache API is available
5537
+ */
5303
5538
  isAvailable() {
5304
5539
  return this.available;
5305
5540
  }
5541
+ /**
5542
+ * Get all cached entries (for debugging)
5543
+ * Returns an object mapping keys to values
5544
+ */
5306
5545
  async getEntries() {
5307
5546
  const entries = {};
5308
5547
  if (!this.available) return entries;
@@ -5325,6 +5564,9 @@ var CacheStorageRepository = class {
5325
5564
  }
5326
5565
  return entries;
5327
5566
  }
5567
+ /**
5568
+ * Get cache statistics
5569
+ */
5328
5570
  async getCacheStats() {
5329
5571
  if (!this.available) {
5330
5572
  return { size: 0, cacheName: this.cacheName };