@intlayer/cli 8.1.1 → 8.1.3-canary.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 (304) hide show
  1. package/dist/cjs/IntlayerEventListener.cjs +1 -186
  2. package/dist/cjs/IntlayerEventListener.cjs.map +1 -1
  3. package/dist/cjs/_virtual/_rolldown/runtime.cjs +1 -29
  4. package/dist/cjs/_virtual/_utils_asset.cjs +2 -98
  5. package/dist/cjs/auth/login.cjs +2 -85
  6. package/dist/cjs/auth/login.cjs.map +1 -1
  7. package/dist/cjs/build.cjs +1 -27
  8. package/dist/cjs/build.cjs.map +1 -1
  9. package/dist/cjs/ci.cjs +1 -73
  10. package/dist/cjs/ci.cjs.map +1 -1
  11. package/dist/cjs/cli.cjs +1 -476
  12. package/dist/cjs/cli.cjs.map +1 -1
  13. package/dist/cjs/config.cjs +1 -12
  14. package/dist/cjs/config.cjs.map +1 -1
  15. package/dist/cjs/editor.cjs +1 -50
  16. package/dist/cjs/editor.cjs.map +1 -1
  17. package/dist/cjs/extract.cjs +1 -96
  18. package/dist/cjs/extract.cjs.map +1 -1
  19. package/dist/cjs/fill/deepMergeContent.cjs +1 -27
  20. package/dist/cjs/fill/deepMergeContent.cjs.map +1 -1
  21. package/dist/cjs/fill/fill.cjs +1 -78
  22. package/dist/cjs/fill/fill.cjs.map +1 -1
  23. package/dist/cjs/fill/formatAutoFilledFilePath.cjs +1 -29
  24. package/dist/cjs/fill/formatAutoFilledFilePath.cjs.map +1 -1
  25. package/dist/cjs/fill/formatFillData.cjs +1 -50
  26. package/dist/cjs/fill/formatFillData.cjs.map +1 -1
  27. package/dist/cjs/fill/getAvailableLocalesInDictionary.cjs +1 -26
  28. package/dist/cjs/fill/getAvailableLocalesInDictionary.cjs.map +1 -1
  29. package/dist/cjs/fill/getFilterMissingContentPerLocale.cjs +1 -50
  30. package/dist/cjs/fill/getFilterMissingContentPerLocale.cjs.map +1 -1
  31. package/dist/cjs/fill/index.cjs +1 -6
  32. package/dist/cjs/fill/listTranslationsTasks.cjs +1 -70
  33. package/dist/cjs/fill/listTranslationsTasks.cjs.map +1 -1
  34. package/dist/cjs/fill/mergeChunks.cjs +1 -28
  35. package/dist/cjs/fill/mergeChunks.cjs.map +1 -1
  36. package/dist/cjs/fill/translateDictionary.cjs +1 -205
  37. package/dist/cjs/fill/translateDictionary.cjs.map +1 -1
  38. package/dist/cjs/fill/writeFill.cjs +1 -54
  39. package/dist/cjs/fill/writeFill.cjs.map +1 -1
  40. package/dist/cjs/getTargetDictionary.cjs +1 -36
  41. package/dist/cjs/getTargetDictionary.cjs.map +1 -1
  42. package/dist/cjs/index.cjs +1 -39
  43. package/dist/cjs/init.cjs +1 -322
  44. package/dist/cjs/init.cjs.map +1 -1
  45. package/dist/cjs/listContentDeclaration.cjs +1 -41
  46. package/dist/cjs/listContentDeclaration.cjs.map +1 -1
  47. package/dist/cjs/listProjects.cjs +1 -28
  48. package/dist/cjs/listProjects.cjs.map +1 -1
  49. package/dist/cjs/liveSync.cjs +8 -151
  50. package/dist/cjs/liveSync.cjs.map +1 -1
  51. package/dist/cjs/pull.cjs +1 -146
  52. package/dist/cjs/pull.cjs.map +1 -1
  53. package/dist/cjs/push/pullLog.cjs +3 -102
  54. package/dist/cjs/push/pullLog.cjs.map +1 -1
  55. package/dist/cjs/push/push.cjs +1 -206
  56. package/dist/cjs/push/push.cjs.map +1 -1
  57. package/dist/cjs/pushConfig.cjs +1 -19
  58. package/dist/cjs/pushConfig.cjs.map +1 -1
  59. package/dist/cjs/pushLog.cjs +3 -84
  60. package/dist/cjs/pushLog.cjs.map +1 -1
  61. package/dist/cjs/reviewDoc/reviewDoc.cjs +1 -68
  62. package/dist/cjs/reviewDoc/reviewDoc.cjs.map +1 -1
  63. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs +1 -94
  64. package/dist/cjs/reviewDoc/reviewDocBlockAware.cjs.map +1 -1
  65. package/dist/cjs/searchDoc.cjs +1 -38
  66. package/dist/cjs/searchDoc.cjs.map +1 -1
  67. package/dist/cjs/test/index.cjs +1 -7
  68. package/dist/cjs/test/listMissingTranslations.cjs +1 -49
  69. package/dist/cjs/test/listMissingTranslations.cjs.map +1 -1
  70. package/dist/cjs/test/test.cjs +1 -51
  71. package/dist/cjs/test/test.cjs.map +1 -1
  72. package/dist/cjs/translateDoc/index.cjs +1 -9
  73. package/dist/cjs/translateDoc/translateDoc.cjs +1 -74
  74. package/dist/cjs/translateDoc/translateDoc.cjs.map +1 -1
  75. package/dist/cjs/translateDoc/translateFile.cjs +2 -103
  76. package/dist/cjs/translateDoc/translateFile.cjs.map +1 -1
  77. package/dist/cjs/translateDoc/validation.cjs +5 -49
  78. package/dist/cjs/translateDoc/validation.cjs.map +1 -1
  79. package/dist/cjs/translation-alignment/alignBlocks.cjs +1 -67
  80. package/dist/cjs/translation-alignment/alignBlocks.cjs.map +1 -1
  81. package/dist/cjs/translation-alignment/computeSimilarity.cjs +1 -25
  82. package/dist/cjs/translation-alignment/computeSimilarity.cjs.map +1 -1
  83. package/dist/cjs/translation-alignment/fingerprintBlock.cjs +1 -23
  84. package/dist/cjs/translation-alignment/fingerprintBlock.cjs.map +1 -1
  85. package/dist/cjs/translation-alignment/index.cjs +1 -22
  86. package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs +1 -18
  87. package/dist/cjs/translation-alignment/mapChangedLinesToBlocks.cjs.map +1 -1
  88. package/dist/cjs/translation-alignment/normalizeBlock.cjs +1 -22
  89. package/dist/cjs/translation-alignment/normalizeBlock.cjs.map +1 -1
  90. package/dist/cjs/translation-alignment/pipeline.cjs +1 -37
  91. package/dist/cjs/translation-alignment/pipeline.cjs.map +1 -1
  92. package/dist/cjs/translation-alignment/planActions.cjs +1 -46
  93. package/dist/cjs/translation-alignment/planActions.cjs.map +1 -1
  94. package/dist/cjs/translation-alignment/rebuildDocument.cjs +2 -49
  95. package/dist/cjs/translation-alignment/rebuildDocument.cjs.map +1 -1
  96. package/dist/cjs/translation-alignment/segmentDocument.cjs +5 -66
  97. package/dist/cjs/translation-alignment/segmentDocument.cjs.map +1 -1
  98. package/dist/cjs/utils/calculateChunks.cjs +2 -89
  99. package/dist/cjs/utils/calculateChunks.cjs.map +1 -1
  100. package/dist/cjs/utils/checkAccess.cjs +1 -81
  101. package/dist/cjs/utils/checkAccess.cjs.map +1 -1
  102. package/dist/cjs/utils/checkConfigConsistency.cjs +1 -16
  103. package/dist/cjs/utils/checkConfigConsistency.cjs.map +1 -1
  104. package/dist/cjs/utils/checkFileModifiedRange.cjs +1 -81
  105. package/dist/cjs/utils/checkFileModifiedRange.cjs.map +1 -1
  106. package/dist/cjs/utils/checkLastUpdateTime.cjs +1 -19
  107. package/dist/cjs/utils/checkLastUpdateTime.cjs.map +1 -1
  108. package/dist/cjs/utils/chunkInference.cjs +1 -45
  109. package/dist/cjs/utils/chunkInference.cjs.map +1 -1
  110. package/dist/cjs/utils/fixChunkStartEndChars.cjs +3 -27
  111. package/dist/cjs/utils/fixChunkStartEndChars.cjs.map +1 -1
  112. package/dist/cjs/utils/formatTimeDiff.cjs +1 -20
  113. package/dist/cjs/utils/formatTimeDiff.cjs.map +1 -1
  114. package/dist/cjs/utils/getIsFileUpdatedRecently.cjs +1 -16
  115. package/dist/cjs/utils/getIsFileUpdatedRecently.cjs.map +1 -1
  116. package/dist/cjs/utils/getOutputFilePath.cjs +1 -74
  117. package/dist/cjs/utils/getOutputFilePath.cjs.map +1 -1
  118. package/dist/cjs/utils/getParentPackageJSON.cjs +1 -20
  119. package/dist/cjs/utils/getParentPackageJSON.cjs.map +1 -1
  120. package/dist/cjs/utils/listSpecialChars.cjs +2 -54
  121. package/dist/cjs/utils/listSpecialChars.cjs.map +1 -1
  122. package/dist/cjs/utils/mapChunksBetweenFiles.cjs +1 -102
  123. package/dist/cjs/utils/mapChunksBetweenFiles.cjs.map +1 -1
  124. package/dist/cjs/utils/openBrowser.cjs +1 -19
  125. package/dist/cjs/utils/openBrowser.cjs.map +1 -1
  126. package/dist/cjs/utils/reorderParagraphs.cjs +3 -91
  127. package/dist/cjs/utils/reorderParagraphs.cjs.map +1 -1
  128. package/dist/cjs/utils/setupAI.cjs +1 -64
  129. package/dist/cjs/utils/setupAI.cjs.map +1 -1
  130. package/dist/cjs/watch.cjs +1 -43
  131. package/dist/cjs/watch.cjs.map +1 -1
  132. package/dist/esm/IntlayerEventListener.mjs +1 -183
  133. package/dist/esm/IntlayerEventListener.mjs.map +1 -1
  134. package/dist/esm/_virtual/_rolldown/runtime.mjs +1 -8
  135. package/dist/esm/_virtual/_utils_asset.mjs +2 -97
  136. package/dist/esm/auth/login.mjs +2 -82
  137. package/dist/esm/auth/login.mjs.map +1 -1
  138. package/dist/esm/build.mjs +1 -25
  139. package/dist/esm/build.mjs.map +1 -1
  140. package/dist/esm/ci.mjs +1 -71
  141. package/dist/esm/ci.mjs.map +1 -1
  142. package/dist/esm/cli.mjs +1 -473
  143. package/dist/esm/cli.mjs.map +1 -1
  144. package/dist/esm/config.mjs +1 -10
  145. package/dist/esm/config.mjs.map +1 -1
  146. package/dist/esm/editor.mjs +1 -49
  147. package/dist/esm/editor.mjs.map +1 -1
  148. package/dist/esm/extract.mjs +1 -93
  149. package/dist/esm/extract.mjs.map +1 -1
  150. package/dist/esm/fill/deepMergeContent.mjs +1 -25
  151. package/dist/esm/fill/deepMergeContent.mjs.map +1 -1
  152. package/dist/esm/fill/fill.mjs +1 -76
  153. package/dist/esm/fill/fill.mjs.map +1 -1
  154. package/dist/esm/fill/formatAutoFilledFilePath.mjs +1 -27
  155. package/dist/esm/fill/formatAutoFilledFilePath.mjs.map +1 -1
  156. package/dist/esm/fill/formatFillData.mjs +1 -49
  157. package/dist/esm/fill/formatFillData.mjs.map +1 -1
  158. package/dist/esm/fill/getAvailableLocalesInDictionary.mjs +1 -24
  159. package/dist/esm/fill/getAvailableLocalesInDictionary.mjs.map +1 -1
  160. package/dist/esm/fill/getFilterMissingContentPerLocale.mjs +1 -48
  161. package/dist/esm/fill/getFilterMissingContentPerLocale.mjs.map +1 -1
  162. package/dist/esm/fill/index.mjs +1 -4
  163. package/dist/esm/fill/listTranslationsTasks.mjs +1 -68
  164. package/dist/esm/fill/listTranslationsTasks.mjs.map +1 -1
  165. package/dist/esm/fill/mergeChunks.mjs +1 -26
  166. package/dist/esm/fill/mergeChunks.mjs.map +1 -1
  167. package/dist/esm/fill/translateDictionary.mjs +1 -203
  168. package/dist/esm/fill/translateDictionary.mjs.map +1 -1
  169. package/dist/esm/fill/writeFill.mjs +1 -52
  170. package/dist/esm/fill/writeFill.mjs.map +1 -1
  171. package/dist/esm/getTargetDictionary.mjs +1 -33
  172. package/dist/esm/getTargetDictionary.mjs.map +1 -1
  173. package/dist/esm/index.mjs +1 -18
  174. package/dist/esm/init.mjs +1 -317
  175. package/dist/esm/init.mjs.map +1 -1
  176. package/dist/esm/listContentDeclaration.mjs +1 -38
  177. package/dist/esm/listContentDeclaration.mjs.map +1 -1
  178. package/dist/esm/listProjects.mjs +1 -26
  179. package/dist/esm/listProjects.mjs.map +1 -1
  180. package/dist/esm/liveSync.mjs +8 -148
  181. package/dist/esm/liveSync.mjs.map +1 -1
  182. package/dist/esm/pull.mjs +1 -144
  183. package/dist/esm/pull.mjs.map +1 -1
  184. package/dist/esm/push/pullLog.mjs +3 -100
  185. package/dist/esm/push/pullLog.mjs.map +1 -1
  186. package/dist/esm/push/push.mjs +1 -203
  187. package/dist/esm/push/push.mjs.map +1 -1
  188. package/dist/esm/pushConfig.mjs +1 -17
  189. package/dist/esm/pushConfig.mjs.map +1 -1
  190. package/dist/esm/pushLog.mjs +3 -82
  191. package/dist/esm/pushLog.mjs.map +1 -1
  192. package/dist/esm/reviewDoc/reviewDoc.mjs +1 -65
  193. package/dist/esm/reviewDoc/reviewDoc.mjs.map +1 -1
  194. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs +1 -92
  195. package/dist/esm/reviewDoc/reviewDocBlockAware.mjs.map +1 -1
  196. package/dist/esm/searchDoc.mjs +1 -36
  197. package/dist/esm/searchDoc.mjs.map +1 -1
  198. package/dist/esm/test/index.mjs +1 -4
  199. package/dist/esm/test/listMissingTranslations.mjs +1 -46
  200. package/dist/esm/test/listMissingTranslations.mjs.map +1 -1
  201. package/dist/esm/test/test.mjs +1 -49
  202. package/dist/esm/test/test.mjs.map +1 -1
  203. package/dist/esm/translateDoc/index.mjs +1 -5
  204. package/dist/esm/translateDoc/translateDoc.mjs +1 -71
  205. package/dist/esm/translateDoc/translateDoc.mjs.map +1 -1
  206. package/dist/esm/translateDoc/translateFile.mjs +2 -101
  207. package/dist/esm/translateDoc/translateFile.mjs.map +1 -1
  208. package/dist/esm/translateDoc/validation.mjs +5 -46
  209. package/dist/esm/translateDoc/validation.mjs.map +1 -1
  210. package/dist/esm/translation-alignment/alignBlocks.mjs +1 -66
  211. package/dist/esm/translation-alignment/alignBlocks.mjs.map +1 -1
  212. package/dist/esm/translation-alignment/computeSimilarity.mjs +1 -22
  213. package/dist/esm/translation-alignment/computeSimilarity.mjs.map +1 -1
  214. package/dist/esm/translation-alignment/fingerprintBlock.mjs +1 -20
  215. package/dist/esm/translation-alignment/fingerprintBlock.mjs.map +1 -1
  216. package/dist/esm/translation-alignment/index.mjs +1 -11
  217. package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs +1 -16
  218. package/dist/esm/translation-alignment/mapChangedLinesToBlocks.mjs.map +1 -1
  219. package/dist/esm/translation-alignment/normalizeBlock.mjs +1 -20
  220. package/dist/esm/translation-alignment/normalizeBlock.mjs.map +1 -1
  221. package/dist/esm/translation-alignment/pipeline.mjs +1 -35
  222. package/dist/esm/translation-alignment/pipeline.mjs.map +1 -1
  223. package/dist/esm/translation-alignment/planActions.mjs +1 -44
  224. package/dist/esm/translation-alignment/planActions.mjs.map +1 -1
  225. package/dist/esm/translation-alignment/rebuildDocument.mjs +2 -46
  226. package/dist/esm/translation-alignment/rebuildDocument.mjs.map +1 -1
  227. package/dist/esm/translation-alignment/segmentDocument.mjs +5 -64
  228. package/dist/esm/translation-alignment/segmentDocument.mjs.map +1 -1
  229. package/dist/esm/utils/calculateChunks.mjs +2 -87
  230. package/dist/esm/utils/calculateChunks.mjs.map +1 -1
  231. package/dist/esm/utils/checkAccess.mjs +1 -78
  232. package/dist/esm/utils/checkAccess.mjs.map +1 -1
  233. package/dist/esm/utils/checkConfigConsistency.mjs +1 -14
  234. package/dist/esm/utils/checkConfigConsistency.mjs.map +1 -1
  235. package/dist/esm/utils/checkFileModifiedRange.mjs +1 -80
  236. package/dist/esm/utils/checkFileModifiedRange.mjs.map +1 -1
  237. package/dist/esm/utils/checkLastUpdateTime.mjs +1 -17
  238. package/dist/esm/utils/checkLastUpdateTime.mjs.map +1 -1
  239. package/dist/esm/utils/chunkInference.mjs +1 -43
  240. package/dist/esm/utils/chunkInference.mjs.map +1 -1
  241. package/dist/esm/utils/fixChunkStartEndChars.mjs +3 -25
  242. package/dist/esm/utils/fixChunkStartEndChars.mjs.map +1 -1
  243. package/dist/esm/utils/formatTimeDiff.mjs +1 -18
  244. package/dist/esm/utils/formatTimeDiff.mjs.map +1 -1
  245. package/dist/esm/utils/getIsFileUpdatedRecently.mjs +1 -14
  246. package/dist/esm/utils/getIsFileUpdatedRecently.mjs.map +1 -1
  247. package/dist/esm/utils/getOutputFilePath.mjs +1 -72
  248. package/dist/esm/utils/getOutputFilePath.mjs.map +1 -1
  249. package/dist/esm/utils/getParentPackageJSON.mjs +1 -18
  250. package/dist/esm/utils/getParentPackageJSON.mjs.map +1 -1
  251. package/dist/esm/utils/listSpecialChars.mjs +2 -52
  252. package/dist/esm/utils/listSpecialChars.mjs.map +1 -1
  253. package/dist/esm/utils/mapChunksBetweenFiles.mjs +1 -100
  254. package/dist/esm/utils/mapChunksBetweenFiles.mjs.map +1 -1
  255. package/dist/esm/utils/openBrowser.mjs +1 -17
  256. package/dist/esm/utils/openBrowser.mjs.map +1 -1
  257. package/dist/esm/utils/reorderParagraphs.mjs +3 -90
  258. package/dist/esm/utils/reorderParagraphs.mjs.map +1 -1
  259. package/dist/esm/utils/setupAI.mjs +1 -62
  260. package/dist/esm/utils/setupAI.mjs.map +1 -1
  261. package/dist/esm/watch.mjs +1 -41
  262. package/dist/esm/watch.mjs.map +1 -1
  263. package/dist/types/auth/login.d.ts +1 -1
  264. package/dist/types/auth/login.d.ts.map +1 -1
  265. package/dist/types/build.d.ts +1 -1
  266. package/dist/types/build.d.ts.map +1 -1
  267. package/dist/types/config.d.ts +1 -1
  268. package/dist/types/extract.d.ts +1 -1
  269. package/dist/types/extract.d.ts.map +1 -1
  270. package/dist/types/fill/fill.d.ts +1 -1
  271. package/dist/types/fill/fill.d.ts.map +1 -1
  272. package/dist/types/fill/translateDictionary.d.ts +2 -2
  273. package/dist/types/fill/translateDictionary.d.ts.map +1 -1
  274. package/dist/types/fill/writeFill.d.ts.map +1 -1
  275. package/dist/types/getTargetDictionary.d.ts +2 -2
  276. package/dist/types/index.d.ts +4 -1
  277. package/dist/types/init.d.ts +1 -1
  278. package/dist/types/listContentDeclaration.d.ts +1 -1
  279. package/dist/types/listContentDeclaration.d.ts.map +1 -1
  280. package/dist/types/listProjects.d.ts +1 -1
  281. package/dist/types/listProjects.d.ts.map +1 -1
  282. package/dist/types/liveSync.d.ts +1 -1
  283. package/dist/types/pull.d.ts +1 -1
  284. package/dist/types/pull.d.ts.map +1 -1
  285. package/dist/types/push/pullLog.d.ts +1 -1
  286. package/dist/types/push/pullLog.d.ts.map +1 -1
  287. package/dist/types/push/push.d.ts +2 -2
  288. package/dist/types/pushConfig.d.ts +1 -1
  289. package/dist/types/reviewDoc/reviewDoc.d.ts +2 -2
  290. package/dist/types/reviewDoc/reviewDoc.d.ts.map +1 -1
  291. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts +1 -1
  292. package/dist/types/reviewDoc/reviewDocBlockAware.d.ts.map +1 -1
  293. package/dist/types/searchDoc.d.ts +1 -1
  294. package/dist/types/searchDoc.d.ts.map +1 -1
  295. package/dist/types/test/listMissingTranslations.d.ts +1 -1
  296. package/dist/types/test/test.d.ts +1 -1
  297. package/dist/types/test/test.d.ts.map +1 -1
  298. package/dist/types/translateDoc/translateDoc.d.ts.map +1 -1
  299. package/dist/types/translateDoc/types.d.ts +2 -2
  300. package/dist/types/translateDoc/validation.d.ts +1 -1
  301. package/dist/types/utils/checkAccess.d.ts.map +1 -1
  302. package/dist/types/watch.d.ts +1 -1
  303. package/dist/types/watch.d.ts.map +1 -1
  304. package/package.json +13 -13
