@lionrapid/core 0.1.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.
Files changed (302) hide show
  1. package/README.md +106 -0
  2. package/dist/base/event-emitter.d.ts +91 -0
  3. package/dist/base/event-emitter.d.ts.map +1 -0
  4. package/dist/base/event-emitter.js +330 -0
  5. package/dist/base/event-emitter.js.map +1 -0
  6. package/dist/base/index.d.ts +5 -0
  7. package/dist/base/index.d.ts.map +1 -0
  8. package/dist/base/index.js +5 -0
  9. package/dist/base/index.js.map +1 -0
  10. package/dist/browser/auto-init.d.ts +57 -0
  11. package/dist/browser/auto-init.d.ts.map +1 -0
  12. package/dist/browser/auto-init.js +304 -0
  13. package/dist/browser/auto-init.js.map +1 -0
  14. package/dist/browser/auto-translator.d.ts +98 -0
  15. package/dist/browser/auto-translator.d.ts.map +1 -0
  16. package/dist/browser/auto-translator.js +218 -0
  17. package/dist/browser/auto-translator.js.map +1 -0
  18. package/dist/browser/block-extractor.d.ts +26 -0
  19. package/dist/browser/block-extractor.d.ts.map +1 -0
  20. package/dist/browser/block-extractor.js +143 -0
  21. package/dist/browser/block-extractor.js.map +1 -0
  22. package/dist/browser/dom-observer.d.ts +42 -0
  23. package/dist/browser/dom-observer.d.ts.map +1 -0
  24. package/dist/browser/dom-observer.js +109 -0
  25. package/dist/browser/dom-observer.js.map +1 -0
  26. package/dist/browser/editor/editor-api.d.ts +67 -0
  27. package/dist/browser/editor/editor-api.d.ts.map +1 -0
  28. package/dist/browser/editor/editor-api.js +233 -0
  29. package/dist/browser/editor/editor-api.js.map +1 -0
  30. package/dist/browser/editor/editor-init.d.ts +11 -0
  31. package/dist/browser/editor/editor-init.d.ts.map +1 -0
  32. package/dist/browser/editor/editor-init.js +181 -0
  33. package/dist/browser/editor/editor-init.js.map +1 -0
  34. package/dist/browser/editor/editor-styles.d.ts +6 -0
  35. package/dist/browser/editor/editor-styles.d.ts.map +1 -0
  36. package/dist/browser/editor/editor-styles.js +419 -0
  37. package/dist/browser/editor/editor-styles.js.map +1 -0
  38. package/dist/browser/editor/inspector.d.ts +22 -0
  39. package/dist/browser/editor/inspector.d.ts.map +1 -0
  40. package/dist/browser/editor/inspector.js +125 -0
  41. package/dist/browser/editor/inspector.js.map +1 -0
  42. package/dist/browser/editor/key-resolver.d.ts +19 -0
  43. package/dist/browser/editor/key-resolver.d.ts.map +1 -0
  44. package/dist/browser/editor/key-resolver.js +49 -0
  45. package/dist/browser/editor/key-resolver.js.map +1 -0
  46. package/dist/browser/editor/live-preview.d.ts +10 -0
  47. package/dist/browser/editor/live-preview.d.ts.map +1 -0
  48. package/dist/browser/editor/live-preview.js +57 -0
  49. package/dist/browser/editor/live-preview.js.map +1 -0
  50. package/dist/browser/editor/sidebar.d.ts +50 -0
  51. package/dist/browser/editor/sidebar.d.ts.map +1 -0
  52. package/dist/browser/editor/sidebar.js +353 -0
  53. package/dist/browser/editor/sidebar.js.map +1 -0
  54. package/dist/browser/editor/toolbar.d.ts +29 -0
  55. package/dist/browser/editor/toolbar.d.ts.map +1 -0
  56. package/dist/browser/editor/toolbar.js +131 -0
  57. package/dist/browser/editor/toolbar.js.map +1 -0
  58. package/dist/browser/exclude-filter.d.ts +21 -0
  59. package/dist/browser/exclude-filter.d.ts.map +1 -0
  60. package/dist/browser/exclude-filter.js +51 -0
  61. package/dist/browser/exclude-filter.js.map +1 -0
  62. package/dist/browser/index.d.ts +32 -0
  63. package/dist/browser/index.d.ts.map +1 -0
  64. package/dist/browser/index.js +28 -0
  65. package/dist/browser/index.js.map +1 -0
  66. package/dist/browser/language-switcher.d.ts +70 -0
  67. package/dist/browser/language-switcher.d.ts.map +1 -0
  68. package/dist/browser/language-switcher.js +339 -0
  69. package/dist/browser/language-switcher.js.map +1 -0
  70. package/dist/browser/lionrapid.auto.dev.js +5757 -0
  71. package/dist/browser/lionrapid.auto.dev.js.map +7 -0
  72. package/dist/browser/lionrapid.auto.js +5757 -0
  73. package/dist/browser/lionrapid.auto.js.map +7 -0
  74. package/dist/browser/lionrapid.auto.min.js +80 -0
  75. package/dist/browser/lionrapid.auto.min.js.map +7 -0
  76. package/dist/browser/lionrapid.editor.js +1869 -0
  77. package/dist/browser/lionrapid.editor.js.map +7 -0
  78. package/dist/browser/lionrapid.editor.min.js +415 -0
  79. package/dist/browser/lionrapid.editor.min.js.map +7 -0
  80. package/dist/browser/lionrapid.esm.js +4786 -0
  81. package/dist/browser/lionrapid.esm.js.map +7 -0
  82. package/dist/browser/lionrapid.esm.min.js +3 -0
  83. package/dist/browser/lionrapid.esm.min.js.map +7 -0
  84. package/dist/browser/lionrapid.iife.dev.js +4809 -0
  85. package/dist/browser/lionrapid.iife.dev.js.map +7 -0
  86. package/dist/browser/lionrapid.iife.js +4809 -0
  87. package/dist/browser/lionrapid.iife.js.map +7 -0
  88. package/dist/browser/lionrapid.iife.min.js +3 -0
  89. package/dist/browser/lionrapid.iife.min.js.map +7 -0
  90. package/dist/browser/lionrapid.umd.js +4822 -0
  91. package/dist/browser/lionrapid.umd.js.map +7 -0
  92. package/dist/browser/lionrapid.umd.min.js +18 -0
  93. package/dist/browser/lionrapid.umd.min.js.map +7 -0
  94. package/dist/browser/markup-parser.d.ts +13 -0
  95. package/dist/browser/markup-parser.d.ts.map +1 -0
  96. package/dist/browser/markup-parser.js +56 -0
  97. package/dist/browser/markup-parser.js.map +1 -0
  98. package/dist/browser/md5.d.ts +16 -0
  99. package/dist/browser/md5.d.ts.map +1 -0
  100. package/dist/browser/md5.js +145 -0
  101. package/dist/browser/md5.js.map +1 -0
  102. package/dist/browser/storage/cache-storage-repository.d.ts +44 -0
  103. package/dist/browser/storage/cache-storage-repository.d.ts.map +1 -0
  104. package/dist/browser/storage/cache-storage-repository.js +186 -0
  105. package/dist/browser/storage/cache-storage-repository.js.map +1 -0
  106. package/dist/browser/storage/localstorage-repository.d.ts +51 -0
  107. package/dist/browser/storage/localstorage-repository.d.ts.map +1 -0
  108. package/dist/browser/storage/localstorage-repository.js +270 -0
  109. package/dist/browser/storage/localstorage-repository.js.map +1 -0
  110. package/dist/builder.d.ts +24 -0
  111. package/dist/builder.d.ts.map +1 -0
  112. package/dist/builder.js +169 -0
  113. package/dist/builder.js.map +1 -0
  114. package/dist/cache/CacheManager.d.ts +132 -0
  115. package/dist/cache/CacheManager.d.ts.map +1 -0
  116. package/dist/cache/CacheManager.js +277 -0
  117. package/dist/cache/CacheManager.js.map +1 -0
  118. package/dist/cache/index.d.ts +6 -0
  119. package/dist/cache/index.d.ts.map +1 -0
  120. package/dist/cache/index.js +5 -0
  121. package/dist/cache/index.js.map +1 -0
  122. package/dist/config/index.d.ts +6 -0
  123. package/dist/config/index.d.ts.map +1 -0
  124. package/dist/config/index.js +6 -0
  125. package/dist/config/index.js.map +1 -0
  126. package/dist/config/lionrapid.config.d.ts +12 -0
  127. package/dist/config/lionrapid.config.d.ts.map +1 -0
  128. package/dist/config/lionrapid.config.js +2 -0
  129. package/dist/config/lionrapid.config.js.map +1 -0
  130. package/dist/config/logger.config.d.ts +19 -0
  131. package/dist/config/logger.config.d.ts.map +1 -0
  132. package/dist/config/logger.config.js +9 -0
  133. package/dist/config/logger.config.js.map +1 -0
  134. package/dist/config/repository.config.d.ts +87 -0
  135. package/dist/config/repository.config.d.ts.map +1 -0
  136. package/dist/config/repository.config.js +5 -0
  137. package/dist/config/repository.config.js.map +1 -0
  138. package/dist/content/index.d.ts +20 -0
  139. package/dist/content/index.d.ts.map +1 -0
  140. package/dist/content/index.js +13 -0
  141. package/dist/content/index.js.map +1 -0
  142. package/dist/content/parser/IParser.d.ts +33 -0
  143. package/dist/content/parser/IParser.d.ts.map +1 -0
  144. package/dist/content/parser/IParser.js +6 -0
  145. package/dist/content/parser/IParser.js.map +1 -0
  146. package/dist/content/parser/MarkupParser.d.ts +67 -0
  147. package/dist/content/parser/MarkupParser.d.ts.map +1 -0
  148. package/dist/content/parser/MarkupParser.js +231 -0
  149. package/dist/content/parser/MarkupParser.js.map +1 -0
  150. package/dist/content/serializer/HTMLSerializer.d.ts +61 -0
  151. package/dist/content/serializer/HTMLSerializer.d.ts.map +1 -0
  152. package/dist/content/serializer/HTMLSerializer.js +100 -0
  153. package/dist/content/serializer/HTMLSerializer.js.map +1 -0
  154. package/dist/content/serializer/ISerializer.d.ts +33 -0
  155. package/dist/content/serializer/ISerializer.d.ts.map +1 -0
  156. package/dist/content/serializer/ISerializer.js +6 -0
  157. package/dist/content/serializer/ISerializer.js.map +1 -0
  158. package/dist/content/style-mapper/DefaultStyleMapper.d.ts +59 -0
  159. package/dist/content/style-mapper/DefaultStyleMapper.d.ts.map +1 -0
  160. package/dist/content/style-mapper/DefaultStyleMapper.js +128 -0
  161. package/dist/content/style-mapper/DefaultStyleMapper.js.map +1 -0
  162. package/dist/content/style-mapper/IStyleMapper.d.ts +50 -0
  163. package/dist/content/style-mapper/IStyleMapper.d.ts.map +1 -0
  164. package/dist/content/style-mapper/IStyleMapper.js +6 -0
  165. package/dist/content/style-mapper/IStyleMapper.js.map +1 -0
  166. package/dist/content/types.d.ts +39 -0
  167. package/dist/content/types.d.ts.map +1 -0
  168. package/dist/content/types.js +6 -0
  169. package/dist/content/types.js.map +1 -0
  170. package/dist/content/validator/ContentValidator.d.ts +57 -0
  171. package/dist/content/validator/ContentValidator.d.ts.map +1 -0
  172. package/dist/content/validator/ContentValidator.js +215 -0
  173. package/dist/content/validator/ContentValidator.js.map +1 -0
  174. package/dist/content/validator/IValidator.d.ts +82 -0
  175. package/dist/content/validator/IValidator.d.ts.map +1 -0
  176. package/dist/content/validator/IValidator.js +6 -0
  177. package/dist/content/validator/IValidator.js.map +1 -0
  178. package/dist/errors/translation-errors.d.ts +55 -0
  179. package/dist/errors/translation-errors.d.ts.map +1 -0
  180. package/dist/errors/translation-errors.js +85 -0
  181. package/dist/errors/translation-errors.js.map +1 -0
  182. package/dist/handlers/async-storage-handler.d.ts +77 -0
  183. package/dist/handlers/async-storage-handler.d.ts.map +1 -0
  184. package/dist/handlers/async-storage-handler.js +239 -0
  185. package/dist/handlers/async-storage-handler.js.map +1 -0
  186. package/dist/handlers/handler-chain.d.ts +79 -0
  187. package/dist/handlers/handler-chain.d.ts.map +1 -0
  188. package/dist/handlers/handler-chain.js +366 -0
  189. package/dist/handlers/handler-chain.js.map +1 -0
  190. package/dist/handlers/index.d.ts +7 -0
  191. package/dist/handlers/index.d.ts.map +1 -0
  192. package/dist/handlers/index.js +7 -0
  193. package/dist/handlers/index.js.map +1 -0
  194. package/dist/handlers/network-handler.d.ts +90 -0
  195. package/dist/handlers/network-handler.d.ts.map +1 -0
  196. package/dist/handlers/network-handler.js +283 -0
  197. package/dist/handlers/network-handler.js.map +1 -0
  198. package/dist/handlers/sync-storage-handler.d.ts +88 -0
  199. package/dist/handlers/sync-storage-handler.d.ts.map +1 -0
  200. package/dist/handlers/sync-storage-handler.js +270 -0
  201. package/dist/handlers/sync-storage-handler.js.map +1 -0
  202. package/dist/index.d.ts +37 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.js +30 -0
  205. package/dist/index.js.map +1 -0
  206. package/dist/interfaces/emitter.interface.d.ts +33 -0
  207. package/dist/interfaces/emitter.interface.d.ts.map +1 -0
  208. package/dist/interfaces/emitter.interface.js +2 -0
  209. package/dist/interfaces/emitter.interface.js.map +1 -0
  210. package/dist/interfaces/handler.interface.d.ts +50 -0
  211. package/dist/interfaces/handler.interface.d.ts.map +1 -0
  212. package/dist/interfaces/handler.interface.js +5 -0
  213. package/dist/interfaces/handler.interface.js.map +1 -0
  214. package/dist/interfaces/index.d.ts +8 -0
  215. package/dist/interfaces/index.d.ts.map +1 -0
  216. package/dist/interfaces/index.js +8 -0
  217. package/dist/interfaces/index.js.map +1 -0
  218. package/dist/interfaces/plugin.interface.d.ts +49 -0
  219. package/dist/interfaces/plugin.interface.d.ts.map +1 -0
  220. package/dist/interfaces/plugin.interface.js +6 -0
  221. package/dist/interfaces/plugin.interface.js.map +1 -0
  222. package/dist/interfaces/repository.interface.d.ts +56 -0
  223. package/dist/interfaces/repository.interface.d.ts.map +1 -0
  224. package/dist/interfaces/repository.interface.js +2 -0
  225. package/dist/interfaces/repository.interface.js.map +1 -0
  226. package/dist/lionRapid.d.ts +225 -0
  227. package/dist/lionRapid.d.ts.map +1 -0
  228. package/dist/lionRapid.js +596 -0
  229. package/dist/lionRapid.js.map +1 -0
  230. package/dist/repositories/index.d.ts +3 -0
  231. package/dist/repositories/index.d.ts.map +1 -0
  232. package/dist/repositories/index.js +3 -0
  233. package/dist/repositories/index.js.map +1 -0
  234. package/dist/repositories/memory-repository.d.ts +30 -0
  235. package/dist/repositories/memory-repository.d.ts.map +1 -0
  236. package/dist/repositories/memory-repository.js +100 -0
  237. package/dist/repositories/memory-repository.js.map +1 -0
  238. package/dist/repositories/network-repository.d.ts +138 -0
  239. package/dist/repositories/network-repository.d.ts.map +1 -0
  240. package/dist/repositories/network-repository.js +516 -0
  241. package/dist/repositories/network-repository.js.map +1 -0
  242. package/dist/sync/missing-translation-queue.d.ts +64 -0
  243. package/dist/sync/missing-translation-queue.d.ts.map +1 -0
  244. package/dist/sync/missing-translation-queue.js +184 -0
  245. package/dist/sync/missing-translation-queue.js.map +1 -0
  246. package/dist/types/cache.types.d.ts +62 -0
  247. package/dist/types/cache.types.d.ts.map +1 -0
  248. package/dist/types/cache.types.js +6 -0
  249. package/dist/types/cache.types.js.map +1 -0
  250. package/dist/types/event-payloads.types.d.ts +46 -0
  251. package/dist/types/event-payloads.types.d.ts.map +1 -0
  252. package/dist/types/event-payloads.types.js +6 -0
  253. package/dist/types/event-payloads.types.js.map +1 -0
  254. package/dist/types/generated.types.d.ts +31 -0
  255. package/dist/types/generated.types.d.ts.map +1 -0
  256. package/dist/types/generated.types.js +6 -0
  257. package/dist/types/generated.types.js.map +1 -0
  258. package/dist/types/index.d.ts +7 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +7 -0
  261. package/dist/types/index.js.map +1 -0
  262. package/dist/types/lionRapid.types.d.ts +169 -0
  263. package/dist/types/lionRapid.types.d.ts.map +1 -0
  264. package/dist/types/lionRapid.types.js +8 -0
  265. package/dist/types/lionRapid.types.js.map +1 -0
  266. package/dist/types/parameters.types.d.ts +36 -0
  267. package/dist/types/parameters.types.d.ts.map +1 -0
  268. package/dist/types/parameters.types.js +6 -0
  269. package/dist/types/parameters.types.js.map +1 -0
  270. package/dist/types/translation-data.types.d.ts +54 -0
  271. package/dist/types/translation-data.types.d.ts.map +1 -0
  272. package/dist/types/translation-data.types.js +6 -0
  273. package/dist/types/translation-data.types.js.map +1 -0
  274. package/dist/types/translation.types.d.ts +94 -0
  275. package/dist/types/translation.types.d.ts.map +1 -0
  276. package/dist/types/translation.types.js +5 -0
  277. package/dist/types/translation.types.js.map +1 -0
  278. package/dist/utils/context-utils.d.ts +23 -0
  279. package/dist/utils/context-utils.d.ts.map +1 -0
  280. package/dist/utils/context-utils.js +36 -0
  281. package/dist/utils/context-utils.js.map +1 -0
  282. package/dist/utils/index.d.ts +10 -0
  283. package/dist/utils/index.d.ts.map +1 -0
  284. package/dist/utils/index.js +19 -0
  285. package/dist/utils/index.js.map +1 -0
  286. package/dist/utils/logger.d.ts +229 -0
  287. package/dist/utils/logger.d.ts.map +1 -0
  288. package/dist/utils/logger.js +345 -0
  289. package/dist/utils/logger.js.map +1 -0
  290. package/dist/utils/namespace-utils.d.ts +30 -0
  291. package/dist/utils/namespace-utils.d.ts.map +1 -0
  292. package/dist/utils/namespace-utils.js +56 -0
  293. package/dist/utils/namespace-utils.js.map +1 -0
  294. package/dist/utils/translation-flow.d.ts +18 -0
  295. package/dist/utils/translation-flow.d.ts.map +1 -0
  296. package/dist/utils/translation-flow.js +74 -0
  297. package/dist/utils/translation-flow.js.map +1 -0
  298. package/dist/utils/translation-value-utils.d.ts +57 -0
  299. package/dist/utils/translation-value-utils.d.ts.map +1 -0
  300. package/dist/utils/translation-value-utils.js +194 -0
  301. package/dist/utils/translation-value-utils.js.map +1 -0
  302. package/package.json +76 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Simplified API handler - no automatic namespace loading
