spindb 0.37.2 → 0.38.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 (811) hide show
  1. package/dist/cli/bin.js +9 -0
  2. package/dist/cli/bin.js.map +1 -0
  3. package/dist/cli/commands/attach.js +102 -0
  4. package/dist/cli/commands/attach.js.map +1 -0
  5. package/dist/cli/commands/backup.js +197 -0
  6. package/dist/cli/commands/backup.js.map +1 -0
  7. package/dist/cli/commands/backups.js +190 -0
  8. package/dist/cli/commands/backups.js.map +1 -0
  9. package/dist/cli/commands/clone.js +119 -0
  10. package/dist/cli/commands/clone.js.map +1 -0
  11. package/dist/cli/commands/config.js +276 -0
  12. package/dist/cli/commands/config.js.map +1 -0
  13. package/dist/cli/commands/connect.js +559 -0
  14. package/dist/cli/commands/connect.js.map +1 -0
  15. package/dist/cli/commands/create.js +952 -0
  16. package/dist/cli/commands/create.js.map +1 -0
  17. package/dist/cli/commands/databases.js +485 -0
  18. package/dist/cli/commands/databases.js.map +1 -0
  19. package/dist/cli/commands/delete.js +106 -0
  20. package/dist/cli/commands/delete.js.map +1 -0
  21. package/dist/cli/commands/deps.js +238 -0
  22. package/dist/cli/commands/deps.js.map +1 -0
  23. package/dist/cli/commands/detach.js +81 -0
  24. package/dist/cli/commands/detach.js.map +1 -0
  25. package/dist/cli/commands/doctor.js +567 -0
  26. package/dist/cli/commands/doctor.js.map +1 -0
  27. package/dist/cli/commands/duckdb.js +207 -0
  28. package/dist/cli/commands/duckdb.js.map +1 -0
  29. package/dist/cli/commands/edit.js +524 -0
  30. package/dist/cli/commands/edit.js.map +1 -0
  31. package/dist/cli/commands/engines.js +1414 -0
  32. package/dist/cli/commands/engines.js.map +1 -0
  33. package/dist/cli/commands/export.js +383 -0
  34. package/dist/cli/commands/export.js.map +1 -0
  35. package/dist/cli/commands/info.js +270 -0
  36. package/dist/cli/commands/info.js.map +1 -0
  37. package/dist/cli/commands/list.js +215 -0
  38. package/dist/cli/commands/list.js.map +1 -0
  39. package/dist/cli/commands/logs.js +81 -0
  40. package/dist/cli/commands/logs.js.map +1 -0
  41. package/dist/cli/commands/menu/backup-handlers.js +1202 -0
  42. package/dist/cli/commands/menu/backup-handlers.js.map +1 -0
  43. package/dist/cli/commands/menu/container-handlers.js +1788 -0
  44. package/dist/cli/commands/menu/container-handlers.js.map +1 -0
  45. package/dist/cli/commands/menu/engine-handlers.js +235 -0
  46. package/dist/cli/commands/menu/engine-handlers.js.map +1 -0
  47. package/dist/cli/commands/menu/index.js +266 -0
  48. package/dist/cli/commands/menu/index.js.map +1 -0
  49. package/dist/cli/commands/menu/settings-handlers.js +320 -0
  50. package/dist/cli/commands/menu/settings-handlers.js.map +1 -0
  51. package/dist/cli/commands/menu/shared.js +13 -0
  52. package/dist/cli/commands/menu/shared.js.map +1 -0
  53. package/dist/cli/commands/menu/shell-handlers.js +1573 -0
  54. package/dist/cli/commands/menu/shell-handlers.js.map +1 -0
  55. package/dist/cli/commands/menu/sql-handlers.js +185 -0
  56. package/dist/cli/commands/menu/sql-handlers.js.map +1 -0
  57. package/dist/cli/commands/menu/update-handlers.js +322 -0
  58. package/dist/cli/commands/menu/update-handlers.js.map +1 -0
  59. package/dist/cli/commands/menu/validators.js +9 -0
  60. package/dist/cli/commands/menu/validators.js.map +1 -0
  61. package/dist/cli/commands/ports.js +166 -0
  62. package/dist/cli/commands/ports.js.map +1 -0
  63. package/dist/cli/commands/pull.js +166 -0
  64. package/dist/cli/commands/pull.js.map +1 -0
  65. package/dist/cli/commands/query.js +180 -0
  66. package/dist/cli/commands/query.js.map +1 -0
  67. package/dist/cli/commands/restore.js +428 -0
  68. package/dist/cli/commands/restore.js.map +1 -0
  69. package/dist/cli/commands/run.js +115 -0
  70. package/dist/cli/commands/run.js.map +1 -0
  71. package/dist/cli/commands/self-update.js +99 -0
  72. package/dist/cli/commands/self-update.js.map +1 -0
  73. package/dist/cli/commands/sqlite.js +207 -0
  74. package/dist/cli/commands/sqlite.js.map +1 -0
  75. package/dist/cli/commands/start.js +196 -0
  76. package/dist/cli/commands/start.js.map +1 -0
  77. package/dist/cli/commands/stop.js +182 -0
  78. package/dist/cli/commands/stop.js.map +1 -0
  79. package/dist/cli/commands/url.js +88 -0
  80. package/dist/cli/commands/url.js.map +1 -0
  81. package/dist/cli/commands/users.js +189 -0
  82. package/dist/cli/commands/users.js.map +1 -0
  83. package/dist/cli/commands/version.js +52 -0
  84. package/dist/cli/commands/version.js.map +1 -0
  85. package/dist/cli/commands/which.js +258 -0
  86. package/dist/cli/commands/which.js.map +1 -0
  87. package/dist/cli/constants.js +212 -0
  88. package/dist/cli/constants.js.map +1 -0
  89. package/dist/cli/helpers.js +1120 -0
  90. package/dist/cli/helpers.js.map +1 -0
  91. package/dist/cli/index.js +146 -0
  92. package/dist/cli/index.js.map +1 -0
  93. package/dist/cli/ui/prompts.js +1002 -0
  94. package/dist/cli/ui/prompts.js.map +1 -0
  95. package/dist/cli/ui/spinner.js +74 -0
  96. package/dist/cli/ui/spinner.js.map +1 -0
  97. package/dist/cli/ui/theme.js +99 -0
  98. package/dist/cli/ui/theme.js.map +1 -0
  99. package/dist/cli/utils/file-follower.js +79 -0
  100. package/dist/cli/utils/file-follower.js.map +1 -0
  101. package/dist/config/backup-formats.js +363 -0
  102. package/dist/config/backup-formats.js.map +1 -0
  103. package/dist/config/defaults.js +25 -0
  104. package/dist/config/defaults.js.map +1 -0
  105. package/dist/config/engine-defaults.js +303 -0
  106. package/dist/config/engine-defaults.js.map +1 -0
  107. package/dist/config/engines-registry.js +103 -0
  108. package/dist/config/engines-registry.js.map +1 -0
  109. package/dist/config/os-dependencies.js +767 -0
  110. package/dist/config/os-dependencies.js.map +1 -0
  111. package/dist/config/paths.js +156 -0
  112. package/dist/config/paths.js.map +1 -0
  113. package/dist/config/version.js +3 -0
  114. package/dist/config/version.js.map +1 -0
  115. package/dist/core/backup-restore.js +219 -0
  116. package/dist/core/backup-restore.js.map +1 -0
  117. package/dist/core/base-binary-manager.js +403 -0
  118. package/dist/core/base-binary-manager.js.map +1 -0
  119. package/dist/core/base-document-binary-manager.js +364 -0
  120. package/dist/core/base-document-binary-manager.js.map +1 -0
  121. package/dist/core/base-embedded-binary-manager.js +364 -0
  122. package/dist/core/base-embedded-binary-manager.js.map +1 -0
  123. package/dist/core/base-server-binary-manager.js +368 -0
  124. package/dist/core/base-server-binary-manager.js.map +1 -0
  125. package/dist/core/config-manager.js +495 -0
  126. package/dist/core/config-manager.js.map +1 -0
  127. package/dist/core/container-manager.js +609 -0
  128. package/dist/core/container-manager.js.map +1 -0
  129. package/dist/core/credential-generator.js +67 -0
  130. package/dist/core/credential-generator.js.map +1 -0
  131. package/dist/core/credential-manager.js +211 -0
  132. package/dist/core/credential-manager.js.map +1 -0
  133. package/dist/core/dblab-utils.js +105 -0
  134. package/dist/core/dblab-utils.js.map +1 -0
  135. package/dist/core/dependency-manager.js +359 -0
  136. package/dist/core/dependency-manager.js.map +1 -0
  137. package/dist/core/docker-exporter.js +1077 -0
  138. package/dist/core/docker-exporter.js.map +1 -0
  139. package/dist/core/error-handler.js +295 -0
  140. package/dist/core/error-handler.js.map +1 -0
  141. package/dist/core/fs-error-utils.js +74 -0
  142. package/dist/core/fs-error-utils.js.map +1 -0
  143. package/dist/core/homebrew-version-manager.js +280 -0
  144. package/dist/core/homebrew-version-manager.js.map +1 -0
  145. package/dist/core/hostdb-client.js +252 -0
  146. package/dist/core/hostdb-client.js.map +1 -0
  147. package/dist/core/hostdb-metadata.js +243 -0
  148. package/dist/core/hostdb-metadata.js.map +1 -0
  149. package/dist/core/hostdb-releases-factory.js +161 -0
  150. package/dist/core/hostdb-releases-factory.js.map +1 -0
  151. package/dist/core/library-env.js +88 -0
  152. package/dist/core/library-env.js.map +1 -0
  153. package/dist/core/pgweb-utils.js +53 -0
  154. package/dist/core/pgweb-utils.js.map +1 -0
  155. package/dist/core/platform-service.js +632 -0
  156. package/dist/core/platform-service.js.map +1 -0
  157. package/dist/core/port-manager.js +136 -0
  158. package/dist/core/port-manager.js.map +1 -0
  159. package/dist/core/process-manager.js +445 -0
  160. package/dist/core/process-manager.js.map +1 -0
  161. package/dist/core/pull-manager.js +418 -0
  162. package/dist/core/pull-manager.js.map +1 -0
  163. package/dist/core/query-parser.js +449 -0
  164. package/dist/core/query-parser.js.map +1 -0
  165. package/dist/core/spawn-utils.js +90 -0
  166. package/dist/core/spawn-utils.js.map +1 -0
  167. package/dist/core/start-with-retry.js +90 -0
  168. package/dist/core/start-with-retry.js.map +1 -0
  169. package/dist/core/test-cleanup.js +85 -0
  170. package/dist/core/test-cleanup.js.map +1 -0
  171. package/dist/core/tls-generator.js +84 -0
  172. package/dist/core/tls-generator.js.map +1 -0
  173. package/dist/core/transaction-manager.js +139 -0
  174. package/dist/core/transaction-manager.js.map +1 -0
  175. package/dist/core/update-manager.js +241 -0
  176. package/dist/core/update-manager.js.map +1 -0
  177. package/dist/core/version-migration.js +260 -0
  178. package/dist/core/version-migration.js.map +1 -0
  179. package/dist/core/version-utils.js +91 -0
  180. package/dist/core/version-utils.js.map +1 -0
  181. package/dist/engines/base-engine.js +179 -0
  182. package/dist/engines/base-engine.js.map +1 -0
  183. package/dist/engines/clickhouse/backup.js +289 -0
  184. package/dist/engines/clickhouse/backup.js.map +1 -0
  185. package/dist/engines/clickhouse/binary-manager.js +145 -0
  186. package/dist/engines/clickhouse/binary-manager.js.map +1 -0
  187. package/dist/engines/clickhouse/binary-urls.js +100 -0
  188. package/dist/engines/clickhouse/binary-urls.js.map +1 -0
  189. package/dist/engines/clickhouse/cli-utils.js +143 -0
  190. package/dist/engines/clickhouse/cli-utils.js.map +1 -0
  191. package/dist/engines/clickhouse/hostdb-releases.js +24 -0
  192. package/dist/engines/clickhouse/hostdb-releases.js.map +1 -0
  193. package/dist/engines/clickhouse/index.js +1077 -0
  194. package/dist/engines/clickhouse/index.js.map +1 -0
  195. package/dist/engines/clickhouse/restore.js +335 -0
  196. package/dist/engines/clickhouse/restore.js.map +1 -0
  197. package/dist/engines/clickhouse/version-maps.js +83 -0
  198. package/dist/engines/clickhouse/version-maps.js.map +1 -0
  199. package/dist/engines/clickhouse/version-validator.js +133 -0
  200. package/dist/engines/clickhouse/version-validator.js.map +1 -0
  201. package/dist/engines/cockroachdb/backup.js +261 -0
  202. package/dist/engines/cockroachdb/backup.js.map +1 -0
  203. package/dist/engines/cockroachdb/binary-manager.js +33 -0
  204. package/dist/engines/cockroachdb/binary-manager.js.map +1 -0
  205. package/dist/engines/cockroachdb/binary-urls.js +33 -0
  206. package/dist/engines/cockroachdb/binary-urls.js.map +1 -0
  207. package/dist/engines/cockroachdb/cli-utils.js +338 -0
  208. package/dist/engines/cockroachdb/cli-utils.js.map +1 -0
  209. package/dist/engines/cockroachdb/hostdb-releases.js +21 -0
  210. package/dist/engines/cockroachdb/hostdb-releases.js.map +1 -0
  211. package/dist/engines/cockroachdb/index.js +1016 -0
  212. package/dist/engines/cockroachdb/index.js.map +1 -0
  213. package/dist/engines/cockroachdb/restore.js +323 -0
  214. package/dist/engines/cockroachdb/restore.js.map +1 -0
  215. package/dist/engines/cockroachdb/version-maps.js +37 -0
  216. package/dist/engines/cockroachdb/version-maps.js.map +1 -0
  217. package/dist/engines/couchdb/api-client.js +64 -0
  218. package/dist/engines/couchdb/api-client.js.map +1 -0
  219. package/dist/engines/couchdb/backup.js +90 -0
  220. package/dist/engines/couchdb/backup.js.map +1 -0
  221. package/dist/engines/couchdb/binary-manager.js +62 -0
  222. package/dist/engines/couchdb/binary-manager.js.map +1 -0
  223. package/dist/engines/couchdb/binary-urls.js +92 -0
  224. package/dist/engines/couchdb/binary-urls.js.map +1 -0
  225. package/dist/engines/couchdb/hostdb-releases.js +21 -0
  226. package/dist/engines/couchdb/hostdb-releases.js.map +1 -0
  227. package/dist/engines/couchdb/index.js +1043 -0
  228. package/dist/engines/couchdb/index.js.map +1 -0
  229. package/dist/engines/couchdb/restore.js +198 -0
  230. package/dist/engines/couchdb/restore.js.map +1 -0
  231. package/dist/engines/couchdb/version-maps.js +67 -0
  232. package/dist/engines/couchdb/version-maps.js.map +1 -0
  233. package/dist/engines/couchdb/version-validator.js +88 -0
  234. package/dist/engines/couchdb/version-validator.js.map +1 -0
  235. package/dist/engines/duckdb/binary-manager.js +33 -0
  236. package/dist/engines/duckdb/binary-manager.js.map +1 -0
  237. package/{engines/duckdb/binary-urls.ts → dist/engines/duckdb/binary-urls.js} +11 -16
  238. package/dist/engines/duckdb/binary-urls.js.map +1 -0
  239. package/dist/engines/duckdb/hostdb-releases.js +21 -0
  240. package/dist/engines/duckdb/hostdb-releases.js.map +1 -0
  241. package/dist/engines/duckdb/index.js +594 -0
  242. package/dist/engines/duckdb/index.js.map +1 -0
  243. package/dist/engines/duckdb/registry.js +265 -0
  244. package/dist/engines/duckdb/registry.js.map +1 -0
  245. package/dist/engines/duckdb/scanner.js +12 -0
  246. package/dist/engines/duckdb/scanner.js.map +1 -0
  247. package/dist/engines/duckdb/version-maps.js +67 -0
  248. package/dist/engines/duckdb/version-maps.js.map +1 -0
  249. package/dist/engines/duckdb/version-validator.js +62 -0
  250. package/dist/engines/duckdb/version-validator.js.map +1 -0
  251. package/dist/engines/ferretdb/backup.js +170 -0
  252. package/dist/engines/ferretdb/backup.js.map +1 -0
  253. package/dist/engines/ferretdb/binary-manager.js +765 -0
  254. package/dist/engines/ferretdb/binary-manager.js.map +1 -0
  255. package/dist/engines/ferretdb/binary-urls.js +135 -0
  256. package/dist/engines/ferretdb/binary-urls.js.map +1 -0
  257. package/dist/engines/ferretdb/index.js +1517 -0
  258. package/dist/engines/ferretdb/index.js.map +1 -0
  259. package/dist/engines/ferretdb/restore.js +310 -0
  260. package/dist/engines/ferretdb/restore.js.map +1 -0
  261. package/{engines/ferretdb/version-maps.ts → dist/engines/ferretdb/version-maps.js} +62 -79
  262. package/dist/engines/ferretdb/version-maps.js.map +1 -0
  263. package/dist/engines/file-based-utils.js +184 -0
  264. package/dist/engines/file-based-utils.js.map +1 -0
  265. package/dist/engines/index.js +124 -0
  266. package/dist/engines/index.js.map +1 -0
  267. package/dist/engines/influxdb/api-client.js +54 -0
  268. package/dist/engines/influxdb/api-client.js.map +1 -0
  269. package/dist/engines/influxdb/backup.js +119 -0
  270. package/dist/engines/influxdb/backup.js.map +1 -0
  271. package/dist/engines/influxdb/binary-manager.js +87 -0
  272. package/dist/engines/influxdb/binary-manager.js.map +1 -0
  273. package/dist/engines/influxdb/binary-urls.js +56 -0
  274. package/dist/engines/influxdb/binary-urls.js.map +1 -0
  275. package/dist/engines/influxdb/hostdb-releases.js +21 -0
  276. package/dist/engines/influxdb/hostdb-releases.js.map +1 -0
  277. package/dist/engines/influxdb/index.js +962 -0
  278. package/dist/engines/influxdb/index.js.map +1 -0
  279. package/dist/engines/influxdb/restore.js +329 -0
  280. package/dist/engines/influxdb/restore.js.map +1 -0
  281. package/dist/engines/influxdb/version-maps.js +64 -0
  282. package/dist/engines/influxdb/version-maps.js.map +1 -0
  283. package/dist/engines/influxdb/version-validator.js +109 -0
  284. package/dist/engines/influxdb/version-validator.js.map +1 -0
  285. package/dist/engines/mariadb/backup.js +178 -0
  286. package/dist/engines/mariadb/backup.js.map +1 -0
  287. package/dist/engines/mariadb/binary-manager.js +33 -0
  288. package/dist/engines/mariadb/binary-manager.js.map +1 -0
  289. package/{engines/mariadb/binary-urls.ts → dist/engines/mariadb/binary-urls.js} +38 -55
  290. package/dist/engines/mariadb/binary-urls.js.map +1 -0
  291. package/dist/engines/mariadb/hostdb-releases.js +21 -0
  292. package/dist/engines/mariadb/hostdb-releases.js.map +1 -0
  293. package/dist/engines/mariadb/index.js +1011 -0
  294. package/dist/engines/mariadb/index.js.map +1 -0
  295. package/dist/engines/mariadb/restore.js +322 -0
  296. package/dist/engines/mariadb/restore.js.map +1 -0
  297. package/dist/engines/mariadb/version-maps.js +63 -0
  298. package/dist/engines/mariadb/version-maps.js.map +1 -0
  299. package/dist/engines/mariadb/version-validator.js +143 -0
  300. package/dist/engines/mariadb/version-validator.js.map +1 -0
  301. package/dist/engines/meilisearch/api-client.js +50 -0
  302. package/dist/engines/meilisearch/api-client.js.map +1 -0
  303. package/dist/engines/meilisearch/backup.js +167 -0
  304. package/dist/engines/meilisearch/backup.js.map +1 -0
  305. package/dist/engines/meilisearch/binary-manager.js +31 -0
  306. package/dist/engines/meilisearch/binary-manager.js.map +1 -0
  307. package/dist/engines/meilisearch/binary-urls.js +56 -0
  308. package/dist/engines/meilisearch/binary-urls.js.map +1 -0
  309. package/dist/engines/meilisearch/hostdb-releases.js +21 -0
  310. package/dist/engines/meilisearch/hostdb-releases.js.map +1 -0
  311. package/dist/engines/meilisearch/index.js +992 -0
  312. package/dist/engines/meilisearch/index.js.map +1 -0
  313. package/dist/engines/meilisearch/restore.js +167 -0
  314. package/dist/engines/meilisearch/restore.js.map +1 -0
  315. package/dist/engines/meilisearch/version-maps.js +67 -0
  316. package/dist/engines/meilisearch/version-maps.js.map +1 -0
  317. package/dist/engines/meilisearch/version-validator.js +109 -0
  318. package/dist/engines/meilisearch/version-validator.js.map +1 -0
  319. package/dist/engines/mongodb/backup.js +109 -0
  320. package/dist/engines/mongodb/backup.js.map +1 -0
  321. package/dist/engines/mongodb/binary-manager.js +36 -0
  322. package/dist/engines/mongodb/binary-manager.js.map +1 -0
  323. package/dist/engines/mongodb/binary-urls.js +46 -0
  324. package/dist/engines/mongodb/binary-urls.js.map +1 -0
  325. package/dist/engines/mongodb/cli-utils.js +131 -0
  326. package/dist/engines/mongodb/cli-utils.js.map +1 -0
  327. package/dist/engines/mongodb/hostdb-releases.js +77 -0
  328. package/dist/engines/mongodb/hostdb-releases.js.map +1 -0
  329. package/dist/engines/mongodb/index.js +873 -0
  330. package/dist/engines/mongodb/index.js.map +1 -0
  331. package/dist/engines/mongodb/restore.js +276 -0
  332. package/dist/engines/mongodb/restore.js.map +1 -0
  333. package/dist/engines/mongodb/version-maps.js +79 -0
  334. package/dist/engines/mongodb/version-maps.js.map +1 -0
  335. package/dist/engines/mongodb/version-validator.js +133 -0
  336. package/dist/engines/mongodb/version-validator.js.map +1 -0
  337. package/dist/engines/mysql/backup.js +210 -0
  338. package/dist/engines/mysql/backup.js.map +1 -0
  339. package/dist/engines/mysql/binary-detection.js +325 -0
  340. package/dist/engines/mysql/binary-detection.js.map +1 -0
  341. package/dist/engines/mysql/binary-manager.js +30 -0
  342. package/dist/engines/mysql/binary-manager.js.map +1 -0
  343. package/dist/engines/mysql/binary-urls.js +87 -0
  344. package/dist/engines/mysql/binary-urls.js.map +1 -0
  345. package/{engines/mysql/hostdb-releases.ts → dist/engines/mysql/hostdb-releases.js} +20 -23
  346. package/dist/engines/mysql/hostdb-releases.js.map +1 -0
  347. package/dist/engines/mysql/index.js +1066 -0
  348. package/dist/engines/mysql/index.js.map +1 -0
  349. package/dist/engines/mysql/restore.js +361 -0
  350. package/dist/engines/mysql/restore.js.map +1 -0
  351. package/dist/engines/mysql/version-maps.js +79 -0
  352. package/dist/engines/mysql/version-maps.js.map +1 -0
  353. package/dist/engines/mysql/version-validator.js +266 -0
  354. package/dist/engines/mysql/version-validator.js.map +1 -0
  355. package/dist/engines/postgresql/backup.js +118 -0
  356. package/dist/engines/postgresql/backup.js.map +1 -0
  357. package/dist/engines/postgresql/binary-manager.js +85 -0
  358. package/dist/engines/postgresql/binary-manager.js.map +1 -0
  359. package/dist/engines/postgresql/binary-urls.js +80 -0
  360. package/dist/engines/postgresql/binary-urls.js.map +1 -0
  361. package/dist/engines/postgresql/hostdb-releases.js +21 -0
  362. package/dist/engines/postgresql/hostdb-releases.js.map +1 -0
  363. package/dist/engines/postgresql/index.js +852 -0
  364. package/dist/engines/postgresql/index.js.map +1 -0
  365. package/dist/engines/postgresql/remote-version.js +109 -0
  366. package/dist/engines/postgresql/remote-version.js.map +1 -0
  367. package/dist/engines/postgresql/restore.js +254 -0
  368. package/dist/engines/postgresql/restore.js.map +1 -0
  369. package/dist/engines/postgresql/version-maps.js +73 -0
  370. package/dist/engines/postgresql/version-maps.js.map +1 -0
  371. package/dist/engines/postgresql/version-validator.js +286 -0
  372. package/dist/engines/postgresql/version-validator.js.map +1 -0
  373. package/dist/engines/qdrant/api-client.js +50 -0
  374. package/dist/engines/qdrant/api-client.js.map +1 -0
  375. package/dist/engines/qdrant/backup.js +115 -0
  376. package/dist/engines/qdrant/backup.js.map +1 -0
  377. package/dist/engines/qdrant/binary-manager.js +31 -0
  378. package/dist/engines/qdrant/binary-manager.js.map +1 -0
  379. package/dist/engines/qdrant/binary-urls.js +92 -0
  380. package/dist/engines/qdrant/binary-urls.js.map +1 -0
  381. package/dist/engines/qdrant/cli-utils.js +39 -0
  382. package/dist/engines/qdrant/cli-utils.js.map +1 -0
  383. package/dist/engines/qdrant/hostdb-releases.js +21 -0
  384. package/dist/engines/qdrant/hostdb-releases.js.map +1 -0
  385. package/dist/engines/qdrant/index.js +1002 -0
  386. package/dist/engines/qdrant/index.js.map +1 -0
  387. package/dist/engines/qdrant/restore.js +154 -0
  388. package/dist/engines/qdrant/restore.js.map +1 -0
  389. package/dist/engines/qdrant/version-maps.js +67 -0
  390. package/dist/engines/qdrant/version-maps.js.map +1 -0
  391. package/dist/engines/qdrant/version-validator.js +109 -0
  392. package/dist/engines/qdrant/version-validator.js.map +1 -0
  393. package/dist/engines/questdb/backup.js +191 -0
  394. package/dist/engines/questdb/backup.js.map +1 -0
  395. package/dist/engines/questdb/binary-manager.js +247 -0
  396. package/dist/engines/questdb/binary-manager.js.map +1 -0
  397. package/dist/engines/questdb/binary-urls.js +27 -0
  398. package/dist/engines/questdb/binary-urls.js.map +1 -0
  399. package/dist/engines/questdb/hostdb-releases.js +21 -0
  400. package/dist/engines/questdb/hostdb-releases.js.map +1 -0
  401. package/dist/engines/questdb/index.js +814 -0
  402. package/dist/engines/questdb/index.js.map +1 -0
  403. package/dist/engines/questdb/restore.js +202 -0
  404. package/dist/engines/questdb/restore.js.map +1 -0
  405. package/dist/engines/questdb/version-maps.js +33 -0
  406. package/dist/engines/questdb/version-maps.js.map +1 -0
  407. package/dist/engines/questdb/version-validator.js +99 -0
  408. package/dist/engines/questdb/version-validator.js.map +1 -0
  409. package/dist/engines/redis/backup.js +292 -0
  410. package/dist/engines/redis/backup.js.map +1 -0
  411. package/dist/engines/redis/binary-manager.js +32 -0
  412. package/dist/engines/redis/binary-manager.js.map +1 -0
  413. package/dist/engines/redis/binary-urls.js +96 -0
  414. package/dist/engines/redis/binary-urls.js.map +1 -0
  415. package/dist/engines/redis/cli-utils.js +38 -0
  416. package/dist/engines/redis/cli-utils.js.map +1 -0
  417. package/dist/engines/redis/hostdb-releases.js +21 -0
  418. package/dist/engines/redis/hostdb-releases.js.map +1 -0
  419. package/dist/engines/redis/index.js +1263 -0
  420. package/dist/engines/redis/index.js.map +1 -0
  421. package/dist/engines/redis/restore.js +338 -0
  422. package/dist/engines/redis/restore.js.map +1 -0
  423. package/dist/engines/redis/version-maps.js +70 -0
  424. package/dist/engines/redis/version-maps.js.map +1 -0
  425. package/dist/engines/redis/version-validator.js +109 -0
  426. package/dist/engines/redis/version-validator.js.map +1 -0
  427. package/dist/engines/sqlite/binary-manager.js +39 -0
  428. package/dist/engines/sqlite/binary-manager.js.map +1 -0
  429. package/{engines/sqlite/binary-urls.ts → dist/engines/sqlite/binary-urls.js} +11 -16
  430. package/dist/engines/sqlite/binary-urls.js.map +1 -0
  431. package/dist/engines/sqlite/hostdb-releases.js +21 -0
  432. package/dist/engines/sqlite/hostdb-releases.js.map +1 -0
  433. package/dist/engines/sqlite/index.js +493 -0
  434. package/dist/engines/sqlite/index.js.map +1 -0
  435. package/dist/engines/sqlite/registry.js +163 -0
  436. package/dist/engines/sqlite/registry.js.map +1 -0
  437. package/dist/engines/sqlite/scanner.js +12 -0
  438. package/dist/engines/sqlite/scanner.js.map +1 -0
  439. package/dist/engines/sqlite/version-maps.js +57 -0
  440. package/dist/engines/sqlite/version-maps.js.map +1 -0
  441. package/dist/engines/surrealdb/backup.js +97 -0
  442. package/dist/engines/surrealdb/backup.js.map +1 -0
  443. package/dist/engines/surrealdb/binary-manager.js +33 -0
  444. package/dist/engines/surrealdb/binary-manager.js.map +1 -0
  445. package/dist/engines/surrealdb/binary-urls.js +33 -0
  446. package/dist/engines/surrealdb/binary-urls.js.map +1 -0
  447. package/dist/engines/surrealdb/cli-utils.js +147 -0
  448. package/dist/engines/surrealdb/cli-utils.js.map +1 -0
  449. package/dist/engines/surrealdb/hostdb-releases.js +21 -0
  450. package/dist/engines/surrealdb/hostdb-releases.js.map +1 -0
  451. package/dist/engines/surrealdb/index.js +1022 -0
  452. package/dist/engines/surrealdb/index.js.map +1 -0
  453. package/dist/engines/surrealdb/restore.js +224 -0
  454. package/dist/engines/surrealdb/restore.js.map +1 -0
  455. package/dist/engines/surrealdb/version-maps.js +36 -0
  456. package/dist/engines/surrealdb/version-maps.js.map +1 -0
  457. package/dist/engines/tigerbeetle/backup.js +36 -0
  458. package/dist/engines/tigerbeetle/backup.js.map +1 -0
  459. package/dist/engines/tigerbeetle/binary-manager.js +72 -0
  460. package/dist/engines/tigerbeetle/binary-manager.js.map +1 -0
  461. package/dist/engines/tigerbeetle/binary-urls.js +49 -0
  462. package/dist/engines/tigerbeetle/binary-urls.js.map +1 -0
  463. package/dist/engines/tigerbeetle/hostdb-releases.js +21 -0
  464. package/dist/engines/tigerbeetle/hostdb-releases.js.map +1 -0
  465. package/dist/engines/tigerbeetle/index.js +559 -0
  466. package/dist/engines/tigerbeetle/index.js.map +1 -0
  467. package/dist/engines/tigerbeetle/restore.js +91 -0
  468. package/dist/engines/tigerbeetle/restore.js.map +1 -0
  469. package/{engines/tigerbeetle/version-maps.ts → dist/engines/tigerbeetle/version-maps.js} +22 -31
  470. package/dist/engines/tigerbeetle/version-maps.js.map +1 -0
  471. package/dist/engines/tigerbeetle/version-validator.js +108 -0
  472. package/dist/engines/tigerbeetle/version-validator.js.map +1 -0
  473. package/dist/engines/typedb/backup.js +129 -0
  474. package/dist/engines/typedb/backup.js.map +1 -0
  475. package/dist/engines/typedb/binary-manager.js +151 -0
  476. package/dist/engines/typedb/binary-manager.js.map +1 -0
  477. package/dist/engines/typedb/binary-urls.js +33 -0
  478. package/dist/engines/typedb/binary-urls.js.map +1 -0
  479. package/dist/engines/typedb/cli-utils.js +163 -0
  480. package/dist/engines/typedb/cli-utils.js.map +1 -0
  481. package/dist/engines/typedb/hostdb-releases.js +21 -0
  482. package/dist/engines/typedb/hostdb-releases.js.map +1 -0
  483. package/dist/engines/typedb/index.js +1003 -0
  484. package/dist/engines/typedb/index.js.map +1 -0
  485. package/dist/engines/typedb/restore.js +279 -0
  486. package/dist/engines/typedb/restore.js.map +1 -0
  487. package/dist/engines/typedb/version-maps.js +40 -0
  488. package/dist/engines/typedb/version-maps.js.map +1 -0
  489. package/dist/engines/typedb/version-validator.js +103 -0
  490. package/dist/engines/typedb/version-validator.js.map +1 -0
  491. package/dist/engines/valkey/backup.js +292 -0
  492. package/dist/engines/valkey/backup.js.map +1 -0
  493. package/dist/engines/valkey/binary-manager.js +33 -0
  494. package/dist/engines/valkey/binary-manager.js.map +1 -0
  495. package/dist/engines/valkey/binary-urls.js +98 -0
  496. package/dist/engines/valkey/binary-urls.js.map +1 -0
  497. package/dist/engines/valkey/cli-utils.js +38 -0
  498. package/dist/engines/valkey/cli-utils.js.map +1 -0
  499. package/dist/engines/valkey/hostdb-releases.js +21 -0
  500. package/dist/engines/valkey/hostdb-releases.js.map +1 -0
  501. package/dist/engines/valkey/index.js +1257 -0
  502. package/dist/engines/valkey/index.js.map +1 -0
  503. package/dist/engines/valkey/restore.js +340 -0
  504. package/dist/engines/valkey/restore.js.map +1 -0
  505. package/dist/engines/valkey/version-maps.js +70 -0
  506. package/dist/engines/valkey/version-maps.js.map +1 -0
  507. package/dist/engines/valkey/version-validator.js +112 -0
  508. package/dist/engines/valkey/version-validator.js.map +1 -0
  509. package/dist/engines/weaviate/api-client.js +50 -0
  510. package/dist/engines/weaviate/api-client.js.map +1 -0
  511. package/dist/engines/weaviate/backup.js +95 -0
  512. package/dist/engines/weaviate/backup.js.map +1 -0
  513. package/dist/engines/weaviate/binary-manager.js +58 -0
  514. package/dist/engines/weaviate/binary-manager.js.map +1 -0
  515. package/dist/engines/weaviate/binary-urls.js +92 -0
  516. package/dist/engines/weaviate/binary-urls.js.map +1 -0
  517. package/dist/engines/weaviate/cli-utils.js +39 -0
  518. package/dist/engines/weaviate/cli-utils.js.map +1 -0
  519. package/dist/engines/weaviate/hostdb-releases.js +21 -0
  520. package/dist/engines/weaviate/hostdb-releases.js.map +1 -0
  521. package/dist/engines/weaviate/index.js +871 -0
  522. package/dist/engines/weaviate/index.js.map +1 -0
  523. package/dist/engines/weaviate/restore.js +185 -0
  524. package/dist/engines/weaviate/restore.js.map +1 -0
  525. package/dist/engines/weaviate/version-maps.js +67 -0
  526. package/dist/engines/weaviate/version-maps.js.map +1 -0
  527. package/dist/engines/weaviate/version-validator.js +109 -0
  528. package/dist/engines/weaviate/version-validator.js.map +1 -0
  529. package/dist/types/index.js +102 -0
  530. package/dist/types/index.js.map +1 -0
  531. package/package.json +12 -9
  532. package/bin/cli.js +0 -68
  533. package/cli/bin.ts +0 -10
  534. package/cli/commands/attach.ts +0 -139
  535. package/cli/commands/backup.ts +0 -290
  536. package/cli/commands/backups.ts +0 -247
  537. package/cli/commands/clone.ts +0 -159
  538. package/cli/commands/config.ts +0 -367
  539. package/cli/commands/connect.ts +0 -684
  540. package/cli/commands/create.ts +0 -1201
  541. package/cli/commands/databases.ts +0 -630
  542. package/cli/commands/delete.ts +0 -133
  543. package/cli/commands/deps.ts +0 -342
  544. package/cli/commands/detach.ts +0 -107
  545. package/cli/commands/doctor.ts +0 -689
  546. package/cli/commands/duckdb.ts +0 -273
  547. package/cli/commands/edit.ts +0 -683
  548. package/cli/commands/engines.ts +0 -1914
  549. package/cli/commands/export.ts +0 -544
  550. package/cli/commands/info.ts +0 -340
  551. package/cli/commands/list.ts +0 -284
  552. package/cli/commands/logs.ts +0 -102
  553. package/cli/commands/menu/backup-handlers.ts +0 -1571
  554. package/cli/commands/menu/container-handlers.ts +0 -2288
  555. package/cli/commands/menu/engine-handlers.ts +0 -355
  556. package/cli/commands/menu/index.ts +0 -342
  557. package/cli/commands/menu/settings-handlers.ts +0 -365
  558. package/cli/commands/menu/shared.ts +0 -23
  559. package/cli/commands/menu/shell-handlers.ts +0 -1811
  560. package/cli/commands/menu/sql-handlers.ts +0 -231
  561. package/cli/commands/menu/update-handlers.ts +0 -378
  562. package/cli/commands/menu/validators.ts +0 -8
  563. package/cli/commands/ports.ts +0 -211
  564. package/cli/commands/pull.ts +0 -223
  565. package/cli/commands/query.ts +0 -241
  566. package/cli/commands/restore.ts +0 -587
  567. package/cli/commands/run.ts +0 -178
  568. package/cli/commands/self-update.ts +0 -121
  569. package/cli/commands/sqlite.ts +0 -273
  570. package/cli/commands/start.ts +0 -218
  571. package/cli/commands/stop.ts +0 -241
  572. package/cli/commands/url.ts +0 -104
  573. package/cli/commands/users.ts +0 -264
  574. package/cli/commands/version.ts +0 -55
  575. package/cli/commands/which.ts +0 -290
  576. package/cli/constants.ts +0 -233
  577. package/cli/helpers.ts +0 -1593
  578. package/cli/index.ts +0 -162
  579. package/cli/ui/prompts.ts +0 -1525
  580. package/cli/ui/spinner.ts +0 -88
  581. package/cli/ui/theme.ts +0 -128
  582. package/cli/utils/file-follower.ts +0 -93
  583. package/config/backup-formats.ts +0 -446
  584. package/config/defaults.ts +0 -56
  585. package/config/engine-defaults.ts +0 -336
  586. package/config/engines-registry.ts +0 -150
  587. package/config/engines.schema.json +0 -135
  588. package/config/os-dependencies.ts +0 -888
  589. package/config/paths.ts +0 -200
  590. package/core/backup-restore.ts +0 -330
  591. package/core/base-binary-manager.ts +0 -562
  592. package/core/base-document-binary-manager.ts +0 -523
  593. package/core/base-embedded-binary-manager.ts +0 -547
  594. package/core/base-server-binary-manager.ts +0 -523
  595. package/core/config-manager.ts +0 -652
  596. package/core/container-manager.ts +0 -787
  597. package/core/credential-generator.ts +0 -93
  598. package/core/credential-manager.ts +0 -259
  599. package/core/dblab-utils.ts +0 -113
  600. package/core/dependency-manager.ts +0 -512
  601. package/core/docker-exporter.ts +0 -1345
  602. package/core/error-handler.ts +0 -419
  603. package/core/fs-error-utils.ts +0 -82
  604. package/core/homebrew-version-manager.ts +0 -352
  605. package/core/hostdb-client.ts +0 -344
  606. package/core/hostdb-metadata.ts +0 -350
  607. package/core/hostdb-releases-factory.ts +0 -237
  608. package/core/library-env.ts +0 -118
  609. package/core/pgweb-utils.ts +0 -62
  610. package/core/platform-service.ts +0 -829
  611. package/core/port-manager.ts +0 -165
  612. package/core/process-manager.ts +0 -576
  613. package/core/pull-manager.ts +0 -511
  614. package/core/query-parser.ts +0 -514
  615. package/core/spawn-utils.ts +0 -122
  616. package/core/start-with-retry.ts +0 -130
  617. package/core/test-cleanup.ts +0 -108
  618. package/core/tls-generator.ts +0 -116
  619. package/core/transaction-manager.ts +0 -158
  620. package/core/update-manager.ts +0 -308
  621. package/core/version-migration.ts +0 -346
  622. package/core/version-utils.ts +0 -104
  623. package/engines/base-engine.ts +0 -340
  624. package/engines/clickhouse/README.md +0 -231
  625. package/engines/clickhouse/backup.ts +0 -398
  626. package/engines/clickhouse/binary-manager.ts +0 -201
  627. package/engines/clickhouse/binary-urls.ts +0 -125
  628. package/engines/clickhouse/cli-utils.ts +0 -176
  629. package/engines/clickhouse/hostdb-releases.ts +0 -30
  630. package/engines/clickhouse/index.ts +0 -1345
  631. package/engines/clickhouse/restore.ts +0 -466
  632. package/engines/clickhouse/version-maps.ts +0 -95
  633. package/engines/clickhouse/version-validator.ts +0 -154
  634. package/engines/cockroachdb/README.md +0 -170
  635. package/engines/cockroachdb/backup.ts +0 -376
  636. package/engines/cockroachdb/binary-manager.ts +0 -45
  637. package/engines/cockroachdb/binary-urls.ts +0 -40
  638. package/engines/cockroachdb/cli-utils.ts +0 -384
  639. package/engines/cockroachdb/hostdb-releases.ts +0 -26
  640. package/engines/cockroachdb/index.ts +0 -1276
  641. package/engines/cockroachdb/restore.ts +0 -455
  642. package/engines/cockroachdb/version-maps.ts +0 -42
  643. package/engines/couchdb/README.md +0 -257
  644. package/engines/couchdb/api-client.ts +0 -81
  645. package/engines/couchdb/backup.ts +0 -137
  646. package/engines/couchdb/binary-manager.ts +0 -86
  647. package/engines/couchdb/binary-urls.ts +0 -115
  648. package/engines/couchdb/hostdb-releases.ts +0 -23
  649. package/engines/couchdb/index.ts +0 -1429
  650. package/engines/couchdb/restore.ts +0 -290
  651. package/engines/couchdb/version-maps.ts +0 -78
  652. package/engines/couchdb/version-validator.ts +0 -111
  653. package/engines/duckdb/README.md +0 -154
  654. package/engines/duckdb/binary-manager.ts +0 -45
  655. package/engines/duckdb/hostdb-releases.ts +0 -23
  656. package/engines/duckdb/index.ts +0 -749
  657. package/engines/duckdb/registry.ts +0 -303
  658. package/engines/duckdb/scanner.ts +0 -22
  659. package/engines/duckdb/version-maps.ts +0 -78
  660. package/engines/duckdb/version-validator.ts +0 -78
  661. package/engines/ferretdb/README.md +0 -262
  662. package/engines/ferretdb/backup.ts +0 -173
  663. package/engines/ferretdb/binary-manager.ts +0 -1095
  664. package/engines/ferretdb/binary-urls.ts +0 -183
  665. package/engines/ferretdb/index.ts +0 -1907
  666. package/engines/ferretdb/restore.ts +0 -357
  667. package/engines/file-based-utils.ts +0 -262
  668. package/engines/index.ts +0 -131
  669. package/engines/influxdb/README.md +0 -180
  670. package/engines/influxdb/api-client.ts +0 -64
  671. package/engines/influxdb/backup.ts +0 -160
  672. package/engines/influxdb/binary-manager.ts +0 -110
  673. package/engines/influxdb/binary-urls.ts +0 -69
  674. package/engines/influxdb/hostdb-releases.ts +0 -23
  675. package/engines/influxdb/index.ts +0 -1272
  676. package/engines/influxdb/restore.ts +0 -417
  677. package/engines/influxdb/version-maps.ts +0 -75
  678. package/engines/influxdb/version-validator.ts +0 -128
  679. package/engines/mariadb/README.md +0 -141
  680. package/engines/mariadb/backup.ts +0 -233
  681. package/engines/mariadb/binary-manager.ts +0 -45
  682. package/engines/mariadb/hostdb-releases.ts +0 -23
  683. package/engines/mariadb/index.ts +0 -1300
  684. package/engines/mariadb/restore.ts +0 -447
  685. package/engines/mariadb/version-maps.ts +0 -72
  686. package/engines/mariadb/version-validator.ts +0 -181
  687. package/engines/meilisearch/README.md +0 -255
  688. package/engines/meilisearch/api-client.ts +0 -61
  689. package/engines/meilisearch/backup.ts +0 -233
  690. package/engines/meilisearch/binary-manager.ts +0 -43
  691. package/engines/meilisearch/binary-urls.ts +0 -69
  692. package/engines/meilisearch/hostdb-releases.ts +0 -26
  693. package/engines/meilisearch/index.ts +0 -1292
  694. package/engines/meilisearch/restore.ts +0 -219
  695. package/engines/meilisearch/version-maps.ts +0 -78
  696. package/engines/meilisearch/version-validator.ts +0 -128
  697. package/engines/mongodb/README.md +0 -162
  698. package/engines/mongodb/backup.ts +0 -127
  699. package/engines/mongodb/binary-manager.ts +0 -48
  700. package/engines/mongodb/binary-urls.ts +0 -63
  701. package/engines/mongodb/cli-utils.ts +0 -171
  702. package/engines/mongodb/hostdb-releases.ts +0 -91
  703. package/engines/mongodb/index.ts +0 -1118
  704. package/engines/mongodb/restore.ts +0 -361
  705. package/engines/mongodb/version-maps.ts +0 -91
  706. package/engines/mongodb/version-validator.ts +0 -160
  707. package/engines/mysql/README.md +0 -142
  708. package/engines/mysql/backup.ts +0 -270
  709. package/engines/mysql/binary-detection.ts +0 -408
  710. package/engines/mysql/binary-manager.ts +0 -42
  711. package/engines/mysql/binary-urls.ts +0 -104
  712. package/engines/mysql/index.ts +0 -1361
  713. package/engines/mysql/restore.ts +0 -500
  714. package/engines/mysql/version-maps.ts +0 -91
  715. package/engines/mysql/version-validator.ts +0 -369
  716. package/engines/postgresql/README.md +0 -158
  717. package/engines/postgresql/backup.ts +0 -151
  718. package/engines/postgresql/binary-manager.ts +0 -114
  719. package/engines/postgresql/binary-urls.ts +0 -99
  720. package/engines/postgresql/hostdb-releases.ts +0 -26
  721. package/engines/postgresql/index.ts +0 -1143
  722. package/engines/postgresql/remote-version.ts +0 -161
  723. package/engines/postgresql/restore.ts +0 -342
  724. package/engines/postgresql/version-maps.ts +0 -83
  725. package/engines/postgresql/version-validator.ts +0 -413
  726. package/engines/qdrant/README.md +0 -222
  727. package/engines/qdrant/api-client.ts +0 -61
  728. package/engines/qdrant/backup.ts +0 -165
  729. package/engines/qdrant/binary-manager.ts +0 -43
  730. package/engines/qdrant/binary-urls.ts +0 -115
  731. package/engines/qdrant/cli-utils.ts +0 -43
  732. package/engines/qdrant/hostdb-releases.ts +0 -23
  733. package/engines/qdrant/index.ts +0 -1312
  734. package/engines/qdrant/restore.ts +0 -203
  735. package/engines/qdrant/version-maps.ts +0 -78
  736. package/engines/qdrant/version-validator.ts +0 -128
  737. package/engines/questdb/README.md +0 -334
  738. package/engines/questdb/backup.ts +0 -220
  739. package/engines/questdb/binary-manager.ts +0 -310
  740. package/engines/questdb/binary-urls.ts +0 -34
  741. package/engines/questdb/hostdb-releases.ts +0 -23
  742. package/engines/questdb/index.ts +0 -1023
  743. package/engines/questdb/restore.ts +0 -260
  744. package/engines/questdb/version-maps.ts +0 -37
  745. package/engines/questdb/version-validator.ts +0 -121
  746. package/engines/redis/README.md +0 -173
  747. package/engines/redis/backup.ts +0 -389
  748. package/engines/redis/binary-manager.ts +0 -44
  749. package/engines/redis/binary-urls.ts +0 -117
  750. package/engines/redis/cli-utils.ts +0 -42
  751. package/engines/redis/hostdb-releases.ts +0 -23
  752. package/engines/redis/index.ts +0 -1583
  753. package/engines/redis/restore.ts +0 -443
  754. package/engines/redis/version-maps.ts +0 -81
  755. package/engines/redis/version-validator.ts +0 -131
  756. package/engines/sqlite/README.md +0 -162
  757. package/engines/sqlite/binary-manager.ts +0 -52
  758. package/engines/sqlite/hostdb-releases.ts +0 -23
  759. package/engines/sqlite/index.ts +0 -641
  760. package/engines/sqlite/registry.ts +0 -198
  761. package/engines/sqlite/scanner.ts +0 -22
  762. package/engines/sqlite/version-maps.ts +0 -64
  763. package/engines/surrealdb/README.md +0 -218
  764. package/engines/surrealdb/backup.ts +0 -131
  765. package/engines/surrealdb/binary-manager.ts +0 -45
  766. package/engines/surrealdb/binary-urls.ts +0 -40
  767. package/engines/surrealdb/cli-utils.ts +0 -173
  768. package/engines/surrealdb/hostdb-releases.ts +0 -23
  769. package/engines/surrealdb/index.ts +0 -1246
  770. package/engines/surrealdb/restore.ts +0 -302
  771. package/engines/surrealdb/version-maps.ts +0 -41
  772. package/engines/tigerbeetle/README.md +0 -61
  773. package/engines/tigerbeetle/backup.ts +0 -49
  774. package/engines/tigerbeetle/binary-manager.ts +0 -95
  775. package/engines/tigerbeetle/binary-urls.ts +0 -62
  776. package/engines/tigerbeetle/hostdb-releases.ts +0 -26
  777. package/engines/tigerbeetle/index.ts +0 -746
  778. package/engines/tigerbeetle/restore.ts +0 -130
  779. package/engines/tigerbeetle/version-validator.ts +0 -126
  780. package/engines/typedb/backup.ts +0 -167
  781. package/engines/typedb/binary-manager.ts +0 -200
  782. package/engines/typedb/binary-urls.ts +0 -40
  783. package/engines/typedb/cli-utils.ts +0 -210
  784. package/engines/typedb/hostdb-releases.ts +0 -23
  785. package/engines/typedb/index.ts +0 -1275
  786. package/engines/typedb/restore.ts +0 -377
  787. package/engines/typedb/version-maps.ts +0 -48
  788. package/engines/typedb/version-validator.ts +0 -127
  789. package/engines/valkey/README.md +0 -219
  790. package/engines/valkey/backup.ts +0 -389
  791. package/engines/valkey/binary-manager.ts +0 -45
  792. package/engines/valkey/binary-urls.ts +0 -122
  793. package/engines/valkey/cli-utils.ts +0 -42
  794. package/engines/valkey/hostdb-releases.ts +0 -23
  795. package/engines/valkey/index.ts +0 -1585
  796. package/engines/valkey/restore.ts +0 -446
  797. package/engines/valkey/version-maps.ts +0 -81
  798. package/engines/valkey/version-validator.ts +0 -131
  799. package/engines/weaviate/README.md +0 -302
  800. package/engines/weaviate/api-client.ts +0 -61
  801. package/engines/weaviate/backup.ts +0 -145
  802. package/engines/weaviate/binary-manager.ts +0 -80
  803. package/engines/weaviate/binary-urls.ts +0 -115
  804. package/engines/weaviate/cli-utils.ts +0 -43
  805. package/engines/weaviate/hostdb-releases.ts +0 -23
  806. package/engines/weaviate/index.ts +0 -1139
  807. package/engines/weaviate/restore.ts +0 -235
  808. package/engines/weaviate/version-maps.ts +0 -78
  809. package/engines/weaviate/version-validator.ts +0 -128
  810. package/types/index.ts +0 -624
  811. /package/{config → dist/config}/engines.json +0 -0