@@ -1 +1 @@
1
- {"version":3,"file":"liveSync.mjs","names":[],"sources":["../../src/liveSync.ts"],"sourcesContent":["import { createServer } from 'node:http';\n// @ts-ignore: @intlayer/backend is not built yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport {\n buildDictionary,\n type ParallelHandle,\n runParallel,\n} from '@intlayer/chokidar';\nimport type { GetConfigurationOptions } from '@intlayer/config';\nimport { getAppLogger, getConfiguration } from '@intlayer/config';\nimport packageJson from '@intlayer/config/package.json';\nimport { getLocalizedContent } from '@intlayer/core';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { IntlayerEventListener } from './IntlayerEventListener';\n\ntype LiveSyncOptions = {\n with?: string | string[];\n configOptions?: GetConfigurationOptions;\n};\n\nconst writeDictionary = async (\n dictionary: DictionaryAPI,\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n appLogger(`Writing dictionary ${dictionary.key}`);\n await buildDictionary([dictionary], configuration);\n};\n\nexport const liveSync = async (options?: LiveSyncOptions) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { liveSyncPort, liveSyncURL } = configuration.editor;\n\n let parallelProcess: ParallelHandle | null = null;\n let eventListener: IntlayerEventListener | null = null;\n let _isHotReloadConnected = false;\n let _connectionStatus = 'disconnected'; // 'connected', 'connecting', 'reconnecting', 'disconnected', 'error'\n\n // Start the parallel process if provided\n if (options?.with) {\n parallelProcess = runParallel(options.with);\n // Handle the promise to avoid unhandled rejection\n parallelProcess.result.catch(() => {\n // Parallel process failed or was terminated\n });\n }\n\n // Initialize the event listener for hot reload if configured\n if (\n configuration.editor.liveSync &&\n configuration.editor.backendURL &&\n configuration.editor.clientId &&\n configuration.editor.clientSecret\n ) {\n eventListener = new IntlayerEventListener(configuration);\n _connectionStatus = 'connecting';\n\n // Set up connection callbacks\n eventListener.onConnectionOpen = () => {\n _connectionStatus = 'connected';\n _isHotReloadConnected = true;\n appLogger('Live sync connection established');\n };\n\n eventListener.onConnectionError = (error) => {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n const errorEvent = error as any;\n appLogger(\n `Live sync connection error: ${errorEvent.message ?? 'Unknown error'}`,\n {\n level: 'warn',\n }\n );\n\n // If this is a \"terminated: other side closed\" error, it's likely a server restart\n if (\n errorEvent.message?.includes('terminated') ||\n errorEvent.message?.includes('closed')\n ) {\n appLogger(\n 'Server connection was terminated, automatic reconnection will be attempted...',\n {\n level: 'info',\n }\n );\n _connectionStatus = 'reconnecting';\n }\n };\n\n // Set up dictionary change callbacks\n eventListener.onDictionaryAdded = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryChange = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryDeleted = (dictionary) =>\n writeDictionary(dictionary, configuration);\n\n try {\n await eventListener.initialize();\n } catch (error) {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n appLogger('Failed to initialize IntlayerEventListener:', {\n level: 'error',\n });\n appLogger(\n `Error: ${error instanceof Error ? error.message : String(error)}`,\n {\n level: 'error',\n }\n );\n }\n } else if (!configuration.editor.liveSync) {\n appLogger(\n 'Hot reload is disabled. Please enable it in the configuration (editor.liveSync).'\n );\n } else if (\n !configuration.editor.clientId ||\n !configuration.editor.clientSecret\n ) {\n appLogger(\n 'Missing client credentials for hot reload. Please configure clientId and clientSecret'\n );\n }\n\n const server = createServer(async (req, res) => {\n // Handle CORS preflight requests\n if (req.method === 'OPTIONS') {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n\n res.end();\n return;\n }\n\n if (req.url?.startsWith('/dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const dictionaries = getDictionaries(configuration);\n\n const prefix = '/dictionaries/';\n if (req.url.startsWith(prefix)) {\n const [key, locale] = decodeURIComponent(req.url)\n .slice(prefix.length)\n .split('/');\n\n const dictionary = dictionaries[key] ?? null;\n\n if (locale) {\n // @ts-ignore Type instantiation is excessively deep and possibly infinite\n const sourceLocaleContent = getLocalizedContent(\n dictionary.content,\n locale,\n {\n dictionaryKey: key,\n keyPath: [],\n }\n );\n\n res.end(JSON.stringify(sourceLocaleContent));\n return;\n }\n\n res.end(JSON.stringify(dictionary));\n return;\n }\n\n res.end(JSON.stringify(dictionaries));\n return;\n }\n\n if (req.url?.startsWith('/unmerged_dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const unmergedDictionaries = getUnmergedDictionaries(configuration);\n\n const prefix = '/unmerged_dictionaries/';\n if (req.url.startsWith(prefix)) {\n const key = decodeURIComponent(req.url.slice(prefix.length));\n const one = unmergedDictionaries[key] ?? null;\n\n res.end(JSON.stringify(one));\n return;\n }\n\n res.end(JSON.stringify(unmergedDictionaries));\n return;\n }\n\n if (req.url === '/configuration') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n res.end(JSON.stringify(configuration));\n return;\n }\n\n if (req.url === '/health') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n res.end('Not found');\n return;\n });\n\n const getLiveSyncParam = () => {\n if (!configuration.editor.liveSync) return '\\x1b[31m✗ Disabled\\x1b[0m';\n\n return '\\x1b[32m✓ Enabled\\x1b[0m';\n };\n server.listen(liveSyncPort, () => {\n console.log(`\n \\x1b[1;90mINTLAYER v${packageJson.version}\\x1b[0m\n \n Live server running at: \\x1b[90m${liveSyncURL}\\x1b[0m\n - Backend URL: \\x1b[90m${configuration.editor.backendURL ?? '-'}\\x1b[0m\n - Live sync: ${getLiveSyncParam()}\n - Parallel process: ${options?.with ? `\\x1b[90m${Array.isArray(options.with) ? options.with.join(' ') : options.with}\\x1b[0m` : '-'}\n - Access key: ${configuration.editor.clientId ?? '-'}\n `);\n });\n\n // Cleanup function to terminate child process and event listener when the main process exits\n const cleanup = () => {\n // Clean up event listener\n if (eventListener) {\n appLogger('Closing SSE connection...');\n eventListener.cleanup();\n }\n\n if (parallelProcess) {\n parallelProcess.kill();\n }\n\n server.close(() => {\n appLogger('Live sync server stopped');\n process.exit(0);\n });\n };\n\n // Handle process termination signals\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n};\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,kBAAkB,OACtB,YACA,kBACG;AAEH,CADkB,aAAa,cAAc,CACnC,sBAAsB,WAAW,MAAM;AACjD,OAAM,gBAAgB,CAAC,WAAW,EAAE,cAAc;;AAGpD,MAAa,WAAW,OAAO,YAA8B;CAC3D,MAAM,gBAAgB,iBAAiB,SAAS,cAAc;CAC9D,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,EAAE,cAAc,gBAAgB,cAAc;CAEpD,IAAI,kBAAyC;CAC7C,IAAI,gBAA8C;AAKlD,KAAI,SAAS,MAAM;AACjB,oBAAkB,YAAY,QAAQ,KAAK;AAE3C,kBAAgB,OAAO,YAAY,GAEjC;;AAIJ,KACE,cAAc,OAAO,YACrB,cAAc,OAAO,cACrB,cAAc,OAAO,YACrB,cAAc,OAAO,cACrB;AACA,kBAAgB,IAAI,sBAAsB,cAAc;AAIxD,gBAAc,yBAAyB;AAGrC,aAAU,mCAAmC;;AAG/C,gBAAc,qBAAqB,UAAU;GAG3C,MAAM,aAAa;AACnB,aACE,+BAA+B,WAAW,WAAW,mBACrD,EACE,OAAO,QACR,CACF;AAGD,OACE,WAAW,SAAS,SAAS,aAAa,IAC1C,WAAW,SAAS,SAAS,SAAS,CAEtC,WACE,iFACA,EACE,OAAO,QACR,CACF;;AAML,gBAAc,qBAAqB,eACjC,gBAAgB,YAAY,cAAc;AAC5C,gBAAc,sBAAsB,eAClC,gBAAgB,YAAY,cAAc;AAC5C,gBAAc,uBAAuB,eACnC,gBAAgB,YAAY,cAAc;AAE5C,MAAI;AACF,SAAM,cAAc,YAAY;WACzB,OAAO;AAGd,aAAU,+CAA+C,EACvD,OAAO,SACR,CAAC;AACF,aACE,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAChE,EACE,OAAO,SACR,CACF;;YAEM,CAAC,cAAc,OAAO,SAC/B,WACE,mFACD;UAED,CAAC,cAAc,OAAO,YACtB,CAAC,cAAc,OAAO,aAEtB,WACE,wFACD;CAGH,MAAM,SAAS,aAAa,OAAO,KAAK,QAAQ;AAE9C,MAAI,IAAI,WAAW,WAAW;AAC5B,OAAI,UAAU,KAAK;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;IACjC,CAAC;AAEF,OAAI,KAAK;AACT;;AAGF,MAAI,IAAI,KAAK,WAAW,gBAAgB,EAAE;AACxC,OAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;IACjC,CAAC;GACF,MAAM,eAAe,gBAAgB,cAAc;AAGnD,OAAI,IAAI,IAAI,WADG,iBACe,EAAE;IAC9B,MAAM,CAAC,KAAK,UAAU,mBAAmB,IAAI,IAAI,CAC9C,MAAM,GAAc,CACpB,MAAM,IAAI;IAEb,MAAM,aAAa,aAAa,QAAQ;AAExC,QAAI,QAAQ;KAEV,MAAM,sBAAsB,oBAC1B,WAAW,SACX,QACA;MACE,eAAe;MACf,SAAS,EAAE;MACZ,CACF;AAED,SAAI,IAAI,KAAK,UAAU,oBAAoB,CAAC;AAC5C;;AAGF,QAAI,IAAI,KAAK,UAAU,WAAW,CAAC;AACnC;;AAGF,OAAI,IAAI,KAAK,UAAU,aAAa,CAAC;AACrC;;AAGF,MAAI,IAAI,KAAK,WAAW,yBAAyB,EAAE;AACjD,OAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;IACjC,CAAC;GACF,MAAM,uBAAuB,wBAAwB,cAAc;AAGnE,OAAI,IAAI,IAAI,WADG,0BACe,EAAE;IAE9B,MAAM,MAAM,qBADA,mBAAmB,IAAI,IAAI,MAAM,GAAc,CAAC,KACnB;AAEzC,QAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC5B;;AAGF,OAAI,IAAI,KAAK,UAAU,qBAAqB,CAAC;AAC7C;;AAGF,MAAI,IAAI,QAAQ,kBAAkB;AAChC,OAAI,UAAU,KAAK;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,+BAA+B;IAC/B,gCAAgC;IAChC,gCAAgC;IACjC,CAAC;AACF,OAAI,IAAI,KAAK,UAAU,cAAc,CAAC;AACtC;;AAGF,MAAI,IAAI,QAAQ,WAAW;AACzB,OAAI,UAAU,KAAK,EACjB,gBAAgB,mCACjB,CAAC;AACF,OAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC;AACzC;;AAGF,MAAI,IAAI,YAAY;GAEpB;CAEF,MAAM,yBAAyB;AAC7B,MAAI,CAAC,cAAc,OAAO,SAAU,QAAO;AAE3C,SAAO;;AAET,QAAO,OAAO,oBAAoB;AAChC,UAAQ,IAAI;4BACY,YAAY,QAAQ;;iDAEC,YAAY;iDACZ,cAAc,OAAO,cAAc,IAAI;yCAC/C,kBAAkB,CAAC;yCACnB,SAAS,OAAO,WAAW,MAAM,QAAQ,QAAQ,KAAK,GAAG,QAAQ,KAAK,KAAK,IAAI,GAAG,QAAQ,KAAK,WAAW,IAAI;yCAC9G,cAAc,OAAO,YAAY,IAAI;QACtE;GACJ;CAGF,MAAM,gBAAgB;AAEpB,MAAI,eAAe;AACjB,aAAU,4BAA4B;AACtC,iBAAc,SAAS;;AAGzB,MAAI,gBACF,iBAAgB,MAAM;AAGxB,SAAO,YAAY;AACjB,aAAU,2BAA2B;AACrC,WAAQ,KAAK,EAAE;IACf;;AAIJ,SAAQ,GAAG,UAAU,QAAQ;AAC7B,SAAQ,GAAG,WAAW,QAAQ;AAC9B,SAAQ,GAAG,QAAQ,QAAQ"}
1
+ {"version":3,"file":"liveSync.mjs","names":[],"sources":["../../src/liveSync.ts"],"sourcesContent":["import { createServer } from 'node:http';\n// @ts-ignore: @intlayer/backend is not built yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport { buildDictionary } from '@intlayer/chokidar/build';\nimport { type ParallelHandle, runParallel } from '@intlayer/chokidar/utils';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport packageJson from '@intlayer/config/package.json';\nimport { getLocalizedContent } from '@intlayer/core/plugins';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { IntlayerConfig } from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { IntlayerEventListener } from './IntlayerEventListener';\n\ntype LiveSyncOptions = {\n with?: string | string[];\n configOptions?: GetConfigurationOptions;\n};\n\nconst writeDictionary = async (\n dictionary: DictionaryAPI,\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration);\n appLogger(`Writing dictionary ${dictionary.key}`);\n await buildDictionary([dictionary], configuration);\n};\n\nexport const liveSync = async (options?: LiveSyncOptions) => {\n const configuration = getConfiguration(options?.configOptions);\n const appLogger = getAppLogger(configuration);\n\n const { liveSyncPort, liveSyncURL } = configuration.editor;\n\n let parallelProcess: ParallelHandle | null = null;\n let eventListener: IntlayerEventListener | null = null;\n let _isHotReloadConnected = false;\n let _connectionStatus = 'disconnected'; // 'connected', 'connecting', 'reconnecting', 'disconnected', 'error'\n\n // Start the parallel process if provided\n if (options?.with) {\n parallelProcess = runParallel(options.with);\n // Handle the promise to avoid unhandled rejection\n parallelProcess.result.catch(() => {\n // Parallel process failed or was terminated\n });\n }\n\n // Initialize the event listener for hot reload if configured\n if (\n configuration.editor.liveSync &&\n configuration.editor.backendURL &&\n configuration.editor.clientId &&\n configuration.editor.clientSecret\n ) {\n eventListener = new IntlayerEventListener(configuration);\n _connectionStatus = 'connecting';\n\n // Set up connection callbacks\n eventListener.onConnectionOpen = () => {\n _connectionStatus = 'connected';\n _isHotReloadConnected = true;\n appLogger('Live sync connection established');\n };\n\n eventListener.onConnectionError = (error) => {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n const errorEvent = error as any;\n appLogger(\n `Live sync connection error: ${errorEvent.message ?? 'Unknown error'}`,\n {\n level: 'warn',\n }\n );\n\n // If this is a \"terminated: other side closed\" error, it's likely a server restart\n if (\n errorEvent.message?.includes('terminated') ||\n errorEvent.message?.includes('closed')\n ) {\n appLogger(\n 'Server connection was terminated, automatic reconnection will be attempted...',\n {\n level: 'info',\n }\n );\n _connectionStatus = 'reconnecting';\n }\n };\n\n // Set up dictionary change callbacks\n eventListener.onDictionaryAdded = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryChange = (dictionary) =>\n writeDictionary(dictionary, configuration);\n eventListener.onDictionaryDeleted = (dictionary) =>\n writeDictionary(dictionary, configuration);\n\n try {\n await eventListener.initialize();\n } catch (error) {\n _connectionStatus = 'error';\n _isHotReloadConnected = false;\n appLogger('Failed to initialize IntlayerEventListener:', {\n level: 'error',\n });\n appLogger(\n `Error: ${error instanceof Error ? error.message : String(error)}`,\n {\n level: 'error',\n }\n );\n }\n } else if (!configuration.editor.liveSync) {\n appLogger(\n 'Hot reload is disabled. Please enable it in the configuration (editor.liveSync).'\n );\n } else if (\n !configuration.editor.clientId ||\n !configuration.editor.clientSecret\n ) {\n appLogger(\n 'Missing client credentials for hot reload. Please configure clientId and clientSecret'\n );\n }\n\n const server = createServer(async (req, res) => {\n // Handle CORS preflight requests\n if (req.method === 'OPTIONS') {\n res.writeHead(200, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n\n res.end();\n return;\n }\n\n if (req.url?.startsWith('/dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const dictionaries = getDictionaries(configuration);\n\n const prefix = '/dictionaries/';\n if (req.url.startsWith(prefix)) {\n const [key, locale] = decodeURIComponent(req.url)\n .slice(prefix.length)\n .split('/');\n\n const dictionary = dictionaries[key] ?? null;\n\n if (locale) {\n // @ts-ignore Type instantiation is excessively deep and possibly infinite\n const sourceLocaleContent = getLocalizedContent(\n dictionary.content,\n locale,\n {\n dictionaryKey: key,\n keyPath: [],\n }\n );\n\n res.end(JSON.stringify(sourceLocaleContent));\n return;\n }\n\n res.end(JSON.stringify(dictionary));\n return;\n }\n\n res.end(JSON.stringify(dictionaries));\n return;\n }\n\n if (req.url?.startsWith('/unmerged_dictionaries')) {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n const unmergedDictionaries = getUnmergedDictionaries(configuration);\n\n const prefix = '/unmerged_dictionaries/';\n if (req.url.startsWith(prefix)) {\n const key = decodeURIComponent(req.url.slice(prefix.length));\n const one = unmergedDictionaries[key] ?? null;\n\n res.end(JSON.stringify(one));\n return;\n }\n\n res.end(JSON.stringify(unmergedDictionaries));\n return;\n }\n\n if (req.url === '/configuration') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization',\n });\n res.end(JSON.stringify(configuration));\n return;\n }\n\n if (req.url === '/health') {\n res.writeHead(200, {\n 'Content-Type': 'application/json; charset=utf-8',\n });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n res.end('Not found');\n return;\n });\n\n const getLiveSyncParam = () => {\n if (!configuration.editor.liveSync) return '\\x1b[31m✗ Disabled\\x1b[0m';\n\n return '\\x1b[32m✓ Enabled\\x1b[0m';\n };\n server.listen(liveSyncPort, () => {\n console.log(`\n \\x1b[1;90mINTLAYER v${packageJson.version}\\x1b[0m\n \n Live server running at: \\x1b[90m${liveSyncURL}\\x1b[0m\n - Backend URL: \\x1b[90m${configuration.editor.backendURL ?? '-'}\\x1b[0m\n - Live sync: ${getLiveSyncParam()}\n - Parallel process: ${options?.with ? `\\x1b[90m${Array.isArray(options.with) ? options.with.join(' ') : options.with}\\x1b[0m` : '-'}\n - Access key: ${configuration.editor.clientId ?? '-'}\n `);\n });\n\n // Cleanup function to terminate child process and event listener when the main process exits\n const cleanup = () => {\n // Clean up event listener\n if (eventListener) {\n appLogger('Closing SSE connection...');\n eventListener.cleanup();\n }\n\n if (parallelProcess) {\n parallelProcess.kill();\n }\n\n server.close(() => {\n appLogger('Live sync server stopped');\n process.exit(0);\n });\n };\n\n // Handle process termination signals\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n process.on('exit', cleanup);\n};\n"],"mappings":"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"}
package/dist/esm/pull.mjs CHANGED
@@ -1,145 +1,2 @@
1
- import { checkCMSAuth } from "./utils/checkAccess.mjs";
2
- import { PullLogger } from "./push/pullLog.mjs";
3
- import { getIntlayerAPIProxy } from "@intlayer/api";
4
- import { parallelize, writeContentDeclaration } from "@intlayer/chokidar";
5
- import { ANSIColors, getAppLogger, getConfiguration, getProjectRequire } from "@intlayer/config";
6
- import { join } from "node:path";
7
- import { existsSync } from "node:fs";
8
- import { getUnmergedDictionaries } from "@intlayer/unmerged-dictionaries-entry";
9
-
10
- //#region src/pull.ts
11
- /**
12
- * Fetch distant dictionaries and write them locally,
13
- * with progress indicators and concurrency control.
14
- */
15
- const pull = async (options) => {
16
- const appLogger = getAppLogger(options?.configOptions?.override);
17
- try {
18
- const config = getConfiguration(options?.configOptions);
19
- if (!await checkCMSAuth(config)) return;
20
- const intlayerAPI = getIntlayerAPIProxy(void 0, config);
21
- const unmergedDictionariesRecord = getUnmergedDictionaries(config);
22
- const getDictionariesUpdateTimestampResult = await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();
23
- if (!getDictionariesUpdateTimestampResult.data) throw new Error("No distant dictionaries found");
24
- let distantDictionariesUpdateTimeStamp = getDictionariesUpdateTimestampResult.data;
25
- if (options?.dictionaries) distantDictionariesUpdateTimeStamp = Object.fromEntries(Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => options.dictionaries?.includes(key)));
26
- distantDictionariesUpdateTimeStamp = Object.fromEntries(Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {
27
- const location = unmergedDictionariesRecord[key]?.[0]?.location ?? config.dictionary?.location ?? "remote";
28
- return location === "remote" || location === "hybrid";
29
- }));
30
- const remoteDictionariesPath = join(config.system.mainDir, "remote_dictionaries.cjs");
31
- const requireFunction = config.build?.require ?? getProjectRequire();
32
- const remoteDictionariesRecord = existsSync(remoteDictionariesPath) ? requireFunction(remoteDictionariesPath) : {};
33
- const entries = Object.entries(distantDictionariesUpdateTimeStamp);
34
- const keysToFetch = entries.filter(([key, remoteUpdatedAtValue]) => {
35
- if (!remoteUpdatedAtValue) return true;
36
- const remoteUpdatedAt = typeof remoteUpdatedAtValue === "object" ? remoteUpdatedAtValue.updatedAt : remoteUpdatedAtValue;
37
- const local = remoteDictionariesRecord[key];
38
- if (!local) return true;
39
- const localUpdatedAtRaw = local?.updatedAt;
40
- const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
41
- if (typeof localUpdatedAt !== "number") return true;
42
- return remoteUpdatedAt > localUpdatedAt;
43
- }).map(([key]) => key);
44
- const cachedKeys = entries.filter(([key, remoteUpdatedAtValue]) => {
45
- const remoteUpdatedAt = typeof remoteUpdatedAtValue === "object" ? remoteUpdatedAtValue.updatedAt : remoteUpdatedAtValue;
46
- const localUpdatedAtRaw = remoteDictionariesRecord[key]?.updatedAt;
47
- const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
48
- return typeof localUpdatedAt === "number" && typeof remoteUpdatedAt === "number" && localUpdatedAt >= remoteUpdatedAt;
49
- }).map(([key]) => key);
50
- if (entries.length === 0) {
51
- appLogger("No dictionaries to fetch", { level: "error" });
52
- return;
53
- }
54
- appLogger("Fetching dictionaries:");
55
- const dictionariesStatuses = [...cachedKeys.map((dictionaryKey) => ({
56
- dictionaryKey,
57
- status: "imported"
58
- })), ...keysToFetch.map((dictionaryKey) => ({
59
- dictionaryKey,
60
- status: "pending"
61
- }))];
62
- const logger = new PullLogger();
63
- logger.update(dictionariesStatuses.map((s) => ({
64
- dictionaryKey: s.dictionaryKey,
65
- status: s.status
66
- })));
67
- const successfullyFetchedDictionaries = [];
68
- const processDictionary = async (statusObj) => {
69
- const isCached = statusObj.status === "imported" || statusObj.status === "up-to-date";
70
- if (!isCached) {
71
- statusObj.status = "fetching";
72
- logger.update([{
73
- dictionaryKey: statusObj.dictionaryKey,
74
- status: "fetching"
75
- }]);
76
- }
77
- try {
78
- let sourceDictionary;
79
- if (isCached) sourceDictionary = remoteDictionariesRecord[statusObj.dictionaryKey];
80
- if (!sourceDictionary) sourceDictionary = (await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey)).data;
81
- if (!sourceDictionary) throw new Error(`Dictionary ${statusObj.dictionaryKey} not found on remote`);
82
- const localAndRemoteDictionary = unmergedDictionariesRecord[statusObj.dictionaryKey]?.find((d) => d.location === "hybrid");
83
- if (localAndRemoteDictionary) sourceDictionary = {
84
- ...sourceDictionary,
85
- location: "hybrid",
86
- filePath: localAndRemoteDictionary.filePath,
87
- localId: localAndRemoteDictionary.localId
88
- };
89
- const { status } = await writeContentDeclaration(sourceDictionary, config, options);
90
- statusObj.status = status;
91
- logger.update([{
92
- dictionaryKey: statusObj.dictionaryKey,
93
- status
94
- }]);
95
- successfullyFetchedDictionaries.push(sourceDictionary);
96
- } catch (error) {
97
- statusObj.status = "error";
98
- statusObj.error = error;
99
- statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;
100
- logger.update([{
101
- dictionaryKey: statusObj.dictionaryKey,
102
- status: "error"
103
- }]);
104
- }
105
- };
106
- await parallelize(dictionariesStatuses, processDictionary, 5);
107
- logger.finish();
108
- const iconFor = (status) => {
109
- switch (status) {
110
- case "fetched":
111
- case "imported":
112
- case "updated":
113
- case "up-to-date":
114
- case "reimported in JSON":
115
- case "new content file": return "✔";
116
- case "error": return "✖";
117
- default: return "⏲";
118
- }
119
- };
120
- const colorFor = (status) => {
121
- switch (status) {
122
- case "fetched":
123
- case "imported":
124
- case "updated":
125
- case "up-to-date": return ANSIColors.GREEN;
126
- case "reimported in JSON":
127
- case "new content file": return ANSIColors.YELLOW;
128
- case "error": return ANSIColors.RED;
129
- default: return ANSIColors.BLUE;
130
- }
131
- };
132
- for (const s of dictionariesStatuses) {
133
- const icon = iconFor(s.status);
134
- const color = colorFor(s.status);
135
- appLogger(` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`);
136
- }
137
- for (const statusObj of dictionariesStatuses) if (statusObj.errorMessage) appLogger(statusObj.errorMessage, { level: "error" });
138
- } catch (error) {
139
- appLogger(error, { level: "error" });
140
- }
141
- };
142
-
143
- //#endregion
144
- export { pull };
1
+ import{checkCMSAuth as e}from"./utils/checkAccess.mjs";import{PullLogger as t}from"./push/pullLog.mjs";import{getIntlayerAPIProxy as n}from"@intlayer/api";import{parallelize as r}from"@intlayer/chokidar/utils";import{getConfiguration as i}from"@intlayer/config/node";import{join as a}from"node:path";import{ANSIColors as o,getAppLogger as s}from"@intlayer/config/logger";import{getProjectRequire as c}from"@intlayer/config/utils";import{existsSync as l}from"node:fs";import{writeContentDeclaration as u}from"@intlayer/chokidar/build";import{getUnmergedDictionaries as d}from"@intlayer/unmerged-dictionaries-entry";const f=async f=>{let p=s(f?.configOptions?.override);try{let s=i(f?.configOptions);if(!await e(s))return;let m=n(void 0,s),h=d(s),g=await m.dictionary.getDictionariesUpdateTimestamp();if(!g.data)throw Error(`No distant dictionaries found`);let _=g.data;f?.dictionaries&&(_=Object.fromEntries(Object.entries(_).filter(([e])=>f.dictionaries?.includes(e)))),_=Object.fromEntries(Object.entries(_).filter(([e])=>{let t=h[e]?.[0]?.location??s.dictionary?.location??`remote`;return t===`remote`||t===`hybrid`}));let v=a(s.system.mainDir,`remote_dictionaries.cjs`),y=s.build?.require??c(),b=l(v)?y(v):{},x=Object.entries(_),S=x.filter(([e,t])=>{if(!t)return!0;let n=typeof t==`object`?t.updatedAt:t,r=b[e];if(!r)return!0;let i=r?.updatedAt,a=typeof i==`number`?i:i?new Date(i).getTime():void 0;return typeof a==`number`?n>a:!0}).map(([e])=>e),C=x.filter(([e,t])=>{let n=typeof t==`object`?t.updatedAt:t,r=b[e]?.updatedAt,i=typeof r==`number`?r:r?new Date(r).getTime():void 0;return typeof i==`number`&&typeof n==`number`&&i>=n}).map(([e])=>e);if(x.length===0){p(`No dictionaries to fetch`,{level:`error`});return}p(`Fetching dictionaries:`);let w=[...C.map(e=>({dictionaryKey:e,status:`imported`})),...S.map(e=>({dictionaryKey:e,status:`pending`}))],T=new t;T.update(w.map(e=>({dictionaryKey:e.dictionaryKey,status:e.status})));let E=[];await r(w,async e=>{let t=e.status===`imported`||e.status===`up-to-date`;t||(e.status=`fetching`,T.update([{dictionaryKey:e.dictionaryKey,status:`fetching`}]));try{let n;if(t&&(n=b[e.dictionaryKey]),n||=(await m.dictionary.getDictionary(e.dictionaryKey)).data,!n)throw Error(`Dictionary ${e.dictionaryKey} not found on remote`);let r=h[e.dictionaryKey]?.find(e=>e.location===`hybrid`);r&&(n={...n,location:`hybrid`,filePath:r.filePath,localId:r.localId});let{status:i}=await u(n,s,f);e.status=i,T.update([{dictionaryKey:e.dictionaryKey,status:i}]),E.push(n)}catch(t){e.status=`error`,e.error=t,e.errorMessage=`Error fetching dictionary ${e.dictionaryKey}: ${t}`,T.update([{dictionaryKey:e.dictionaryKey,status:`error`}])}},5),T.finish();let D=e=>{switch(e){case`fetched`:case`imported`:case`updated`:case`up-to-date`:case`reimported in JSON`:case`new content file`:return`✔`;case`error`:return`✖`;default:return`⏲`}},O=e=>{switch(e){case`fetched`:case`imported`:case`updated`:case`up-to-date`:return o.GREEN;case`reimported in JSON`:case`new content file`:return o.YELLOW;case`error`:return o.RED;default:return o.BLUE}};for(let e of w){let t=D(e.status),n=O(e.status);p(` - ${e.dictionaryKey} ${o.GREY}[${n}${t} ${e.status}${o.GREY}]${o.RESET}`)}for(let e of w)e.errorMessage&&p(e.errorMessage,{level:`error`})}catch(e){p(e,{level:`error`})}};export{f as pull};
145
2
  //# sourceMappingURL=pull.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pull.mjs","names":[],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n parallelize,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n ANSIColors,\n type GetConfigurationOptions,\n getAppLogger,\n getConfiguration,\n getProjectRequire,\n} from '@intlayer/config';\nimport type { Dictionary } from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"pull.mjs","names":[],"sources":["../../src/pull.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport {\n type DictionaryStatus,\n writeContentDeclaration,\n} from '@intlayer/chokidar/build';\nimport { parallelize } from '@intlayer/chokidar/utils';\nimport { ANSIColors, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { getProjectRequire } from '@intlayer/config/utils';\nimport type { Dictionary } from '@intlayer/types';\nimport { getUnmergedDictionaries } from '@intlayer/unmerged-dictionaries-entry';\nimport { PullLogger, type PullStatus } from './push/pullLog';\nimport { checkCMSAuth } from './utils/checkAccess';\n\ntype PullOptions = {\n dictionaries?: string[];\n newDictionariesPath?: string;\n configOptions?: GetConfigurationOptions;\n};\n\ntype DictionariesStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching' | 'error';\n error?: Error;\n errorMessage?: string;\n};\n\n/**\n * Fetch distant dictionaries and write them locally,\n * with progress indicators and concurrency control.\n */\nexport const pull = async (options?: PullOptions): Promise<void> => {\n const appLogger = getAppLogger(options?.configOptions?.override);\n\n try {\n const config = getConfiguration(options?.configOptions);\n\n const hasCMSAuth = await checkCMSAuth(config);\n\n if (!hasCMSAuth) return;\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, config);\n\n const unmergedDictionariesRecord = getUnmergedDictionaries(config);\n\n // Get remote update timestamps map\n const getDictionariesUpdateTimestampResult =\n await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();\n\n if (!getDictionariesUpdateTimestampResult.data) {\n throw new Error('No distant dictionaries found');\n }\n\n let distantDictionariesUpdateTimeStamp: Record<string, any> =\n getDictionariesUpdateTimestampResult.data;\n\n // Optional filtering by requested dictionaries\n if (options?.dictionaries) {\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) =>\n options.dictionaries?.includes(key)\n )\n );\n }\n\n // Filter by location\n distantDictionariesUpdateTimeStamp = Object.fromEntries(\n Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => {\n const localDictionaries = unmergedDictionariesRecord[key];\n const location =\n localDictionaries?.[0]?.location ??\n config.dictionary?.location ??\n 'remote';\n\n return location === 'remote' || location === 'hybrid';\n })\n );\n\n // Load local cached remote dictionaries (if any)\n const remoteDictionariesPath = join(\n config.system.mainDir,\n 'remote_dictionaries.cjs'\n );\n const requireFunction = config.build?.require ?? getProjectRequire();\n const remoteDictionariesRecord: Record<string, any> = existsSync(\n remoteDictionariesPath\n )\n ? (requireFunction(remoteDictionariesPath) as any)\n : {};\n\n // Determine which keys need fetching by comparing updatedAt with local cache\n const entries = Object.entries(distantDictionariesUpdateTimeStamp);\n const keysToFetch = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n if (!remoteUpdatedAtValue) return true;\n\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n if (!local) return true;\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n if (typeof localUpdatedAt !== 'number') return true;\n return remoteUpdatedAt > localUpdatedAt;\n })\n .map(([key]) => key);\n\n const cachedKeys = entries\n .filter(([key, remoteUpdatedAtValue]) => {\n const remoteUpdatedAt =\n typeof remoteUpdatedAtValue === 'object'\n ? (remoteUpdatedAtValue as any).updatedAt\n : remoteUpdatedAtValue;\n\n const local = (remoteDictionariesRecord as any)[key];\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n })\n .map(([key]) => key);\n\n // Check if dictionaries list is empty\n if (entries.length === 0) {\n appLogger('No dictionaries to fetch', {\n level: 'error',\n });\n return;\n }\n\n appLogger('Fetching dictionaries:');\n\n // Prepare dictionaries statuses\n const dictionariesStatuses: DictionariesStatus[] = [\n ...cachedKeys.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'imported' as DictionaryStatus,\n })),\n ...keysToFetch.map((dictionaryKey) => ({\n dictionaryKey,\n status: 'pending' as const,\n })),\n ];\n\n // Initialize aggregated logger\n const logger = new PullLogger();\n logger.update(\n dictionariesStatuses.map<PullStatus>((s) => ({\n dictionaryKey: s.dictionaryKey,\n status: s.status,\n }))\n );\n\n const successfullyFetchedDictionaries: Dictionary[] = [];\n\n const processDictionary = async (\n statusObj: DictionariesStatus\n ): Promise<void> => {\n const isCached =\n statusObj.status === 'imported' || statusObj.status === 'up-to-date';\n\n if (!isCached) {\n statusObj.status = 'fetching';\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'fetching' },\n ]);\n }\n\n try {\n let sourceDictionary: Dictionary | undefined;\n\n if (isCached) {\n sourceDictionary = remoteDictionariesRecord[\n statusObj.dictionaryKey\n ] as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n // Fetch the dictionary\n const getDictionaryResult =\n await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey);\n\n sourceDictionary = getDictionaryResult.data as Dictionary | undefined;\n }\n\n if (!sourceDictionary) {\n throw new Error(\n `Dictionary ${statusObj.dictionaryKey} not found on remote`\n );\n }\n\n // Check if there is a local version of this dictionary that is hybrid\n const localDictionaries =\n unmergedDictionariesRecord[statusObj.dictionaryKey];\n const localAndRemoteDictionary = localDictionaries?.find(\n (d) => d.location === 'hybrid'\n );\n\n if (localAndRemoteDictionary) {\n // We want to preserve the local properties but use the remote content\n sourceDictionary = {\n ...sourceDictionary,\n location: 'hybrid',\n filePath: localAndRemoteDictionary.filePath,\n localId: localAndRemoteDictionary.localId,\n };\n }\n\n // Now, write the dictionary to local file\n const { status } = await writeContentDeclaration(\n sourceDictionary,\n config,\n options\n );\n\n statusObj.status = status;\n logger.update([{ dictionaryKey: statusObj.dictionaryKey, status }]);\n\n successfullyFetchedDictionaries.push(sourceDictionary);\n } catch (error) {\n statusObj.status = 'error';\n statusObj.error = error as Error;\n statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;\n logger.update([\n { dictionaryKey: statusObj.dictionaryKey, status: 'error' },\n ]);\n }\n };\n\n // Process dictionaries in parallel with concurrency limit\n await parallelize(dictionariesStatuses, processDictionary, 5);\n\n // Stop the logger and render final state\n logger.finish();\n\n // Per-dictionary summary\n const iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n case 'reimported in JSON':\n case 'new content file':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n };\n\n const colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'fetched':\n case 'imported':\n case 'updated':\n case 'up-to-date':\n return ANSIColors.GREEN;\n case 'reimported in JSON':\n case 'new content file':\n return ANSIColors.YELLOW;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n };\n\n for (const s of dictionariesStatuses) {\n const icon = iconFor(s.status);\n const color = colorFor(s.status);\n appLogger(\n ` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n // Output any error messages\n for (const statusObj of dictionariesStatuses) {\n if (statusObj.errorMessage) {\n appLogger(statusObj.errorMessage, {\n level: 'error',\n });\n }\n }\n } catch (error) {\n appLogger(error, {\n level: 'error',\n });\n }\n};\n"],"mappings":"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"}
