synapse-mcp 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (413) hide show
  1. package/README.md +1820 -147
  2. package/dist/constants.d.ts +10 -4
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +18 -8
  5. package/dist/constants.js.map +1 -1
  6. package/dist/events/emitter.d.ts +63 -0
  7. package/dist/events/emitter.d.ts.map +1 -0
  8. package/dist/events/emitter.js +112 -0
  9. package/dist/events/emitter.js.map +1 -0
  10. package/dist/events/index.d.ts +3 -0
  11. package/dist/events/index.d.ts.map +1 -0
  12. package/dist/events/index.js +3 -0
  13. package/dist/events/index.js.map +1 -0
  14. package/dist/events/types.d.ts +51 -0
  15. package/dist/events/types.d.ts.map +1 -0
  16. package/dist/events/types.js +3 -0
  17. package/dist/events/types.js.map +1 -0
  18. package/dist/formatters/compose.d.ts +185 -0
  19. package/dist/formatters/compose.d.ts.map +1 -0
  20. package/dist/formatters/compose.js +397 -0
  21. package/dist/formatters/compose.js.map +1 -0
  22. package/dist/formatters/container.d.ts +84 -0
  23. package/dist/formatters/container.d.ts.map +1 -0
  24. package/dist/formatters/container.js +323 -0
  25. package/dist/formatters/container.js.map +1 -0
  26. package/dist/formatters/diagnostics.d.ts +20 -0
  27. package/dist/formatters/diagnostics.d.ts.map +1 -0
  28. package/dist/formatters/diagnostics.js +73 -0
  29. package/dist/formatters/diagnostics.js.map +1 -0
  30. package/dist/formatters/docker.d.ts +139 -0
  31. package/dist/formatters/docker.d.ts.map +1 -0
  32. package/dist/formatters/docker.js +216 -0
  33. package/dist/formatters/docker.js.map +1 -0
  34. package/dist/formatters/host.d.ts +137 -0
  35. package/dist/formatters/host.d.ts.map +1 -0
  36. package/dist/formatters/host.js +198 -0
  37. package/dist/formatters/host.js.map +1 -0
  38. package/dist/formatters/index.d.ts +17 -270
  39. package/dist/formatters/index.d.ts.map +1 -1
  40. package/dist/formatters/index.js +21 -456
  41. package/dist/formatters/index.js.map +1 -1
  42. package/dist/formatters/scout.d.ts +424 -0
  43. package/dist/formatters/scout.d.ts.map +1 -0
  44. package/dist/formatters/scout.js +687 -0
  45. package/dist/formatters/scout.js.map +1 -0
  46. package/dist/formatters/strategy.d.ts +105 -0
  47. package/dist/formatters/strategy.d.ts.map +1 -0
  48. package/dist/formatters/strategy.js +120 -0
  49. package/dist/formatters/strategy.js.map +1 -0
  50. package/dist/formatters/utils.d.ts +84 -0
  51. package/dist/formatters/utils.d.ts.map +1 -0
  52. package/dist/formatters/utils.js +129 -0
  53. package/dist/formatters/utils.js.map +1 -0
  54. package/dist/health-rate-limiter.d.ts +59 -0
  55. package/dist/health-rate-limiter.d.ts.map +1 -0
  56. package/dist/health-rate-limiter.js +159 -0
  57. package/dist/health-rate-limiter.js.map +1 -0
  58. package/dist/index.js +61 -100
  59. package/dist/index.js.map +1 -1
  60. package/dist/middleware/async-handler.d.ts +62 -0
  61. package/dist/middleware/async-handler.d.ts.map +1 -0
  62. package/dist/middleware/async-handler.js +58 -0
  63. package/dist/middleware/async-handler.js.map +1 -0
  64. package/dist/middleware/auth.d.ts +32 -0
  65. package/dist/middleware/auth.d.ts.map +1 -0
  66. package/dist/middleware/auth.js +63 -0
  67. package/dist/middleware/auth.js.map +1 -0
  68. package/dist/middleware/csrf-protection.d.ts +58 -0
  69. package/dist/middleware/csrf-protection.d.ts.map +1 -0
  70. package/dist/middleware/csrf-protection.js +123 -0
  71. package/dist/middleware/csrf-protection.js.map +1 -0
  72. package/dist/middleware/error-handler.d.ts +49 -0
  73. package/dist/middleware/error-handler.d.ts.map +1 -0
  74. package/dist/middleware/error-handler.js +90 -0
  75. package/dist/middleware/error-handler.js.map +1 -0
  76. package/dist/middleware/error-mapper.d.ts +44 -0
  77. package/dist/middleware/error-mapper.d.ts.map +1 -0
  78. package/dist/middleware/error-mapper.js +127 -0
  79. package/dist/middleware/error-mapper.js.map +1 -0
  80. package/dist/middleware/index.d.ts +13 -0
  81. package/dist/middleware/index.d.ts.map +1 -0
  82. package/dist/middleware/index.js +13 -0
  83. package/dist/middleware/index.js.map +1 -0
  84. package/dist/middleware/request-id.d.ts +22 -0
  85. package/dist/middleware/request-id.d.ts.map +1 -0
  86. package/dist/middleware/request-id.js +31 -0
  87. package/dist/middleware/request-id.js.map +1 -0
  88. package/dist/middleware/types.d.ts +33 -0
  89. package/dist/middleware/types.d.ts.map +1 -0
  90. package/dist/middleware/types.js +2 -0
  91. package/dist/middleware/types.js.map +1 -0
  92. package/dist/schemas/common.d.ts +205 -8
  93. package/dist/schemas/common.d.ts.map +1 -1
  94. package/dist/schemas/common.js +290 -17
  95. package/dist/schemas/common.js.map +1 -1
  96. package/dist/schemas/flux/compose.d.ts +307 -44
  97. package/dist/schemas/flux/compose.d.ts.map +1 -1
  98. package/dist/schemas/flux/compose.js +74 -48
  99. package/dist/schemas/flux/compose.js.map +1 -1
  100. package/dist/schemas/flux/container.d.ts +423 -56
  101. package/dist/schemas/flux/container.d.ts.map +1 -1
  102. package/dist/schemas/flux/container.js +83 -61
  103. package/dist/schemas/flux/container.js.map +1 -1
  104. package/dist/schemas/flux/docker.d.ts +254 -37
  105. package/dist/schemas/flux/docker.d.ts.map +1 -1
  106. package/dist/schemas/flux/docker.js +69 -39
  107. package/dist/schemas/flux/docker.js.map +1 -1
  108. package/dist/schemas/flux/host.d.ts +312 -29
  109. package/dist/schemas/flux/host.d.ts.map +1 -1
  110. package/dist/schemas/flux/host.js +74 -31
  111. package/dist/schemas/flux/host.js.map +1 -1
  112. package/dist/schemas/flux/index.d.ts +503 -11
  113. package/dist/schemas/flux/index.d.ts.map +1 -1
  114. package/dist/schemas/flux/index.js +34 -70
  115. package/dist/schemas/flux/index.js.map +1 -1
  116. package/dist/schemas/host-config.d.ts +76 -0
  117. package/dist/schemas/host-config.d.ts.map +1 -0
  118. package/dist/schemas/host-config.js +105 -0
  119. package/dist/schemas/host-config.js.map +1 -0
  120. package/dist/schemas/scout/index.d.ts +80 -23
  121. package/dist/schemas/scout/index.d.ts.map +1 -1
  122. package/dist/schemas/scout/index.js +26 -11
  123. package/dist/schemas/scout/index.js.map +1 -1
  124. package/dist/schemas/scout/logs.d.ts +17 -5
  125. package/dist/schemas/scout/logs.d.ts.map +1 -1
  126. package/dist/schemas/scout/logs.js +41 -31
  127. package/dist/schemas/scout/logs.js.map +1 -1
  128. package/dist/schemas/scout/simple.d.ts +126 -11
  129. package/dist/schemas/scout/simple.d.ts.map +1 -1
  130. package/dist/schemas/scout/simple.js +112 -57
  131. package/dist/schemas/scout/simple.js.map +1 -1
  132. package/dist/schemas/scout/zfs.d.ts +17 -5
  133. package/dist/schemas/scout/zfs.d.ts.map +1 -1
  134. package/dist/schemas/scout/zfs.js +34 -25
  135. package/dist/schemas/scout/zfs.js.map +1 -1
  136. package/dist/services/cache-layer.d.ts +160 -0
  137. package/dist/services/cache-layer.d.ts.map +1 -0
  138. package/dist/services/cache-layer.js +138 -0
  139. package/dist/services/cache-layer.js.map +1 -0
  140. package/dist/services/compose-cache.d.ts +75 -0
  141. package/dist/services/compose-cache.d.ts.map +1 -0
  142. package/dist/services/compose-cache.js +178 -0
  143. package/dist/services/compose-cache.js.map +1 -0
  144. package/dist/services/compose-discovery.d.ts +46 -0
  145. package/dist/services/compose-discovery.d.ts.map +1 -0
  146. package/dist/services/compose-discovery.js +219 -0
  147. package/dist/services/compose-discovery.js.map +1 -0
  148. package/dist/services/compose-project-lister.d.ts +27 -0
  149. package/dist/services/compose-project-lister.d.ts.map +1 -0
  150. package/dist/services/compose-project-lister.js +71 -0
  151. package/dist/services/compose-project-lister.js.map +1 -0
  152. package/dist/services/compose-scanner.d.ts +63 -0
  153. package/dist/services/compose-scanner.d.ts.map +1 -0
  154. package/dist/services/compose-scanner.js +253 -0
  155. package/dist/services/compose-scanner.js.map +1 -0
  156. package/dist/services/compose.d.ts +64 -28
  157. package/dist/services/compose.d.ts.map +1 -1
  158. package/dist/services/compose.js +220 -98
  159. package/dist/services/compose.js.map +1 -1
  160. package/dist/services/config-loader.d.ts +23 -0
  161. package/dist/services/config-loader.d.ts.map +1 -0
  162. package/dist/services/config-loader.js +124 -0
  163. package/dist/services/config-loader.js.map +1 -0
  164. package/dist/services/config-service.d.ts +38 -0
  165. package/dist/services/config-service.d.ts.map +1 -0
  166. package/dist/services/config-service.js +225 -0
  167. package/dist/services/config-service.js.map +1 -0
  168. package/dist/services/container-host-map-cache.d.ts +121 -0
  169. package/dist/services/container-host-map-cache.d.ts.map +1 -0
  170. package/dist/services/container-host-map-cache.js +188 -0
  171. package/dist/services/container-host-map-cache.js.map +1 -0
  172. package/dist/services/container.d.ts +194 -6
  173. package/dist/services/container.d.ts.map +1 -1
  174. package/dist/services/container.js +386 -11
  175. package/dist/services/container.js.map +1 -1
  176. package/dist/services/diagnostics.d.ts +57 -0
  177. package/dist/services/diagnostics.d.ts.map +1 -0
  178. package/dist/services/diagnostics.js +271 -0
  179. package/dist/services/diagnostics.js.map +1 -0
  180. package/dist/services/docker/container-service.d.ts +123 -0
  181. package/dist/services/docker/container-service.d.ts.map +1 -0
  182. package/dist/services/docker/container-service.js +347 -0
  183. package/dist/services/docker/container-service.js.map +1 -0
  184. package/dist/services/docker/image-service.d.ts +82 -0
  185. package/dist/services/docker/image-service.d.ts.map +1 -0
  186. package/dist/services/docker/image-service.js +193 -0
  187. package/dist/services/docker/image-service.js.map +1 -0
  188. package/dist/services/docker/index.d.ts +80 -0
  189. package/dist/services/docker/index.d.ts.map +1 -0
  190. package/dist/services/docker/index.js +103 -0
  191. package/dist/services/docker/index.js.map +1 -0
  192. package/dist/services/docker/network-service.d.ts +22 -0
  193. package/dist/services/docker/network-service.d.ts.map +1 -0
  194. package/dist/services/docker/network-service.js +43 -0
  195. package/dist/services/docker/network-service.js.map +1 -0
  196. package/dist/services/docker/system-service.d.ts +49 -0
  197. package/dist/services/docker/system-service.d.ts.map +1 -0
  198. package/dist/services/docker/system-service.js +215 -0
  199. package/dist/services/docker/system-service.js.map +1 -0
  200. package/dist/services/docker/utils/client-factory.d.ts +56 -0
  201. package/dist/services/docker/utils/client-factory.d.ts.map +1 -0
  202. package/dist/services/docker/utils/client-factory.js +139 -0
  203. package/dist/services/docker/utils/client-factory.js.map +1 -0
  204. package/dist/services/docker/utils/client-manager.d.ts +88 -0
  205. package/dist/services/docker/utils/client-manager.d.ts.map +1 -0
  206. package/dist/services/docker/utils/client-manager.js +124 -0
  207. package/dist/services/docker/utils/client-manager.js.map +1 -0
  208. package/dist/services/docker/utils/exec-handler.d.ts +94 -0
  209. package/dist/services/docker/utils/exec-handler.d.ts.map +1 -0
  210. package/dist/services/docker/utils/exec-handler.js +197 -0
  211. package/dist/services/docker/utils/exec-handler.js.map +1 -0
  212. package/dist/services/docker/utils/formatters.d.ts +13 -0
  213. package/dist/services/docker/utils/formatters.d.ts.map +1 -0
  214. package/dist/services/docker/utils/formatters.js +33 -0
  215. package/dist/services/docker/utils/formatters.js.map +1 -0
  216. package/dist/services/docker/utils/log-parser.d.ts +10 -0
  217. package/dist/services/docker/utils/log-parser.d.ts.map +1 -0
  218. package/dist/services/docker/utils/log-parser.js +48 -0
  219. package/dist/services/docker/utils/log-parser.js.map +1 -0
  220. package/dist/services/docker/utils/stats-calculator.d.ts +68 -0
  221. package/dist/services/docker/utils/stats-calculator.d.ts.map +1 -0
  222. package/dist/services/docker/utils/stats-calculator.js +61 -0
  223. package/dist/services/docker/utils/stats-calculator.js.map +1 -0
  224. package/dist/services/docker/volume-service.d.ts +22 -0
  225. package/dist/services/docker/volume-service.d.ts.map +1 -0
  226. package/dist/services/docker/volume-service.js +48 -0
  227. package/dist/services/docker/volume-service.js.map +1 -0
  228. package/dist/services/docker-interfaces.d.ts +283 -0
  229. package/dist/services/docker-interfaces.d.ts.map +1 -0
  230. package/dist/services/docker-interfaces.js +13 -0
  231. package/dist/services/docker-interfaces.js.map +1 -0
  232. package/dist/services/docker.d.ts +42 -5
  233. package/dist/services/docker.d.ts.map +1 -1
  234. package/dist/services/docker.js +335 -127
  235. package/dist/services/docker.js.map +1 -1
  236. package/dist/services/file-service.d.ts +6 -2
  237. package/dist/services/file-service.d.ts.map +1 -1
  238. package/dist/services/file-service.js +156 -52
  239. package/dist/services/file-service.js.map +1 -1
  240. package/dist/services/host-config-repository.d.ts +133 -0
  241. package/dist/services/host-config-repository.d.ts.map +1 -0
  242. package/dist/services/host-config-repository.js +323 -0
  243. package/dist/services/host-config-repository.js.map +1 -0
  244. package/dist/services/host-resolver.d.ts +49 -0
  245. package/dist/services/host-resolver.d.ts.map +1 -0
  246. package/dist/services/host-resolver.js +176 -0
  247. package/dist/services/host-resolver.js.map +1 -0
  248. package/dist/services/interfaces.d.ts +61 -194
  249. package/dist/services/interfaces.d.ts.map +1 -1
  250. package/dist/services/local-executor.d.ts +31 -0
  251. package/dist/services/local-executor.d.ts.map +1 -0
  252. package/dist/services/local-executor.js +71 -0
  253. package/dist/services/local-executor.js.map +1 -0
  254. package/dist/services/ssh-config-loader.d.ts +35 -0
  255. package/dist/services/ssh-config-loader.d.ts.map +1 -0
  256. package/dist/services/ssh-config-loader.js +218 -0
  257. package/dist/services/ssh-config-loader.js.map +1 -0
  258. package/dist/services/ssh-pool.d.ts +26 -1
  259. package/dist/services/ssh-pool.d.ts.map +1 -1
  260. package/dist/services/ssh-pool.js +166 -25
  261. package/dist/services/ssh-pool.js.map +1 -1
  262. package/dist/services/ssh-service.d.ts +3 -0
  263. package/dist/services/ssh-service.d.ts.map +1 -1
  264. package/dist/services/ssh-service.js +53 -31
  265. package/dist/services/ssh-service.js.map +1 -1
  266. package/dist/services/ssh.d.ts +2 -6
  267. package/dist/services/ssh.d.ts.map +1 -1
  268. package/dist/services/ssh.js +9 -40
  269. package/dist/services/ssh.js.map +1 -1
  270. package/dist/tools/definitions/flux.d.ts +13 -0
  271. package/dist/tools/definitions/flux.d.ts.map +1 -0
  272. package/dist/tools/definitions/flux.js +101 -0
  273. package/dist/tools/definitions/flux.js.map +1 -0
  274. package/dist/tools/definitions/index.d.ts +8 -0
  275. package/dist/tools/definitions/index.d.ts.map +1 -0
  276. package/dist/tools/definitions/index.js +8 -0
  277. package/dist/tools/definitions/index.js.map +1 -0
  278. package/dist/tools/definitions/scout.d.ts +13 -0
  279. package/dist/tools/definitions/scout.d.ts.map +1 -0
  280. package/dist/tools/definitions/scout.js +78 -0
  281. package/dist/tools/definitions/scout.js.map +1 -0
  282. package/dist/tools/flux.d.ts +16 -8
  283. package/dist/tools/flux.d.ts.map +1 -1
  284. package/dist/tools/flux.js +27 -66
  285. package/dist/tools/flux.js.map +1 -1
  286. package/dist/tools/handlers/base-handler.d.ts +172 -0
  287. package/dist/tools/handlers/base-handler.d.ts.map +1 -0
  288. package/dist/tools/handlers/base-handler.js +234 -0
  289. package/dist/tools/handlers/base-handler.js.map +1 -0
  290. package/dist/tools/handlers/compose-handlers.d.ts +108 -0
  291. package/dist/tools/handlers/compose-handlers.d.ts.map +1 -0
  292. package/dist/tools/handlers/compose-handlers.js +293 -0
  293. package/dist/tools/handlers/compose-handlers.js.map +1 -0
  294. package/dist/tools/handlers/compose-utils.d.ts +35 -0
  295. package/dist/tools/handlers/compose-utils.d.ts.map +1 -0
  296. package/dist/tools/handlers/compose-utils.js +76 -0
  297. package/dist/tools/handlers/compose-utils.js.map +1 -0
  298. package/dist/tools/handlers/compose.d.ts +23 -0
  299. package/dist/tools/handlers/compose.d.ts.map +1 -0
  300. package/dist/tools/handlers/compose.js +125 -0
  301. package/dist/tools/handlers/compose.js.map +1 -0
  302. package/dist/tools/handlers/container.d.ts +23 -0
  303. package/dist/tools/handlers/container.d.ts.map +1 -0
  304. package/dist/tools/handlers/container.js +333 -0
  305. package/dist/tools/handlers/container.js.map +1 -0
  306. package/dist/tools/handlers/docker.d.ts +24 -0
  307. package/dist/tools/handlers/docker.d.ts.map +1 -0
  308. package/dist/tools/handlers/docker.js +155 -0
  309. package/dist/tools/handlers/docker.js.map +1 -0
  310. package/dist/tools/handlers/host.d.ts +23 -0
  311. package/dist/tools/handlers/host.d.ts.map +1 -0
  312. package/dist/tools/handlers/host.js +196 -0
  313. package/dist/tools/handlers/host.js.map +1 -0
  314. package/dist/tools/handlers/scout-logs.d.ts +24 -0
  315. package/dist/tools/handlers/scout-logs.d.ts.map +1 -0
  316. package/dist/tools/handlers/scout-logs.js +119 -0
  317. package/dist/tools/handlers/scout-logs.js.map +1 -0
  318. package/dist/tools/handlers/scout-simple.d.ts +23 -0
  319. package/dist/tools/handlers/scout-simple.d.ts.map +1 -0
  320. package/dist/tools/handlers/scout-simple.js +286 -0
  321. package/dist/tools/handlers/scout-simple.js.map +1 -0
  322. package/dist/tools/handlers/scout-zfs.d.ts +23 -0
  323. package/dist/tools/handlers/scout-zfs.d.ts.map +1 -0
  324. package/dist/tools/handlers/scout-zfs.js +82 -0
  325. package/dist/tools/handlers/scout-zfs.js.map +1 -0
  326. package/dist/tools/index.d.ts +32 -2
  327. package/dist/tools/index.d.ts.map +1 -1
  328. package/dist/tools/index.js +41 -35
  329. package/dist/tools/index.js.map +1 -1
  330. package/dist/tools/registry.d.ts +135 -0
  331. package/dist/tools/registry.d.ts.map +1 -0
  332. package/dist/tools/registry.js +151 -0
  333. package/dist/tools/registry.js.map +1 -0
  334. package/dist/tools/scout.d.ts +16 -8
  335. package/dist/tools/scout.d.ts.map +1 -1
  336. package/dist/tools/scout.js +36 -78
  337. package/dist/tools/scout.js.map +1 -1
  338. package/dist/types.d.ts +629 -1
  339. package/dist/types.d.ts.map +1 -1
  340. package/dist/types.js.map +1 -1
  341. package/dist/utils/command-security.d.ts +82 -0
  342. package/dist/utils/command-security.d.ts.map +1 -0
  343. package/dist/utils/command-security.js +122 -0
  344. package/dist/utils/command-security.js.map +1 -0
  345. package/dist/utils/error-sanitization.d.ts +77 -0
  346. package/dist/utils/error-sanitization.d.ts.map +1 -0
  347. package/dist/utils/error-sanitization.js +107 -0
  348. package/dist/utils/error-sanitization.js.map +1 -0
  349. package/dist/utils/errors.d.ts +30 -6
  350. package/dist/utils/errors.d.ts.map +1 -1
  351. package/dist/utils/errors.js +91 -12
  352. package/dist/utils/errors.js.map +1 -1
  353. package/dist/utils/help-handler.d.ts +23 -0
  354. package/dist/utils/help-handler.d.ts.map +1 -0
  355. package/dist/utils/help-handler.js +21 -0
  356. package/dist/utils/help-handler.js.map +1 -0
  357. package/dist/utils/help.d.ts +1 -1
  358. package/dist/utils/help.d.ts.map +1 -1
  359. package/dist/utils/help.js +57 -16
  360. package/dist/utils/help.js.map +1 -1
  361. package/dist/utils/host-utils.d.ts +31 -0
  362. package/dist/utils/host-utils.d.ts.map +1 -0
  363. package/dist/utils/host-utils.js +80 -0
  364. package/dist/utils/host-utils.js.map +1 -0
  365. package/dist/utils/index.d.ts +8 -2
  366. package/dist/utils/index.d.ts.map +1 -1
  367. package/dist/utils/index.js +8 -2
  368. package/dist/utils/index.js.map +1 -1
  369. package/dist/utils/init-detection.d.ts +36 -0
  370. package/dist/utils/init-detection.d.ts.map +1 -0
  371. package/dist/utils/init-detection.js +79 -0
  372. package/dist/utils/init-detection.js.map +1 -0
  373. package/dist/utils/logger.d.ts +11 -0
  374. package/dist/utils/logger.d.ts.map +1 -0
  375. package/dist/utils/logger.js +32 -0
  376. package/dist/utils/logger.js.map +1 -0
  377. package/dist/utils/pagination.d.ts +20 -0
  378. package/dist/utils/pagination.d.ts.map +1 -0
  379. package/dist/utils/pagination.js +29 -0
  380. package/dist/utils/pagination.js.map +1 -0
  381. package/dist/utils/path-security.d.ts +132 -18
  382. package/dist/utils/path-security.d.ts.map +1 -1
  383. package/dist/utils/path-security.js +164 -35
  384. package/dist/utils/path-security.js.map +1 -1
  385. package/dist/utils/sorting.d.ts +33 -0
  386. package/dist/utils/sorting.d.ts.map +1 -0
  387. package/dist/utils/sorting.js +57 -0
  388. package/dist/utils/sorting.js.map +1 -0
  389. package/dist/utils/text-filters.d.ts +13 -0
  390. package/dist/utils/text-filters.d.ts.map +1 -0
  391. package/dist/utils/text-filters.js +18 -0
  392. package/dist/utils/text-filters.js.map +1 -0
  393. package/dist/utils/time.d.ts +11 -0
  394. package/dist/utils/time.d.ts.map +1 -0
  395. package/dist/utils/time.js +13 -0
  396. package/dist/utils/time.js.map +1 -0
  397. package/dist/utils/validation.d.ts +25 -0
  398. package/dist/utils/validation.d.ts.map +1 -0
  399. package/dist/utils/validation.js +56 -0
  400. package/dist/utils/validation.js.map +1 -0
  401. package/package.json +45 -19
  402. package/dist/schemas/discriminator.d.ts +0 -20
  403. package/dist/schemas/discriminator.d.ts.map +0 -1
  404. package/dist/schemas/discriminator.js +0 -25
  405. package/dist/schemas/discriminator.js.map +0 -1
  406. package/dist/schemas/unified.d.ts +0 -674
  407. package/dist/schemas/unified.d.ts.map +0 -1
  408. package/dist/schemas/unified.js +0 -453
  409. package/dist/schemas/unified.js.map +0 -1
  410. package/dist/tools/unified.d.ts +0 -7
  411. package/dist/tools/unified.d.ts.map +0 -1
  412. package/dist/tools/unified.js +0 -827
  413. package/dist/tools/unified.js.map +0 -1
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Cache statistics tracking cache performance and resource usage.
3
+ * Used by ICacheLayer implementations to report operational metrics.
4
+ */
5
+ export interface CacheStats {
6
+ /**
7
+ * Number of successful cache lookups (key found).
8
+ */
9
+ hits: number;
10
+ /**
11
+ * Number of failed cache lookups (key not found).
12
+ */
13
+ misses: number;
14
+ /**
15
+ * Current number of entries stored in the cache.
16
+ */
17
+ size: number;
18
+ /**
19
+ * Maximum number of entries the cache can hold before eviction occurs.
20
+ */
21
+ maxSize: number;
22
+ /**
23
+ * Total number of entries that have been evicted due to capacity limits.
24
+ */
25
+ evictions: number;
26
+ }
27
+ /**
28
+ * Generic cache layer interface providing key-value storage with eviction policies.
29
+ * Implementations should handle storage, retrieval, and automatic eviction when capacity is reached.
30
+ *
31
+ * @template K - Type of cache keys (must be comparable for lookups)
32
+ * @template V - Type of cached values
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // Create a cache for host configurations
37
+ * const cache: ICacheLayer<string, HostConfig> = new LRUCacheLayer(100);
38
+ *
39
+ * // Store a value
40
+ * cache.set('prod-host', hostConfig);
41
+ *
42
+ * // Retrieve a value
43
+ * const config = cache.get('prod-host');
44
+ *
45
+ * // Check cache performance
46
+ * const stats = cache.getStats();
47
+ * console.log(`Hit rate: ${stats.hits / (stats.hits + stats.misses)}`);
48
+ * ```
49
+ */
50
+ export interface ICacheLayer<K, V> {
51
+ /**
52
+ * Retrieve a value from the cache by its key.
53
+ * Updates access tracking for eviction policy (e.g., LRU tracking).
54
+ *
55
+ * @param key - The cache key to lookup
56
+ * @returns The cached value if found, undefined if not in cache
57
+ */
58
+ get(key: K): V | undefined;
59
+ /**
60
+ * Store a value in the cache with the specified key.
61
+ * If the cache is at capacity, evicts entries according to the eviction policy.
62
+ * If the key already exists, updates the value and resets access tracking.
63
+ *
64
+ * @param key - The cache key to store under
65
+ * @param value - The value to cache
66
+ */
67
+ set(key: K, value: V): void;
68
+ /**
69
+ * Remove a specific entry from the cache by its key.
70
+ * Does nothing if the key is not in the cache.
71
+ *
72
+ * @param key - The cache key to remove
73
+ */
74
+ delete(key: K): void;
75
+ /**
76
+ * Remove all entries from the cache and reset statistics.
77
+ * Resets the cache to its initial empty state.
78
+ */
79
+ clear(): void;
80
+ /**
81
+ * Get current cache statistics for monitoring and debugging.
82
+ * Statistics should reflect the current state of the cache accurately.
83
+ *
84
+ * @returns Cache statistics including hits, misses, size, capacity, and evictions
85
+ */
86
+ getStats(): CacheStats;
87
+ }
88
+ /**
89
+ * Least Recently Used (LRU) cache implementation with TTL support.
90
+ * Evicts the least recently accessed item when cache reaches max capacity.
91
+ * Uses Map for O(1) lookups and leverages insertion order for LRU tracking.
92
+ *
93
+ * @template K - Type of cache keys (must be comparable for Map lookups)
94
+ * @template V - Type of cached values
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // Create cache with 100 max entries and 1 hour TTL
99
+ * const cache = new LRUCacheLayer<string, UserData>(100, 3600000);
100
+ *
101
+ * // Store and retrieve
102
+ * cache.set('user-123', userData);
103
+ * const data = cache.get('user-123');
104
+ *
105
+ * // Monitor performance
106
+ * const stats = cache.getStats();
107
+ * console.log(`Hit rate: ${stats.hits / (stats.hits + stats.misses)}`);
108
+ * ```
109
+ */
110
+ export declare class LRUCacheLayer<K, V> implements ICacheLayer<K, V> {
111
+ private readonly cache;
112
+ private readonly maxSize;
113
+ private readonly ttlMs;
114
+ private stats;
115
+ /**
116
+ * Create a new LRU cache layer.
117
+ *
118
+ * @param maxSize - Maximum number of entries (default: 50)
119
+ * @param ttlMs - Time-to-live in milliseconds (default: 24 hours)
120
+ */
121
+ constructor(maxSize?: number, ttlMs?: number);
122
+ /**
123
+ * Retrieve a value from the cache by its key.
124
+ * Moves the accessed entry to the end of the Map (marks as most recently used).
125
+ * Returns undefined if key doesn't exist or entry has expired.
126
+ *
127
+ * @param key - The cache key to lookup
128
+ * @returns The cached value if found and not expired, undefined otherwise
129
+ */
130
+ get(key: K): V | undefined;
131
+ /**
132
+ * Store a value in the cache with the specified key.
133
+ * If key exists, updates value and moves to end (most recently used).
134
+ * If cache is full, evicts the least recently used entry first.
135
+ *
136
+ * @param key - The cache key to store under
137
+ * @param value - The value to cache
138
+ */
139
+ set(key: K, value: V): void;
140
+ /**
141
+ * Remove a specific entry from the cache by its key.
142
+ * Does nothing if the key is not in the cache.
143
+ *
144
+ * @param key - The cache key to remove
145
+ */
146
+ delete(key: K): void;
147
+ /**
148
+ * Remove all entries from the cache and reset statistics.
149
+ * Resets the cache to its initial empty state.
150
+ */
151
+ clear(): void;
152
+ /**
153
+ * Get current cache statistics for monitoring and debugging.
154
+ * Statistics reflect the current state including all tracked metrics.
155
+ *
156
+ * @returns Cache statistics including hits, misses, size, capacity, and evictions
157
+ */
158
+ getStats(): CacheStats;
159
+ }
160
+ //# sourceMappingURL=cache-layer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-layer.d.ts","sourceRoot":"","sources":["../../src/services/cache-layer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC;IAC/B;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAE3B;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAE5B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IAErB;;;OAGG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;;;;OAKG;IACH,QAAQ,IAAI,UAAU,CAAC;CACxB;AAaD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAa,CAAC,CAAC,EAAE,CAAC,CAAE,YAAW,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,KAAK,CAIX;IAEF;;;;;OAKG;gBACS,OAAO,SAAK,EAAE,KAAK,GAAE,MAA4B;IAW7D;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IA6B1B;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAmB3B;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI;IAIpB;;;OAGG;IACH,KAAK,IAAI,IAAI;IASb;;;;;OAKG;IACH,QAAQ,IAAI,UAAU;CASvB"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Least Recently Used (LRU) cache implementation with TTL support.
3
+ * Evicts the least recently accessed item when cache reaches max capacity.
4
+ * Uses Map for O(1) lookups and leverages insertion order for LRU tracking.
5
+ *
6
+ * @template K - Type of cache keys (must be comparable for Map lookups)
7
+ * @template V - Type of cached values
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // Create cache with 100 max entries and 1 hour TTL
12
+ * const cache = new LRUCacheLayer<string, UserData>(100, 3600000);
13
+ *
14
+ * // Store and retrieve
15
+ * cache.set('user-123', userData);
16
+ * const data = cache.get('user-123');
17
+ *
18
+ * // Monitor performance
19
+ * const stats = cache.getStats();
20
+ * console.log(`Hit rate: ${stats.hits / (stats.hits + stats.misses)}`);
21
+ * ```
22
+ */
23
+ export class LRUCacheLayer {
24
+ cache;
25
+ maxSize;
26
+ ttlMs;
27
+ stats;
28
+ /**
29
+ * Create a new LRU cache layer.
30
+ *
31
+ * @param maxSize - Maximum number of entries (default: 50)
32
+ * @param ttlMs - Time-to-live in milliseconds (default: 24 hours)
33
+ */
34
+ constructor(maxSize = 50, ttlMs = 24 * 60 * 60 * 1000) {
35
+ this.cache = new Map();
36
+ this.maxSize = maxSize;
37
+ this.ttlMs = ttlMs;
38
+ this.stats = {
39
+ hits: 0,
40
+ misses: 0,
41
+ evictions: 0,
42
+ };
43
+ }
44
+ /**
45
+ * Retrieve a value from the cache by its key.
46
+ * Moves the accessed entry to the end of the Map (marks as most recently used).
47
+ * Returns undefined if key doesn't exist or entry has expired.
48
+ *
49
+ * @param key - The cache key to lookup
50
+ * @returns The cached value if found and not expired, undefined otherwise
51
+ */
52
+ get(key) {
53
+ const entry = this.cache.get(key);
54
+ if (!entry) {
55
+ this.stats.misses++;
56
+ return undefined;
57
+ }
58
+ // Check if entry has expired
59
+ const now = Date.now();
60
+ if (now - entry.timestamp > this.ttlMs) {
61
+ // Entry expired - remove it and count as miss
62
+ this.cache.delete(key);
63
+ this.stats.misses++;
64
+ return undefined;
65
+ }
66
+ // Entry is valid - move to end (most recently used)
67
+ // Note: delete-and-reinsert is O(1) but performs 2 Map operations per hit.
68
+ // For higher throughput (>10k ops/sec), consider doubly-linked-list + Map
69
+ // approach (e.g., lru-cache npm package) for O(1) single-operation reordering.
70
+ // Current implementation is sufficient for typical workloads (<1k ops/sec).
71
+ this.cache.delete(key);
72
+ this.cache.set(key, entry);
73
+ this.stats.hits++;
74
+ return entry.value;
75
+ }
76
+ /**
77
+ * Store a value in the cache with the specified key.
78
+ * If key exists, updates value and moves to end (most recently used).
79
+ * If cache is full, evicts the least recently used entry first.
80
+ *
81
+ * @param key - The cache key to store under
82
+ * @param value - The value to cache
83
+ */
84
+ set(key, value) {
85
+ const now = Date.now();
86
+ // If key already exists, delete it first (we'll re-add at end)
87
+ if (this.cache.has(key)) {
88
+ this.cache.delete(key);
89
+ }
90
+ else if (this.cache.size >= this.maxSize) {
91
+ // Cache is full and this is a new key - evict LRU (first entry)
92
+ const firstKey = this.cache.keys().next().value;
93
+ if (firstKey !== undefined) {
94
+ this.cache.delete(firstKey);
95
+ this.stats.evictions++;
96
+ }
97
+ }
98
+ // Add entry at end (most recently used position)
99
+ this.cache.set(key, { value, timestamp: now });
100
+ }
101
+ /**
102
+ * Remove a specific entry from the cache by its key.
103
+ * Does nothing if the key is not in the cache.
104
+ *
105
+ * @param key - The cache key to remove
106
+ */
107
+ delete(key) {
108
+ this.cache.delete(key);
109
+ }
110
+ /**
111
+ * Remove all entries from the cache and reset statistics.
112
+ * Resets the cache to its initial empty state.
113
+ */
114
+ clear() {
115
+ this.cache.clear();
116
+ this.stats = {
117
+ hits: 0,
118
+ misses: 0,
119
+ evictions: 0,
120
+ };
121
+ }
122
+ /**
123
+ * Get current cache statistics for monitoring and debugging.
124
+ * Statistics reflect the current state including all tracked metrics.
125
+ *
126
+ * @returns Cache statistics including hits, misses, size, capacity, and evictions
127
+ */
128
+ getStats() {
129
+ return {
130
+ hits: this.stats.hits,
131
+ misses: this.stats.misses,
132
+ size: this.cache.size,
133
+ maxSize: this.maxSize,
134
+ evictions: this.stats.evictions,
135
+ };
136
+ }
137
+ }
138
+ //# sourceMappingURL=cache-layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-layer.js","sourceRoot":"","sources":["../../src/services/cache-layer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { type CacheStats } from "./cache-layer.js";
2
+ export interface CachedProject {
3
+ path: string;
4
+ name: string;
5
+ discoveredFrom: "docker-ls" | "scan" | "user-provided";
6
+ lastSeen: string;
7
+ }
8
+ export interface CacheData {
9
+ lastScan: string;
10
+ searchPaths: string[];
11
+ projects: Record<string, CachedProject>;
12
+ }
13
+ /**
14
+ * Two-tier cache for Docker Compose project metadata.
15
+ * Uses an in-memory LRU cache (L1) backed by file-based storage (L2).
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const cache = new ComposeProjectCache('.cache/compose-projects', 24*60*60*1000, 50);
20
+ * await cache.updateProject('host', 'plex', projectData);
21
+ * const project = await cache.getProject('host', 'plex'); // Fast memory lookup
22
+ * ```
23
+ */
24
+ export declare class ComposeProjectCache {
25
+ private cacheDir;
26
+ private cacheTtlMs;
27
+ private memoryCache;
28
+ /**
29
+ * Create a new ComposeProjectCache with two-tier caching.
30
+ *
31
+ * @param cacheDir - Directory for file-based cache storage
32
+ * @param cacheTtlMs - Time-to-live for cache entries in milliseconds (default: 24 hours)
33
+ * @param memoryCacheSize - Maximum number of entries in memory cache (default: 50)
34
+ */
35
+ constructor(cacheDir?: string, cacheTtlMs?: number, memoryCacheSize?: number);
36
+ load(host: string): Promise<CacheData>;
37
+ save(host: string, data: CacheData): Promise<void>;
38
+ /**
39
+ * Retrieve a project from cache (memory first, then file).
40
+ * Returns undefined if project doesn't exist or is stale.
41
+ *
42
+ * @param host - The host identifier
43
+ * @param projectName - The project name
44
+ * @returns The cached project or undefined if not found/stale
45
+ */
46
+ getProject(host: string, projectName: string): Promise<CachedProject | undefined>;
47
+ /**
48
+ * Check if a cache entry is stale based on TTL
49
+ */
50
+ private isStale;
51
+ /**
52
+ * Update or add a project in both memory and file cache.
53
+ *
54
+ * @param host - The host identifier
55
+ * @param projectName - The project name
56
+ * @param project - The project data to cache
57
+ */
58
+ updateProject(host: string, projectName: string, project: CachedProject): Promise<void>;
59
+ /**
60
+ * Remove a project from both memory and file cache.
61
+ *
62
+ * @param host - The host identifier
63
+ * @param projectName - The project name to remove
64
+ */
65
+ removeProject(host: string, projectName: string): Promise<void>;
66
+ /**
67
+ * Get memory cache statistics for monitoring and debugging.
68
+ * Provides metrics on cache performance and resource usage.
69
+ *
70
+ * @returns Cache statistics including hits, misses, size, and evictions
71
+ */
72
+ getCacheStats(): CacheStats;
73
+ private emptyCache;
74
+ }
75
+ //# sourceMappingURL=compose-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-cache.d.ts","sourceRoot":"","sources":["../../src/services/compose-cache.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAmC,MAAM,kBAAkB,CAAC;AAEpF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,WAAW,GAAG,MAAM,GAAG,eAAe,CAAC;IACvD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACzC;AAkBD;;;;;;;;;;GAUG;AACH,qBAAa,mBAAmB;IAW5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAXpB,OAAO,CAAC,WAAW,CAAqC;IAExD;;;;;;OAMG;gBAEO,QAAQ,SAA4B,EACpC,UAAU,SAAuB,EACzC,eAAe,SAAK;IAKhB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAwBtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD;;;;;;;OAOG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAkCvF;;OAEG;IACH,OAAO,CAAC,OAAO;IAMf;;;;;;OAMG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7F;;;;;OAKG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBrE;;;;;OAKG;IACH,aAAa,IAAI,UAAU;IAI3B,OAAO,CAAC,UAAU;CAOnB"}
@@ -0,0 +1,178 @@
1
+ // src/services/compose-cache.ts
2
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { z } from "zod";
5
+ import { validateHostname } from "../utils/path-security.js";
6
+ import { getCurrentTimestamp } from "../utils/time.js";
7
+ import { LRUCacheLayer } from "./cache-layer.js";
8
+ const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
9
+ // Zod schemas for runtime validation of JSON cache files
10
+ const CachedProjectSchema = z.object({
11
+ path: z.string(),
12
+ name: z.string(),
13
+ discoveredFrom: z.enum(["docker-ls", "scan", "user-provided"]),
14
+ lastSeen: z.string(),
15
+ });
16
+ const CacheDataSchema = z.object({
17
+ lastScan: z.string(),
18
+ searchPaths: z.array(z.string()),
19
+ projects: z.record(z.string(), CachedProjectSchema),
20
+ });
21
+ /**
22
+ * Two-tier cache for Docker Compose project metadata.
23
+ * Uses an in-memory LRU cache (L1) backed by file-based storage (L2).
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const cache = new ComposeProjectCache('.cache/compose-projects', 24*60*60*1000, 50);
28
+ * await cache.updateProject('host', 'plex', projectData);
29
+ * const project = await cache.getProject('host', 'plex'); // Fast memory lookup
30
+ * ```
31
+ */
32
+ export class ComposeProjectCache {
33
+ cacheDir;
34
+ cacheTtlMs;
35
+ memoryCache;
36
+ /**
37
+ * Create a new ComposeProjectCache with two-tier caching.
38
+ *
39
+ * @param cacheDir - Directory for file-based cache storage
40
+ * @param cacheTtlMs - Time-to-live for cache entries in milliseconds (default: 24 hours)
41
+ * @param memoryCacheSize - Maximum number of entries in memory cache (default: 50)
42
+ */
43
+ constructor(cacheDir = ".cache/compose-projects", cacheTtlMs = DEFAULT_CACHE_TTL_MS, memoryCacheSize = 50) {
44
+ this.cacheDir = cacheDir;
45
+ this.cacheTtlMs = cacheTtlMs;
46
+ this.memoryCache = new LRUCacheLayer(memoryCacheSize, cacheTtlMs);
47
+ }
48
+ async load(host) {
49
+ // SECURITY: Validate host to prevent path traversal attacks (CWE-22)
50
+ validateHostname(host);
51
+ const file = join(this.cacheDir, `${host}.json`);
52
+ try {
53
+ const data = await readFile(file, "utf-8");
54
+ const parsed = JSON.parse(data);
55
+ // Runtime validation: protect against corrupted cache files
56
+ return CacheDataSchema.parse(parsed);
57
+ }
58
+ catch (error) {
59
+ // Only return empty cache if file doesn't exist
60
+ // Re-throw validation errors to catch corrupted cache files
61
+ if (error instanceof z.ZodError) {
62
+ throw new Error(`Cache file validation failed for ${host}: ${error.message}`, {
63
+ cause: error,
64
+ });
65
+ }
66
+ // File not found or JSON parse error - return empty cache
67
+ return this.emptyCache();
68
+ }
69
+ }
70
+ async save(host, data) {
71
+ // SECURITY: Validate host to prevent path traversal attacks (CWE-22)
72
+ validateHostname(host);
73
+ await mkdir(this.cacheDir, { recursive: true });
74
+ const file = join(this.cacheDir, `${host}.json`);
75
+ const tempFile = join(this.cacheDir, `${host}.json.tmp`);
76
+ // Atomic write: write to temp file in same directory, then rename
77
+ // Using same directory ensures rename works across all filesystems
78
+ await writeFile(tempFile, JSON.stringify(data, null, 2));
79
+ await rename(tempFile, file);
80
+ }
81
+ /**
82
+ * Retrieve a project from cache (memory first, then file).
83
+ * Returns undefined if project doesn't exist or is stale.
84
+ *
85
+ * @param host - The host identifier
86
+ * @param projectName - The project name
87
+ * @returns The cached project or undefined if not found/stale
88
+ */
89
+ async getProject(host, projectName) {
90
+ // SECURITY: Validate host to prevent path traversal attacks (CWE-22)
91
+ validateHostname(host);
92
+ const cacheKey = `${host}:${projectName}`;
93
+ // L1 Cache: Check memory cache first (fast path)
94
+ const memoryHit = this.memoryCache.get(cacheKey);
95
+ if (memoryHit) {
96
+ // Check TTL - return undefined if stale
97
+ if (this.isStale(memoryHit.lastSeen)) {
98
+ this.memoryCache.delete(cacheKey);
99
+ return undefined;
100
+ }
101
+ return memoryHit;
102
+ }
103
+ // L2 Cache: Fall back to file cache
104
+ const data = await this.load(host);
105
+ const project = data.projects[projectName];
106
+ // Check TTL - return undefined if stale
107
+ if (project && this.isStale(project.lastSeen)) {
108
+ return undefined;
109
+ }
110
+ // If found in file cache, populate memory cache (cache warming)
111
+ if (project) {
112
+ this.memoryCache.set(cacheKey, project);
113
+ }
114
+ return project;
115
+ }
116
+ /**
117
+ * Check if a cache entry is stale based on TTL
118
+ */
119
+ isStale(lastSeenIso) {
120
+ const lastSeen = new Date(lastSeenIso).getTime();
121
+ const now = Date.now();
122
+ return now - lastSeen > this.cacheTtlMs;
123
+ }
124
+ /**
125
+ * Update or add a project in both memory and file cache.
126
+ *
127
+ * @param host - The host identifier
128
+ * @param projectName - The project name
129
+ * @param project - The project data to cache
130
+ */
131
+ async updateProject(host, projectName, project) {
132
+ // SECURITY: Validate host to prevent path traversal attacks (CWE-22)
133
+ validateHostname(host);
134
+ const cacheKey = `${host}:${projectName}`;
135
+ // Update file cache (L2) - persistence layer
136
+ const data = await this.load(host);
137
+ data.projects[projectName] = project;
138
+ data.lastScan = getCurrentTimestamp();
139
+ await this.save(host, data);
140
+ // Update memory cache (L1) - fast access layer
141
+ this.memoryCache.set(cacheKey, project);
142
+ }
143
+ /**
144
+ * Remove a project from both memory and file cache.
145
+ *
146
+ * @param host - The host identifier
147
+ * @param projectName - The project name to remove
148
+ */
149
+ async removeProject(host, projectName) {
150
+ // SECURITY: Validate host to prevent path traversal attacks (CWE-22)
151
+ validateHostname(host);
152
+ const cacheKey = `${host}:${projectName}`;
153
+ // Remove from memory cache (L1)
154
+ this.memoryCache.delete(cacheKey);
155
+ // Remove from file cache (L2)
156
+ const data = await this.load(host);
157
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
158
+ delete data.projects[projectName];
159
+ await this.save(host, data);
160
+ }
161
+ /**
162
+ * Get memory cache statistics for monitoring and debugging.
163
+ * Provides metrics on cache performance and resource usage.
164
+ *
165
+ * @returns Cache statistics including hits, misses, size, and evictions
166
+ */
167
+ getCacheStats() {
168
+ return this.memoryCache.getStats();
169
+ }
170
+ emptyCache() {
171
+ return {
172
+ lastScan: getCurrentTimestamp(),
173
+ searchPaths: [],
174
+ projects: {},
175
+ };
176
+ }
177
+ }
178
+ //# sourceMappingURL=compose-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-cache.js","sourceRoot":"","sources":["../../src/services/compose-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { HostConfig } from "../types.js";
2
+ import type { ComposeProjectCache } from "./compose-cache.js";
3
+ import type { ComposeScanner } from "./compose-scanner.js";
4
+ import type { IComposeProjectLister } from "./interfaces.js";
5
+ export declare class ComposeDiscovery {
6
+ private projectLister;
7
+ cache: ComposeProjectCache;
8
+ private scanner;
9
+ /**
10
+ * In-flight filesystem scan promises keyed by host name.
11
+ * Coalesces concurrent scan requests for the same host into a single scan,
12
+ * preventing redundant filesystem operations (200-1000ms each).
13
+ */
14
+ private inflightScans;
15
+ constructor(projectLister: IComposeProjectLister, cache: ComposeProjectCache, // Public for cache invalidation in handlers
16
+ scanner: ComposeScanner);
17
+ private getSearchPaths;
18
+ private discoverFromDockerLs;
19
+ /**
20
+ * Scan a host's filesystem for compose projects, coalescing concurrent requests.
21
+ * If a scan is already in flight for this host, returns the existing promise.
22
+ *
23
+ * @param host - Host to scan
24
+ * @returns Array of discovered projects with name and path
25
+ */
26
+ private scanHostFilesystem;
27
+ private discoverFromFilesystem;
28
+ /**
29
+ * Resolve compose file path for a project
30
+ * Strategy:
31
+ * 1. Check cache (trust it - lazy invalidation at handler level)
32
+ * 2. Check docker compose ls (running projects) - FAST
33
+ * 3. Scan filesystem if not found - SLOWER
34
+ * 4. Error if not found
35
+ */
36
+ resolveProjectPath(host: HostConfig, projectName: string): Promise<string>;
37
+ /**
38
+ * Warm cache by discovering all projects on a host in the background.
39
+ * This mitigates cold-start penalty (200-1000ms) on first compose operation.
40
+ * Call this on server startup or after cache invalidation.
41
+ *
42
+ * @param host - Host to warm cache for
43
+ */
44
+ warmCache(host: HostConfig): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=compose-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-discovery.d.ts","sourceRoot":"","sources":["../../src/services/compose-discovery.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAiB,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAI7D,qBAAa,gBAAgB;IASzB,OAAO,CAAC,aAAa;IACd,KAAK,EAAE,mBAAmB;IACjC,OAAO,CAAC,OAAO;IAVjB;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAAqE;gBAGhF,aAAa,EAAE,qBAAqB,EACrC,KAAK,EAAE,mBAAmB,EAAE,4CAA4C;IACvE,OAAO,EAAE,cAAc;IAGjC,OAAO,CAAC,cAAc;YAuBR,oBAAoB;IA0BlC;;;;;;OAMG;YACW,kBAAkB;YAyClB,sBAAsB;IAoCpC;;;;;;;OAOG;IACG,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA+BhF;;;;;;OAMG;IACG,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CA4DjD"}