@@ -0,0 +1,1257 @@
1
+ import { spawn, exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { existsSync } from 'fs';
4
+ import { mkdir, writeFile, readFile, unlink } from 'fs/promises';
5
+ import { join } from 'path';
6
+ import { BaseEngine } from '../base-engine.js';
7
+ import { paths } from '../../config/paths.js';
8
+ import { getEngineDefaults } from '../../config/defaults.js';
9
+ import { platformService, isWindows } from '../../core/platform-service.js';
10
+ import { configManager } from '../../core/config-manager.js';
11
+ import { logDebug, logWarning, assertValidUsername, } from '../../core/error-handler.js';
12
+ import { processManager } from '../../core/process-manager.js';
13
+ import { valkeyBinaryManager } from './binary-manager.js';
14
+ import { getBinaryUrl } from './binary-urls.js';
15
+ import { normalizeVersion, SUPPORTED_MAJOR_VERSIONS, VALKEY_VERSION_MAP, } from './version-maps.js';
16
+ import { fetchAvailableVersions as fetchHostdbVersions } from './hostdb-releases.js';
17
+ import { detectBackupFormat as detectBackupFormatImpl, restoreBackup, } from './restore.js';
18
+ import { createBackup } from './backup.js';
19
+ import { getValkeyCliPath, VALKEY_CLI_NOT_FOUND_ERROR } from './cli-utils.js';
20
+ import { parseRedisResult } from '../../core/query-parser.js';
21
+ import { getLibraryEnv, detectLibraryError } from '../../core/library-env.js';
22
+ const execAsync = promisify(exec);
23
+ const ENGINE = 'valkey';
24
+ /**
25
+ * Escape a Valkey key for use in CLI commands.
26
+ * Escapes backslashes, double quotes, and control characters to prevent
27
+ * command injection and ensure keys are parsed correctly by the CLI.
28
+ */
29
+ function escapeKeyForCommand(key) {
30
+ return key
31
+ .replace(/\\/g, '\\\\') // Backslashes first to prevent double-escaping
32
+ .replace(/"/g, '\\"') // Double quotes
33
+ .replace(/\n/g, '\\n') // Newline
34
+ .replace(/\r/g, '\\r') // Carriage return
35
+ .replace(/\t/g, '\\t'); // Tab
36
+ }
37
+ const engineDef = getEngineDefaults(ENGINE);
38
+ /**
39
+ * Shell metacharacters that indicate potential command injection
40
+ * These patterns shouldn't appear in valid Valkey commands
41
+ */
42
+ const SHELL_INJECTION_PATTERNS = [
43
+ /;\s*\S/, // Command chaining: ; followed by another command
44
+ /\$\(/, // Command substitution: $(...)
45
+ /\$\{/, // Variable substitution: ${...}
46
+ /`/, // Backtick command substitution
47
+ /&&/, // Logical AND chaining
48
+ /\|\|/, // Logical OR chaining
49
+ /\|\s*\S/, // Pipe to another command
50
+ ];
51
+ // Validate that a command doesn't contain shell injection patterns
52
+ function validateCommand(command) {
53
+ for (const pattern of SHELL_INJECTION_PATTERNS) {
54
+ if (pattern.test(command)) {
55
+ throw new Error(`Command contains shell metacharacters that are not valid in Valkey commands. ` +
56
+ `If you need complex commands, use a script file instead.`);
57
+ }
58
+ }
59
+ }
60
+ /**
61
+ * Convert a Windows path to Cygwin path format.
62
+ * Valkey Windows binaries are built with Cygwin runtime and expect paths
63
+ * in /cygdrive/c/... format when passed as command-line arguments.
64
+ *
65
+ * Example: C:\Users\foo\config.conf -> /cygdrive/c/Users/foo/config.conf
66
+ */
67
+ function toCygwinPath(windowsPath) {
68
+ // Match drive letter at start (e.g., C:\ or D:/)
69
+ const driveMatch = windowsPath.match(/^([A-Za-z]):[/\\]/);
70
+ if (!driveMatch) {
71
+ // Not a Windows absolute path, return as-is with forward slashes
72
+ return windowsPath.replace(/\\/g, '/');
73
+ }
74
+ const driveLetter = driveMatch[1].toLowerCase();
75
+ const restOfPath = windowsPath.slice(3).replace(/\\/g, '/');
76
+ return `/cygdrive/${driveLetter}/${restOfPath}`;
77
+ }
78
+ /**
79
+ * Parse a Valkey connection string
80
+ * Supported schemes:
81
+ * - redis:// (plain, no TLS)
82
+ * - rediss:// (TLS enabled)
83
+ * - valkey:// (plain, no TLS)
84
+ * - valkeys:// (TLS enabled)
85
+ *
86
+ * Format: scheme://[user:password@]host[:port][/database]
87
+ *
88
+ * Examples:
89
+ * - redis://localhost:6379
90
+ * - rediss://secure.host:6379/0 (TLS)
91
+ * - valkey://localhost:6379
92
+ * - valkeys://secure.host:6379 (TLS)
93
+ */
94
+ function parseValkeyConnectionString(connectionString) {
95
+ let url;
96
+ const normalized = connectionString.trim();
97
+ // Check for valid schemes
98
+ const validSchemes = ['redis://', 'rediss://', 'valkey://', 'valkeys://'];
99
+ const hasValidScheme = validSchemes.some((scheme) => normalized.startsWith(scheme));
100
+ if (!hasValidScheme) {
101
+ throw new Error(`Invalid Valkey connection string: ${connectionString}\n` +
102
+ 'Expected format: scheme://[user:password@]host:port[/database]\n' +
103
+ 'Supported schemes: redis://, rediss://, valkey://, valkeys://\n' +
104
+ '(Use rediss:// or valkeys:// for TLS connections)');
105
+ }
106
+ // Normalize valkey(s):// to redis(s):// for URL parsing
107
+ let urlString = normalized;
108
+ if (normalized.startsWith('valkeys://')) {
109
+ urlString = normalized.replace('valkeys://', 'rediss://');
110
+ }
111
+ else if (normalized.startsWith('valkey://')) {
112
+ urlString = normalized.replace('valkey://', 'redis://');
113
+ }
114
+ try {
115
+ url = new URL(urlString);
116
+ }
117
+ catch {
118
+ throw new Error(`Invalid Valkey connection string: ${connectionString}\n` +
119
+ 'Expected format: scheme://[user:password@]host:port[/database]');
120
+ }
121
+ // Determine TLS based on original scheme
122
+ const tls = normalized.startsWith('rediss://') || normalized.startsWith('valkeys://');
123
+ const host = url.hostname || 'localhost';
124
+ const port = parseInt(url.port, 10) || 6379;
125
+ // Valkey supports ACL with usernames (inherited from Redis 6.0+)
126
+ // Format: redis://username:password@host:port/db
127
+ const username = url.username || undefined;
128
+ const password = url.password || undefined;
129
+ // Database is in the path (e.g., /5 means database 5)
130
+ let database = 0;
131
+ if (url.pathname && url.pathname !== '/') {
132
+ const dbNum = parseInt(url.pathname.replace('/', ''), 10);
133
+ if (!isNaN(dbNum)) {
134
+ if (dbNum < 0 || dbNum > 15) {
135
+ throw new RangeError(`Invalid Valkey database number: ${dbNum} (from path "${url.pathname}").\n` +
136
+ 'Valkey databases must be 0-15.');
137
+ }
138
+ database = dbNum;
139
+ }
140
+ }
141
+ return { host, port, username, password, database, tls };
142
+ }
143
+ // Build a valkey-cli command for inline command execution
144
+ export function buildValkeyCliCommand(valkeyCliPath, port, command, options) {
145
+ // Validate command doesn't contain shell injection patterns
146
+ validateCommand(command);
147
+ const db = options?.database || '0';
148
+ // Escape double quotes consistently on all platforms to prevent shell interpretation issues
149
+ const escaped = command.replace(/"/g, '\\"');
150
+ return `"${valkeyCliPath}" -h 127.0.0.1 -p ${port} -n ${db} ${escaped}`;
151
+ }
152
+ // Generate Valkey configuration file content
153
+ function generateValkeyConfig(options) {
154
+ // Windows Valkey doesn't support daemonize natively, use detached spawn instead
155
+ const daemonizeValue = options.daemonize ?? true;
156
+ // Valkey config requires forward slashes even on Windows
157
+ const normalizePathForValkey = (p) => p.replace(/\\/g, '/');
158
+ return `# SpinDB generated Valkey configuration
159
+ port ${options.port}
160
+ bind 127.0.0.1
161
+ dir ${normalizePathForValkey(options.dataDir)}
162
+ daemonize ${daemonizeValue ? 'yes' : 'no'}
163
+ logfile ${normalizePathForValkey(options.logFile)}
164
+ pidfile ${normalizePathForValkey(options.pidFile)}
165
+
166
+ # Persistence - RDB snapshots
167
+ save 900 1
168
+ save 300 10
169
+ save 60 10000
170
+ dbfilename dump.rdb
171
+
172
+ # Append Only File (disabled for local dev)
173
+ appendonly no
174
+
175
+ # Suppress ARM64 copy-on-write warning with Transparent Huge Pages.
176
+ # Redis/Valkey refuses to start on ARM64 with THP enabled unless this is set.
177
+ # Safe for local development (SpinDB's use case).
178
+ ignore-warnings ARM64-COW-BUG
179
+ `;
180
+ }
181
+ export class ValkeyEngine extends BaseEngine {
182
+ name = ENGINE;
183
+ displayName = 'Valkey';
184
+ defaultPort = engineDef.defaultPort;
185
+ supportedVersions = SUPPORTED_MAJOR_VERSIONS;
186
+ // Get platform info for binary operations
187
+ getPlatformInfo() {
188
+ return platformService.getPlatformInfo();
189
+ }
190
+ // Fetch available versions from hostdb (dynamically or from cache/fallback)
191
+ async fetchAvailableVersions() {
192
+ return fetchHostdbVersions();
193
+ }
194
+ // Get binary download URL from hostdb
195
+ getBinaryUrl(version, platform, arch) {
196
+ return getBinaryUrl(version, platform, arch);
197
+ }
198
+ // Resolves version string to full version (e.g., '8' -> '8.0.6')
199
+ resolveFullVersion(version) {
200
+ // Check if already a full version (has at least two dots)
201
+ if (/^\d+\.\d+\.\d+$/.test(version)) {
202
+ return version;
203
+ }
204
+ // It's a major version, resolve using version map
205
+ return VALKEY_VERSION_MAP[version] || `${version}.0.0`;
206
+ }
207
+ // Get the path where binaries for a version would be installed
208
+ getBinaryPath(version) {
209
+ const fullVersion = this.resolveFullVersion(version);
210
+ const { platform: p, arch: a } = this.getPlatformInfo();
211
+ return paths.getBinaryPath({
212
+ engine: 'valkey',
213
+ version: fullVersion,
214
+ platform: p,
215
+ arch: a,
216
+ });
217
+ }
218
+ // Verify that Valkey binaries are available
219
+ async verifyBinary(binPath) {
220
+ const ext = platformService.getExecutableExtension();
221
+ const serverPath = join(binPath, 'bin', `valkey-server${ext}`);
222
+ return existsSync(serverPath);
223
+ }
224
+ //Check if a specific Valkey version is installed (downloaded)
225
+ async isBinaryInstalled(version) {
226
+ const { platform, arch } = this.getPlatformInfo();
227
+ return valkeyBinaryManager.isInstalled(version, platform, arch);
228
+ }
229
+ /**
230
+ * Ensure Valkey binaries are available for a specific version
231
+ * Downloads from hostdb if not already installed
232
+ * Returns the path to the bin directory
233
+ */
234
+ async ensureBinaries(version, onProgress) {
235
+ const { platform, arch } = this.getPlatformInfo();
236
+ const binPath = await valkeyBinaryManager.ensureInstalled(version, platform, arch, onProgress);
237
+ // Register binaries in config
238
+ const ext = platformService.getExecutableExtension();
239
+ const tools = ['valkey-server', 'valkey-cli'];
240
+ for (const tool of tools) {
241
+ const toolPath = join(binPath, 'bin', `${tool}${ext}`);
242
+ if (existsSync(toolPath)) {
243
+ await configManager.setBinaryPath(tool, toolPath, 'bundled');
244
+ }
245
+ }
246
+ return binPath;
247
+ }
248
+ /**
249
+ * Initialize a new Valkey data directory
250
+ * Creates the directory and generates valkey.conf
251
+ */
252
+ async initDataDir(containerName, _version, options = {}) {
253
+ const dataDir = paths.getContainerDataPath(containerName, {
254
+ engine: ENGINE,
255
+ });
256
+ const containerDir = paths.getContainerPath(containerName, {
257
+ engine: ENGINE,
258
+ });
259
+ const logFile = paths.getContainerLogPath(containerName, { engine: ENGINE });
260
+ const pidFile = join(containerDir, 'valkey.pid');
261
+ const port = options.port || engineDef.defaultPort;
262
+ // Create data directory if it doesn't exist
263
+ if (!existsSync(dataDir)) {
264
+ await mkdir(dataDir, { recursive: true });
265
+ logDebug(`Created Valkey data directory: ${dataDir}`);
266
+ }
267
+ // Generate valkey.conf
268
+ const configPath = join(containerDir, 'valkey.conf');
269
+ const configContent = generateValkeyConfig({
270
+ port,
271
+ dataDir,
272
+ logFile,
273
+ pidFile,
274
+ });
275
+ await writeFile(configPath, configContent);
276
+ logDebug(`Generated Valkey config: ${configPath}`);
277
+ return dataDir;
278
+ }
279
+ // Get the path to valkey-server for a version
280
+ async getValkeyServerPath(version) {
281
+ const { platform, arch } = this.getPlatformInfo();
282
+ const fullVersion = normalizeVersion(version);
283
+ const binPath = paths.getBinaryPath({
284
+ engine: 'valkey',
285
+ version: fullVersion,
286
+ platform,
287
+ arch,
288
+ });
289
+ const ext = platformService.getExecutableExtension();
290
+ const serverPath = join(binPath, 'bin', `valkey-server${ext}`);
291
+ if (existsSync(serverPath)) {
292
+ return serverPath;
293
+ }
294
+ throw new Error(`Valkey ${version} is not installed. Run: spindb engines download valkey ${version}`);
295
+ }
296
+ // Get the path to valkey-cli for a version
297
+ async getValkeyCliPath(version) {
298
+ // Check config cache first
299
+ const cached = await configManager.getBinaryPath('valkey-cli');
300
+ if (cached && existsSync(cached)) {
301
+ return cached;
302
+ }
303
+ // If version provided, use downloaded binary
304
+ if (version) {
305
+ const { platform, arch } = this.getPlatformInfo();
306
+ const fullVersion = normalizeVersion(version);
307
+ const binPath = paths.getBinaryPath({
308
+ engine: 'valkey',
309
+ version: fullVersion,
310
+ platform,
311
+ arch,
312
+ });
313
+ const ext = platformService.getExecutableExtension();
314
+ const cliPath = join(binPath, 'bin', `valkey-cli${ext}`);
315
+ if (existsSync(cliPath)) {
316
+ return cliPath;
317
+ }
318
+ }
319
+ throw new Error('valkey-cli not found. Run: spindb engines download valkey <version>');
320
+ }
321
+ /**
322
+ * Start Valkey server
323
+ * CLI wrapper: valkey-server /path/to/valkey.conf
324
+ */
325
+ async start(container, onProgress) {
326
+ const { name, port, version, binaryPath } = container;
327
+ // Check if already running (idempotent behavior)
328
+ const alreadyRunning = await processManager.isRunning(name, {
329
+ engine: ENGINE,
330
+ });
331
+ if (alreadyRunning) {
332
+ return {
333
+ port,
334
+ connectionString: this.getConnectionString(container),
335
+ };
336
+ }
337
+ // Use stored binary path if available (from container creation)
338
+ // This ensures version consistency - the container uses the same binary it was created with
339
+ let valkeyServer = null;
340
+ if (binaryPath && existsSync(binaryPath)) {
341
+ // binaryPath is the directory (e.g., ~/.spindb/bin/valkey-8.0.6-linux-arm64)
342
+ // We need to construct the full path to valkey-server
343
+ const ext = platformService.getExecutableExtension();
344
+ const serverPath = join(binaryPath, 'bin', `valkey-server${ext}`);
345
+ if (existsSync(serverPath)) {
346
+ valkeyServer = serverPath;
347
+ logDebug(`Using stored binary path: ${valkeyServer}`);
348
+ }
349
+ }
350
+ // If we didn't find the binary above, fall back to normal path
351
+ if (!valkeyServer) {
352
+ // Get binary from downloaded hostdb binaries
353
+ try {
354
+ valkeyServer = await this.getValkeyServerPath(version);
355
+ }
356
+ catch (error) {
357
+ // Binary not downloaded yet - this is an orphaned container situation
358
+ const originalMessage = error instanceof Error ? error.message : String(error);
359
+ throw new Error(`Valkey ${version} is not installed. Run: spindb engines download valkey ${version}\n` +
360
+ ` Original error: ${originalMessage}`);
361
+ }
362
+ }
363
+ logDebug(`Using valkey-server for version ${version}: ${valkeyServer}`);
364
+ // Compute library fallback paths from the binary directory
365
+ const binBaseDir = binaryPath || this.getBinaryPath(version);
366
+ const libraryEnv = getLibraryEnv(binBaseDir);
367
+ const containerDir = paths.getContainerPath(name, { engine: ENGINE });
368
+ const configPath = join(containerDir, 'valkey.conf');
369
+ const dataDir = paths.getContainerDataPath(name, { engine: ENGINE });
370
+ const logFile = paths.getContainerLogPath(name, { engine: ENGINE });
371
+ const pidFile = join(containerDir, 'valkey.pid');
372
+ // Windows Valkey doesn't support daemonize natively
373
+ // Use detached spawn on Windows instead, similar to MongoDB
374
+ const useDetachedSpawn = isWindows();
375
+ // Regenerate config with current port (in case it changed)
376
+ const configContent = generateValkeyConfig({
377
+ port,
378
+ dataDir,
379
+ logFile,
380
+ pidFile,
381
+ daemonize: !useDetachedSpawn, // Disable daemonize on Windows
382
+ });
383
+ await writeFile(configPath, configContent);
384
+ onProgress?.({ stage: 'starting', message: 'Starting Valkey...' });
385
+ logDebug(`Starting valkey-server with config: ${configPath}`);
386
+ /**
387
+ * Check log file for port binding errors
388
+ * Returns error message if found, null otherwise
389
+ */
390
+ const checkLogForPortError = async () => {
391
+ try {
392
+ const logContent = await readFile(logFile, 'utf-8');
393
+ const recentLog = logContent.slice(-2000); // Last 2KB
394
+ if (recentLog.includes('Address already in use') ||
395
+ recentLog.includes('bind: Address already in use')) {
396
+ return `Port ${port} is already in use (address already in use)`;
397
+ }
398
+ if (recentLog.includes('Failed listening on port')) {
399
+ return `Port ${port} is already in use`;
400
+ }
401
+ }
402
+ catch {
403
+ // Log file might not exist yet
404
+ }
405
+ return null;
406
+ };
407
+ if (useDetachedSpawn) {
408
+ // Windows: spawn detached process with proper error handling
409
+ // This follows the pattern used by MySQL which works on Windows
410
+ return new Promise((resolve, reject) => {
411
+ const spawnOpts = {
412
+ stdio: ['ignore', 'pipe', 'pipe'],
413
+ detached: true,
414
+ windowsHide: true,
415
+ env: { ...process.env, ...libraryEnv },
416
+ };
417
+ // Convert Windows path to Cygwin format for Cygwin-built binaries
418
+ const cygwinConfigPath = toCygwinPath(configPath);
419
+ const proc = spawn(valkeyServer, [cygwinConfigPath], spawnOpts);
420
+ let settled = false;
421
+ let stderrOutput = '';
422
+ let stdoutOutput = '';
423
+ // Handle spawn errors (binary not found, DLL issues, etc.)
424
+ proc.on('error', (err) => {
425
+ if (settled)
426
+ return;
427
+ settled = true;
428
+ reject(new Error(`Failed to spawn Valkey server: ${err.message}`));
429
+ });
430
+ proc.stdout?.on('data', (data) => {
431
+ const str = data.toString();
432
+ stdoutOutput += str;
433
+ logDebug(`valkey-server stdout: ${str}`);
434
+ });
435
+ proc.stderr?.on('data', (data) => {
436
+ const str = data.toString();
437
+ stderrOutput += str;
438
+ logDebug(`valkey-server stderr: ${str}`);
439
+ });
440
+ // Detach the process so it continues running after parent exits
441
+ proc.unref();
442
+ // Give spawn a moment to fail if it's going to, then check readiness
443
+ setTimeout(async () => {
444
+ if (settled)
445
+ return;
446
+ // Verify process actually started
447
+ if (!proc.pid) {
448
+ settled = true;
449
+ reject(new Error('Valkey server process failed to start (no PID)'));
450
+ return;
451
+ }
452
+ // Write PID file for consistency with other engines
453
+ try {
454
+ await writeFile(pidFile, String(proc.pid));
455
+ }
456
+ catch {
457
+ // Non-fatal - process is running, PID file is for convenience
458
+ }
459
+ // Wait for Valkey to be ready
460
+ const ready = await this.waitForReady(port, version);
461
+ if (settled)
462
+ return;
463
+ if (ready) {
464
+ // On Windows, Cygwin binaries may fork internally, making proc.pid stale.
465
+ // Find the actual PID by port and update the PID file (same pattern as QuestDB).
466
+ try {
467
+ const pids = await platformService.findProcessByPort(port);
468
+ if (pids.length > 0 && pids[0] !== proc.pid) {
469
+ logDebug(`Valkey actual PID ${pids[0]} differs from spawn PID ${proc.pid}, updating PID file`);
470
+ await writeFile(pidFile, String(pids[0]));
471
+ }
472
+ }
473
+ catch {
474
+ // Non-fatal - PID file already has proc.pid from earlier write
475
+ }
476
+ settled = true;
477
+ resolve({
478
+ port,
479
+ connectionString: this.getConnectionString(container),
480
+ });
481
+ }
482
+ else {
483
+ settled = true;
484
+ const portError = await checkLogForPortError();
485
+ // Read log file content for better error diagnostics
486
+ let logContent = '';
487
+ try {
488
+ logContent = await readFile(logFile, 'utf-8');
489
+ }
490
+ catch {
491
+ logContent = '(log file not found or empty)';
492
+ }
493
+ // Check for library loading errors first
494
+ const libError = detectLibraryError(stderrOutput + logContent, 'Valkey');
495
+ if (libError) {
496
+ reject(new Error(libError));
497
+ return;
498
+ }
499
+ const errorDetails = [
500
+ portError || 'Valkey failed to start within timeout.',
501
+ `Binary: ${valkeyServer}`,
502
+ `Config: ${configPath}`,
503
+ `Log file: ${logFile}`,
504
+ `Log content:\n${logContent || '(empty)'}`,
505
+ stderrOutput ? `Stderr:\n${stderrOutput}` : '',
506
+ stdoutOutput ? `Stdout:\n${stdoutOutput}` : '',
507
+ ]
508
+ .filter(Boolean)
509
+ .join('\n');
510
+ reject(new Error(errorDetails));
511
+ }
512
+ }, 500);
513
+ });
514
+ }
515
+ // Unix: Valkey with daemonize: yes handles its own forking
516
+ return new Promise((resolve, reject) => {
517
+ const proc = spawn(valkeyServer, [configPath], {
518
+ stdio: ['ignore', 'pipe', 'pipe'],
519
+ env: { ...process.env, ...libraryEnv },
520
+ });
521
+ let stdout = '';
522
+ let stderr = '';
523
+ proc.stdout?.on('data', (data) => {
524
+ stdout += data.toString();
525
+ logDebug(`valkey-server stdout: ${data.toString()}`);
526
+ });
527
+ proc.stderr?.on('data', (data) => {
528
+ stderr += data.toString();
529
+ logDebug(`valkey-server stderr: ${data.toString()}`);
530
+ });
531
+ proc.on('error', reject);
532
+ proc.on('close', async (code) => {
533
+ // Valkey with daemonize: yes exits immediately after forking
534
+ // Exit code 0 means the parent forked successfully, but the child may still fail
535
+ if (code === 0 || code === null) {
536
+ // Give the child process a moment to start (or fail)
537
+ await new Promise((r) => setTimeout(r, 500));
538
+ // Check log for early startup failures (like port conflicts)
539
+ const earlyError = await checkLogForPortError();
540
+ if (earlyError) {
541
+ reject(new Error(earlyError));
542
+ return;
543
+ }
544
+ // Wait for Valkey to be ready
545
+ const ready = await this.waitForReady(port, version);
546
+ if (ready) {
547
+ resolve({
548
+ port,
549
+ connectionString: this.getConnectionString(container),
550
+ });
551
+ }
552
+ else {
553
+ // Check log again for errors if not ready
554
+ const portError = await checkLogForPortError();
555
+ if (portError) {
556
+ reject(new Error(portError));
557
+ return;
558
+ }
559
+ // Check for library loading errors
560
+ let logContent = '';
561
+ try {
562
+ logContent = await readFile(logFile, 'utf-8');
563
+ }
564
+ catch {
565
+ logContent = '';
566
+ }
567
+ const libError = detectLibraryError(stderr + logContent, 'Valkey');
568
+ if (libError) {
569
+ reject(new Error(libError));
570
+ return;
571
+ }
572
+ reject(new Error(`Valkey failed to start within timeout. Check logs at: ${logFile}`));
573
+ }
574
+ }
575
+ else {
576
+ // Check for library loading errors on non-zero exit
577
+ const libError = detectLibraryError(stderr || stdout, 'Valkey');
578
+ if (libError) {
579
+ reject(new Error(libError));
580
+ return;
581
+ }
582
+ reject(new Error(stderr || stdout || `valkey-server exited with code ${code}`));
583
+ }
584
+ });
585
+ });
586
+ }
587
+ // Wait for Valkey to be ready to accept connections
588
+ // TODO - consider copying the mongodb logic for this
589
+ async waitForReady(port, version, timeoutMs = 60000) {
590
+ const startTime = Date.now();
591
+ const checkInterval = 500;
592
+ let valkeyCli;
593
+ try {
594
+ valkeyCli = await this.getValkeyCliPathForVersion(version);
595
+ }
596
+ catch {
597
+ logWarning('valkey-cli not found, cannot verify Valkey is ready. Assuming ready after brief delay.');
598
+ // Give Valkey a moment to start, then assume success
599
+ await new Promise((resolve) => setTimeout(resolve, 2000));
600
+ return true;
601
+ }
602
+ while (Date.now() - startTime < timeoutMs) {
603
+ try {
604
+ const cmd = `"${valkeyCli}" -h 127.0.0.1 -p ${port} PING`;
605
+ const { stdout } = await execAsync(cmd, { timeout: 5000 });
606
+ if (stdout.trim() === 'PONG') {
607
+ logDebug(`Valkey ready on port ${port}`);
608
+ return true;
609
+ }
610
+ }
611
+ catch {
612
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
613
+ }
614
+ }
615
+ logWarning(`Valkey did not become ready within ${timeoutMs}ms`);
616
+ return false;
617
+ }
618
+ /**
619
+ * Stop Valkey server
620
+ * Uses SHUTDOWN SAVE via valkey-cli to persist data before stopping
621
+ */
622
+ async stop(container) {
623
+ const { name, port, version } = container;
624
+ const containerDir = paths.getContainerPath(name, { engine: ENGINE });
625
+ const pidFile = join(containerDir, 'valkey.pid');
626
+ logDebug(`Stopping Valkey container "${name}" on port ${port}`);
627
+ // Try graceful shutdown via valkey-cli
628
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
629
+ if (valkeyCli) {
630
+ try {
631
+ const cmd = `"${valkeyCli}" -h 127.0.0.1 -p ${port} SHUTDOWN SAVE`;
632
+ await execAsync(cmd, { timeout: 10000 });
633
+ logDebug('Valkey shutdown command sent');
634
+ // Wait a bit for process to exit
635
+ await new Promise((resolve) => setTimeout(resolve, 2000));
636
+ }
637
+ catch (error) {
638
+ logDebug(`valkey-cli shutdown failed: ${error}`);
639
+ // Continue to PID-based shutdown
640
+ }
641
+ }
642
+ // Get PID and force kill if needed
643
+ let pid = null;
644
+ if (existsSync(pidFile)) {
645
+ try {
646
+ const content = await readFile(pidFile, 'utf8');
647
+ pid = parseInt(content.trim(), 10);
648
+ }
649
+ catch {
650
+ // Ignore
651
+ }
652
+ }
653
+ // Kill process if still running
654
+ if (pid && platformService.isProcessRunning(pid)) {
655
+ logDebug(`Killing Valkey process ${pid}`);
656
+ try {
657
+ await platformService.terminateProcess(pid, false);
658
+ await new Promise((resolve) => setTimeout(resolve, 2000));
659
+ if (platformService.isProcessRunning(pid)) {
660
+ logWarning(`Graceful termination failed, force killing ${pid}`);
661
+ await platformService.terminateProcess(pid, true);
662
+ }
663
+ }
664
+ catch (error) {
665
+ logDebug(`Process termination error: ${error}`);
666
+ }
667
+ }
668
+ // Cleanup PID file
669
+ if (existsSync(pidFile)) {
670
+ try {
671
+ await unlink(pidFile);
672
+ }
673
+ catch {
674
+ // Ignore
675
+ }
676
+ }
677
+ logDebug('Valkey stopped');
678
+ }
679
+ // Get Valkey server status
680
+ async status(container) {
681
+ const { name, port, version } = container;
682
+ const containerDir = paths.getContainerPath(name, { engine: ENGINE });
683
+ const pidFile = join(containerDir, 'valkey.pid');
684
+ // Try pinging with valkey-cli
685
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
686
+ if (valkeyCli) {
687
+ try {
688
+ const cmd = `"${valkeyCli}" -h 127.0.0.1 -p ${port} PING`;
689
+ const { stdout } = await execAsync(cmd, { timeout: 5000 });
690
+ if (stdout.trim() === 'PONG') {
691
+ return { running: true, message: 'Valkey is running' };
692
+ }
693
+ }
694
+ catch {
695
+ // Not responding, check PID
696
+ }
697
+ }
698
+ // Check PID file
699
+ if (existsSync(pidFile)) {
700
+ try {
701
+ const content = await readFile(pidFile, 'utf8');
702
+ const pid = parseInt(content.trim(), 10);
703
+ if (!isNaN(pid) && pid > 0 && platformService.isProcessRunning(pid)) {
704
+ return {
705
+ running: true,
706
+ message: `Valkey is running (PID: ${pid})`,
707
+ };
708
+ }
709
+ }
710
+ catch {
711
+ // Ignore
712
+ }
713
+ }
714
+ return { running: false, message: 'Valkey is not running' };
715
+ }
716
+ // Detect backup format
717
+ async detectBackupFormat(filePath) {
718
+ return detectBackupFormatImpl(filePath);
719
+ }
720
+ /**
721
+ * Restore a backup
722
+ * IMPORTANT: Valkey must be stopped before restore
723
+ */
724
+ async restore(container, backupPath, options = {}) {
725
+ const { name, port } = container;
726
+ const dataDir = paths.getContainerDataPath(name, { engine: ENGINE });
727
+ return restoreBackup(backupPath, {
728
+ containerName: name,
729
+ dataDir,
730
+ port,
731
+ database: options.database || container.database || '0',
732
+ flush: options.flush,
733
+ });
734
+ }
735
+ /**
736
+ * Get connection string
737
+ * Format: redis://127.0.0.1:PORT/DATABASE
738
+ * (Uses redis:// scheme for client compatibility)
739
+ */
740
+ getConnectionString(container, database) {
741
+ const { port } = container;
742
+ const db = database || container.database || '0';
743
+ return `redis://127.0.0.1:${port}/${db}`;
744
+ }
745
+ /**
746
+ * Get path to valkey-cli for a specific version
747
+ * @param version - Optional version (e.g., "8", "9"). If not provided, uses cached path.
748
+ * @deprecated Use getValkeyCliPath() instead
749
+ */
750
+ async getValkeyCliPathForVersion(version) {
751
+ return this.getValkeyCliPath(version);
752
+ }
753
+ // Open valkey-cli interactive shell
754
+ async connect(container, database) {
755
+ const { port, version } = container;
756
+ const db = database || container.database || '0';
757
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
758
+ const spawnOptions = {
759
+ stdio: 'inherit',
760
+ };
761
+ return new Promise((resolve, reject) => {
762
+ const proc = spawn(valkeyCli, ['-h', '127.0.0.1', '-p', String(port), '-n', db], spawnOptions);
763
+ proc.on('error', reject);
764
+ proc.on('close', () => resolve());
765
+ });
766
+ }
767
+ // Get path to iredis (enhanced CLI) if installed
768
+ // Note: iredis works with Valkey since it's protocol-compatible
769
+ async getIredisPath() {
770
+ // Check config cache first
771
+ const cached = await configManager.getBinaryPath('iredis');
772
+ if (cached && existsSync(cached)) {
773
+ return cached;
774
+ }
775
+ // Check system PATH
776
+ const systemPath = await platformService.findToolPath('iredis');
777
+ if (systemPath) {
778
+ return systemPath;
779
+ }
780
+ return null;
781
+ }
782
+ // Connect with iredis (enhanced CLI)
783
+ async connectWithIredis(container, database) {
784
+ const { port } = container;
785
+ const db = database || container.database || '0';
786
+ const iredis = await this.getIredisPath();
787
+ if (!iredis) {
788
+ throw new Error('iredis not found. Install it with:\n' +
789
+ ' macOS: brew install iredis\n' +
790
+ ' pip: pip install iredis');
791
+ }
792
+ const spawnOptions = {
793
+ stdio: 'inherit',
794
+ };
795
+ return new Promise((resolve, reject) => {
796
+ const proc = spawn(iredis, ['-h', '127.0.0.1', '-p', String(port), '-n', db], spawnOptions);
797
+ proc.on('error', reject);
798
+ proc.on('close', () => resolve());
799
+ });
800
+ }
801
+ /**
802
+ * Create a new database
803
+ * Valkey uses numbered databases (0-15), they always exist
804
+ * This is effectively a no-op
805
+ */
806
+ async createDatabase(_container, database) {
807
+ const dbNum = parseInt(database, 10);
808
+ if (isNaN(dbNum) || dbNum < 0 || dbNum > 15) {
809
+ throw new Error(`Invalid Valkey database number: ${database}. Must be 0-15.`);
810
+ }
811
+ // No-op - Valkey databases always exist
812
+ logDebug(`Valkey database ${database} is available (databases 0-15 always exist)`);
813
+ }
814
+ /**
815
+ * Drop a database
816
+ * Uses FLUSHDB to clear all keys in the specified database
817
+ */
818
+ async dropDatabase(container, database) {
819
+ const { port, version } = container;
820
+ const dbNum = parseInt(database, 10);
821
+ if (isNaN(dbNum) || dbNum < 0 || dbNum > 15) {
822
+ throw new Error(`Invalid Valkey database number: ${database}. Must be 0-15.`);
823
+ }
824
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
825
+ // SELECT the database and FLUSHDB
826
+ const cmd = `"${valkeyCli}" -h 127.0.0.1 -p ${port} -n ${database} FLUSHDB`;
827
+ try {
828
+ await execAsync(cmd, { timeout: 10000 });
829
+ logDebug(`Flushed Valkey database ${database}`);
830
+ }
831
+ catch (error) {
832
+ const err = error;
833
+ logDebug(`FLUSHDB failed: ${err.message}`);
834
+ throw new Error(`Failed to flush Valkey database ${database}: ${err.message}`);
835
+ }
836
+ }
837
+ /**
838
+ * Get the memory usage of the Valkey server in bytes
839
+ *
840
+ * NOTE: Valkey does not provide per-database memory statistics.
841
+ * This returns the total server memory (used_memory from INFO memory),
842
+ * not the size of a specific numbered database (0-15).
843
+ * This is acceptable for SpinDB since each container runs one Valkey server.
844
+ */
845
+ async getDatabaseSize(container) {
846
+ const { port, version } = container;
847
+ try {
848
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
849
+ // INFO memory returns server-wide stats (database selection has no effect)
850
+ const cmd = `"${valkeyCli}" -h 127.0.0.1 -p ${port} INFO memory`;
851
+ const { stdout } = await execAsync(cmd, { timeout: 10000 });
852
+ // Parse used_memory (total server memory) from INFO output
853
+ const match = stdout.match(/used_memory:(\d+)/);
854
+ if (match) {
855
+ return parseInt(match[1], 10);
856
+ }
857
+ return null;
858
+ }
859
+ catch {
860
+ return null;
861
+ }
862
+ }
863
+ /**
864
+ * Dump from a remote Valkey connection
865
+ * Creates a text-format backup by scanning all keys from the remote server
866
+ *
867
+ * Connection string format: redis://[user:password@]host:port[/db]
868
+ * Note: Uses redis:// scheme for compatibility (Valkey is Redis-compatible)
869
+ */
870
+ async dumpFromConnectionString(connectionString, outputPath) {
871
+ const valkeyCli = await getValkeyCliPath();
872
+ if (!valkeyCli) {
873
+ throw new Error(VALKEY_CLI_NOT_FOUND_ERROR);
874
+ }
875
+ // Parse connection string (uses redis:// for compatibility)
876
+ const { host, port, username, password, database, tls } = parseValkeyConnectionString(connectionString);
877
+ logDebug(`Connecting to remote Valkey at ${host}:${port} (db: ${database}, tls: ${tls})`);
878
+ // Build CLI args for remote connection (password passed via env var for security)
879
+ const buildArgs = () => {
880
+ const args = ['-h', host, '-p', String(port)];
881
+ // ACL: pass username via --user flag (inherited from Redis 6.0+)
882
+ if (username) {
883
+ args.push('--user', username);
884
+ }
885
+ // Enable TLS for rediss:// or valkeys:// schemes
886
+ if (tls) {
887
+ args.push('--tls');
888
+ }
889
+ // Note: password is passed via REDISCLI_AUTH env var, not command line
890
+ args.push('-n', String(database));
891
+ return args;
892
+ };
893
+ // Execute a Valkey command on the remote server with timeout
894
+ const execRemote = async (command, timeoutMs = 30000) => {
895
+ return new Promise((resolve, reject) => {
896
+ const args = buildArgs();
897
+ // Pass password via REDISCLI_AUTH env var to avoid exposing it in process listings
898
+ const env = password
899
+ ? { ...process.env, REDISCLI_AUTH: password }
900
+ : process.env;
901
+ const proc = spawn(valkeyCli, args, {
902
+ stdio: ['pipe', 'pipe', 'pipe'],
903
+ env,
904
+ });
905
+ let stdout = '';
906
+ let stderr = '';
907
+ let settled = false;
908
+ // Timeout handler to prevent hanging
909
+ const timeoutId = setTimeout(() => {
910
+ if (settled)
911
+ return;
912
+ settled = true;
913
+ proc.kill();
914
+ reject(new Error(`Command timed out after ${timeoutMs}ms: ${command.slice(0, 50)}...`));
915
+ }, timeoutMs);
916
+ proc.stdout.on('data', (data) => {
917
+ stdout += data.toString();
918
+ });
919
+ proc.stderr.on('data', (data) => {
920
+ stderr += data.toString();
921
+ });
922
+ proc.on('error', (err) => {
923
+ if (settled)
924
+ return;
925
+ settled = true;
926
+ clearTimeout(timeoutId);
927
+ reject(err);
928
+ });
929
+ proc.on('close', (code) => {
930
+ if (settled)
931
+ return;
932
+ settled = true;
933
+ clearTimeout(timeoutId);
934
+ // Ignore auth-related warnings in stderr (password provided via REDISCLI_AUTH)
935
+ if (code === 0 || code === null) {
936
+ resolve(stdout);
937
+ }
938
+ else {
939
+ reject(new Error(stderr || `valkey-cli exited with code ${code}`));
940
+ }
941
+ });
942
+ proc.stdin.write(command + '\n');
943
+ proc.stdin.end();
944
+ });
945
+ };
946
+ // Test connectivity
947
+ try {
948
+ const pingResult = await execRemote('PING');
949
+ if (!pingResult.trim().includes('PONG')) {
950
+ throw new Error(`Unexpected PING response: ${pingResult.trim()}`);
951
+ }
952
+ }
953
+ catch (error) {
954
+ throw new Error(`Failed to connect to Valkey at ${host}:${port}: ${error.message}`);
955
+ }
956
+ // Build text backup from remote keys
957
+ const commands = [];
958
+ commands.push('# Valkey backup generated by SpinDB');
959
+ commands.push(`# Source: ${host}:${port}`);
960
+ commands.push(`# Date: ${new Date().toISOString()}`);
961
+ commands.push('');
962
+ // WARNING: KEYS * blocks the Valkey server during execution.
963
+ // This is acceptable for small datasets but will cause performance issues
964
+ // on large databases. For production use with large datasets, consider
965
+ // implementing SCAN-based iteration instead.
966
+ // TODO: Replace with SCAN iterator for large dataset support
967
+ const keysOutput = await execRemote('KEYS *');
968
+ const keys = keysOutput
969
+ .trim()
970
+ .split(/\r?\n/)
971
+ .map((k) => k.trim())
972
+ .filter((k) => k);
973
+ logDebug(`Found ${keys.length} keys on remote Valkey`);
974
+ // Warn about large key counts that may cause performance issues
975
+ if (keys.length > 10000) {
976
+ logWarning(`Large key count detected: ${keys.length} keys. ` +
977
+ 'This operation may be slow. Consider using SCAN-based iteration for production workloads.');
978
+ }
979
+ // TODO: Optimize with pipelining or Lua script to batch TYPE/TTL/value fetches
980
+ // Currently makes O(3N) round trips which is slow for large datasets.
981
+ // A pipelined approach could fetch all data in fewer round trips.
982
+ for (const key of keys) {
983
+ // Get key type
984
+ const typeOutput = await execRemote(`TYPE "${escapeKeyForCommand(key)}"`);
985
+ const keyType = typeOutput.trim();
986
+ // Get TTL
987
+ const ttlOutput = await execRemote(`TTL "${escapeKeyForCommand(key)}"`);
988
+ const ttl = parseInt(ttlOutput.trim(), 10);
989
+ // Quote the key for output commands if it contains special chars
990
+ const quotedKey = key.includes(' ') || /[*?[\]{}$`"'\\!<>|;&()]/.test(key)
991
+ ? `"${key.replace(/"/g, '\\"')}"`
992
+ : key;
993
+ // Redis-cli compatible double-quote escaping for values
994
+ // Escapes backslashes and double quotes, converts newlines to \n sequences
995
+ // Note: This approach doesn't handle binary data.
996
+ // For binary-safe backups, consider using DUMP/RESTORE commands instead.
997
+ const escapeValue = (value) => {
998
+ const escaped = value
999
+ .replace(/\\/g, '\\\\')
1000
+ .replace(/"/g, '\\"')
1001
+ .replace(/\n/g, '\\n')
1002
+ .replace(/\r/g, '\\r');
1003
+ return `"${escaped}"`;
1004
+ };
1005
+ // Strip only trailing newline from execRemote output, preserving intentional whitespace
1006
+ const stripTrailingNewline = (s) => s.replace(/\r?\n$/, '');
1007
+ switch (keyType) {
1008
+ case 'string': {
1009
+ const value = await execRemote(`GET "${escapeKeyForCommand(key)}"`);
1010
+ commands.push(`SET ${quotedKey} ${escapeValue(stripTrailingNewline(value))}`);
1011
+ break;
1012
+ }
1013
+ case 'hash': {
1014
+ const hashData = await execRemote(`HGETALL "${escapeKeyForCommand(key)}"`);
1015
+ const lines = stripTrailingNewline(hashData)
1016
+ .split(/\r?\n/)
1017
+ .filter((l) => l);
1018
+ if (lines.length >= 2) {
1019
+ const pairs = [];
1020
+ // Handle odd number of lines (incomplete field/value pair)
1021
+ const completeCount = lines.length - (lines.length % 2);
1022
+ if (lines.length % 2 !== 0) {
1023
+ logWarning(`Hash ${quotedKey} has incomplete field/value pair, skipping last field`);
1024
+ }
1025
+ for (let i = 0; i < completeCount; i += 2) {
1026
+ const field = lines[i];
1027
+ const value = lines[i + 1];
1028
+ const quotedField = field.includes(' ') || /[*?[\]{}$`"'\\!<>|;&()]/.test(field)
1029
+ ? `"${field.replace(/"/g, '\\"')}"`
1030
+ : field;
1031
+ pairs.push(`${quotedField} ${escapeValue(value)}`);
1032
+ }
1033
+ if (pairs.length > 0) {
1034
+ commands.push(`HSET ${quotedKey} ${pairs.join(' ')}`);
1035
+ }
1036
+ }
1037
+ break;
1038
+ }
1039
+ case 'list': {
1040
+ const listData = await execRemote(`LRANGE "${escapeKeyForCommand(key)}" 0 -1`);
1041
+ const items = stripTrailingNewline(listData)
1042
+ .split(/\r?\n/)
1043
+ .filter((l) => l);
1044
+ if (items.length > 0) {
1045
+ const escapedItems = items.map((item) => escapeValue(item));
1046
+ commands.push(`RPUSH ${quotedKey} ${escapedItems.join(' ')}`);
1047
+ }
1048
+ break;
1049
+ }
1050
+ case 'set': {
1051
+ const setData = await execRemote(`SMEMBERS "${escapeKeyForCommand(key)}"`);
1052
+ const members = stripTrailingNewline(setData)
1053
+ .split(/\r?\n/)
1054
+ .filter((l) => l);
1055
+ if (members.length > 0) {
1056
+ const escapedMembers = members.map((m) => escapeValue(m));
1057
+ commands.push(`SADD ${quotedKey} ${escapedMembers.join(' ')}`);
1058
+ }
1059
+ break;
1060
+ }
1061
+ case 'zset': {
1062
+ const zsetData = await execRemote(`ZRANGE "${escapeKeyForCommand(key)}" 0 -1 WITHSCORES`);
1063
+ const lines = stripTrailingNewline(zsetData)
1064
+ .split(/\r?\n/)
1065
+ .filter((l) => l);
1066
+ if (lines.length >= 2) {
1067
+ const pairs = [];
1068
+ // Handle odd number of lines (incomplete member/score pair)
1069
+ const completeCount = lines.length - (lines.length % 2);
1070
+ if (lines.length % 2 !== 0) {
1071
+ logWarning(`ZSet ${quotedKey} has odd line count, skipping incomplete entry: ${lines[lines.length - 1]}`);
1072
+ }
1073
+ for (let i = 0; i < completeCount; i += 2) {
1074
+ const member = lines[i];
1075
+ const score = lines[i + 1];
1076
+ pairs.push(`${score} ${escapeValue(member)}`);
1077
+ }
1078
+ if (pairs.length > 0) {
1079
+ commands.push(`ZADD ${quotedKey} ${pairs.join(' ')}`);
1080
+ }
1081
+ }
1082
+ break;
1083
+ }
1084
+ default:
1085
+ logWarning(`Skipping key ${key} with unsupported type: ${keyType}`);
1086
+ }
1087
+ // Add EXPIRE if key has TTL
1088
+ if (ttl > 0) {
1089
+ commands.push(`EXPIRE ${quotedKey} ${ttl}`);
1090
+ }
1091
+ }
1092
+ // Write commands to file
1093
+ const content = commands.join('\n') + '\n';
1094
+ await writeFile(outputPath, content, 'utf-8');
1095
+ return {
1096
+ filePath: outputPath,
1097
+ warnings: keys.length === 0 ? ['Remote Valkey database is empty'] : undefined,
1098
+ };
1099
+ }
1100
+ // Create a backup
1101
+ async backup(container, outputPath, options) {
1102
+ return createBackup(container, outputPath, options);
1103
+ }
1104
+ // Run a Valkey command file or inline command
1105
+ async runScript(container, options) {
1106
+ const { port, version } = container;
1107
+ const db = options.database || container.database || '0';
1108
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
1109
+ if (options.file) {
1110
+ // Read file and pipe to valkey-cli via stdin (avoids shell interpolation issues)
1111
+ const fileContent = await readFile(options.file, 'utf-8');
1112
+ const args = ['-h', '127.0.0.1', '-p', String(port), '-n', db];
1113
+ await new Promise((resolve, reject) => {
1114
+ const proc = spawn(valkeyCli, args, {
1115
+ stdio: ['pipe', 'inherit', 'inherit'],
1116
+ });
1117
+ let rejected = false;
1118
+ proc.on('error', (err) => {
1119
+ rejected = true;
1120
+ reject(err);
1121
+ });
1122
+ proc.on('close', (code) => {
1123
+ if (rejected)
1124
+ return;
1125
+ if (code === 0 || code === null) {
1126
+ resolve();
1127
+ }
1128
+ else {
1129
+ reject(new Error(`valkey-cli exited with code ${code}`));
1130
+ }
1131
+ });
1132
+ // Write file content to stdin and close it
1133
+ proc.stdin?.write(fileContent);
1134
+ proc.stdin?.end();
1135
+ });
1136
+ }
1137
+ else if (options.sql) {
1138
+ // Run inline command by piping to valkey-cli stdin (avoids shell quoting issues on Windows)
1139
+ const args = ['-h', '127.0.0.1', '-p', String(port), '-n', db];
1140
+ await new Promise((resolve, reject) => {
1141
+ const proc = spawn(valkeyCli, args, {
1142
+ stdio: ['pipe', 'inherit', 'inherit'],
1143
+ });
1144
+ let rejected = false;
1145
+ proc.on('error', (err) => {
1146
+ rejected = true;
1147
+ reject(err);
1148
+ });
1149
+ proc.on('close', (code) => {
1150
+ if (rejected)
1151
+ return;
1152
+ if (code === 0 || code === null) {
1153
+ resolve();
1154
+ }
1155
+ else {
1156
+ reject(new Error(`valkey-cli exited with code ${code}`));
1157
+ }
1158
+ });
1159
+ // Write command to stdin and close it
1160
+ proc.stdin?.write(options.sql + '\n');
1161
+ proc.stdin?.end();
1162
+ });
1163
+ }
1164
+ else {
1165
+ throw new Error('Either file or sql option must be provided');
1166
+ }
1167
+ }
1168
+ async executeQuery(container, query, options) {
1169
+ const { port, version } = container;
1170
+ const db = options?.database || container.database || '0';
1171
+ const valkeyCli = await this.getValkeyCliPathForVersion(version);
1172
+ return new Promise((resolve, reject) => {
1173
+ const args = ['-h', '127.0.0.1', '-p', String(port), '-n', db];
1174
+ const proc = spawn(valkeyCli, args, {
1175
+ stdio: ['pipe', 'pipe', 'pipe'],
1176
+ });
1177
+ let stdout = '';
1178
+ let stderr = '';
1179
+ proc.stdout?.on('data', (data) => {
1180
+ stdout += data.toString();
1181
+ });
1182
+ proc.stderr?.on('data', (data) => {
1183
+ stderr += data.toString();
1184
+ });
1185
+ proc.on('error', reject);
1186
+ proc.on('close', (code) => {
1187
+ if (code === 0 || code === null) {
1188
+ // Use Redis parser since Valkey is Redis-compatible
1189
+ resolve(parseRedisResult(stdout, query));
1190
+ }
1191
+ else {
1192
+ reject(new Error(stderr || `valkey-cli exited with code ${code}`));
1193
+ }
1194
+ });
1195
+ // Write command to stdin and close it
1196
+ proc.stdin?.write(query + '\n');
1197
+ proc.stdin?.end();
1198
+ });
1199
+ }
1200
+ /**
1201
+ * List databases for Valkey.
1202
+ * Valkey uses numbered databases (0-15 by default), not named databases.
1203
+ * Returns the configured database number as a single-item array.
1204
+ */
1205
+ async listDatabases(container) {
1206
+ // Valkey has numbered databases, not named ones
1207
+ // Return the container's configured database
1208
+ return [container.database];
1209
+ }
1210
+ async createUser(container, options) {
1211
+ const { username, password } = options;
1212
+ assertValidUsername(username);
1213
+ const { port, version } = container;
1214
+ const db = options.database ?? container.database ?? '0';
1215
+ const valkeyCli = await this.getValkeyCliPath(version);
1216
+ // Reject passwords with characters that break ACL SETUSER syntax:
1217
+ // '>' sets password, '#' sets hash, '<' removes password — all are ACL delimiters.
1218
+ // Whitespace and newlines would split the command unexpectedly.
1219
+ if (/[>#<\s\n\r]/.test(password)) {
1220
+ throw new Error('Password contains invalid characters for Valkey ACL. Passwords must not contain ">", "#", "<", whitespace, or newlines.');
1221
+ }
1222
+ // ACL SETUSER is idempotent - sets user with full access
1223
+ // Send ACL command via stdin to avoid leaking password in process argv
1224
+ const cliArgs = ['-h', '127.0.0.1', '-p', String(port), '-n', db];
1225
+ await new Promise((resolve, reject) => {
1226
+ const proc = spawn(valkeyCli, cliArgs, {
1227
+ stdio: ['pipe', 'pipe', 'pipe'],
1228
+ });
1229
+ let stderr = '';
1230
+ proc.stderr?.on('data', (data) => {
1231
+ stderr += data.toString();
1232
+ });
1233
+ proc.on('close', (code) => {
1234
+ if (code === 0)
1235
+ resolve();
1236
+ else
1237
+ reject(new Error(`Failed to create user: ${stderr}`));
1238
+ });
1239
+ proc.on('error', reject);
1240
+ proc.stdin?.write(`ACL SETUSER ${username} on >${password} ~* &* +@all\n`);
1241
+ proc.stdin?.end();
1242
+ });
1243
+ logDebug(`Created Valkey user: ${username}`);
1244
+ // Valkey uses redis:// scheme for compatibility
1245
+ const connectionString = `redis://${encodeURIComponent(username)}:${encodeURIComponent(password)}@127.0.0.1:${port}/${db}`;
1246
+ return {
1247
+ username,
1248
+ password,
1249
+ connectionString,
1250
+ engine: container.engine,
1251
+ container: container.name,
1252
+ database: db,
1253
+ };
1254
+ }
1255
+ }
1256
+ export const valkeyEngine = new ValkeyEngine();
1257
+ //# sourceMappingURL=index.js.map