@@ -1,101 +1,4 @@
1
- import { ANSIColors, colorize, getConfiguration, spinnerFrames } from "@intlayer/config";
2
-
3
- //#region src/push/pullLog.ts
4
- var PullLogger = class {
5
- statuses = [];
6
- spinnerTimer = null;
7
- spinnerIndex = 0;
8
- renderedLines = 0;
9
- spinnerFrames = spinnerFrames;
10
- isFinished = false;
11
- prefix;
12
- lastRenderedState = "";
13
- constructor() {
14
- this.prefix = getConfiguration().log.prefix;
15
- }
16
- update(newStatuses) {
17
- if (this.isFinished) return;
18
- for (const status of newStatuses) {
19
- const index = this.statuses.findIndex((s) => s.dictionaryKey === status.dictionaryKey);
20
- if (index >= 0) this.statuses[index] = status;
21
- else this.statuses.push(status);
22
- }
23
- this.startSpinner();
24
- this.render();
25
- }
26
- finish() {
27
- this.isFinished = true;
28
- this.stopSpinner();
29
- this.render();
30
- }
31
- startSpinner() {
32
- if (this.spinnerTimer || this.isFinished) return;
33
- this.spinnerTimer = setInterval(() => {
34
- this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
35
- this.render();
36
- }, 100);
37
- }
38
- stopSpinner() {
39
- if (!this.spinnerTimer) return;
40
- clearInterval(this.spinnerTimer);
41
- this.spinnerTimer = null;
42
- }
43
- render() {
44
- const { total, done, success, errors } = this.computeProgress();
45
- const frame = this.spinnerFrames[this.spinnerIndex];
46
- const lines = [];
47
- const isDone = done === total;
48
- const progressLabel = `dictionaries: ${done}/${total}`;
49
- const details = [];
50
- if (success > 0) details.push(`ok: ${success}`);
51
- if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));
52
- const suffix = details.length > 0 ? ` (${details.join(", ")})` : "";
53
- if (isDone) lines.push(`${this.prefix} ${colorize("✔", ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`);
54
- else lines.push(`${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`);
55
- const currentState = lines.join("\n");
56
- if (currentState === this.lastRenderedState) return;
57
- this.lastRenderedState = currentState;
58
- if (this.renderedLines > 0) process.stdout.write(`\x1b[${this.renderedLines}F`);
59
- const totalLinesToClear = Math.max(this.renderedLines, lines.length);
60
- for (let i = 0; i < totalLinesToClear; i++) {
61
- process.stdout.write("\x1B[2K");
62
- const line = lines[i];
63
- if (line !== void 0) process.stdout.write(line);
64
- process.stdout.write("\n");
65
- }
66
- this.renderedLines = lines.length;
67
- }
68
- computeProgress() {
69
- const keys = new Set(this.statuses.map((s) => s.dictionaryKey));
70
- const doneSet = new Set([
71
- "fetched",
72
- "imported",
73
- "updated",
74
- "up-to-date",
75
- "reimported in JSON",
76
- "new content file",
77
- "error"
78
- ]);
79
- const successesSet = new Set([
80
- "fetched",
81
- "imported",
82
- "updated",
83
- "up-to-date",
84
- "reimported in JSON",
85
- "new content file"
86
- ]);
87
- const done = this.statuses.filter((s) => doneSet.has(s.status)).length;
88
- const success = this.statuses.filter((s) => successesSet.has(s.status)).length;
89
- const errors = this.statuses.filter((s) => s.status === "error").length;
90
- return {
91
- total: keys.size,
92
- done,
93
- success,
94
- errors
95
- };
96
- }
97
- };
98
-
99
- //#endregion
100
- export { PullLogger };
1
+ import{getConfiguration as e}from"@intlayer/config/node";import{ANSIColors as t,colorize as n,spinnerFrames as r}from"@intlayer/config/logger";var i=class{statuses=[];spinnerTimer=null;spinnerIndex=0;renderedLines=0;spinnerFrames=r;isFinished=!1;prefix;lastRenderedState=``;constructor(){this.prefix=e().log.prefix}update(e){if(!this.isFinished){for(let t of e){let e=this.statuses.findIndex(e=>e.dictionaryKey===t.dictionaryKey);e>=0?this.statuses[e]=t:this.statuses.push(t)}this.startSpinner(),this.render()}}finish(){this.isFinished=!0,this.stopSpinner(),this.render()}startSpinner(){this.spinnerTimer||this.isFinished||(this.spinnerTimer=setInterval(()=>{this.spinnerIndex=(this.spinnerIndex+1)%this.spinnerFrames.length,this.render()},100))}stopSpinner(){this.spinnerTimer&&=(clearInterval(this.spinnerTimer),null)}render(){let{total:e,done:r,success:i,errors:a}=this.computeProgress(),o=this.spinnerFrames[this.spinnerIndex],s=[],c=r===e,l=`dictionaries: ${r}/${e}`,u=[];i>0&&u.push(`ok: ${i}`),a>0&&u.push(n(`errors: ${a}`,t.RED));let d=u.length>0?` (${u.join(`, `)})`:``;c?s.push(`${this.prefix} ${n(`✔`,t.GREEN)} fetched ${l}${d}`):s.push(`${this.prefix} ${n(o,t.BLUE)} fetching ${l}${d}`);let f=s.join(`
2
+ `);if(f===this.lastRenderedState)return;this.lastRenderedState=f,this.renderedLines>0&&process.stdout.write(`\x1b[${this.renderedLines}F`);let p=Math.max(this.renderedLines,s.length);for(let e=0;e<p;e++){process.stdout.write(`\x1B[2K`);let t=s[e];t!==void 0&&process.stdout.write(t),process.stdout.write(`
3
+ `)}this.renderedLines=s.length}computeProgress(){let e=new Set(this.statuses.map(e=>e.dictionaryKey)),t=new Set([`fetched`,`imported`,`updated`,`up-to-date`,`reimported in JSON`,`new content file`,`error`]),n=new Set([`fetched`,`imported`,`updated`,`up-to-date`,`reimported in JSON`,`new content file`]),r=this.statuses.filter(e=>t.has(e.status)).length,i=this.statuses.filter(e=>n.has(e.status)).length,a=this.statuses.filter(e=>e.status===`error`).length;return{total:e.size,done:r,success:i,errors:a}}};export{i as PullLogger};
101
4
  //# sourceMappingURL=pullLog.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pullLog.mjs","names":[],"sources":["../../../src/push/pullLog.ts"],"sourcesContent":["import type { DictionaryStatus } from '@intlayer/chokidar';\nimport {\n ANSIColors,\n colorize,\n getConfiguration,\n spinnerFrames,\n} from '@intlayer/config';\n\nexport type PullStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching';\n errorMessage?: string;\n};\n\nexport class PullLogger {\n private statuses: PullStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PullStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, success, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (success > 0) details.push(`ok: ${success}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const doneSet = new Set<DictionaryStatus | 'error'>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n 'error',\n ] as const);\n\n const successesSet = new Set<DictionaryStatus>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n ] as const);\n\n const done = this.statuses.filter((s) =>\n doneSet.has(s.status as any)\n ).length;\n const success = this.statuses.filter((s) =>\n successesSet.has(s.status as any)\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n\n return {\n total: keys.size,\n done,\n success,\n errors,\n } as const;\n }\n}\n"],"mappings":";;;AAcA,IAAa,aAAb,MAAwB;CACtB,AAAQ,WAAyB,EAAE;CACnC,AAAQ,eAAsC;CAC9C,AAAQ,eAAe;CACvB,AAAQ,gBAAgB;CACxB,AAAiB,gBAAgB;CACjC,AAAQ,aAAa;CACrB,AAAiB;CACjB,AAAQ,oBAA4B;CAEpC,cAAc;AAEZ,OAAK,SADiB,kBAAkB,CACZ,IAAI;;CAGlC,OAAO,aAA2B;AAChC,MAAI,KAAK,WAAY;AACrB,OAAK,MAAM,UAAU,aAAa;GAChC,MAAM,QAAQ,KAAK,SAAS,WACzB,MAAM,EAAE,kBAAkB,OAAO,cACnC;AACD,OAAI,SAAS,EACX,MAAK,SAAS,SAAS;OAEvB,MAAK,SAAS,KAAK,OAAO;;AAI9B,OAAK,cAAc;AACnB,OAAK,QAAQ;;CAGf,SAAS;AACP,OAAK,aAAa;AAClB,OAAK,aAAa;AAClB,OAAK,QAAQ;;CAGf,AAAQ,eAAe;AACrB,MAAI,KAAK,gBAAgB,KAAK,WAAY;AAC1C,OAAK,eAAe,kBAAkB;AACpC,QAAK,gBAAgB,KAAK,eAAe,KAAK,KAAK,cAAc;AACjE,QAAK,QAAQ;KACZ,IAAI;;CAGT,AAAQ,cAAc;AACpB,MAAI,CAAC,KAAK,aAAc;AACxB,gBAAc,KAAK,aAAa;AAChC,OAAK,eAAe;;CAGtB,AAAQ,SAAS;EACf,MAAM,EAAE,OAAO,MAAM,SAAS,WAAW,KAAK,iBAAiB;EAE/D,MAAM,QAAQ,KAAK,cAAc,KAAK;EACtC,MAAM,QAAkB,EAAE;EAE1B,MAAM,SAAS,SAAS;EACxB,MAAM,gBAAgB,iBAAiB,KAAK,GAAG;EAC/C,MAAM,UAAoB,EAAE;AAC5B,MAAI,UAAU,EAAG,SAAQ,KAAK,OAAO,UAAU;AAC/C,MAAI,SAAS,EAAG,SAAQ,KAAK,SAAS,WAAW,UAAU,WAAW,IAAI,CAAC;EAE3E,MAAM,SAAS,QAAQ,SAAS,IAAI,KAAK,QAAQ,KAAK,KAAK,CAAC,KAAK;AAEjE,MAAI,OACF,OAAM,KACJ,GAAG,KAAK,OAAO,GAAG,SAAS,KAAK,WAAW,MAAM,CAAC,WAAW,gBAAgB,SAC9E;MAED,OAAM,KACJ,GAAG,KAAK,OAAO,GAAG,SAAS,OAAO,WAAW,KAAK,CAAC,YAAY,gBAAgB,SAChF;EAGH,MAAM,eAAe,MAAM,KAAK,KAAK;AACrC,MAAI,iBAAiB,KAAK,kBACxB;AAEF,OAAK,oBAAoB;AAEzB,MAAI,KAAK,gBAAgB,EACvB,SAAQ,OAAO,MAAM,QAAQ,KAAK,cAAc,GAAG;EAGrD,MAAM,oBAAoB,KAAK,IAAI,KAAK,eAAe,MAAM,OAAO;AACpE,OAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,KAAK;AAC1C,WAAQ,OAAO,MAAM,UAAU;GAC/B,MAAM,OAAO,MAAM;AACnB,OAAI,SAAS,OACX,SAAQ,OAAO,MAAM,KAAK;AAE5B,WAAQ,OAAO,MAAM,KAAK;;AAG5B,OAAK,gBAAgB,MAAM;;CAG7B,AAAQ,kBAAkB;EACxB,MAAM,OAAO,IAAI,IAAI,KAAK,SAAS,KAAK,MAAM,EAAE,cAAc,CAAC;EAE/D,MAAM,UAAU,IAAI,IAAgC;GAClD;GACA;GACA;GACA;GACA;GACA;GACA;GACD,CAAU;EAEX,MAAM,eAAe,IAAI,IAAsB;GAC7C;GACA;GACA;GACA;GACA;GACA;GACD,CAAU;EAEX,MAAM,OAAO,KAAK,SAAS,QAAQ,MACjC,QAAQ,IAAI,EAAE,OAAc,CAC7B,CAAC;EACF,MAAM,UAAU,KAAK,SAAS,QAAQ,MACpC,aAAa,IAAI,EAAE,OAAc,CAClC,CAAC;EACF,MAAM,SAAS,KAAK,SAAS,QAAQ,MAAM,EAAE,WAAW,QAAQ,CAAC;AAEjE,SAAO;GACL,OAAO,KAAK;GACZ;GACA;GACA;GACD"}