3
+ * Namespace loading is now explicit via builder configuration
4
+ */
5
+ import { isRetryableError, TranslationLockedError, TranslationNotFoundError, } from '../errors/translation-errors.js';
6
+ import { logger, resolveNestedKey } from '../utils/index.js';
7
+ /**
8
+ * Simple API handler - only loads individual keys
9
+ * Namespace loading is handled explicitly by builder
10
+ */
11
+ export class NetworkHandler {
12
+ repository;
13
+ name;
14
+ priority;
15
+ version = '1.0.0';
16
+ type = 'network';
17
+ enabled;
18
+ bus;
19
+ retryCount;
20
+ retryDelay;
21
+ constructor(eventEmitter, repository) {
22
+ this.bus = eventEmitter;
23
+ this.repository = repository;
24
+ this.name = repository.name;
25
+ const config = repository.getConfig();
26
+ this.enabled = config.enabled ?? false;
27
+ this.priority = config.priority ?? 0;
28
+ this.retryCount = config.options?.retries ?? 3;
29
+ this.retryDelay = config.options?.retryDelay ?? 1000;
30
+ }
31
+ initialize() {
32
+ return Promise.resolve();
33
+ }
34
+ getSourceType() {
35
+ return 'network';
36
+ }
37
+ /**
38
+ * ✅ Lookup translation with full error handling
39
+ * Strategy: Key first, namespace as fallback
40
+ * Returns TranslationResult with status, source, duration, styles, and optional error
41
+ */
42
+ async lookup(request) {
43
+ const startTime = Date.now();
44
+ const fallbackValue = request.parsedDefaultValue || request.cleanKey;
45
+ if (!this.enabled) {
46
+ return this.createTranslationResult(fallbackValue, 'fallback', 0, startTime);
47
+ }
48
+ const networkBus = this.bus.network(request, this.name);
49
+ networkBus.start();
50
+ logger.debug(`Network lookup: ${request.cleanKey}`);
51
+ // Strategy 1: Try individual key lookup first (returns ContentUnit with styles)
52
+ try {
53
+ const contentUnit = await this.lookupContentUnitWithRetry(request.individualCacheKey);
54
+ logger.debug(`Network hit: ${request.cleanKey}`);
55
+ networkBus.success(contentUnit.text);
56
+ // Return text + styles for caching
57
+ return this.createTranslationResult(contentUnit.text, 'network', 200, startTime, undefined, false, undefined, contentUnit.styles);
58
+ }
59
+ catch (error) {
60
+ // Handle 404 - key not found, try namespace fallback
61
+ if (error instanceof TranslationNotFoundError && request.namespace) {
62
+ logger.debug(`Individual key not found, trying namespace: ${request.cleanKey}`);
63
+ return this.lookupFromNamespace(request, fallbackValue, startTime, networkBus);
64
+ }
65
+ // Handle 423 - locked translation
66
+ if (error instanceof TranslationLockedError) {
67
+ logger.debug(`Translation locked (423): ${request.cleanKey}`);
68
+ return this.handleTranslationLocked(request, fallbackValue, error, startTime, networkBus);
69
+ }
70
+ // Handle other errors (server errors, network errors)
71
+ logger.debug(`Network error: ${request.cleanKey}`, error);
72
+ networkBus.error(error);
73
+ return this.createTranslationResult(fallbackValue, 'fallback', 0, startTime, error);
74
+ }
75
+ }
76
+ /**
77
+ * Strategy 2: Namespace fallback when individual key not found
78
+ */
79
+ async lookupFromNamespace(request, fallbackValue, startTime,
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ networkBus) {
82
+ try {
83
+ const namespaceResult = await this.loadNamespace(request.locale, request.namespace);
84
+ if (namespaceResult && namespaceResult.data) {
85
+ const nestedValue = resolveNestedKey(namespaceResult.data, request.cleanKey);
86
+ if (nestedValue !== undefined && nestedValue !== null) {
87
+ // Handle both ContentUnit format and plain strings
88
+ let resolvedValue;
89
+ let styles = {};
90
+ if (typeof nestedValue === 'object' && nestedValue !== null && 'text' in nestedValue) {
91
+ // ContentUnit format: { text, styles }
92
+ const contentUnit = nestedValue;
93
+ resolvedValue = String(contentUnit.text);
94
+ styles = contentUnit.styles || {};
95
+ }
96
+ else {
97
+ // Plain string
98
+ resolvedValue = String(nestedValue);
99
+ }
100
+ logger.debug(`Network namespace hit: ${request.cleanKey}, hasStyles=${Object.keys(styles).length > 0}`);
101
+ networkBus.success(resolvedValue);
102
+ return this.createTranslationResult(resolvedValue, 'network', 200, startTime, undefined, false, {
103
+ locale: request.locale,
104
+ namespace: request.namespace,
105
+ data: namespaceResult.data,
106
+ }, styles);
107
+ }
108
+ }
109
+ // Key not found in namespace either
110
+ const error = new TranslationNotFoundError(request.cleanKey);
111
+ return this.handleTranslationNotFound(request, fallbackValue, error, startTime);
112
+ }
113
+ catch (nsError) {
114
+ // Namespace load failed
115
+ logger.debug(`Namespace load failed: ${request.cleanKey}`, nsError);
116
+ if (nsError instanceof TranslationNotFoundError) {
117
+ return this.handleTranslationNotFound(request, fallbackValue, nsError, startTime);
118
+ }
119
+ if (nsError instanceof TranslationLockedError) {
120
+ return this.handleTranslationLocked(request, fallbackValue, nsError, startTime, networkBus);
121
+ }
122
+ networkBus.error(nsError);
123
+ return this.createTranslationResult(fallbackValue, 'fallback', 0, startTime, nsError);
124
+ }
125
+ }
126
+ /**
127
+ * ✅ Load entire namespace (used for preloading)
128
+ * Returns NamespaceResult with status and error information
129
+ */
130
+ async loadNamespace(locale, namespace) {
131
+ const startTime = Date.now();
132
+ if (!this.enabled) {
133
+ return this.createNamespaceResult(null, 'fallback', 0, startTime);
134
+ }
135
+ try {
136
+ const data = await this.loadNamespaceWithRetry(locale, namespace);
137
+ // 304 Not Modified — cached translations are still fresh
138
+ if (data === null) {
139
+ logger.debug(`Network namespace not modified: ${locale}:${namespace}`);
140
+ return this.createNamespaceResult(null, 'network', 304, startTime);
141
+ }
142
+ logger.debug(`Network namespace loaded: ${locale}:${namespace}`);
143
+ return this.createNamespaceResult(data, 'network', 200, startTime);
144
+ }
145
+ catch (error) {
146
+ if (error instanceof TranslationLockedError) {
147
+ logger.debug(`Namespace locked (423): ${locale}:${namespace}`);
148
+ return this.createNamespaceResult(null, 'fallback', 423, startTime, error);
149
+ }
150
+ if (error instanceof TranslationNotFoundError) {
151
+ logger.debug(`Network namespace not found: ${locale}:${namespace}`);
152
+ return this.createNamespaceResult(null, 'fallback', 404, startTime, error);
153
+ }
154
+ logger.debug(`Network namespace error: ${locale}:${namespace}`, error);
155
+ return this.createNamespaceResult(null, 'fallback', 0, startTime, error);
156
+ }
157
+ }
158
+ /**
159
+ * ✅ Namespace lookup with retry logic
160
+ * Throws custom errors (TranslationNotFoundError, TranslationLockedError, etc.)
161
+ */
162
+ async loadNamespaceWithRetry(locale, namespace) {
163
+ return this.withRetry(() => this.repository.getNamespace(locale, namespace), `${locale}:${namespace}`, 'namespace request');
164
+ }
165
+ /**
166
+ * Simple save implementation (API usually doesn't save)
167
+ */
168
+ async save(request, result) {
169
+ // APIs usually don't save translations, but we could implement PUT if needed
170
+ void request;
171
+ void result;
172
+ }
173
+ /**
174
+ * ✅ Lookup with retry logic for individual keys
175
+ * Throws custom errors (TranslationNotFoundError, TranslationLockedError, etc.)
176
+ */
177
+ async lookupWithRetry(cacheKey) {
178
+ return this.withRetry(() => this.repository.get(cacheKey), cacheKey, 'network request');
179
+ }
180
+ /**
181
+ * ✅ Lookup ContentUnit with retry logic for individual keys
182
+ * Returns full ContentUnit with text and styles
183
+ * Throws custom errors (TranslationNotFoundError, TranslationLockedError, etc.)
184
+ */
185
+ async lookupContentUnitWithRetry(cacheKey) {
186
+ // Check if repository supports getContentUnit (NetworkRepository does)
187
+ const repo = this.repository;
188
+ if (typeof repo.getContentUnit !== 'function') {
189
+ // Fallback: use get() and wrap in ContentUnit
190
+ const text = await this.lookupWithRetry(cacheKey);
191
+ return { text, styles: {} };
192
+ }
193
+ return this.withRetry(() => repo.getContentUnit(cacheKey), cacheKey, 'network content unit request');
194
+ }
195
+ /**
196
+ * Delay utility for retries
197
+ */
198
+ delay(ms) {
199
+ return new Promise(resolve => setTimeout(resolve, ms));
200
+ }
201
+ calculateBackoff(attempt) {
202
+ const baseDelay = this.retryDelay;
203
+ const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
204
+ const maxDelay = 10000; // 10 seconds max
205
+ // Add jitter to prevent thundering herd
206
+ const jitter = Math.random() * 0.1 * exponentialDelay;
207
+ return Math.min(exponentialDelay + jitter, maxDelay);
208
+ }
209
+ /**
210
+ * Generic retry wrapper for repository operations
211
+ * Handles retryable errors with exponential backoff
212
+ */
213
+ async withRetry(operation, contextKey, contextDescription, attempt = 1) {
214
+ const networkBus = this.bus.network(contextKey, 'withRetry');
215
+ try {
216
+ return await operation();
217
+ }
218
+ catch (error) {
219
+ // Retry only on retryable errors (5xx, network errors)
220
+ if (attempt <= this.retryCount && isRetryableError(error)) {
221
+ const delay = this.calculateBackoff(attempt);
222
+ networkBus.retry(attempt, delay, error.message);
223
+ await this.delay(delay);
224
+ logger.debug(`Retrying ${contextDescription} (${attempt}/${this.retryCount}) after ${delay}ms`);
225
+ return this.withRetry(operation, contextKey, contextDescription, attempt + 1);
226
+ }
227
+ // Don't retry client errors (404, 423)
228
+ throw error;
229
+ }
230
+ }
231
+ /**
232
+ * Handle translation not found (after namespace fallback also failed)
233
+ */
234
+ handleTranslationNotFound(request, fallbackValue, error, startTime) {
235
+ logger.debug(`Network namespace miss: ${request.cleanKey}`);
236
+ const translateBus = this.bus.translation(request);
237
+ translateBus.notFound(fallbackValue, request.locale, request.namespace || 'default');
238
+ return this.createTranslationResult(fallbackValue, 'fallback', 404, startTime, error);
239
+ }
240
+ /**
241
+ * Handle TranslationLockedError for translation lookups
242
+ */
243
+ handleTranslationLocked(request, fallbackValue, error, startTime,
244
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
+ networkBus) {
246
+ const translateBus = this.bus.translation(request);
247
+ translateBus.locked(fallbackValue, request.locale, request.namespace || 'default');
248
+ networkBus.error(error, 423);
249
+ return this.createTranslationResult(fallbackValue, 'fallback', 423, startTime, error);
250
+ }
251
+ /**
252
+ * Helper to create consistent TranslationResult objects
253
+ */
254
+ createTranslationResult(value, source, status, startTime, error, cached, namespaceLoaded, styles) {
255
+ return {
256
+ value,
257
+ source,
258
+ status,
259
+ duration: Date.now() - startTime,
260
+ ...(error && { error }),
261
+ ...(cached !== undefined && { cached }),
262
+ ...(namespaceLoaded && { namespaceLoaded }),
263
+ ...(styles && Object.keys(styles).length > 0 && { styles }),
264
+ };
265
+ }
266
+ /**
267
+ * Helper to create consistent NamespaceResult objects
268
+ */
269
+ createNamespaceResult(data, source, status, startTime, error) {
270
+ return {
271
+ data,
272
+ source,
273
+ status,
274
+ duration: Date.now() - startTime,
275
+ ...(error && { error }),
276
+ };
277
+ }
278
+ getPreload() {
279
+ const config = this.repository.getConfig();
280
+ return config.options?.preloadNamespaces || [];
281
+ }
282
+ }
283
+ //# sourceMappingURL=network-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-handler.js","sourceRoot":"","sources":["../../src/handlers/network-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Simplified memory cache handler
3
+ */
4
+ import { EventEmitter } from '../base/event-emitter.js';
5
+ import { ISyncHandler } from '../interfaces/handler.interface.js';
6
+ import { IStatsProvider, ISyncRepository } from '../interfaces/repository.interface.js';
7
+ import type { TranslationData } from '../types/translation-data.types.js';
8
+ import type { TranslationContext, TranslationRequest, TranslationResult } from '../types/translation.types.js';
9
+ /**
10
+ * Simple memory cache handler
11
+ */
12
+ export declare class SyncHandler implements ISyncHandler {
13
+ readonly name: string;
14
+ readonly version = "1.0.0";
15
+ readonly priority: number;
16
+ readonly type: "memory";
17
+ readonly enabled: boolean;
18
+ private ttlMap;
19
+ private ttl;
20
+ private repository;
21
+ private bus;
22
+ constructor(eventEmitter: EventEmitter, repository: ISyncRepository & IStatsProvider);
23
+ getSourceType(): 'memory' | 'storage' | 'network' | 'fallback';
24
+ /**
25
+ * Simple lookup implementation
26
+ * Returns ContentUnit with both text and styles
27
+ */
28
+ lookup(request: TranslationRequest): TranslationResult;
29
+ /**
30
+ * Simple save implementation
31
+ * Stores ContentUnit (text + styles) as JSON
32
+ */
33
+ save(request: TranslationRequest, result: TranslationResult): void;
34
+ /**
35
+ * Namespace saving implementation
36
+ */
37
+ saveNamespace(translations: TranslationData, context: TranslationContext): void;
38
+ /**
39
+ * ✅ Strategy 1: Direct cache lookup using unified pattern
40
+ * Returns parsed ContentUnit (text + styles) or null
41
+ */
42
+ private tryDirectLookup;
43
+ /**
44
+ * ✅ Strategy 2: Namespace lookup using unified pattern
45
+ * Returns parsed ContentUnit (text + styles) or null
46
+ */
47
+ private tryNamespaceLookup;
48
+ /**
49
+ * Helper to create consistent TranslationResult objects
50
+ * Now includes styles from ContentUnit
51
+ */
52
+ private createResult;
53
+ /**
54
+ * Check TTL and expire if needed
55
+ * Returns true if expired, false if still valid
56
+ */
57
+ private checkAndExpireTTL;
58
+ /**
59
+ * Set value in repository and update TTL
60
+ */
61
+ private setWithTTL;
62
+ /**
63
+ * Refresh TTL on access
64
+ */
65
+ private refreshTTL;
66
+ /**
67
+ * Get TTL information for debugging
68
+ */
69
+ getTTLInfo(): Record<string, {
70
+ timestamp: number;
71
+ age: number;
72
+ remaining: number;
73
+ }>;
74
+ getEntries(): Record<string, string> | undefined;
75
+ /**
76
+ * Clear all entries for a specific namespace
77
+ * Removes namespace cache entry, individual keys, and TTL entries
78
+ */
79
+ clearNamespace(locale: string, namespace: string): void;
80
+ destroy(): void;
81
+ /**
82
+ * Direct cache set (for optimistic updates)
83
+ * Bypasses event emission for direct cache manipulation
84
+ * Stores as ContentUnit JSON (text + styles)
85
+ */
86
+ setCache(key: string, value: string, styles?: Record<string, string[]>): void;
87
+ }
88
+ //# sourceMappingURL=sync-storage-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-storage-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/sync-storage-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EACL,cAAc,EACd,eAAe,EAChB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,+BAA+B,CAAC;AAgBvC;;GAEG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,WAAW;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,WAAqB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,GAAG,CAAe;gBAGxB,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,eAAe,GAAG,cAAc;IAW9C,aAAa,IAAI,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU;IAI9D;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB;IAyCtD;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAelE;;OAEG;IACH,aAAa,CACX,YAAY,EAAE,eAAe,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,IAAI;IA4BP;;;OAGG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAuD1B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiBpB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,UAAU,IAAI,MAAM,CAClB,MAAM,EACN;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CACtD;IAgBD,UAAU;IAMV;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAsBvD,OAAO,IAAI,IAAI;IAKf;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;CAQ9E"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Simplified memory cache handler
3
+ */
4
+ import { logger } from '../utils/index.js';
5
+ import { createNamespaceCacheKey, flattenTranslations, resolveNestedKey, } from '../utils/translation-value-utils.js';
6
+ /**
7
+ * Simple memory cache handler
8
+ */
9
+ export class SyncHandler {
10
+ name;
11
+ version = '1.0.0';
12
+ priority;
13
+ type = 'memory';
14
+ enabled;
15
+ ttlMap = new Map();
16
+ ttl;
17
+ repository;
18
+ bus;
19
+ constructor(eventEmitter, repository) {
20
+ this.bus = eventEmitter;
21
+ this.repository = repository;
22
+ this.name = repository.name;
23
+ const config = repository.getConfig();
24
+ this.enabled = config.enabled ?? true;
25
+ this.priority = config.priority ?? 0;
26
+ this.ttl = config.options?.ttl ?? 30 * 60 * 1000; // Default 30 minutes
27
+ }
28
+ getSourceType() {
29
+ return 'memory';
30
+ }
31
+ /**
32
+ * Simple lookup implementation
33
+ * Returns ContentUnit with both text and styles
34
+ */
35
+ lookup(request) {
36
+ const startTime = Date.now();
37
+ logger.debug(`Sync lookup: ${request.cleanKey}`);
38
+ const repoBus = this.bus.repo(request, this.name);
39
+ repoBus.getStart();
40
+ const directResult = this.tryDirectLookup(request);
41
+ if (directResult !== null) {
42
+ logger.debug(`Cache hit: ${request.cleanKey}`);
43
+ repoBus.getSuccess(directResult.text);
44
+ return this.createResult(directResult, 'memory', 200, startTime, true);
45
+ }
46
+ // Try namespace lookup for nested keys
47
+ if (request.cleanKey.includes('.') && request.namespace) {
48
+ const namespaceResult = this.tryNamespaceLookup(request);
49
+ if (namespaceResult !== null) {
50
+ logger.debug(`Namespace hit: ${request.cleanKey}`);
51
+ repoBus.getSuccess(namespaceResult.text);
52
+ return this.createResult(namespaceResult, 'memory', 200, startTime, true);
53
+ }
54
+ }
55
+ logger.debug(`Cache miss: ${request.cleanKey}`);
56
+ repoBus.getMiss();
57
+ // Return fallback result (no styles for fallback)
58
+ return this.createResult({ text: request.parsedDefaultValue || request.cleanKey, styles: {} }, 'fallback', 404, startTime);
59
+ }
60
+ /**
61
+ * Simple save implementation
62
+ * Stores ContentUnit (text + styles) as JSON
63
+ */
64
+ save(request, result) {
65
+ if (!result.value)
66
+ return;
67
+ const repoBus = this.bus.repo(request, this.name);
68
+ // Store as ContentUnit JSON (text + styles together)
69
+ const contentUnit = {
70
+ text: result.value,
71
+ styles: result.styles || {},
72
+ };
73
+ this.setWithTTL(request.individualCacheKey, JSON.stringify(contentUnit));
74
+ logger.debug(`Saved to cache: ${request.cleanKey}`);
75
+ repoBus.setSuccess(result.value);
76
+ }
77
+ /**
78
+ * Namespace saving implementation
79
+ */
80
+ saveNamespace(translations, context) {
81
+ if (!context.namespace)
82
+ return;
83
+ const repoBus = this.bus.repo(context.locale + ':' + context.namespace, this.name);
84
+ // Store full namespace: @locale:namespace
85
+ const namespaceCacheKey = createNamespaceCacheKey(context.locale, context.namespace);
86
+ this.setWithTTL(namespaceCacheKey, JSON.stringify(translations));
87
+ // Store flattened individual keys: locale:namespace:key
88
+ const flattened = flattenTranslations(translations, '', context.locale, context.namespace);
89
+ for (const [flatKey, flatValue] of Object.entries(flattened)) {
90
+ this.setWithTTL(flatKey, flatValue);
91
+ }
92
+ repoBus.setSuccess(JSON.stringify(translations));
93
+ }
94
+ /**
95
+ * ✅ Strategy 1: Direct cache lookup using unified pattern
96
+ * Returns parsed ContentUnit (text + styles) or null
97
+ */
98
+ tryDirectLookup(request) {
99
+ // Check TTL and expire if needed
100
+ if (this.checkAndExpireTTL(request.individualCacheKey)) {
101
+ return null;
102
+ }
103
+ const cachedValue = this.repository.get(request.individualCacheKey);
104
+ if (!cachedValue)
105
+ return null;
106
+ this.refreshTTL(request.individualCacheKey); // Refresh TTL on access
107
+ // Parse cached ContentUnit JSON
108
+ try {
109
+ const parsed = JSON.parse(cachedValue);
110
+ if (typeof parsed === 'object' && 'text' in parsed) {
111
+ return {
112
+ text: String(parsed.text),
113
+ styles: parsed.styles || {},
114
+ };
115
+ }
116
+ // Legacy format: plain string (shouldn't happen with new data)
117
+ return { text: cachedValue, styles: {} };
118
+ }
119
+ catch {
120
+ // If parse fails, treat as legacy plain string
121
+ return { text: cachedValue, styles: {} };
122
+ }
123
+ }
124
+ /**
125
+ * ✅ Strategy 2: Namespace lookup using unified pattern
126
+ * Returns parsed ContentUnit (text + styles) or null
127
+ */
128
+ tryNamespaceLookup(request) {
129
+ if (!request.namespace)
130
+ return null;
131
+ const namespaceCacheKey = createNamespaceCacheKey(request.locale, request.namespace);
132
+ // Check TTL for namespace
133
+ if (this.checkAndExpireTTL(namespaceCacheKey)) {
134
+ return null;
135
+ }
136
+ const namespaceData = this.repository.get(namespaceCacheKey);
137
+ if (!namespaceData)
138
+ return null;
139
+ this.refreshTTL(namespaceCacheKey); // Refresh TTL on access
140
+ try {
141
+ const translations = JSON.parse(namespaceData);
142
+ const value = resolveNestedKey(translations, request.cleanKey);
143
+ if (value !== null && value !== undefined) {
144
+ // Extract ContentUnit from namespace data
145
+ let contentUnit;
146
+ if (typeof value === 'object' && value !== null && 'text' in value) {
147
+ // Server ContentUnit format: { text, styles }
148
+ contentUnit = {
149
+ text: String(value.text),
150
+ styles: value.styles || {},
151
+ };
152
+ }
153
+ else {
154
+ // Plain string fallback
155
+ contentUnit = { text: String(value), styles: {} };
156
+ }
157
+ // Cache the individual key for faster future access (as JSON)
158
+ this.setWithTTL(request.individualCacheKey, JSON.stringify(contentUnit));
159
+ logger.debug(`Cached from namespace: ${request.cleanKey}`);
160
+ return contentUnit;
161
+ }
162
+ }
163
+ catch (error) {
164
+ // Invalid JSON in namespace cache
165
+ logger.debug(`Invalid JSON in namespace cache: ${namespaceCacheKey}`, error);
166
+ this.repository.remove(namespaceCacheKey);
167
+ this.ttlMap.delete(namespaceCacheKey);
168
+ }
169
+ return null;
170
+ }
171
+ /**
172
+ * Helper to create consistent TranslationResult objects
173
+ * Now includes styles from ContentUnit
174
+ */
175
+ createResult(contentUnit, source, status, startTime, cached) {
176
+ return {
177
+ value: contentUnit.text,
178
+ styles: contentUnit.styles,
179
+ source,
180
+ status,
181
+ duration: Date.now() - startTime,
182
+ ...(cached !== undefined && { cached }),
183
+ };
184
+ }
185
+ /**
186
+ * Check TTL and expire if needed
187
+ * Returns true if expired, false if still valid
188
+ */
189
+ checkAndExpireTTL(cacheKey) {
190
+ const timestamp = this.ttlMap.get(cacheKey);
191
+ if (timestamp && Date.now() - timestamp > this.ttl) {
192
+ this.repository.remove(cacheKey);
193
+ this.ttlMap.delete(cacheKey);
194
+ logger.debug(`TTL expired: ${cacheKey}`);
195
+ return true;
196
+ }
197
+ return false;
198
+ }
199
+ /**
200
+ * Set value in repository and update TTL
201
+ */
202
+ setWithTTL(cacheKey, value) {
203
+ this.repository.set(cacheKey, value);
204
+ this.ttlMap.set(cacheKey, Date.now());
205
+ }
206
+ /**
207
+ * Refresh TTL on access
208
+ */
209
+ refreshTTL(cacheKey) {
210
+ this.ttlMap.set(cacheKey, Date.now());
211
+ }
212
+ /**
213
+ * Get TTL information for debugging
214
+ */
215
+ getTTLInfo() {
216
+ const ttlInfo = {};
217
+ const now = Date.now();
218
+ for (const [key, timestamp] of this.ttlMap.entries()) {
219
+ const age = now - timestamp;
220
+ const remaining = Math.max(0, this.ttl - age);
221
+ ttlInfo[key] = { timestamp, age, remaining };
222
+ }
223
+ return ttlInfo;
224
+ }
225
+ getEntries() {
226
+ if (this.repository.getEntries !== undefined) {
227
+ return this.repository.getEntries();
228
+ }
229
+ }
230
+ /**
231
+ * Clear all entries for a specific namespace
232
+ * Removes namespace cache entry, individual keys, and TTL entries
233
+ */
234
+ clearNamespace(locale, namespace) {
235
+ const namespaceCacheKey = createNamespaceCacheKey(locale, namespace);
236
+ const keyPrefix = `${locale}:${namespace}:`;
237
+ // Remove namespace cache entry
238
+ this.repository.remove(namespaceCacheKey);
239
+ this.ttlMap.delete(namespaceCacheKey);
240
+ // Remove individual translation keys and their TTL entries
241
+ const entries = this.repository.getEntries?.();
242
+ if (entries) {
243
+ for (const key of Object.keys(entries)) {
244
+ if (key.startsWith(keyPrefix)) {
245
+ this.repository.remove(key);
246
+ this.ttlMap.delete(key);
247
+ }
248
+ }
249
+ }
250
+ logger.debug(`Cleared namespace: ${locale}:${namespace}`);
251
+ }
252
+ destroy() {
253
+ this.repository.clear();
254
+ this.ttlMap.clear();
255
+ }
256
+ /**
257
+ * Direct cache set (for optimistic updates)
258
+ * Bypasses event emission for direct cache manipulation
259
+ * Stores as ContentUnit JSON (text + styles)
260
+ */
261
+ setCache(key, value, styles) {
262
+ const contentUnit = {
263
+ text: value,
264
+ styles: styles || {},
265
+ };
266
+ this.setWithTTL(key, JSON.stringify(contentUnit));
267
+ logger.debug(`Direct cache set: ${key}`);
268
+ }
269
+ }
270
+ //# sourceMappingURL=sync-storage-handler.js.map