@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
@@ -2911,6 +2911,7 @@ var LionRapidCore = class {
2911
2911
  // 🔥 EMBEDDED: Core integration maps
2912
2912
  __publicField(this, "formatters", /* @__PURE__ */ new Map());
2913
2913
  __publicField(this, "processors", /* @__PURE__ */ new Map());
2914
+ __publicField(this, "warnedNoInterpolate", false);
2914
2915
  // 📡 EVENT-DRIVEN: Just track for cleanup
2915
2916
  __publicField(this, "eventPlugins", /* @__PURE__ */ new Set());
2916
2917
  // 📦 CONTENT: Parser and serializer for ContentUnit processing
@@ -3203,6 +3204,11 @@ var LionRapidCore = class {
3203
3204
  resolvedLocale,
3204
3205
  resolvedKey
3205
3206
  );
3207
+ } else if (!this.warnedNoInterpolate && params && Object.keys(params).length > 0 && processedValue.includes("{")) {
3208
+ this.warnedNoInterpolate = true;
3209
+ console.warn(
3210
+ "[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."
3211
+ );
3206
3212
  }
3207
3213
  if (this.processors.size > 0) {
3208
3214
  for (const [name, processor] of this.processors.entries()) {
@@ -3983,6 +3989,31 @@ var _NetworkRepository = class _NetworkRepository {
3983
3989
  * and payload can never desync because they live and die together.
3984
3990
  */
3985
3991
  __publicField(this, "namespaceSnapshots", /* @__PURE__ */ new Map());
3992
+ /**
3993
+ * Miss-path flood protection (READINESS before-scale #1: one cold locale
3994
+ * switch measured ~380 requests in 10 s — every t() miss refired a key GET
3995
+ * and a namespace GET on every re-render, forever on animated pages).
3996
+ */
3997
+ /** GETs currently on the wire, keyed by `url|if-none-match` — identical
3998
+ * concurrent requests share one fetch; each awaiter gets a clone. The
3999
+ * If-None-Match value is part of the key so the 304-without-snapshot
4000
+ * unconditional refetch never coalesces onto a conditional flight. */
4001
+ __publicField(this, "inflightGets", /* @__PURE__ */ new Map());
4002
+ /** URL → 404/423 seen recently: repeats are answered locally (same typed
4003
+ * error, no network) until `until`. 423 honors the server's Retry-After.
4004
+ * Cleared entirely by any successful write — discovery sync keeps its
4005
+ * miss → batch → served-back round-trip. */
4006
+ __publicField(this, "negativeCache", /* @__PURE__ */ new Map());
4007
+ /** One-way latch: a 401 anywhere (or a 403 on a READ) means the key is
4008
+ * wrong or unauthorized for this project, and retrying cannot heal it —
4009
+ * after the first one nothing touches the network again for this
4010
+ * instance (a page reload starts fresh). Holds the status that tripped
4011
+ * it so short-circuits answer honestly. */
4012
+ __publicField(this, "authFailedStatus", null);
4013
+ /** Write-only latch (auth-byok Phase 18): a 403 (scope) or 429 (quota) on
4014
+ * a WRITE degrades this instance to read-only — writes stop, silently
4015
+ * and without retries, while reads keep serving the page. */
4016
+ __publicField(this, "writesFailedStatus", null);
3986
4017
  /**
3987
4018
  * Default endpoint templates with placeholder support
3988
4019
  * Placeholders: :key, :locale, :namespace
@@ -3990,6 +4021,7 @@ var _NetworkRepository = class _NetworkRepository {
3990
4021
  __publicField(this, "DEFAULT_ENDPOINTS", {
3991
4022
  getTranslation: "/api/integrations/translations/:key",
3992
4023
  getNamespace: "/api/integrations/translations/:locale/:namespace",
4024
+ getProjectConfig: "/api/integrations/project-config",
3993
4025
  setTranslation: "/api/integrations/sync/:key",
3994
4026
  setNamespace: "/api/integrations/sync/:locale/:namespace",
3995
4027
  setBatch: "/api/integrations/sync/batch",
@@ -4101,6 +4133,40 @@ var _NetworkRepository = class _NetworkRepository {
4101
4133
  this.handleCaughtError(error);
4102
4134
  }
4103
4135
  }
4136
+ /**
4137
+ * Project-level config for this key — the dashboard's language list,
4138
+ * served under the same trust model as translation reads (docs/20,
4139
+ * companion track). Returns null when the server doesn't expose the
4140
+ * endpoint (404 — older server, feature not deployed) or the payload is
4141
+ * unusable: absence means "keep your local fallback", never an error.
4142
+ */
4143
+ async getProjectConfig() {
4144
+ if (!this.config?.options?.baseUrl) {
4145
+ throw new NetworkError("API base URL is not set");
4146
+ }
4147
+ const url = this.buildUrl("getProjectConfig", {});
4148
+ logger.debug(`API GET ProjectConfig: ${url}`);
4149
+ try {
4150
+ const response = await this.makeRequest(url, "GET");
4151
+ if (response.status === 404) {
4152
+ return null;
4153
+ }
4154
+ if (!response.ok) {
4155
+ this.handleHttpError(response, "project-config");
4156
+ }
4157
+ const data = await response.json();
4158
+ if (!data || typeof data.defaultLocale !== "string" || !Array.isArray(data.languages)) {
4159
+ logger.warn("project-config payload unusable \u2014 keeping local fallback");
4160
+ return null;
4161
+ }
4162
+ return {
4163
+ defaultLocale: data.defaultLocale,
4164
+ languages: data.languages.map(String)
4165
+ };
4166
+ } catch (error) {
4167
+ this.handleCaughtError(error);
4168
+ }
4169
+ }
4104
4170
  /**
4105
4171
  * Shared namespace fetch with the canonical 304 contract:
4106
4172
  * - If-None-Match is sent ONLY when a snapshot (version + payload) is in hand.
@@ -4425,7 +4491,87 @@ var _NetworkRepository = class _NetworkRepository {
4425
4491
  /**
4426
4492
  * Make HTTP request with timeout and headers
4427
4493
  */
4428
- async makeRequest(url, method, body, extraHeaders) {
4494
+ makeRequest(url, method, body, extraHeaders) {
4495
+ if (this.authFailedStatus !== null) {
4496
+ return Promise.resolve(
4497
+ new Response(null, {
4498
+ status: this.authFailedStatus,
4499
+ statusText: `auth latched off after ${this.authFailedStatus}`
4500
+ })
4501
+ );
4502
+ }
4503
+ if (method !== "GET") {
4504
+ if (this.writesFailedStatus !== null) {
4505
+ return Promise.resolve(
4506
+ new Response(null, {
4507
+ status: this.writesFailedStatus,
4508
+ statusText: `writes latched off after ${this.writesFailedStatus}`
4509
+ })
4510
+ );
4511
+ }
4512
+ return this.doFetch(url, method, body, extraHeaders).then(
4513
+ (resp) => this.recordOutcome(url, method, resp)
4514
+ );
4515
+ }
4516
+ const negative = this.negativeCache.get(url);
4517
+ if (negative) {
4518
+ if (Date.now() < negative.until) {
4519
+ logger.debug(`Negative-cache hit (${negative.status}): ${url}`);
4520
+ const headers = negative.status === 423 ? { "Retry-After": String(Math.ceil((negative.until - Date.now()) / 1e3)) } : void 0;
4521
+ return Promise.resolve(
4522
+ new Response(null, { status: negative.status, statusText: "negative cache", headers })
4523
+ );
4524
+ }
4525
+ this.negativeCache.delete(url);
4526
+ }
4527
+ const flightKey = `${url}|${extraHeaders?.["If-None-Match"] ?? ""}`;
4528
+ const existing = this.inflightGets.get(flightKey);
4529
+ if (existing) {
4530
+ return existing.then((resp) => this.cloneResponse(resp));
4531
+ }
4532
+ const flight = this.doFetch(url, method, body, extraHeaders).then((resp) => this.recordOutcome(url, method, resp)).finally(() => this.inflightGets.delete(flightKey));
4533
+ this.inflightGets.set(flightKey, flight);
4534
+ return flight.then((resp) => this.cloneResponse(resp));
4535
+ }
4536
+ /** Bookkeeping on every real (non-synthesized) response — runs once per
4537
+ * physical fetch, never once per coalesced awaiter. */
4538
+ recordOutcome(url, method, response) {
4539
+ const status = response.status;
4540
+ if (status === 401 || status === 403 && method === "GET") {
4541
+ if (this.authFailedStatus === null) {
4542
+ this.authFailedStatus = status;
4543
+ console.warn(
4544
+ `[LionRapid] API key rejected (${status}) \u2014 network translations are disabled for this session. Fix the key and reload; retrying cannot heal an auth failure.`
4545
+ );
4546
+ }
4547
+ return response;
4548
+ }
4549
+ if ((status === 403 || status === 429) && method !== "GET") {
4550
+ if (this.writesFailedStatus === null) {
4551
+ this.writesFailedStatus = status;
4552
+ logger.warn(
4553
+ `Write path disabled after ${status} (scope/quota) \u2014 running read-only`
4554
+ );
4555
+ }
4556
+ return response;
4557
+ }
4558
+ if (method === "GET" && (status === 404 || status === 423)) {
4559
+ const retryAfterSec = status === 423 ? Number(response.headers?.get?.("Retry-After")) : NaN;
4560
+ const ttl = Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? retryAfterSec * 1e3 : this.config.options?.negativeCacheTtlMs ?? _NetworkRepository.DEFAULT_NEGATIVE_TTL_MS;
4561
+ this.negativeCache.set(url, { status, until: Date.now() + ttl });
4562
+ } else if (method !== "GET" && response.ok) {
4563
+ this.negativeCache.clear();
4564
+ } else if (method === "GET" && response.ok) {
4565
+ this.negativeCache.delete(url);
4566
+ }
4567
+ return response;
4568
+ }
4569
+ /** Test doubles (and exotic runtimes) hand us plain objects — only real
4570
+ * Responses need cloning so each coalesced awaiter can read the body. */
4571
+ cloneResponse(response) {
4572
+ return typeof response.clone === "function" ? response.clone() : response;
4573
+ }
4574
+ async doFetch(url, method, body, extraHeaders) {
4429
4575
  const controller = new AbortController();
4430
4576
  const timeout = this.config.options?.timeout ?? 1e4;
4431
4577
  const timeoutId = setTimeout(
@@ -4458,6 +4604,7 @@ __publicField(_NetworkRepository, "SNAPSHOT_PREFIX", "lionrapid:ns:");
4458
4604
  /** Legacy bare-version prefix — a version WITHOUT its payload is exactly the
4459
4605
  * desync the snapshot store exists to prevent; entries are deleted on sight. */
4460
4606
  __publicField(_NetworkRepository, "LEGACY_VERSION_PREFIX", "lionrapid:v:");
4607
+ __publicField(_NetworkRepository, "DEFAULT_NEGATIVE_TTL_MS", 6e4);
4461
4608
  var NetworkRepository = _NetworkRepository;
4462
4609
 
4463
4610
  // src/content/validator/ContentValidator.ts
@@ -5056,9 +5203,11 @@ var LocalStorageRepository = class {
5056
5203
  this.config = {
5057
5204
  enabled: config.enabled ?? true,
5058
5205
  priority: config.priority ?? 0,
5206
+ // Use build sequence by default
5059
5207
  options: {
5060
5208
  prefix: config.options?.prefix ?? STORAGE_PREFIX,
5061
5209
  ttl: config.options?.ttl ?? 24 * 60 * 60 * 1e3,
5210
+ // 24 hours default
5062
5211
  maxSize: config.options?.maxSize ?? 500,
5063
5212
  ...config.options
5064
5213
  }
@@ -5071,6 +5220,10 @@ var LocalStorageRepository = class {
5071
5220
  this.migrateIfNeeded();
5072
5221
  }
5073
5222
  }
5223
+ /**
5224
+ * Check if localStorage is available
5225
+ * Returns false in SSR, private browsing, or when quota is 0
5226
+ */
5074
5227
  checkAvailability() {
5075
5228
  if (typeof window === "undefined") {
5076
5229
  return false;
@@ -5084,6 +5237,9 @@ var LocalStorageRepository = class {
5084
5237
  return false;
5085
5238
  }
5086
5239
  }
5240
+ /**
5241
+ * Handle version migrations - clear cache when version changes
5242
+ */
5087
5243
  migrateIfNeeded() {
5088
5244
  try {
5089
5245
  const storedVersion = window.localStorage.getItem(VERSION_KEY);
@@ -5094,6 +5250,10 @@ var LocalStorageRepository = class {
5094
5250
  } catch {
5095
5251
  }
5096
5252
  }
5253
+ /**
5254
+ * Get a translation value by key
5255
+ * Returns null if not found or expired
5256
+ */
5097
5257
  get(key) {
5098
5258
  if (!this.available) return null;
5099
5259
  try {
@@ -5110,6 +5270,10 @@ var LocalStorageRepository = class {
5110
5270
  return null;
5111
5271
  }
5112
5272
  }
5273
+ /**
5274
+ * Set a translation value
5275
+ * Automatically handles quota exceeded by evicting oldest entries
5276
+ */
5113
5277
  set(key, value) {
5114
5278
  if (!this.available) return;
5115
5279
  const fullKey = this.prefix + key;
@@ -5134,6 +5298,9 @@ var LocalStorageRepository = class {
5134
5298
  }
5135
5299
  }
5136
5300
  }
5301
+ /**
5302
+ * Remove a translation by key
5303
+ */
5137
5304
  remove(key) {
5138
5305
  if (!this.available) return;
5139
5306
  try {
@@ -5141,6 +5308,10 @@ var LocalStorageRepository = class {
5141
5308
  } catch {
5142
5309
  }
5143
5310
  }
5311
+ /**
5312
+ * Clear all LionRapid entries from localStorage
5313
+ * Preserves entries from other applications
5314
+ */
5144
5315
  clear() {
5145
5316
  if (!this.available) return;
5146
5317
  try {
@@ -5155,6 +5326,9 @@ var LocalStorageRepository = class {
5155
5326
  } catch {
5156
5327
  }
5157
5328
  }
5329
+ /**
5330
+ * Clear all entries for a specific namespace
5331
+ */
5158
5332
  clearNamespace(locale, namespace) {
5159
5333
  if (!this.available) return;
5160
5334
  const namespaceCacheKey = `@${locale}:${namespace}`;
@@ -5173,6 +5347,9 @@ var LocalStorageRepository = class {
5173
5347
  } catch {
5174
5348
  }
5175
5349
  }
5350
+ /**
5351
+ * Get namespace translations
5352
+ */
5176
5353
  getNamespace(locale, namespace) {
5177
5354
  const namespaceCacheKey = `@${locale}:${namespace}`;
5178
5355
  const value = this.get(namespaceCacheKey);
@@ -5184,10 +5361,16 @@ var LocalStorageRepository = class {
5184
5361
  return null;
5185
5362
  }
5186
5363
  }
5364
+ /**
5365
+ * Set namespace translations
5366
+ */
5187
5367
  setNamespace(locale, namespace, translations) {
5188
5368
  const namespaceCacheKey = `@${locale}:${namespace}`;
5189
5369
  this.set(namespaceCacheKey, JSON.stringify(translations));
5190
5370
  }
5371
+ /**
5372
+ * Get all cache entries for debugging
5373
+ */
5191
5374
  getEntries() {
5192
5375
  const entries = {};
5193
5376
  if (!this.available) return entries;
@@ -5207,12 +5390,21 @@ var LocalStorageRepository = class {
5207
5390
  }
5208
5391
  return entries;
5209
5392
  }
5393
+ /**
5394
+ * Get repository configuration
5395
+ */
5210
5396
  getConfig() {
5211
5397
  return this.config;
5212
5398
  }
5399
+ /**
5400
+ * Check if localStorage is available
5401
+ */
5213
5402
  isAvailable() {
5214
5403
  return this.available;
5215
5404
  }
5405
+ /**
5406
+ * Get the number of entries in the cache
5407
+ */
5216
5408
  getEntryCount() {
5217
5409
  if (!this.available) return 0;
5218
5410
  let count = 0;
@@ -5227,12 +5419,18 @@ var LocalStorageRepository = class {
5227
5419
  }
5228
5420
  return count;
5229
5421
  }
5422
+ /**
5423
+ * Check if error is a quota exceeded error
5424
+ */
5230
5425
  isQuotaError(error) {
5231
5426
  if (error instanceof DOMException) {
5232
5427
  return error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED";
5233
5428
  }
5234
5429
  return false;
5235
5430
  }
5431
+ /**
5432
+ * Evict oldest 25% of entries when quota is exceeded
5433
+ */
5236
5434
  evictOldest() {
5237
5435
  if (!this.available) return;
5238
5436
  try {
@@ -5260,6 +5458,9 @@ var LocalStorageRepository = class {
5260
5458
  } catch {
5261
5459
  }
5262
5460
  }
5461
+ /**
5462
+ * Get cache statistics
5463
+ */
5263
5464
  getCacheStats() {
5264
5465
  const size = this.getEntryCount();
5265
5466
  const usage = this.maxSize > 0 ? `${Math.round(size / this.maxSize * 100)}%` : "0%";
@@ -5273,7 +5474,7 @@ var LocalStorageRepository = class {
5273
5474
 
5274
5475
  // src/browser/storage/cache-storage-repository.ts
5275
5476
  var CACHE_NAME = "lionrapid-v1";
5276
- var CACHE_PREFIX = "lionrapid:";
5477
+ var CACHE_PREFIX = "https://cache.lionrapid.internal/";
5277
5478
  var CacheStorageRepository = class {
5278
5479
  constructor(config = {}) {
5279
5480
  __publicField(this, "name", "CacheStorageRepository");
@@ -5288,6 +5489,7 @@ var CacheStorageRepository = class {
5288
5489
  options: {
5289
5490
  cacheName: config.options?.cacheName ?? CACHE_NAME,
5290
5491
  ttl: config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3,
5492
+ // 7 days default
5291
5493
  ...config.options
5292
5494
  }
5293
5495
  };
@@ -5295,9 +5497,17 @@ var CacheStorageRepository = class {
5295
5497
  this.defaultTTL = this.config.options?.ttl ?? 7 * 24 * 60 * 60 * 1e3;
5296
5498
  this.available = this.checkAvailability();
5297
5499
  }
5500
+ /**
5501
+ * Check if Cache API is available
5502
+ * Returns false in SSR, old browsers, or insecure contexts
5503
+ */
5298
5504
  checkAvailability() {
5299
5505
  return typeof caches !== "undefined";
5300
5506
  }
5507
+ /**
5508
+ * Get a translation value by key
5509
+ * @throws {TranslationNotFoundError} When translation doesn't exist or is expired
5510
+ */
5301
5511
  async get(key) {
5302
5512
  if (!this.available) {
5303
5513
  throw new TranslationNotFoundError(key);
@@ -5321,6 +5531,9 @@ var CacheStorageRepository = class {
5321
5531
  throw new TranslationNotFoundError(key);
5322
5532
  }
5323
5533
  }
5534
+ /**
5535
+ * Set a translation value
5536
+ */
5324
5537
  async set(key, value) {
5325
5538
  if (!this.available) return;
5326
5539
  try {
@@ -5339,6 +5552,9 @@ var CacheStorageRepository = class {
5339
5552
  } catch {
5340
5553
  }
5341
5554
  }
5555
+ /**
5556
+ * Remove a translation by key
5557
+ */
5342
5558
  async remove(key) {
5343
5559
  if (!this.available) return;
5344
5560
  try {
@@ -5347,6 +5563,9 @@ var CacheStorageRepository = class {
5347
5563
  } catch {
5348
5564
  }
5349
5565
  }
5566
+ /**
5567
+ * Clear all LionRapid entries from the cache
5568
+ */
5350
5569
  async clear() {
5351
5570
  if (!this.available) return;
5352
5571
  try {
@@ -5358,6 +5577,9 @@ var CacheStorageRepository = class {
5358
5577
  } catch {
5359
5578
  }
5360
5579
  }
5580
+ /**
5581
+ * Clear all entries for a specific namespace
5582
+ */
5361
5583
  async clearNamespace(locale, namespace) {
5362
5584
  if (!this.available) return;
5363
5585
  const namespaceCacheKey = `@${locale}:${namespace}`;
@@ -5375,6 +5597,10 @@ var CacheStorageRepository = class {
5375
5597
  } catch {
5376
5598
  }
5377
5599
  }
5600
+ /**
5601
+ * Get namespace translations
5602
+ * @throws {TranslationNotFoundError} When namespace doesn't exist
5603
+ */
5378
5604
  async getNamespace(locale, namespace) {
5379
5605
  const namespaceCacheKey = `@${locale}:${namespace}`;
5380
5606
  const value = await this.get(namespaceCacheKey);
@@ -5385,16 +5611,29 @@ var CacheStorageRepository = class {
5385
5611
  throw new TranslationNotFoundError(namespaceCacheKey);
5386
5612
  }
5387
5613
  }
5614
+ /**
5615
+ * Set namespace translations
5616
+ */
5388
5617
  async setNamespace(locale, namespace, translations) {
5389
5618
  const namespaceCacheKey = `@${locale}:${namespace}`;
5390
5619
  await this.set(namespaceCacheKey, JSON.stringify(translations));
5391
5620
  }
5621
+ /**
5622
+ * Get repository configuration
5623
+ */
5392
5624
  getConfig() {
5393
5625
  return this.config;
5394
5626
  }
5627
+ /**
5628
+ * Check if Cache API is available
5629
+ */
5395
5630
  isAvailable() {
5396
5631
  return this.available;
5397
5632
  }
5633
+ /**
5634
+ * Get all cached entries (for debugging)
5635
+ * Returns an object mapping keys to values
5636
+ */
5398
5637
  async getEntries() {
5399
5638
  const entries = {};
5400
5639
  if (!this.available) return entries;
@@ -5417,6 +5656,9 @@ var CacheStorageRepository = class {
5417
5656
  }
5418
5657
  return entries;
5419
5658
  }
5659
+ /**
5660
+ * Get cache statistics
5661
+ */
5420
5662
  async getCacheStats() {
5421
5663
  if (!this.available) {
5422
5664
  return { size: 0, cacheName: this.cacheName };