1
+ {"version":3,"file":"pullLog.mjs","names":[],"sources":["../../../src/push/pullLog.ts"],"sourcesContent":["import type { DictionaryStatus } from '@intlayer/chokidar/build';\nimport { ANSIColors, colorize, spinnerFrames } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\n\nexport type PullStatus = {\n dictionaryKey: string;\n status: DictionaryStatus | 'pending' | 'fetching';\n errorMessage?: string;\n};\n\nexport class PullLogger {\n private statuses: PullStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n\n constructor() {\n const configuration = getConfiguration();\n this.prefix = configuration.log.prefix;\n }\n\n update(newStatuses: PullStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) => s.dictionaryKey === status.dictionaryKey\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n private render() {\n const { total, done, success, errors } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const lines: string[] = [];\n\n const isDone = done === total;\n const progressLabel = `dictionaries: ${done}/${total}`;\n const details: string[] = [];\n if (success > 0) details.push(`ok: ${success}`);\n if (errors > 0) details.push(colorize(`errors: ${errors}`, ANSIColors.RED));\n\n const suffix = details.length > 0 ? ` (${details.join(', ')})` : '';\n\n if (isDone) {\n lines.push(\n `${this.prefix} ${colorize('✔', ANSIColors.GREEN)} fetched ${progressLabel}${suffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${colorize(frame, ANSIColors.BLUE)} fetching ${progressLabel}${suffix}`\n );\n }\n\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const keys = new Set(this.statuses.map((s) => s.dictionaryKey));\n\n const doneSet = new Set<DictionaryStatus | 'error'>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n 'error',\n ] as const);\n\n const successesSet = new Set<DictionaryStatus>([\n 'fetched',\n 'imported',\n 'updated',\n 'up-to-date',\n 'reimported in JSON',\n 'new content file',\n ] as const);\n\n const done = this.statuses.filter((s) =>\n doneSet.has(s.status as any)\n ).length;\n const success = this.statuses.filter((s) =>\n successesSet.has(s.status as any)\n ).length;\n const errors = this.statuses.filter((s) => s.status === 'error').length;\n\n return {\n total: keys.size,\n done,\n success,\n errors,\n } as const;\n }\n}\n"],"mappings":"+IAUA,IAAa,EAAb,KAAwB,CACtB,SAAiC,EAAE,CACnC,aAA8C,KAC9C,aAAuB,EACvB,cAAwB,EACxB,cAAiC,EACjC,WAAqB,GACrB,OACA,kBAAoC,GAEpC,aAAc,CAEZ,KAAK,OADiB,GAAkB,CACZ,IAAI,OAGlC,OAAO,EAA2B,CAC5B,SAAK,WACT,KAAK,IAAM,KAAU,EAAa,CAChC,IAAM,EAAQ,KAAK,SAAS,UACzB,GAAM,EAAE,gBAAkB,EAAO,cACnC,CACG,GAAS,EACX,KAAK,SAAS,GAAS,EAEvB,KAAK,SAAS,KAAK,EAAO,CAI9B,KAAK,cAAc,CACnB,KAAK,QAAQ,EAGf,QAAS,CACP,KAAK,WAAa,GAClB,KAAK,aAAa,CAClB,KAAK,QAAQ,CAGf,cAAuB,CACjB,KAAK,cAAgB,KAAK,aAC9B,KAAK,aAAe,gBAAkB,CACpC,KAAK,cAAgB,KAAK,aAAe,GAAK,KAAK,cAAc,OACjE,KAAK,QAAQ,EACZ,IAAI,EAGT,aAAsB,CACf,AAEL,KAAK,gBADL,cAAc,KAAK,aAAa,CACZ,MAGtB,QAAiB,CACf,GAAM,CAAE,QAAO,OAAM,UAAS,UAAW,KAAK,iBAAiB,CAEzD,EAAQ,KAAK,cAAc,KAAK,cAChC,EAAkB,EAAE,CAEpB,EAAS,IAAS,EAClB,EAAgB,iBAAiB,EAAK,GAAG,IACzC,EAAoB,EAAE,CACxB,EAAU,GAAG,EAAQ,KAAK,OAAO,IAAU,CAC3C,EAAS,GAAG,EAAQ,KAAK,EAAS,WAAW,IAAU,EAAW,IAAI,CAAC,CAE3E,IAAM,EAAS,EAAQ,OAAS,EAAI,KAAK,EAAQ,KAAK,KAAK,CAAC,GAAK,GAE7D,EACF,EAAM,KACJ,GAAG,KAAK,OAAO,GAAG,EAAS,IAAK,EAAW,MAAM,CAAC,WAAW,IAAgB,IAC9E,CAED,EAAM,KACJ,GAAG,KAAK,OAAO,GAAG,EAAS,EAAO,EAAW,KAAK,CAAC,YAAY,IAAgB,IAChF,CAGH,IAAM,EAAe,EAAM,KAAK;EAAK,CACrC,GAAI,IAAiB,KAAK,kBACxB,OAEF,KAAK,kBAAoB,EAErB,KAAK,cAAgB,GACvB,QAAQ,OAAO,MAAM,QAAQ,KAAK,cAAc,GAAG,CAGrD,IAAM,EAAoB,KAAK,IAAI,KAAK,cAAe,EAAM,OAAO,CACpE,IAAK,IAAI,EAAI,EAAG,EAAI,EAAmB,IAAK,CAC1C,QAAQ,OAAO,MAAM,UAAU,CAC/B,IAAM,EAAO,EAAM,GACf,IAAS,IAAA,IACX,QAAQ,OAAO,MAAM,EAAK,CAE5B,QAAQ,OAAO,MAAM;EAAK,CAG5B,KAAK,cAAgB,EAAM,OAG7B,iBAA0B,CACxB,IAAM,EAAO,IAAI,IAAI,KAAK,SAAS,IAAK,GAAM,EAAE,cAAc,CAAC,CAEzD,EAAU,IAAI,IAAgC,CAClD,UACA,WACA,UACA,aACA,qBACA,mBACA,QACD,CAAU,CAEL,EAAe,IAAI,IAAsB,CAC7C,UACA,WACA,UACA,aACA,qBACA,mBACD,CAAU,CAEL,EAAO,KAAK,SAAS,OAAQ,GACjC,EAAQ,IAAI,EAAE,OAAc,CAC7B,CAAC,OACI,EAAU,KAAK,SAAS,OAAQ,GACpC,EAAa,IAAI,EAAE,OAAc,CAClC,CAAC,OACI,EAAS,KAAK,SAAS,OAAQ,GAAM,EAAE,SAAW,QAAQ,CAAC,OAEjE,MAAO,CACL,MAAO,EAAK,KACZ,OACA,UACA,SACD"}