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.
- package/dist/cli/bin.js +9 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/attach.js +102 -0
- package/dist/cli/commands/attach.js.map +1 -0
- package/dist/cli/commands/backup.js +197 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/backups.js +190 -0
- package/dist/cli/commands/backups.js.map +1 -0
- package/dist/cli/commands/clone.js +119 -0
- package/dist/cli/commands/clone.js.map +1 -0
- package/dist/cli/commands/config.js +276 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/connect.js +559 -0
- package/dist/cli/commands/connect.js.map +1 -0
- package/dist/cli/commands/create.js +952 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/databases.js +485 -0
- package/dist/cli/commands/databases.js.map +1 -0
- package/dist/cli/commands/delete.js +106 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/deps.js +238 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/detach.js +81 -0
- package/dist/cli/commands/detach.js.map +1 -0
- package/dist/cli/commands/doctor.js +567 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/duckdb.js +207 -0
- package/dist/cli/commands/duckdb.js.map +1 -0
- package/dist/cli/commands/edit.js +524 -0
- package/dist/cli/commands/edit.js.map +1 -0
- package/dist/cli/commands/engines.js +1414 -0
- package/dist/cli/commands/engines.js.map +1 -0
- package/dist/cli/commands/export.js +383 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/info.js +270 -0
- package/dist/cli/commands/info.js.map +1 -0
- package/dist/cli/commands/list.js +215 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/logs.js +81 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/menu/backup-handlers.js +1202 -0
- package/dist/cli/commands/menu/backup-handlers.js.map +1 -0
- package/dist/cli/commands/menu/container-handlers.js +1788 -0
- package/dist/cli/commands/menu/container-handlers.js.map +1 -0
- package/dist/cli/commands/menu/engine-handlers.js +235 -0
- package/dist/cli/commands/menu/engine-handlers.js.map +1 -0
- package/dist/cli/commands/menu/index.js +266 -0
- package/dist/cli/commands/menu/index.js.map +1 -0
- package/dist/cli/commands/menu/settings-handlers.js +320 -0
- package/dist/cli/commands/menu/settings-handlers.js.map +1 -0
- package/dist/cli/commands/menu/shared.js +13 -0
- package/dist/cli/commands/menu/shared.js.map +1 -0
- package/dist/cli/commands/menu/shell-handlers.js +1573 -0
- package/dist/cli/commands/menu/shell-handlers.js.map +1 -0
- package/dist/cli/commands/menu/sql-handlers.js +185 -0
- package/dist/cli/commands/menu/sql-handlers.js.map +1 -0
- package/dist/cli/commands/menu/update-handlers.js +322 -0
- package/dist/cli/commands/menu/update-handlers.js.map +1 -0
- package/dist/cli/commands/menu/validators.js +9 -0
- package/dist/cli/commands/menu/validators.js.map +1 -0
- package/dist/cli/commands/ports.js +166 -0
- package/dist/cli/commands/ports.js.map +1 -0
- package/dist/cli/commands/pull.js +166 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/query.js +180 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/restore.js +428 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/run.js +115 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/self-update.js +99 -0
- package/dist/cli/commands/self-update.js.map +1 -0
- package/dist/cli/commands/sqlite.js +207 -0
- package/dist/cli/commands/sqlite.js.map +1 -0
- package/dist/cli/commands/start.js +196 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/stop.js +182 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/url.js +88 -0
- package/dist/cli/commands/url.js.map +1 -0
- package/dist/cli/commands/users.js +189 -0
- package/dist/cli/commands/users.js.map +1 -0
- package/dist/cli/commands/version.js +52 -0
- package/dist/cli/commands/version.js.map +1 -0
- package/dist/cli/commands/which.js +258 -0
- package/dist/cli/commands/which.js.map +1 -0
- package/dist/cli/constants.js +212 -0
- package/dist/cli/constants.js.map +1 -0
- package/dist/cli/helpers.js +1120 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.js +146 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ui/prompts.js +1002 -0
- package/dist/cli/ui/prompts.js.map +1 -0
- package/dist/cli/ui/spinner.js +74 -0
- package/dist/cli/ui/spinner.js.map +1 -0
- package/dist/cli/ui/theme.js +99 -0
- package/dist/cli/ui/theme.js.map +1 -0
- package/dist/cli/utils/file-follower.js +79 -0
- package/dist/cli/utils/file-follower.js.map +1 -0
- package/dist/config/backup-formats.js +363 -0
- package/dist/config/backup-formats.js.map +1 -0
- package/dist/config/defaults.js +25 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/engine-defaults.js +303 -0
- package/dist/config/engine-defaults.js.map +1 -0
- package/dist/config/engines-registry.js +103 -0
- package/dist/config/engines-registry.js.map +1 -0
- package/dist/config/os-dependencies.js +767 -0
- package/dist/config/os-dependencies.js.map +1 -0
- package/dist/config/paths.js +156 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/version.js +3 -0
- package/dist/config/version.js.map +1 -0
- package/dist/core/backup-restore.js +219 -0
- package/dist/core/backup-restore.js.map +1 -0
- package/dist/core/base-binary-manager.js +403 -0
- package/dist/core/base-binary-manager.js.map +1 -0
- package/dist/core/base-document-binary-manager.js +364 -0
- package/dist/core/base-document-binary-manager.js.map +1 -0
- package/dist/core/base-embedded-binary-manager.js +364 -0
- package/dist/core/base-embedded-binary-manager.js.map +1 -0
- package/dist/core/base-server-binary-manager.js +368 -0
- package/dist/core/base-server-binary-manager.js.map +1 -0
- package/dist/core/config-manager.js +495 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/container-manager.js +609 -0
- package/dist/core/container-manager.js.map +1 -0
- package/dist/core/credential-generator.js +67 -0
- package/dist/core/credential-generator.js.map +1 -0
- package/dist/core/credential-manager.js +211 -0
- package/dist/core/credential-manager.js.map +1 -0
- package/dist/core/dblab-utils.js +105 -0
- package/dist/core/dblab-utils.js.map +1 -0
- package/dist/core/dependency-manager.js +359 -0
- package/dist/core/dependency-manager.js.map +1 -0
- package/dist/core/docker-exporter.js +1077 -0
- package/dist/core/docker-exporter.js.map +1 -0
- package/dist/core/error-handler.js +295 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/fs-error-utils.js +74 -0
- package/dist/core/fs-error-utils.js.map +1 -0
- package/dist/core/homebrew-version-manager.js +280 -0
- package/dist/core/homebrew-version-manager.js.map +1 -0
- package/dist/core/hostdb-client.js +252 -0
- package/dist/core/hostdb-client.js.map +1 -0
- package/dist/core/hostdb-metadata.js +243 -0
- package/dist/core/hostdb-metadata.js.map +1 -0
- package/dist/core/hostdb-releases-factory.js +161 -0
- package/dist/core/hostdb-releases-factory.js.map +1 -0
- package/dist/core/library-env.js +88 -0
- package/dist/core/library-env.js.map +1 -0
- package/dist/core/pgweb-utils.js +53 -0
- package/dist/core/pgweb-utils.js.map +1 -0
- package/dist/core/platform-service.js +632 -0
- package/dist/core/platform-service.js.map +1 -0
- package/dist/core/port-manager.js +136 -0
- package/dist/core/port-manager.js.map +1 -0
- package/dist/core/process-manager.js +445 -0
- package/dist/core/process-manager.js.map +1 -0
- package/dist/core/pull-manager.js +418 -0
- package/dist/core/pull-manager.js.map +1 -0
- package/dist/core/query-parser.js +449 -0
- package/dist/core/query-parser.js.map +1 -0
- package/dist/core/spawn-utils.js +90 -0
- package/dist/core/spawn-utils.js.map +1 -0
- package/dist/core/start-with-retry.js +90 -0
- package/dist/core/start-with-retry.js.map +1 -0
- package/dist/core/test-cleanup.js +85 -0
- package/dist/core/test-cleanup.js.map +1 -0
- package/dist/core/tls-generator.js +84 -0
- package/dist/core/tls-generator.js.map +1 -0
- package/dist/core/transaction-manager.js +139 -0
- package/dist/core/transaction-manager.js.map +1 -0
- package/dist/core/update-manager.js +241 -0
- package/dist/core/update-manager.js.map +1 -0
- package/dist/core/version-migration.js +260 -0
- package/dist/core/version-migration.js.map +1 -0
- package/dist/core/version-utils.js +91 -0
- package/dist/core/version-utils.js.map +1 -0
- package/dist/engines/base-engine.js +179 -0
- package/dist/engines/base-engine.js.map +1 -0
- package/dist/engines/clickhouse/backup.js +289 -0
- package/dist/engines/clickhouse/backup.js.map +1 -0
- package/dist/engines/clickhouse/binary-manager.js +145 -0
- package/dist/engines/clickhouse/binary-manager.js.map +1 -0
- package/dist/engines/clickhouse/binary-urls.js +100 -0
- package/dist/engines/clickhouse/binary-urls.js.map +1 -0
- package/dist/engines/clickhouse/cli-utils.js +143 -0
- package/dist/engines/clickhouse/cli-utils.js.map +1 -0
- package/dist/engines/clickhouse/hostdb-releases.js +24 -0
- package/dist/engines/clickhouse/hostdb-releases.js.map +1 -0
- package/dist/engines/clickhouse/index.js +1077 -0
- package/dist/engines/clickhouse/index.js.map +1 -0
- package/dist/engines/clickhouse/restore.js +335 -0
- package/dist/engines/clickhouse/restore.js.map +1 -0
- package/dist/engines/clickhouse/version-maps.js +83 -0
- package/dist/engines/clickhouse/version-maps.js.map +1 -0
- package/dist/engines/clickhouse/version-validator.js +133 -0
- package/dist/engines/clickhouse/version-validator.js.map +1 -0
- package/dist/engines/cockroachdb/backup.js +261 -0
- package/dist/engines/cockroachdb/backup.js.map +1 -0
- package/dist/engines/cockroachdb/binary-manager.js +33 -0
- package/dist/engines/cockroachdb/binary-manager.js.map +1 -0
- package/dist/engines/cockroachdb/binary-urls.js +33 -0
- package/dist/engines/cockroachdb/binary-urls.js.map +1 -0
- package/dist/engines/cockroachdb/cli-utils.js +338 -0
- package/dist/engines/cockroachdb/cli-utils.js.map +1 -0
- package/dist/engines/cockroachdb/hostdb-releases.js +21 -0
- package/dist/engines/cockroachdb/hostdb-releases.js.map +1 -0
- package/dist/engines/cockroachdb/index.js +1016 -0
- package/dist/engines/cockroachdb/index.js.map +1 -0
- package/dist/engines/cockroachdb/restore.js +323 -0
- package/dist/engines/cockroachdb/restore.js.map +1 -0
- package/dist/engines/cockroachdb/version-maps.js +37 -0
- package/dist/engines/cockroachdb/version-maps.js.map +1 -0
- package/dist/engines/couchdb/api-client.js +64 -0
- package/dist/engines/couchdb/api-client.js.map +1 -0
- package/dist/engines/couchdb/backup.js +90 -0
- package/dist/engines/couchdb/backup.js.map +1 -0
- package/dist/engines/couchdb/binary-manager.js +62 -0
- package/dist/engines/couchdb/binary-manager.js.map +1 -0
- package/dist/engines/couchdb/binary-urls.js +92 -0
- package/dist/engines/couchdb/binary-urls.js.map +1 -0
- package/dist/engines/couchdb/hostdb-releases.js +21 -0
- package/dist/engines/couchdb/hostdb-releases.js.map +1 -0
- package/dist/engines/couchdb/index.js +1043 -0
- package/dist/engines/couchdb/index.js.map +1 -0
- package/dist/engines/couchdb/restore.js +198 -0
- package/dist/engines/couchdb/restore.js.map +1 -0
- package/dist/engines/couchdb/version-maps.js +67 -0
- package/dist/engines/couchdb/version-maps.js.map +1 -0
- package/dist/engines/couchdb/version-validator.js +88 -0
- package/dist/engines/couchdb/version-validator.js.map +1 -0
- package/dist/engines/duckdb/binary-manager.js +33 -0
- package/dist/engines/duckdb/binary-manager.js.map +1 -0
- package/{engines/duckdb/binary-urls.ts → dist/engines/duckdb/binary-urls.js} +11 -16
- package/dist/engines/duckdb/binary-urls.js.map +1 -0
- package/dist/engines/duckdb/hostdb-releases.js +21 -0
- package/dist/engines/duckdb/hostdb-releases.js.map +1 -0
- package/dist/engines/duckdb/index.js +594 -0
- package/dist/engines/duckdb/index.js.map +1 -0
- package/dist/engines/duckdb/registry.js +265 -0
- package/dist/engines/duckdb/registry.js.map +1 -0
- package/dist/engines/duckdb/scanner.js +12 -0
- package/dist/engines/duckdb/scanner.js.map +1 -0
- package/dist/engines/duckdb/version-maps.js +67 -0
- package/dist/engines/duckdb/version-maps.js.map +1 -0
- package/dist/engines/duckdb/version-validator.js +62 -0
- package/dist/engines/duckdb/version-validator.js.map +1 -0
- package/dist/engines/ferretdb/backup.js +170 -0
- package/dist/engines/ferretdb/backup.js.map +1 -0
- package/dist/engines/ferretdb/binary-manager.js +765 -0
- package/dist/engines/ferretdb/binary-manager.js.map +1 -0
- package/dist/engines/ferretdb/binary-urls.js +135 -0
- package/dist/engines/ferretdb/binary-urls.js.map +1 -0
- package/dist/engines/ferretdb/index.js +1517 -0
- package/dist/engines/ferretdb/index.js.map +1 -0
- package/dist/engines/ferretdb/restore.js +310 -0
- package/dist/engines/ferretdb/restore.js.map +1 -0
- package/{engines/ferretdb/version-maps.ts → dist/engines/ferretdb/version-maps.js} +62 -79
- package/dist/engines/ferretdb/version-maps.js.map +1 -0
- package/dist/engines/file-based-utils.js +184 -0
- package/dist/engines/file-based-utils.js.map +1 -0
- package/dist/engines/index.js +124 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/influxdb/api-client.js +54 -0
- package/dist/engines/influxdb/api-client.js.map +1 -0
- package/dist/engines/influxdb/backup.js +119 -0
- package/dist/engines/influxdb/backup.js.map +1 -0
- package/dist/engines/influxdb/binary-manager.js +87 -0
- package/dist/engines/influxdb/binary-manager.js.map +1 -0
- package/dist/engines/influxdb/binary-urls.js +56 -0
- package/dist/engines/influxdb/binary-urls.js.map +1 -0
- package/dist/engines/influxdb/hostdb-releases.js +21 -0
- package/dist/engines/influxdb/hostdb-releases.js.map +1 -0
- package/dist/engines/influxdb/index.js +962 -0
- package/dist/engines/influxdb/index.js.map +1 -0
- package/dist/engines/influxdb/restore.js +329 -0
- package/dist/engines/influxdb/restore.js.map +1 -0
- package/dist/engines/influxdb/version-maps.js +64 -0
- package/dist/engines/influxdb/version-maps.js.map +1 -0
- package/dist/engines/influxdb/version-validator.js +109 -0
- package/dist/engines/influxdb/version-validator.js.map +1 -0
- package/dist/engines/mariadb/backup.js +178 -0
- package/dist/engines/mariadb/backup.js.map +1 -0
- package/dist/engines/mariadb/binary-manager.js +33 -0
- package/dist/engines/mariadb/binary-manager.js.map +1 -0
- package/{engines/mariadb/binary-urls.ts → dist/engines/mariadb/binary-urls.js} +38 -55
- package/dist/engines/mariadb/binary-urls.js.map +1 -0
- package/dist/engines/mariadb/hostdb-releases.js +21 -0
- package/dist/engines/mariadb/hostdb-releases.js.map +1 -0
- package/dist/engines/mariadb/index.js +1011 -0
- package/dist/engines/mariadb/index.js.map +1 -0
- package/dist/engines/mariadb/restore.js +322 -0
- package/dist/engines/mariadb/restore.js.map +1 -0
- package/dist/engines/mariadb/version-maps.js +63 -0
- package/dist/engines/mariadb/version-maps.js.map +1 -0
- package/dist/engines/mariadb/version-validator.js +143 -0
- package/dist/engines/mariadb/version-validator.js.map +1 -0
- package/dist/engines/meilisearch/api-client.js +50 -0
- package/dist/engines/meilisearch/api-client.js.map +1 -0
- package/dist/engines/meilisearch/backup.js +167 -0
- package/dist/engines/meilisearch/backup.js.map +1 -0
- package/dist/engines/meilisearch/binary-manager.js +31 -0
- package/dist/engines/meilisearch/binary-manager.js.map +1 -0
- package/dist/engines/meilisearch/binary-urls.js +56 -0
- package/dist/engines/meilisearch/binary-urls.js.map +1 -0
- package/dist/engines/meilisearch/hostdb-releases.js +21 -0
- package/dist/engines/meilisearch/hostdb-releases.js.map +1 -0
- package/dist/engines/meilisearch/index.js +992 -0
- package/dist/engines/meilisearch/index.js.map +1 -0
- package/dist/engines/meilisearch/restore.js +167 -0
- package/dist/engines/meilisearch/restore.js.map +1 -0
- package/dist/engines/meilisearch/version-maps.js +67 -0
- package/dist/engines/meilisearch/version-maps.js.map +1 -0
- package/dist/engines/meilisearch/version-validator.js +109 -0
- package/dist/engines/meilisearch/version-validator.js.map +1 -0
- package/dist/engines/mongodb/backup.js +109 -0
- package/dist/engines/mongodb/backup.js.map +1 -0
- package/dist/engines/mongodb/binary-manager.js +36 -0
- package/dist/engines/mongodb/binary-manager.js.map +1 -0
- package/dist/engines/mongodb/binary-urls.js +46 -0
- package/dist/engines/mongodb/binary-urls.js.map +1 -0
- package/dist/engines/mongodb/cli-utils.js +131 -0
- package/dist/engines/mongodb/cli-utils.js.map +1 -0
- package/dist/engines/mongodb/hostdb-releases.js +77 -0
- package/dist/engines/mongodb/hostdb-releases.js.map +1 -0
- package/dist/engines/mongodb/index.js +873 -0
- package/dist/engines/mongodb/index.js.map +1 -0
- package/dist/engines/mongodb/restore.js +276 -0
- package/dist/engines/mongodb/restore.js.map +1 -0
- package/dist/engines/mongodb/version-maps.js +79 -0
- package/dist/engines/mongodb/version-maps.js.map +1 -0
- package/dist/engines/mongodb/version-validator.js +133 -0
- package/dist/engines/mongodb/version-validator.js.map +1 -0
- package/dist/engines/mysql/backup.js +210 -0
- package/dist/engines/mysql/backup.js.map +1 -0
- package/dist/engines/mysql/binary-detection.js +325 -0
- package/dist/engines/mysql/binary-detection.js.map +1 -0
- package/dist/engines/mysql/binary-manager.js +30 -0
- package/dist/engines/mysql/binary-manager.js.map +1 -0
- package/dist/engines/mysql/binary-urls.js +87 -0
- package/dist/engines/mysql/binary-urls.js.map +1 -0
- package/{engines/mysql/hostdb-releases.ts → dist/engines/mysql/hostdb-releases.js} +20 -23
- package/dist/engines/mysql/hostdb-releases.js.map +1 -0
- package/dist/engines/mysql/index.js +1066 -0
- package/dist/engines/mysql/index.js.map +1 -0
- package/dist/engines/mysql/restore.js +361 -0
- package/dist/engines/mysql/restore.js.map +1 -0
- package/dist/engines/mysql/version-maps.js +79 -0
- package/dist/engines/mysql/version-maps.js.map +1 -0
- package/dist/engines/mysql/version-validator.js +266 -0
- package/dist/engines/mysql/version-validator.js.map +1 -0
- package/dist/engines/postgresql/backup.js +118 -0
- package/dist/engines/postgresql/backup.js.map +1 -0
- package/dist/engines/postgresql/binary-manager.js +85 -0
- package/dist/engines/postgresql/binary-manager.js.map +1 -0
- package/dist/engines/postgresql/binary-urls.js +80 -0
- package/dist/engines/postgresql/binary-urls.js.map +1 -0
- package/dist/engines/postgresql/hostdb-releases.js +21 -0
- package/dist/engines/postgresql/hostdb-releases.js.map +1 -0
- package/dist/engines/postgresql/index.js +852 -0
- package/dist/engines/postgresql/index.js.map +1 -0
- package/dist/engines/postgresql/remote-version.js +109 -0
- package/dist/engines/postgresql/remote-version.js.map +1 -0
- package/dist/engines/postgresql/restore.js +254 -0
- package/dist/engines/postgresql/restore.js.map +1 -0
- package/dist/engines/postgresql/version-maps.js +73 -0
- package/dist/engines/postgresql/version-maps.js.map +1 -0
- package/dist/engines/postgresql/version-validator.js +286 -0
- package/dist/engines/postgresql/version-validator.js.map +1 -0
- package/dist/engines/qdrant/api-client.js +50 -0
- package/dist/engines/qdrant/api-client.js.map +1 -0
- package/dist/engines/qdrant/backup.js +115 -0
- package/dist/engines/qdrant/backup.js.map +1 -0
- package/dist/engines/qdrant/binary-manager.js +31 -0
- package/dist/engines/qdrant/binary-manager.js.map +1 -0
- package/dist/engines/qdrant/binary-urls.js +92 -0
- package/dist/engines/qdrant/binary-urls.js.map +1 -0
- package/dist/engines/qdrant/cli-utils.js +39 -0
- package/dist/engines/qdrant/cli-utils.js.map +1 -0
- package/dist/engines/qdrant/hostdb-releases.js +21 -0
- package/dist/engines/qdrant/hostdb-releases.js.map +1 -0
- package/dist/engines/qdrant/index.js +1002 -0
- package/dist/engines/qdrant/index.js.map +1 -0
- package/dist/engines/qdrant/restore.js +154 -0
- package/dist/engines/qdrant/restore.js.map +1 -0
- package/dist/engines/qdrant/version-maps.js +67 -0
- package/dist/engines/qdrant/version-maps.js.map +1 -0
- package/dist/engines/qdrant/version-validator.js +109 -0
- package/dist/engines/qdrant/version-validator.js.map +1 -0
- package/dist/engines/questdb/backup.js +191 -0
- package/dist/engines/questdb/backup.js.map +1 -0
- package/dist/engines/questdb/binary-manager.js +247 -0
- package/dist/engines/questdb/binary-manager.js.map +1 -0
- package/dist/engines/questdb/binary-urls.js +27 -0
- package/dist/engines/questdb/binary-urls.js.map +1 -0
- package/dist/engines/questdb/hostdb-releases.js +21 -0
- package/dist/engines/questdb/hostdb-releases.js.map +1 -0
- package/dist/engines/questdb/index.js +814 -0
- package/dist/engines/questdb/index.js.map +1 -0
- package/dist/engines/questdb/restore.js +202 -0
- package/dist/engines/questdb/restore.js.map +1 -0
- package/dist/engines/questdb/version-maps.js +33 -0
- package/dist/engines/questdb/version-maps.js.map +1 -0
- package/dist/engines/questdb/version-validator.js +99 -0
- package/dist/engines/questdb/version-validator.js.map +1 -0
- package/dist/engines/redis/backup.js +292 -0
- package/dist/engines/redis/backup.js.map +1 -0
- package/dist/engines/redis/binary-manager.js +32 -0
- package/dist/engines/redis/binary-manager.js.map +1 -0
- package/dist/engines/redis/binary-urls.js +96 -0
- package/dist/engines/redis/binary-urls.js.map +1 -0
- package/dist/engines/redis/cli-utils.js +38 -0
- package/dist/engines/redis/cli-utils.js.map +1 -0
- package/dist/engines/redis/hostdb-releases.js +21 -0
- package/dist/engines/redis/hostdb-releases.js.map +1 -0
- package/dist/engines/redis/index.js +1263 -0
- package/dist/engines/redis/index.js.map +1 -0
- package/dist/engines/redis/restore.js +338 -0
- package/dist/engines/redis/restore.js.map +1 -0
- package/dist/engines/redis/version-maps.js +70 -0
- package/dist/engines/redis/version-maps.js.map +1 -0
- package/dist/engines/redis/version-validator.js +109 -0
- package/dist/engines/redis/version-validator.js.map +1 -0
- package/dist/engines/sqlite/binary-manager.js +39 -0
- package/dist/engines/sqlite/binary-manager.js.map +1 -0
- package/{engines/sqlite/binary-urls.ts → dist/engines/sqlite/binary-urls.js} +11 -16
- package/dist/engines/sqlite/binary-urls.js.map +1 -0
- package/dist/engines/sqlite/hostdb-releases.js +21 -0
- package/dist/engines/sqlite/hostdb-releases.js.map +1 -0
- package/dist/engines/sqlite/index.js +493 -0
- package/dist/engines/sqlite/index.js.map +1 -0
- package/dist/engines/sqlite/registry.js +163 -0
- package/dist/engines/sqlite/registry.js.map +1 -0
- package/dist/engines/sqlite/scanner.js +12 -0
- package/dist/engines/sqlite/scanner.js.map +1 -0
- package/dist/engines/sqlite/version-maps.js +57 -0
- package/dist/engines/sqlite/version-maps.js.map +1 -0
- package/dist/engines/surrealdb/backup.js +97 -0
- package/dist/engines/surrealdb/backup.js.map +1 -0
- package/dist/engines/surrealdb/binary-manager.js +33 -0
- package/dist/engines/surrealdb/binary-manager.js.map +1 -0
- package/dist/engines/surrealdb/binary-urls.js +33 -0
- package/dist/engines/surrealdb/binary-urls.js.map +1 -0
- package/dist/engines/surrealdb/cli-utils.js +147 -0
- package/dist/engines/surrealdb/cli-utils.js.map +1 -0
- package/dist/engines/surrealdb/hostdb-releases.js +21 -0
- package/dist/engines/surrealdb/hostdb-releases.js.map +1 -0
- package/dist/engines/surrealdb/index.js +1022 -0
- package/dist/engines/surrealdb/index.js.map +1 -0
- package/dist/engines/surrealdb/restore.js +224 -0
- package/dist/engines/surrealdb/restore.js.map +1 -0
- package/dist/engines/surrealdb/version-maps.js +36 -0
- package/dist/engines/surrealdb/version-maps.js.map +1 -0
- package/dist/engines/tigerbeetle/backup.js +36 -0
- package/dist/engines/tigerbeetle/backup.js.map +1 -0
- package/dist/engines/tigerbeetle/binary-manager.js +72 -0
- package/dist/engines/tigerbeetle/binary-manager.js.map +1 -0
- package/dist/engines/tigerbeetle/binary-urls.js +49 -0
- package/dist/engines/tigerbeetle/binary-urls.js.map +1 -0
- package/dist/engines/tigerbeetle/hostdb-releases.js +21 -0
- package/dist/engines/tigerbeetle/hostdb-releases.js.map +1 -0
- package/dist/engines/tigerbeetle/index.js +559 -0
- package/dist/engines/tigerbeetle/index.js.map +1 -0
- package/dist/engines/tigerbeetle/restore.js +91 -0
- package/dist/engines/tigerbeetle/restore.js.map +1 -0
- package/{engines/tigerbeetle/version-maps.ts → dist/engines/tigerbeetle/version-maps.js} +22 -31
- package/dist/engines/tigerbeetle/version-maps.js.map +1 -0
- package/dist/engines/tigerbeetle/version-validator.js +108 -0
- package/dist/engines/tigerbeetle/version-validator.js.map +1 -0
- package/dist/engines/typedb/backup.js +129 -0
- package/dist/engines/typedb/backup.js.map +1 -0
- package/dist/engines/typedb/binary-manager.js +151 -0
- package/dist/engines/typedb/binary-manager.js.map +1 -0
- package/dist/engines/typedb/binary-urls.js +33 -0
- package/dist/engines/typedb/binary-urls.js.map +1 -0
- package/dist/engines/typedb/cli-utils.js +163 -0
- package/dist/engines/typedb/cli-utils.js.map +1 -0
- package/dist/engines/typedb/hostdb-releases.js +21 -0
- package/dist/engines/typedb/hostdb-releases.js.map +1 -0
- package/dist/engines/typedb/index.js +1003 -0
- package/dist/engines/typedb/index.js.map +1 -0
- package/dist/engines/typedb/restore.js +279 -0
- package/dist/engines/typedb/restore.js.map +1 -0
- package/dist/engines/typedb/version-maps.js +40 -0
- package/dist/engines/typedb/version-maps.js.map +1 -0
- package/dist/engines/typedb/version-validator.js +103 -0
- package/dist/engines/typedb/version-validator.js.map +1 -0
- package/dist/engines/valkey/backup.js +292 -0
- package/dist/engines/valkey/backup.js.map +1 -0
- package/dist/engines/valkey/binary-manager.js +33 -0
- package/dist/engines/valkey/binary-manager.js.map +1 -0
- package/dist/engines/valkey/binary-urls.js +98 -0
- package/dist/engines/valkey/binary-urls.js.map +1 -0
- package/dist/engines/valkey/cli-utils.js +38 -0
- package/dist/engines/valkey/cli-utils.js.map +1 -0
- package/dist/engines/valkey/hostdb-releases.js +21 -0
- package/dist/engines/valkey/hostdb-releases.js.map +1 -0
- package/dist/engines/valkey/index.js +1257 -0
- package/dist/engines/valkey/index.js.map +1 -0
- package/dist/engines/valkey/restore.js +340 -0
- package/dist/engines/valkey/restore.js.map +1 -0
- package/dist/engines/valkey/version-maps.js +70 -0
- package/dist/engines/valkey/version-maps.js.map +1 -0
- package/dist/engines/valkey/version-validator.js +112 -0
- package/dist/engines/valkey/version-validator.js.map +1 -0
- package/dist/engines/weaviate/api-client.js +50 -0
- package/dist/engines/weaviate/api-client.js.map +1 -0
- package/dist/engines/weaviate/backup.js +95 -0
- package/dist/engines/weaviate/backup.js.map +1 -0
- package/dist/engines/weaviate/binary-manager.js +58 -0
- package/dist/engines/weaviate/binary-manager.js.map +1 -0
- package/dist/engines/weaviate/binary-urls.js +92 -0
- package/dist/engines/weaviate/binary-urls.js.map +1 -0
- package/dist/engines/weaviate/cli-utils.js +39 -0
- package/dist/engines/weaviate/cli-utils.js.map +1 -0
- package/dist/engines/weaviate/hostdb-releases.js +21 -0
- package/dist/engines/weaviate/hostdb-releases.js.map +1 -0
- package/dist/engines/weaviate/index.js +871 -0
- package/dist/engines/weaviate/index.js.map +1 -0
- package/dist/engines/weaviate/restore.js +185 -0
- package/dist/engines/weaviate/restore.js.map +1 -0
- package/dist/engines/weaviate/version-maps.js +67 -0
- package/dist/engines/weaviate/version-maps.js.map +1 -0
- package/dist/engines/weaviate/version-validator.js +109 -0
- package/dist/engines/weaviate/version-validator.js.map +1 -0
- package/dist/types/index.js +102 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +12 -9
- package/bin/cli.js +0 -68
- package/cli/bin.ts +0 -10
- package/cli/commands/attach.ts +0 -139
- package/cli/commands/backup.ts +0 -290
- package/cli/commands/backups.ts +0 -247
- package/cli/commands/clone.ts +0 -159
- package/cli/commands/config.ts +0 -367
- package/cli/commands/connect.ts +0 -684
- package/cli/commands/create.ts +0 -1201
- package/cli/commands/databases.ts +0 -630
- package/cli/commands/delete.ts +0 -133
- package/cli/commands/deps.ts +0 -342
- package/cli/commands/detach.ts +0 -107
- package/cli/commands/doctor.ts +0 -689
- package/cli/commands/duckdb.ts +0 -273
- package/cli/commands/edit.ts +0 -683
- package/cli/commands/engines.ts +0 -1914
- package/cli/commands/export.ts +0 -544
- package/cli/commands/info.ts +0 -340
- package/cli/commands/list.ts +0 -284
- package/cli/commands/logs.ts +0 -102
- package/cli/commands/menu/backup-handlers.ts +0 -1571
- package/cli/commands/menu/container-handlers.ts +0 -2288
- package/cli/commands/menu/engine-handlers.ts +0 -355
- package/cli/commands/menu/index.ts +0 -342
- package/cli/commands/menu/settings-handlers.ts +0 -365
- package/cli/commands/menu/shared.ts +0 -23
- package/cli/commands/menu/shell-handlers.ts +0 -1811
- package/cli/commands/menu/sql-handlers.ts +0 -231
- package/cli/commands/menu/update-handlers.ts +0 -378
- package/cli/commands/menu/validators.ts +0 -8
- package/cli/commands/ports.ts +0 -211
- package/cli/commands/pull.ts +0 -223
- package/cli/commands/query.ts +0 -241
- package/cli/commands/restore.ts +0 -587
- package/cli/commands/run.ts +0 -178
- package/cli/commands/self-update.ts +0 -121
- package/cli/commands/sqlite.ts +0 -273
- package/cli/commands/start.ts +0 -218
- package/cli/commands/stop.ts +0 -241
- package/cli/commands/url.ts +0 -104
- package/cli/commands/users.ts +0 -264
- package/cli/commands/version.ts +0 -55
- package/cli/commands/which.ts +0 -290
- package/cli/constants.ts +0 -233
- package/cli/helpers.ts +0 -1593
- package/cli/index.ts +0 -162
- package/cli/ui/prompts.ts +0 -1525
- package/cli/ui/spinner.ts +0 -88
- package/cli/ui/theme.ts +0 -128
- package/cli/utils/file-follower.ts +0 -93
- package/config/backup-formats.ts +0 -446
- package/config/defaults.ts +0 -56
- package/config/engine-defaults.ts +0 -336
- package/config/engines-registry.ts +0 -150
- package/config/engines.schema.json +0 -135
- package/config/os-dependencies.ts +0 -888
- package/config/paths.ts +0 -200
- package/core/backup-restore.ts +0 -330
- package/core/base-binary-manager.ts +0 -562
- package/core/base-document-binary-manager.ts +0 -523
- package/core/base-embedded-binary-manager.ts +0 -547
- package/core/base-server-binary-manager.ts +0 -523
- package/core/config-manager.ts +0 -652
- package/core/container-manager.ts +0 -787
- package/core/credential-generator.ts +0 -93
- package/core/credential-manager.ts +0 -259
- package/core/dblab-utils.ts +0 -113
- package/core/dependency-manager.ts +0 -512
- package/core/docker-exporter.ts +0 -1345
- package/core/error-handler.ts +0 -419
- package/core/fs-error-utils.ts +0 -82
- package/core/homebrew-version-manager.ts +0 -352
- package/core/hostdb-client.ts +0 -344
- package/core/hostdb-metadata.ts +0 -350
- package/core/hostdb-releases-factory.ts +0 -237
- package/core/library-env.ts +0 -118
- package/core/pgweb-utils.ts +0 -62
- package/core/platform-service.ts +0 -829
- package/core/port-manager.ts +0 -165
- package/core/process-manager.ts +0 -576
- package/core/pull-manager.ts +0 -511
- package/core/query-parser.ts +0 -514
- package/core/spawn-utils.ts +0 -122
- package/core/start-with-retry.ts +0 -130
- package/core/test-cleanup.ts +0 -108
- package/core/tls-generator.ts +0 -116
- package/core/transaction-manager.ts +0 -158
- package/core/update-manager.ts +0 -308
- package/core/version-migration.ts +0 -346
- package/core/version-utils.ts +0 -104
- package/engines/base-engine.ts +0 -340
- package/engines/clickhouse/README.md +0 -231
- package/engines/clickhouse/backup.ts +0 -398
- package/engines/clickhouse/binary-manager.ts +0 -201
- package/engines/clickhouse/binary-urls.ts +0 -125
- package/engines/clickhouse/cli-utils.ts +0 -176
- package/engines/clickhouse/hostdb-releases.ts +0 -30
- package/engines/clickhouse/index.ts +0 -1345
- package/engines/clickhouse/restore.ts +0 -466
- package/engines/clickhouse/version-maps.ts +0 -95
- package/engines/clickhouse/version-validator.ts +0 -154
- package/engines/cockroachdb/README.md +0 -170
- package/engines/cockroachdb/backup.ts +0 -376
- package/engines/cockroachdb/binary-manager.ts +0 -45
- package/engines/cockroachdb/binary-urls.ts +0 -40
- package/engines/cockroachdb/cli-utils.ts +0 -384
- package/engines/cockroachdb/hostdb-releases.ts +0 -26
- package/engines/cockroachdb/index.ts +0 -1276
- package/engines/cockroachdb/restore.ts +0 -455
- package/engines/cockroachdb/version-maps.ts +0 -42
- package/engines/couchdb/README.md +0 -257
- package/engines/couchdb/api-client.ts +0 -81
- package/engines/couchdb/backup.ts +0 -137
- package/engines/couchdb/binary-manager.ts +0 -86
- package/engines/couchdb/binary-urls.ts +0 -115
- package/engines/couchdb/hostdb-releases.ts +0 -23
- package/engines/couchdb/index.ts +0 -1429
- package/engines/couchdb/restore.ts +0 -290
- package/engines/couchdb/version-maps.ts +0 -78
- package/engines/couchdb/version-validator.ts +0 -111
- package/engines/duckdb/README.md +0 -154
- package/engines/duckdb/binary-manager.ts +0 -45
- package/engines/duckdb/hostdb-releases.ts +0 -23
- package/engines/duckdb/index.ts +0 -749
- package/engines/duckdb/registry.ts +0 -303
- package/engines/duckdb/scanner.ts +0 -22
- package/engines/duckdb/version-maps.ts +0 -78
- package/engines/duckdb/version-validator.ts +0 -78
- package/engines/ferretdb/README.md +0 -262
- package/engines/ferretdb/backup.ts +0 -173
- package/engines/ferretdb/binary-manager.ts +0 -1095
- package/engines/ferretdb/binary-urls.ts +0 -183
- package/engines/ferretdb/index.ts +0 -1907
- package/engines/ferretdb/restore.ts +0 -357
- package/engines/file-based-utils.ts +0 -262
- package/engines/index.ts +0 -131
- package/engines/influxdb/README.md +0 -180
- package/engines/influxdb/api-client.ts +0 -64
- package/engines/influxdb/backup.ts +0 -160
- package/engines/influxdb/binary-manager.ts +0 -110
- package/engines/influxdb/binary-urls.ts +0 -69
- package/engines/influxdb/hostdb-releases.ts +0 -23
- package/engines/influxdb/index.ts +0 -1272
- package/engines/influxdb/restore.ts +0 -417
- package/engines/influxdb/version-maps.ts +0 -75
- package/engines/influxdb/version-validator.ts +0 -128
- package/engines/mariadb/README.md +0 -141
- package/engines/mariadb/backup.ts +0 -233
- package/engines/mariadb/binary-manager.ts +0 -45
- package/engines/mariadb/hostdb-releases.ts +0 -23
- package/engines/mariadb/index.ts +0 -1300
- package/engines/mariadb/restore.ts +0 -447
- package/engines/mariadb/version-maps.ts +0 -72
- package/engines/mariadb/version-validator.ts +0 -181
- package/engines/meilisearch/README.md +0 -255
- package/engines/meilisearch/api-client.ts +0 -61
- package/engines/meilisearch/backup.ts +0 -233
- package/engines/meilisearch/binary-manager.ts +0 -43
- package/engines/meilisearch/binary-urls.ts +0 -69
- package/engines/meilisearch/hostdb-releases.ts +0 -26
- package/engines/meilisearch/index.ts +0 -1292
- package/engines/meilisearch/restore.ts +0 -219
- package/engines/meilisearch/version-maps.ts +0 -78
- package/engines/meilisearch/version-validator.ts +0 -128
- package/engines/mongodb/README.md +0 -162
- package/engines/mongodb/backup.ts +0 -127
- package/engines/mongodb/binary-manager.ts +0 -48
- package/engines/mongodb/binary-urls.ts +0 -63
- package/engines/mongodb/cli-utils.ts +0 -171
- package/engines/mongodb/hostdb-releases.ts +0 -91
- package/engines/mongodb/index.ts +0 -1118
- package/engines/mongodb/restore.ts +0 -361
- package/engines/mongodb/version-maps.ts +0 -91
- package/engines/mongodb/version-validator.ts +0 -160
- package/engines/mysql/README.md +0 -142
- package/engines/mysql/backup.ts +0 -270
- package/engines/mysql/binary-detection.ts +0 -408
- package/engines/mysql/binary-manager.ts +0 -42
- package/engines/mysql/binary-urls.ts +0 -104
- package/engines/mysql/index.ts +0 -1361
- package/engines/mysql/restore.ts +0 -500
- package/engines/mysql/version-maps.ts +0 -91
- package/engines/mysql/version-validator.ts +0 -369
- package/engines/postgresql/README.md +0 -158
- package/engines/postgresql/backup.ts +0 -151
- package/engines/postgresql/binary-manager.ts +0 -114
- package/engines/postgresql/binary-urls.ts +0 -99
- package/engines/postgresql/hostdb-releases.ts +0 -26
- package/engines/postgresql/index.ts +0 -1143
- package/engines/postgresql/remote-version.ts +0 -161
- package/engines/postgresql/restore.ts +0 -342
- package/engines/postgresql/version-maps.ts +0 -83
- package/engines/postgresql/version-validator.ts +0 -413
- package/engines/qdrant/README.md +0 -222
- package/engines/qdrant/api-client.ts +0 -61
- package/engines/qdrant/backup.ts +0 -165
- package/engines/qdrant/binary-manager.ts +0 -43
- package/engines/qdrant/binary-urls.ts +0 -115
- package/engines/qdrant/cli-utils.ts +0 -43
- package/engines/qdrant/hostdb-releases.ts +0 -23
- package/engines/qdrant/index.ts +0 -1312
- package/engines/qdrant/restore.ts +0 -203
- package/engines/qdrant/version-maps.ts +0 -78
- package/engines/qdrant/version-validator.ts +0 -128
- package/engines/questdb/README.md +0 -334
- package/engines/questdb/backup.ts +0 -220
- package/engines/questdb/binary-manager.ts +0 -310
- package/engines/questdb/binary-urls.ts +0 -34
- package/engines/questdb/hostdb-releases.ts +0 -23
- package/engines/questdb/index.ts +0 -1023
- package/engines/questdb/restore.ts +0 -260
- package/engines/questdb/version-maps.ts +0 -37
- package/engines/questdb/version-validator.ts +0 -121
- package/engines/redis/README.md +0 -173
- package/engines/redis/backup.ts +0 -389
- package/engines/redis/binary-manager.ts +0 -44
- package/engines/redis/binary-urls.ts +0 -117
- package/engines/redis/cli-utils.ts +0 -42
- package/engines/redis/hostdb-releases.ts +0 -23
- package/engines/redis/index.ts +0 -1583
- package/engines/redis/restore.ts +0 -443
- package/engines/redis/version-maps.ts +0 -81
- package/engines/redis/version-validator.ts +0 -131
- package/engines/sqlite/README.md +0 -162
- package/engines/sqlite/binary-manager.ts +0 -52
- package/engines/sqlite/hostdb-releases.ts +0 -23
- package/engines/sqlite/index.ts +0 -641
- package/engines/sqlite/registry.ts +0 -198
- package/engines/sqlite/scanner.ts +0 -22
- package/engines/sqlite/version-maps.ts +0 -64
- package/engines/surrealdb/README.md +0 -218
- package/engines/surrealdb/backup.ts +0 -131
- package/engines/surrealdb/binary-manager.ts +0 -45
- package/engines/surrealdb/binary-urls.ts +0 -40
- package/engines/surrealdb/cli-utils.ts +0 -173
- package/engines/surrealdb/hostdb-releases.ts +0 -23
- package/engines/surrealdb/index.ts +0 -1246
- package/engines/surrealdb/restore.ts +0 -302
- package/engines/surrealdb/version-maps.ts +0 -41
- package/engines/tigerbeetle/README.md +0 -61
- package/engines/tigerbeetle/backup.ts +0 -49
- package/engines/tigerbeetle/binary-manager.ts +0 -95
- package/engines/tigerbeetle/binary-urls.ts +0 -62
- package/engines/tigerbeetle/hostdb-releases.ts +0 -26
- package/engines/tigerbeetle/index.ts +0 -746
- package/engines/tigerbeetle/restore.ts +0 -130
- package/engines/tigerbeetle/version-validator.ts +0 -126
- package/engines/typedb/backup.ts +0 -167
- package/engines/typedb/binary-manager.ts +0 -200
- package/engines/typedb/binary-urls.ts +0 -40
- package/engines/typedb/cli-utils.ts +0 -210
- package/engines/typedb/hostdb-releases.ts +0 -23
- package/engines/typedb/index.ts +0 -1275
- package/engines/typedb/restore.ts +0 -377
- package/engines/typedb/version-maps.ts +0 -48
- package/engines/typedb/version-validator.ts +0 -127
- package/engines/valkey/README.md +0 -219
- package/engines/valkey/backup.ts +0 -389
- package/engines/valkey/binary-manager.ts +0 -45
- package/engines/valkey/binary-urls.ts +0 -122
- package/engines/valkey/cli-utils.ts +0 -42
- package/engines/valkey/hostdb-releases.ts +0 -23
- package/engines/valkey/index.ts +0 -1585
- package/engines/valkey/restore.ts +0 -446
- package/engines/valkey/version-maps.ts +0 -81
- package/engines/valkey/version-validator.ts +0 -131
- package/engines/weaviate/README.md +0 -302
- package/engines/weaviate/api-client.ts +0 -61
- package/engines/weaviate/backup.ts +0 -145
- package/engines/weaviate/binary-manager.ts +0 -80
- package/engines/weaviate/binary-urls.ts +0 -115
- package/engines/weaviate/cli-utils.ts +0 -43
- package/engines/weaviate/hostdb-releases.ts +0 -23
- package/engines/weaviate/index.ts +0 -1139
- package/engines/weaviate/restore.ts +0 -235
- package/engines/weaviate/version-maps.ts +0 -78
- package/engines/weaviate/version-validator.ts +0 -128
- package/types/index.ts +0 -624
- /package/{config → dist/config}/engines.json +0 -0
package/engines/mysql/index.ts
DELETED
|
@@ -1,1361 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MySQL Engine implementation
|
|
3
|
-
* Manages MySQL database containers using pre-built binaries from hostdb
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { spawn, exec, type SpawnOptions } from 'child_process'
|
|
7
|
-
import { promisify } from 'util'
|
|
8
|
-
import { existsSync, createReadStream } from 'fs'
|
|
9
|
-
import { mkdir, writeFile, readFile, unlink, rm } from 'fs/promises'
|
|
10
|
-
import { join } from 'path'
|
|
11
|
-
import { BaseEngine } from '../base-engine'
|
|
12
|
-
import { paths } from '../../config/paths'
|
|
13
|
-
import { getEngineDefaults } from '../../config/defaults'
|
|
14
|
-
import {
|
|
15
|
-
platformService,
|
|
16
|
-
isWindows,
|
|
17
|
-
getWindowsSpawnOptions,
|
|
18
|
-
} from '../../core/platform-service'
|
|
19
|
-
import { configManager } from '../../core/config-manager'
|
|
20
|
-
import {
|
|
21
|
-
logDebug,
|
|
22
|
-
logWarning,
|
|
23
|
-
ErrorCodes,
|
|
24
|
-
SpinDBError,
|
|
25
|
-
assertValidDatabaseName,
|
|
26
|
-
assertValidUsername,
|
|
27
|
-
} from '../../core/error-handler'
|
|
28
|
-
import { mysqlBinaryManager } from './binary-manager'
|
|
29
|
-
import { getBinaryUrl } from './binary-urls'
|
|
30
|
-
import { fetchAvailableVersions, getLatestVersion } from './hostdb-releases'
|
|
31
|
-
import { SUPPORTED_MAJOR_VERSIONS, FALLBACK_VERSION_MAP } from './version-maps'
|
|
32
|
-
import {
|
|
33
|
-
detectBackupFormat as detectBackupFormatImpl,
|
|
34
|
-
restoreBackup,
|
|
35
|
-
parseConnectionString,
|
|
36
|
-
} from './restore'
|
|
37
|
-
import { createBackup } from './backup'
|
|
38
|
-
import {
|
|
39
|
-
Platform,
|
|
40
|
-
type Arch,
|
|
41
|
-
type ContainerConfig,
|
|
42
|
-
type ProgressCallback,
|
|
43
|
-
type BackupFormat,
|
|
44
|
-
type BackupOptions,
|
|
45
|
-
type BackupResult,
|
|
46
|
-
type RestoreResult,
|
|
47
|
-
type DumpResult,
|
|
48
|
-
type StatusResult,
|
|
49
|
-
type QueryResult,
|
|
50
|
-
type QueryOptions,
|
|
51
|
-
type CreateUserOptions,
|
|
52
|
-
type UserCredentials,
|
|
53
|
-
} from '../../types'
|
|
54
|
-
import { parseTSVToQueryResult } from '../../core/query-parser'
|
|
55
|
-
|
|
56
|
-
const execAsync = promisify(exec)
|
|
57
|
-
|
|
58
|
-
const ENGINE = 'mysql'
|
|
59
|
-
const engineDef = getEngineDefaults(ENGINE)
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Build a Windows-safe mysql command string for either a file or inline SQL.
|
|
63
|
-
* This is exported for unit testing.
|
|
64
|
-
*/
|
|
65
|
-
export function buildWindowsMysqlCommand(
|
|
66
|
-
mysqlPath: string,
|
|
67
|
-
port: number,
|
|
68
|
-
user: string,
|
|
69
|
-
db: string,
|
|
70
|
-
options: { file?: string; sql?: string },
|
|
71
|
-
): string {
|
|
72
|
-
if (!options.file && !options.sql) {
|
|
73
|
-
throw new Error('Either file or sql option must be provided')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
let cmd = `"${mysqlPath}" -h 127.0.0.1 -P ${port} -u ${user} ${db}`
|
|
77
|
-
|
|
78
|
-
if (options.file) {
|
|
79
|
-
// Redirection requires shell, so use < operator
|
|
80
|
-
cmd += ` < "${options.file}"`
|
|
81
|
-
} else if (options.sql) {
|
|
82
|
-
const escaped = options.sql.replace(/"/g, '\\"')
|
|
83
|
-
cmd += ` -e "${escaped}"`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return cmd
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Build a platform-safe mysql command string with SQL inline.
|
|
91
|
-
* On Unix, uses single quotes to prevent shell interpretation of backticks.
|
|
92
|
-
* On Windows, uses double quotes (backticks are literal in cmd.exe).
|
|
93
|
-
* This is exported for unit testing.
|
|
94
|
-
*/
|
|
95
|
-
export function buildMysqlInlineCommand(
|
|
96
|
-
mysqlPath: string,
|
|
97
|
-
port: number,
|
|
98
|
-
user: string,
|
|
99
|
-
sql: string,
|
|
100
|
-
options: { database?: string } = {},
|
|
101
|
-
): string {
|
|
102
|
-
const dbArg = options.database ? ` ${options.database}` : ''
|
|
103
|
-
|
|
104
|
-
if (isWindows()) {
|
|
105
|
-
// Windows: use double quotes, escape inner double quotes
|
|
106
|
-
const escaped = sql.replace(/"/g, '\\"')
|
|
107
|
-
return `"${mysqlPath}" -h 127.0.0.1 -P ${port} -u ${user}${dbArg} -e "${escaped}"`
|
|
108
|
-
} else {
|
|
109
|
-
// Unix: use single quotes to prevent backtick interpretation
|
|
110
|
-
// Escape any single quotes in the SQL by ending the string, adding escaped quote, starting new string
|
|
111
|
-
const escaped = sql.replace(/'/g, "'\\''")
|
|
112
|
-
return `"${mysqlPath}" -h 127.0.0.1 -P ${port} -u ${user}${dbArg} -e '${escaped}'`
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export class MySQLEngine extends BaseEngine {
|
|
117
|
-
name = ENGINE
|
|
118
|
-
displayName = 'MySQL'
|
|
119
|
-
defaultPort = engineDef.defaultPort
|
|
120
|
-
supportedVersions = SUPPORTED_MAJOR_VERSIONS
|
|
121
|
-
|
|
122
|
-
async fetchAvailableVersions(): Promise<Record<string, string[]>> {
|
|
123
|
-
return fetchAvailableVersions()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
getPlatformInfo(): { platform: Platform; arch: Arch } {
|
|
127
|
-
const info = platformService.getPlatformInfo()
|
|
128
|
-
return {
|
|
129
|
-
platform: info.platform,
|
|
130
|
-
arch: info.arch,
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
resolveFullVersion(version: string): string {
|
|
135
|
-
// Check if already a full version (has at least two dots)
|
|
136
|
-
if (/^\d+\.\d+\.\d+/.test(version)) {
|
|
137
|
-
return version
|
|
138
|
-
}
|
|
139
|
-
// It's a major version, resolve using fallback map
|
|
140
|
-
const resolved = FALLBACK_VERSION_MAP[version]
|
|
141
|
-
if (!resolved) {
|
|
142
|
-
const availableVersions = Object.keys(FALLBACK_VERSION_MAP).join(', ')
|
|
143
|
-
logWarning(
|
|
144
|
-
`Unknown MySQL major version "${version}". Available versions: ${availableVersions}. ` +
|
|
145
|
-
`Falling back to ${version}.0.0 which may not exist.`,
|
|
146
|
-
)
|
|
147
|
-
return `${version}.0.0`
|
|
148
|
-
}
|
|
149
|
-
return resolved
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async resolveFullVersionAsync(version: string): Promise<string> {
|
|
153
|
-
if (/^\d+\.\d+\.\d+/.test(version)) {
|
|
154
|
-
return version
|
|
155
|
-
}
|
|
156
|
-
return getLatestVersion(version)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
getBinaryPath(version: string): string {
|
|
160
|
-
const fullVersion = this.resolveFullVersion(version)
|
|
161
|
-
const { platform: p, arch: a } = this.getPlatformInfo()
|
|
162
|
-
return paths.getBinaryPath({
|
|
163
|
-
engine: 'mysql',
|
|
164
|
-
version: fullVersion,
|
|
165
|
-
platform: p,
|
|
166
|
-
arch: a,
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
getBinaryUrl(version: string, plat: Platform, arc: Arch): string {
|
|
171
|
-
return getBinaryUrl(version, plat, arc)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Verify MySQL binaries are installed and working.
|
|
176
|
-
*
|
|
177
|
-
* **Prefer passing `version` explicitly** - the fallback path extraction is fragile.
|
|
178
|
-
*
|
|
179
|
-
* When `version` is provided, verification uses it directly. Otherwise, the method
|
|
180
|
-
* attempts to extract a semver-like pattern (`\d+\.\d+\.\d+`) from the basename of
|
|
181
|
-
* `binPath` (e.g., "mysql-8.0.40-darwin-arm64" → "8.0.40"). This fallback can fail
|
|
182
|
-
* if the path doesn't follow the expected naming convention, resulting in false negatives.
|
|
183
|
-
*
|
|
184
|
-
* Platform and architecture are derived internally via `getPlatformInfo()`.
|
|
185
|
-
* Verification is delegated to `mysqlBinaryManager.verify(version, platform, arch)`.
|
|
186
|
-
*
|
|
187
|
-
* @param binPath - Path to the binary directory (used for fallback version extraction)
|
|
188
|
-
* @param version - Explicit version string (e.g., "8.0.40", "9.5.0"). Always pass this
|
|
189
|
-
* when available to avoid relying on path-based extraction.
|
|
190
|
-
* @returns `true` if binaries are verified, `false` if verification fails or version
|
|
191
|
-
* cannot be determined
|
|
192
|
-
*
|
|
193
|
-
* @example
|
|
194
|
-
* // Preferred: pass version explicitly
|
|
195
|
-
* await engine.verifyBinary('/path/to/mysql-8.0.40-darwin-arm64', '8.0.40')
|
|
196
|
-
*
|
|
197
|
-
* // Fallback: version extracted from path (less reliable)
|
|
198
|
-
* await engine.verifyBinary('/path/to/mysql-8.0.40-darwin-arm64')
|
|
199
|
-
*/
|
|
200
|
-
async verifyBinary(binPath: string, version?: string): Promise<boolean> {
|
|
201
|
-
const { platform: p, arch: a } = this.getPlatformInfo()
|
|
202
|
-
|
|
203
|
-
// Use explicit version if provided
|
|
204
|
-
if (version) {
|
|
205
|
-
return mysqlBinaryManager.verify(version, p, a)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Fallback: extract version from path (less reliable)
|
|
209
|
-
// Matches patterns like mysql-8.0.40-darwin-arm64 or mysql-9.0.0-linux-x64
|
|
210
|
-
const basename = binPath.split('/').pop() || binPath.split('\\').pop() || ''
|
|
211
|
-
const versionMatch = basename.match(/\b(\d+\.\d+\.\d+)\b/)
|
|
212
|
-
if (!versionMatch) {
|
|
213
|
-
logDebug(`Could not extract version from binary path: ${binPath}`)
|
|
214
|
-
return false
|
|
215
|
-
}
|
|
216
|
-
logDebug(
|
|
217
|
-
`Extracted version ${versionMatch[1]} from path (prefer explicit version)`,
|
|
218
|
-
)
|
|
219
|
-
return mysqlBinaryManager.verify(versionMatch[1], p, a)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async ensureBinaries(
|
|
223
|
-
version: string,
|
|
224
|
-
onProgress?: ProgressCallback,
|
|
225
|
-
): Promise<string> {
|
|
226
|
-
const { platform: p, arch: a } = this.getPlatformInfo()
|
|
227
|
-
const binPath = await mysqlBinaryManager.ensureInstalled(
|
|
228
|
-
version,
|
|
229
|
-
p,
|
|
230
|
-
a,
|
|
231
|
-
onProgress,
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
// Register all MySQL binaries from downloaded package
|
|
235
|
-
const ext = platformService.getExecutableExtension()
|
|
236
|
-
const tools = ['mysqld', 'mysqladmin', 'mysql', 'mysqldump'] as const
|
|
237
|
-
|
|
238
|
-
for (const tool of tools) {
|
|
239
|
-
const toolPath = join(binPath, 'bin', `${tool}${ext}`)
|
|
240
|
-
if (existsSync(toolPath)) {
|
|
241
|
-
await configManager.setBinaryPath(tool, toolPath, 'bundled')
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return binPath
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
async isBinaryInstalled(version: string): Promise<boolean> {
|
|
249
|
-
const { platform: p, arch: a } = this.getPlatformInfo()
|
|
250
|
-
return mysqlBinaryManager.isInstalled(version, p, a)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
async initDataDir(
|
|
254
|
-
containerName: string,
|
|
255
|
-
version: string,
|
|
256
|
-
_options: Record<string, unknown> = {},
|
|
257
|
-
): Promise<string> {
|
|
258
|
-
const binPath = this.getBinaryPath(version)
|
|
259
|
-
const ext = platformService.getExecutableExtension()
|
|
260
|
-
const dataDir = paths.getContainerDataPath(containerName, {
|
|
261
|
-
engine: ENGINE,
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
let createdDataDir = false
|
|
265
|
-
|
|
266
|
-
if (!existsSync(dataDir)) {
|
|
267
|
-
await mkdir(dataDir, { recursive: true })
|
|
268
|
-
createdDataDir = true
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const cleanupOnFailure = async () => {
|
|
272
|
-
if (createdDataDir) {
|
|
273
|
-
try {
|
|
274
|
-
await rm(dataDir, { recursive: true, force: true })
|
|
275
|
-
logDebug(`Cleaned up data directory after init failure: ${dataDir}`)
|
|
276
|
-
} catch (cleanupErr) {
|
|
277
|
-
logDebug(
|
|
278
|
-
`Failed to clean up data directory: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`,
|
|
279
|
-
)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// MySQL uses mysqld --initialize-insecure
|
|
285
|
-
const mysqld = join(binPath, 'bin', `mysqld${ext}`)
|
|
286
|
-
|
|
287
|
-
if (!existsSync(mysqld)) {
|
|
288
|
-
await cleanupOnFailure()
|
|
289
|
-
throw new Error(
|
|
290
|
-
`MySQL server binary not found in ${binPath}/bin/.\n` +
|
|
291
|
-
'Re-download the MySQL binaries: spindb engines download mysql',
|
|
292
|
-
)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// MySQL initialization
|
|
296
|
-
// --initialize-insecure creates root user without password (for local dev)
|
|
297
|
-
const logFile = paths.getContainerLogPath(containerName, { engine: ENGINE })
|
|
298
|
-
if (isWindows()) {
|
|
299
|
-
// On Windows, use exec with properly quoted command
|
|
300
|
-
const cmd = `"${mysqld}" --initialize-insecure --datadir="${dataDir}" --log-error="${logFile}"`
|
|
301
|
-
|
|
302
|
-
return new Promise((resolve, reject) => {
|
|
303
|
-
exec(cmd, { timeout: 120000 }, async (error, stdout, stderr) => {
|
|
304
|
-
if (error) {
|
|
305
|
-
await cleanupOnFailure()
|
|
306
|
-
reject(
|
|
307
|
-
new Error(
|
|
308
|
-
`MySQL initialization failed with code ${error.code}: ${stderr || stdout || error.message}`,
|
|
309
|
-
),
|
|
310
|
-
)
|
|
311
|
-
} else {
|
|
312
|
-
resolve(dataDir)
|
|
313
|
-
}
|
|
314
|
-
})
|
|
315
|
-
})
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Unix path - use spawn without shell
|
|
319
|
-
// --user: Required for non-root, but when running as root we can skip it to avoid
|
|
320
|
-
// needing a dedicated 'mysql' user to exist on the system
|
|
321
|
-
const isRunningAsRoot = process.getuid?.() === 0
|
|
322
|
-
const args = [
|
|
323
|
-
'--initialize-insecure',
|
|
324
|
-
`--datadir=${dataDir}`,
|
|
325
|
-
`--basedir=${binPath}`,
|
|
326
|
-
`--log-error=${logFile}`,
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
// Only add --user when not running as root
|
|
330
|
-
// When running as root, mysqld --initialize-insecure works without specifying a user
|
|
331
|
-
if (!isRunningAsRoot && process.env.USER) {
|
|
332
|
-
args.push(`--user=${process.env.USER}`)
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Timeout for initialization (same as Windows path)
|
|
336
|
-
const INIT_TIMEOUT_MS = 120000
|
|
337
|
-
|
|
338
|
-
return new Promise((resolve, reject) => {
|
|
339
|
-
let settled = false
|
|
340
|
-
let timeoutId: NodeJS.Timeout | null = null
|
|
341
|
-
|
|
342
|
-
const proc = spawn(mysqld, args, {
|
|
343
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
let stdout = ''
|
|
347
|
-
let stderr = ''
|
|
348
|
-
|
|
349
|
-
// Set up timeout
|
|
350
|
-
timeoutId = setTimeout(async () => {
|
|
351
|
-
if (settled) return
|
|
352
|
-
settled = true
|
|
353
|
-
|
|
354
|
-
// Kill the process
|
|
355
|
-
try {
|
|
356
|
-
proc.kill('SIGKILL')
|
|
357
|
-
} catch {
|
|
358
|
-
// Ignore errors if process already exited
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
await cleanupOnFailure()
|
|
362
|
-
reject(
|
|
363
|
-
new Error(
|
|
364
|
-
`MySQL initialization timed out after ${INIT_TIMEOUT_MS / 1000}s. Check logs at: ${logFile}`,
|
|
365
|
-
),
|
|
366
|
-
)
|
|
367
|
-
}, INIT_TIMEOUT_MS)
|
|
368
|
-
|
|
369
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
370
|
-
stdout += data.toString()
|
|
371
|
-
})
|
|
372
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
373
|
-
stderr += data.toString()
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
proc.on('close', async (code) => {
|
|
377
|
-
if (settled) return
|
|
378
|
-
settled = true
|
|
379
|
-
|
|
380
|
-
if (timeoutId) {
|
|
381
|
-
clearTimeout(timeoutId)
|
|
382
|
-
timeoutId = null
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (code === 0) {
|
|
386
|
-
resolve(dataDir)
|
|
387
|
-
} else {
|
|
388
|
-
await cleanupOnFailure()
|
|
389
|
-
reject(
|
|
390
|
-
new Error(
|
|
391
|
-
`MySQL initialization failed with code ${code}: ${stderr || stdout}`,
|
|
392
|
-
),
|
|
393
|
-
)
|
|
394
|
-
}
|
|
395
|
-
})
|
|
396
|
-
|
|
397
|
-
proc.on('error', async (err) => {
|
|
398
|
-
if (settled) return
|
|
399
|
-
settled = true
|
|
400
|
-
|
|
401
|
-
if (timeoutId) {
|
|
402
|
-
clearTimeout(timeoutId)
|
|
403
|
-
timeoutId = null
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
await cleanupOnFailure()
|
|
407
|
-
reject(err)
|
|
408
|
-
})
|
|
409
|
-
})
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
async start(
|
|
413
|
-
container: ContainerConfig,
|
|
414
|
-
onProgress?: ProgressCallback,
|
|
415
|
-
): Promise<{ port: number; connectionString: string }> {
|
|
416
|
-
const { name, port, version } = container
|
|
417
|
-
|
|
418
|
-
const alreadyRunning = await this.isRunning(name)
|
|
419
|
-
if (alreadyRunning) {
|
|
420
|
-
return {
|
|
421
|
-
port,
|
|
422
|
-
connectionString: this.getConnectionString(container),
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const binPath = this.getBinaryPath(version)
|
|
427
|
-
const ext = platformService.getExecutableExtension()
|
|
428
|
-
const mysqld = join(binPath, 'bin', `mysqld${ext}`)
|
|
429
|
-
|
|
430
|
-
if (!existsSync(mysqld)) {
|
|
431
|
-
throw new Error(
|
|
432
|
-
`MySQL server binary not found in ${binPath}/bin/.\n` +
|
|
433
|
-
'Re-download the MySQL binaries: spindb engines download mysql',
|
|
434
|
-
)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const dataDir = paths.getContainerDataPath(name, { engine: ENGINE })
|
|
438
|
-
const logFile = paths.getContainerLogPath(name, { engine: ENGINE })
|
|
439
|
-
const pidFile = paths.getContainerPidPath(name, { engine: ENGINE })
|
|
440
|
-
const { platform } = platformService.getPlatformInfo()
|
|
441
|
-
|
|
442
|
-
onProgress?.({ stage: 'starting', message: 'Starting MySQL...' })
|
|
443
|
-
|
|
444
|
-
const args = [
|
|
445
|
-
`--datadir=${dataDir}`,
|
|
446
|
-
`--port=${port}`,
|
|
447
|
-
`--pid-file=${pidFile}`,
|
|
448
|
-
`--log-error=${logFile}`,
|
|
449
|
-
'--bind-address=127.0.0.1',
|
|
450
|
-
`--max-connections=${engineDef.maxConnections}`,
|
|
451
|
-
]
|
|
452
|
-
|
|
453
|
-
if (platform !== Platform.Win32) {
|
|
454
|
-
const socketFile = join(
|
|
455
|
-
paths.getContainerPath(name, { engine: ENGINE }),
|
|
456
|
-
'mysql.sock',
|
|
457
|
-
)
|
|
458
|
-
args.push(`--socket=${socketFile}`)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
let proc: ReturnType<typeof spawn> | null = null
|
|
462
|
-
|
|
463
|
-
if (isWindows()) {
|
|
464
|
-
proc = spawn(mysqld, args, {
|
|
465
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
466
|
-
detached: true,
|
|
467
|
-
windowsHide: true,
|
|
468
|
-
})
|
|
469
|
-
|
|
470
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
471
|
-
logDebug(`mysqld stdout: ${data.toString()}`)
|
|
472
|
-
})
|
|
473
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
474
|
-
logDebug(`mysqld stderr: ${data.toString()}`)
|
|
475
|
-
})
|
|
476
|
-
|
|
477
|
-
proc.unref()
|
|
478
|
-
} else {
|
|
479
|
-
proc = spawn(mysqld, args, {
|
|
480
|
-
stdio: ['ignore', 'ignore', 'ignore'],
|
|
481
|
-
detached: true,
|
|
482
|
-
})
|
|
483
|
-
proc.unref()
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
return new Promise((resolve, reject) => {
|
|
487
|
-
// Track whether we've already settled the promise to avoid race conditions
|
|
488
|
-
let settled = false
|
|
489
|
-
|
|
490
|
-
const errorHandler = (err: Error) => {
|
|
491
|
-
if (settled) return
|
|
492
|
-
settled = true
|
|
493
|
-
if (proc) {
|
|
494
|
-
proc.removeListener('error', errorHandler)
|
|
495
|
-
}
|
|
496
|
-
reject(err)
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
if (proc) {
|
|
500
|
-
proc.on('error', errorHandler)
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
setTimeout(async () => {
|
|
504
|
-
if (proc && proc.pid) {
|
|
505
|
-
try {
|
|
506
|
-
await writeFile(pidFile, String(proc.pid))
|
|
507
|
-
} catch (error) {
|
|
508
|
-
logDebug(`Could not write PID file: ${error}`)
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// Wait for MySQL to be ready
|
|
513
|
-
let attempts = 0
|
|
514
|
-
const maxAttempts = 60
|
|
515
|
-
const checkInterval = 500
|
|
516
|
-
|
|
517
|
-
const checkReady = async () => {
|
|
518
|
-
if (settled) return
|
|
519
|
-
attempts++
|
|
520
|
-
try {
|
|
521
|
-
const mysqladmin = await this.getMysqladminPath()
|
|
522
|
-
await execAsync(
|
|
523
|
-
`"${mysqladmin}" -h 127.0.0.1 -P ${port} -u root ping`,
|
|
524
|
-
)
|
|
525
|
-
if (settled) return
|
|
526
|
-
settled = true
|
|
527
|
-
if (proc) {
|
|
528
|
-
proc.removeListener('error', errorHandler)
|
|
529
|
-
}
|
|
530
|
-
resolve({
|
|
531
|
-
port,
|
|
532
|
-
connectionString: this.getConnectionString(container),
|
|
533
|
-
})
|
|
534
|
-
} catch {
|
|
535
|
-
if (settled) return
|
|
536
|
-
if (attempts < maxAttempts) {
|
|
537
|
-
setTimeout(checkReady, checkInterval)
|
|
538
|
-
} else {
|
|
539
|
-
if (settled) return
|
|
540
|
-
settled = true
|
|
541
|
-
if (proc) {
|
|
542
|
-
proc.removeListener('error', errorHandler)
|
|
543
|
-
}
|
|
544
|
-
reject(new Error('MySQL failed to start within timeout'))
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
checkReady()
|
|
550
|
-
}, 1000)
|
|
551
|
-
})
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
private async isRunning(containerName: string): Promise<boolean> {
|
|
555
|
-
const pidFile = paths.getContainerPidPath(containerName, { engine: ENGINE })
|
|
556
|
-
if (!existsSync(pidFile)) {
|
|
557
|
-
return false
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
try {
|
|
561
|
-
const pid = parseInt(await readFile(pidFile, 'utf8'), 10)
|
|
562
|
-
return platformService.isProcessRunning(pid)
|
|
563
|
-
} catch {
|
|
564
|
-
return false
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
async stop(container: ContainerConfig): Promise<void> {
|
|
569
|
-
const { name, port } = container
|
|
570
|
-
const pidFile = paths.getContainerPidPath(name, { engine: ENGINE })
|
|
571
|
-
|
|
572
|
-
logDebug(`Stopping MySQL container "${name}" on port ${port}`)
|
|
573
|
-
|
|
574
|
-
const pid = await this.getValidatedPid(pidFile)
|
|
575
|
-
if (pid === null) {
|
|
576
|
-
logDebug('No valid PID, checking if MySQL is responding on port')
|
|
577
|
-
try {
|
|
578
|
-
const mysqladmin = await this.getMysqladminPath()
|
|
579
|
-
await execAsync(
|
|
580
|
-
`"${mysqladmin}" -h 127.0.0.1 -P ${port} -u root ping`,
|
|
581
|
-
{ timeout: 2000 },
|
|
582
|
-
)
|
|
583
|
-
logWarning(`MySQL responding on port ${port} but no valid PID file`)
|
|
584
|
-
await this.gracefulShutdown(port)
|
|
585
|
-
} catch {
|
|
586
|
-
logDebug('MySQL not responding, nothing to stop')
|
|
587
|
-
}
|
|
588
|
-
return
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const gracefulSuccess = await this.gracefulShutdown(port, pid)
|
|
592
|
-
if (gracefulSuccess) {
|
|
593
|
-
await this.cleanupPidFile(pidFile)
|
|
594
|
-
logDebug('MySQL stopped gracefully')
|
|
595
|
-
return
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
await this.forceKillWithEscalation(pid, pidFile)
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
private async getValidatedPid(pidFile: string): Promise<number | null> {
|
|
602
|
-
if (!existsSync(pidFile)) {
|
|
603
|
-
logDebug('PID file does not exist')
|
|
604
|
-
return null
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
try {
|
|
608
|
-
const content = await readFile(pidFile, 'utf8')
|
|
609
|
-
const pid = parseInt(content.trim(), 10)
|
|
610
|
-
|
|
611
|
-
if (isNaN(pid) || pid <= 0) {
|
|
612
|
-
logWarning(`PID file contains invalid value: "${content.trim()}"`)
|
|
613
|
-
await this.cleanupPidFile(pidFile)
|
|
614
|
-
return null
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
if (platformService.isProcessRunning(pid)) {
|
|
618
|
-
logDebug(`Validated PID ${pid}`)
|
|
619
|
-
return pid
|
|
620
|
-
} else {
|
|
621
|
-
logWarning(`PID file references non-existent process ${pid}`)
|
|
622
|
-
await this.cleanupPidFile(pidFile)
|
|
623
|
-
return null
|
|
624
|
-
}
|
|
625
|
-
} catch (error) {
|
|
626
|
-
const e = error as NodeJS.ErrnoException
|
|
627
|
-
if (e.code !== 'ENOENT') {
|
|
628
|
-
logWarning(`Failed to read PID file: ${e.message}`)
|
|
629
|
-
}
|
|
630
|
-
return null
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
private async gracefulShutdown(
|
|
635
|
-
port: number,
|
|
636
|
-
pid?: number,
|
|
637
|
-
timeoutMs = 10000,
|
|
638
|
-
): Promise<boolean> {
|
|
639
|
-
try {
|
|
640
|
-
const mysqladmin = await this.getMysqladminPath()
|
|
641
|
-
logDebug('Attempting mysqladmin shutdown')
|
|
642
|
-
await execAsync(
|
|
643
|
-
`"${mysqladmin}" -h 127.0.0.1 -P ${port} -u root shutdown`,
|
|
644
|
-
{ timeout: 5000 },
|
|
645
|
-
)
|
|
646
|
-
} catch (error) {
|
|
647
|
-
const e = error as Error
|
|
648
|
-
logDebug(`mysqladmin shutdown failed: ${e.message}`)
|
|
649
|
-
if (pid) {
|
|
650
|
-
try {
|
|
651
|
-
await platformService.terminateProcess(pid, false)
|
|
652
|
-
} catch (terminateError) {
|
|
653
|
-
const termErr = terminateError as NodeJS.ErrnoException
|
|
654
|
-
// ESRCH means process doesn't exist - it's already gone
|
|
655
|
-
if (termErr.code === 'ESRCH') {
|
|
656
|
-
logDebug(`Process ${pid} already terminated (ESRCH)`)
|
|
657
|
-
return true
|
|
658
|
-
}
|
|
659
|
-
logDebug(`terminateProcess failed for PID ${pid}: ${termErr.message}`)
|
|
660
|
-
return false
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
if (pid) {
|
|
666
|
-
const startTime = Date.now()
|
|
667
|
-
const checkIntervalMs = 200
|
|
668
|
-
|
|
669
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
670
|
-
if (!platformService.isProcessRunning(pid)) {
|
|
671
|
-
logDebug(`Process ${pid} terminated after graceful shutdown`)
|
|
672
|
-
return true
|
|
673
|
-
}
|
|
674
|
-
await this.sleep(checkIntervalMs)
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
logDebug(`Graceful shutdown timed out after ${timeoutMs}ms`)
|
|
678
|
-
return false
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
return true
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
private async forceKillWithEscalation(
|
|
685
|
-
pid: number,
|
|
686
|
-
pidFile: string,
|
|
687
|
-
): Promise<void> {
|
|
688
|
-
logWarning(`Graceful shutdown failed, force killing process ${pid}`)
|
|
689
|
-
|
|
690
|
-
try {
|
|
691
|
-
await platformService.terminateProcess(pid, false)
|
|
692
|
-
await this.sleep(2000)
|
|
693
|
-
|
|
694
|
-
if (!platformService.isProcessRunning(pid)) {
|
|
695
|
-
logDebug(`Process ${pid} terminated after graceful signal`)
|
|
696
|
-
await this.cleanupPidFile(pidFile)
|
|
697
|
-
return
|
|
698
|
-
}
|
|
699
|
-
} catch (error) {
|
|
700
|
-
const e = error as NodeJS.ErrnoException
|
|
701
|
-
if (e.code === 'ESRCH') {
|
|
702
|
-
await this.cleanupPidFile(pidFile)
|
|
703
|
-
return
|
|
704
|
-
}
|
|
705
|
-
logDebug(`Graceful termination failed: ${e.message}`)
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
const { platform } = platformService.getPlatformInfo()
|
|
709
|
-
const killCmd = platform === Platform.Win32 ? 'taskkill /F' : 'kill -9'
|
|
710
|
-
logWarning(`Escalating to force kill for process ${pid}`)
|
|
711
|
-
try {
|
|
712
|
-
await platformService.terminateProcess(pid, true)
|
|
713
|
-
await this.sleep(1000)
|
|
714
|
-
|
|
715
|
-
if (platformService.isProcessRunning(pid)) {
|
|
716
|
-
throw new SpinDBError(
|
|
717
|
-
ErrorCodes.PROCESS_STOP_TIMEOUT,
|
|
718
|
-
`Failed to stop MySQL process ${pid} even with force kill`,
|
|
719
|
-
'error',
|
|
720
|
-
`Try manually killing the process: ${killCmd} ${pid}`,
|
|
721
|
-
)
|
|
722
|
-
}
|
|
723
|
-
logDebug(`Process ${pid} terminated after force kill`)
|
|
724
|
-
await this.cleanupPidFile(pidFile)
|
|
725
|
-
} catch (error) {
|
|
726
|
-
if (error instanceof SpinDBError) throw error
|
|
727
|
-
const e = error as NodeJS.ErrnoException
|
|
728
|
-
if (e.code === 'ESRCH') {
|
|
729
|
-
await this.cleanupPidFile(pidFile)
|
|
730
|
-
return
|
|
731
|
-
}
|
|
732
|
-
logDebug(`Force kill failed: ${e.message}`)
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
private async cleanupPidFile(pidFile: string): Promise<void> {
|
|
737
|
-
try {
|
|
738
|
-
await unlink(pidFile)
|
|
739
|
-
logDebug('PID file cleaned up')
|
|
740
|
-
} catch (error) {
|
|
741
|
-
const e = error as NodeJS.ErrnoException
|
|
742
|
-
if (e.code !== 'ENOENT') {
|
|
743
|
-
logDebug(`Failed to clean up PID file: ${e.message}`)
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
private sleep(ms: number): Promise<void> {
|
|
749
|
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
async status(container: ContainerConfig): Promise<StatusResult> {
|
|
753
|
-
const { name, port } = container
|
|
754
|
-
const pidFile = paths.getContainerPidPath(name, { engine: ENGINE })
|
|
755
|
-
|
|
756
|
-
if (!existsSync(pidFile)) {
|
|
757
|
-
return { running: false, message: 'MySQL is not running' }
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
try {
|
|
761
|
-
const mysqladmin = await this.getMysqladminPath()
|
|
762
|
-
await execAsync(`"${mysqladmin}" -h 127.0.0.1 -P ${port} -u root ping`)
|
|
763
|
-
return { running: true, message: 'MySQL is running' }
|
|
764
|
-
} catch {
|
|
765
|
-
return { running: false, message: 'MySQL is not responding' }
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
async detectBackupFormat(filePath: string): Promise<BackupFormat> {
|
|
770
|
-
return detectBackupFormatImpl(filePath)
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
async restore(
|
|
774
|
-
container: ContainerConfig,
|
|
775
|
-
backupPath: string,
|
|
776
|
-
options: Record<string, unknown> = {},
|
|
777
|
-
): Promise<RestoreResult> {
|
|
778
|
-
const { port, version } = container
|
|
779
|
-
const database = (options.database as string) || container.database
|
|
780
|
-
const binPath = this.getBinaryPath(version)
|
|
781
|
-
|
|
782
|
-
if (options.createDatabase !== false) {
|
|
783
|
-
await this.createDatabase(container, database)
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
return restoreBackup(backupPath, {
|
|
787
|
-
port,
|
|
788
|
-
database,
|
|
789
|
-
user: engineDef.superuser,
|
|
790
|
-
createDatabase: false,
|
|
791
|
-
validateVersion: options.validateVersion !== false,
|
|
792
|
-
binPath,
|
|
793
|
-
containerVersion: version,
|
|
794
|
-
})
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
getConnectionString(container: ContainerConfig, database?: string): string {
|
|
798
|
-
const { port } = container
|
|
799
|
-
const db = database || container.database || 'mysql'
|
|
800
|
-
return `mysql://${engineDef.superuser}@127.0.0.1:${port}/${db}`
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
override async getMysqlClientPath(): Promise<string> {
|
|
804
|
-
const configPath = await configManager.getBinaryPath('mysql')
|
|
805
|
-
if (configPath) return configPath
|
|
806
|
-
|
|
807
|
-
throw new Error(
|
|
808
|
-
'mysql client not found. Ensure MySQL binaries are downloaded:\n' +
|
|
809
|
-
' spindb engines download mysql',
|
|
810
|
-
)
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
override async getMysqladminPath(): Promise<string> {
|
|
814
|
-
const cfg = await configManager.getBinaryPath('mysqladmin')
|
|
815
|
-
if (cfg) return cfg
|
|
816
|
-
|
|
817
|
-
throw new Error(
|
|
818
|
-
'mysqladmin not found. Ensure MySQL binaries are downloaded:\n' +
|
|
819
|
-
' spindb engines download mysql',
|
|
820
|
-
)
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
async connect(container: ContainerConfig, database?: string): Promise<void> {
|
|
824
|
-
const { port } = container
|
|
825
|
-
const db = database || container.database || 'mysql'
|
|
826
|
-
|
|
827
|
-
const mysql = await this.getMysqlClientPath()
|
|
828
|
-
|
|
829
|
-
const spawnOptions: SpawnOptions = {
|
|
830
|
-
stdio: 'inherit',
|
|
831
|
-
...getWindowsSpawnOptions(),
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
return new Promise((resolve, reject) => {
|
|
835
|
-
const proc = spawn(
|
|
836
|
-
mysql,
|
|
837
|
-
['-h', '127.0.0.1', '-P', String(port), '-u', engineDef.superuser, db],
|
|
838
|
-
spawnOptions,
|
|
839
|
-
)
|
|
840
|
-
|
|
841
|
-
proc.on('error', reject)
|
|
842
|
-
proc.on('close', () => resolve())
|
|
843
|
-
})
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
async createDatabase(
|
|
847
|
-
container: ContainerConfig,
|
|
848
|
-
database: string,
|
|
849
|
-
): Promise<void> {
|
|
850
|
-
assertValidDatabaseName(database)
|
|
851
|
-
const { port } = container
|
|
852
|
-
|
|
853
|
-
const mysql = await this.getMysqlClientPath()
|
|
854
|
-
|
|
855
|
-
try {
|
|
856
|
-
const cmd = buildMysqlInlineCommand(
|
|
857
|
-
mysql,
|
|
858
|
-
port,
|
|
859
|
-
engineDef.superuser,
|
|
860
|
-
`CREATE DATABASE IF NOT EXISTS \`${database}\``,
|
|
861
|
-
)
|
|
862
|
-
await execAsync(cmd)
|
|
863
|
-
} catch (error) {
|
|
864
|
-
const err = error as Error
|
|
865
|
-
if (!err.message.includes('database exists')) {
|
|
866
|
-
throw error
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
async dropDatabase(
|
|
872
|
-
container: ContainerConfig,
|
|
873
|
-
database: string,
|
|
874
|
-
): Promise<void> {
|
|
875
|
-
assertValidDatabaseName(database)
|
|
876
|
-
const { port } = container
|
|
877
|
-
|
|
878
|
-
const mysql = await this.getMysqlClientPath()
|
|
879
|
-
|
|
880
|
-
try {
|
|
881
|
-
const cmd = buildMysqlInlineCommand(
|
|
882
|
-
mysql,
|
|
883
|
-
port,
|
|
884
|
-
engineDef.superuser,
|
|
885
|
-
`DROP DATABASE IF EXISTS \`${database}\``,
|
|
886
|
-
)
|
|
887
|
-
await execAsync(cmd)
|
|
888
|
-
} catch (error) {
|
|
889
|
-
const err = error as Error
|
|
890
|
-
if (!err.message.includes("database doesn't exist")) {
|
|
891
|
-
throw error
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
async getDatabaseSize(container: ContainerConfig): Promise<number | null> {
|
|
897
|
-
const { port, database } = container
|
|
898
|
-
const db = database || 'mysql'
|
|
899
|
-
|
|
900
|
-
assertValidDatabaseName(db)
|
|
901
|
-
|
|
902
|
-
try {
|
|
903
|
-
const mysql = await this.getMysqlClientPath()
|
|
904
|
-
|
|
905
|
-
const { stdout } = await execAsync(
|
|
906
|
-
`"${mysql}" -h 127.0.0.1 -P ${port} -u ${engineDef.superuser} -N -e "SELECT COALESCE(SUM(data_length + index_length), 0) FROM information_schema.tables WHERE table_schema = '${db}'"`,
|
|
907
|
-
)
|
|
908
|
-
const size = parseInt(stdout.trim(), 10)
|
|
909
|
-
return isNaN(size) ? null : size
|
|
910
|
-
} catch {
|
|
911
|
-
return null
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
async dumpFromConnectionString(
|
|
916
|
-
connectionString: string,
|
|
917
|
-
outputPath: string,
|
|
918
|
-
): Promise<DumpResult> {
|
|
919
|
-
const dumpPath = await this.getDumpPath()
|
|
920
|
-
|
|
921
|
-
const { host, port, user, password, database } =
|
|
922
|
-
parseConnectionString(connectionString)
|
|
923
|
-
|
|
924
|
-
if (isWindows()) {
|
|
925
|
-
let cmd = `"${dumpPath}" -h ${host} -P ${port} -u ${user} --result-file "${outputPath}" ${database}`
|
|
926
|
-
let safeCmd = cmd
|
|
927
|
-
|
|
928
|
-
if (password) {
|
|
929
|
-
cmd = `"${dumpPath}" -h ${host} -P ${port} -u ${user} -p"${password}" --result-file "${outputPath}" ${database}`
|
|
930
|
-
safeCmd = `"${dumpPath}" -h ${host} -P ${port} -u ${user} -p"****" --result-file "${outputPath}" ${database}`
|
|
931
|
-
}
|
|
932
|
-
try {
|
|
933
|
-
logDebug('Executing mysqldump command', { cmd: safeCmd })
|
|
934
|
-
await execAsync(cmd)
|
|
935
|
-
return {
|
|
936
|
-
filePath: outputPath,
|
|
937
|
-
stdout: '',
|
|
938
|
-
stderr: '',
|
|
939
|
-
code: 0,
|
|
940
|
-
}
|
|
941
|
-
} catch (error) {
|
|
942
|
-
throw new Error((error as Error).message)
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
const args = [
|
|
947
|
-
'-h',
|
|
948
|
-
host,
|
|
949
|
-
'-P',
|
|
950
|
-
port,
|
|
951
|
-
'-u',
|
|
952
|
-
user,
|
|
953
|
-
'--result-file',
|
|
954
|
-
outputPath,
|
|
955
|
-
]
|
|
956
|
-
|
|
957
|
-
if (password) {
|
|
958
|
-
args.push(`-p${password}`)
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
args.push(database)
|
|
962
|
-
|
|
963
|
-
const spawnOptions: SpawnOptions = {
|
|
964
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
965
|
-
...getWindowsSpawnOptions(),
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
return new Promise((resolve, reject) => {
|
|
969
|
-
const proc = spawn(dumpPath, args, spawnOptions)
|
|
970
|
-
|
|
971
|
-
let stdout = ''
|
|
972
|
-
let stderr = ''
|
|
973
|
-
|
|
974
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
975
|
-
stdout += data.toString()
|
|
976
|
-
})
|
|
977
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
978
|
-
stderr += data.toString()
|
|
979
|
-
})
|
|
980
|
-
|
|
981
|
-
proc.on('error', reject)
|
|
982
|
-
|
|
983
|
-
proc.on('close', (code) => {
|
|
984
|
-
if (code === 0) {
|
|
985
|
-
resolve({
|
|
986
|
-
filePath: outputPath,
|
|
987
|
-
stdout,
|
|
988
|
-
stderr,
|
|
989
|
-
code,
|
|
990
|
-
})
|
|
991
|
-
} else {
|
|
992
|
-
reject(new Error(stderr || `mysqldump exited with code ${code}`))
|
|
993
|
-
}
|
|
994
|
-
})
|
|
995
|
-
})
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
private async getDumpPath(): Promise<string> {
|
|
999
|
-
const configPath = await configManager.getBinaryPath('mysqldump')
|
|
1000
|
-
if (configPath) return configPath
|
|
1001
|
-
|
|
1002
|
-
throw new Error(
|
|
1003
|
-
'mysqldump not found. Ensure MySQL binaries are downloaded:\n' +
|
|
1004
|
-
' spindb engines download mysql',
|
|
1005
|
-
)
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
async backup(
|
|
1009
|
-
container: ContainerConfig,
|
|
1010
|
-
outputPath: string,
|
|
1011
|
-
options: BackupOptions,
|
|
1012
|
-
): Promise<BackupResult> {
|
|
1013
|
-
return createBackup(container, outputPath, options)
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
async terminateConnections(
|
|
1017
|
-
container: ContainerConfig,
|
|
1018
|
-
database: string,
|
|
1019
|
-
): Promise<void> {
|
|
1020
|
-
assertValidDatabaseName(database)
|
|
1021
|
-
const { port } = container
|
|
1022
|
-
const mysql = await this.getMysqlClientPath()
|
|
1023
|
-
|
|
1024
|
-
// Get all connection IDs for the target database and kill them
|
|
1025
|
-
// We need to do this in two steps since MySQL doesn't support subqueries in KILL
|
|
1026
|
-
const getIdsCmd = buildMysqlInlineCommand(
|
|
1027
|
-
mysql,
|
|
1028
|
-
port,
|
|
1029
|
-
engineDef.superuser,
|
|
1030
|
-
`SELECT ID FROM information_schema.PROCESSLIST WHERE DB = '${database}' AND ID != CONNECTION_ID()`,
|
|
1031
|
-
)
|
|
1032
|
-
|
|
1033
|
-
try {
|
|
1034
|
-
const { stdout } = await execAsync(getIdsCmd)
|
|
1035
|
-
const lines = stdout
|
|
1036
|
-
.trim()
|
|
1037
|
-
.split('\n')
|
|
1038
|
-
.filter((l) => l.trim())
|
|
1039
|
-
// Skip header row if present
|
|
1040
|
-
const ids = lines
|
|
1041
|
-
.slice(1)
|
|
1042
|
-
.map((l) => l.trim())
|
|
1043
|
-
.filter((l) => /^\d+$/.test(l))
|
|
1044
|
-
|
|
1045
|
-
for (const id of ids) {
|
|
1046
|
-
const killCmd = buildMysqlInlineCommand(
|
|
1047
|
-
mysql,
|
|
1048
|
-
port,
|
|
1049
|
-
engineDef.superuser,
|
|
1050
|
-
`KILL CONNECTION ${id}`,
|
|
1051
|
-
)
|
|
1052
|
-
try {
|
|
1053
|
-
await execAsync(killCmd)
|
|
1054
|
-
} catch {
|
|
1055
|
-
// Connection may already be gone
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
} catch {
|
|
1059
|
-
// Ignore errors - connections may already be gone
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
async runScript(
|
|
1064
|
-
container: ContainerConfig,
|
|
1065
|
-
options: { file?: string; sql?: string; database?: string },
|
|
1066
|
-
): Promise<void> {
|
|
1067
|
-
const { port } = container
|
|
1068
|
-
const db = options.database || container.database || 'mysql'
|
|
1069
|
-
assertValidDatabaseName(db)
|
|
1070
|
-
|
|
1071
|
-
const mysql = await this.getMysqlClientPath()
|
|
1072
|
-
|
|
1073
|
-
if (isWindows()) {
|
|
1074
|
-
const cmd = buildWindowsMysqlCommand(
|
|
1075
|
-
mysql,
|
|
1076
|
-
port,
|
|
1077
|
-
engineDef.superuser,
|
|
1078
|
-
db,
|
|
1079
|
-
options,
|
|
1080
|
-
)
|
|
1081
|
-
try {
|
|
1082
|
-
const { stdout, stderr } = await execAsync(cmd)
|
|
1083
|
-
if (stdout) process.stdout.write(stdout)
|
|
1084
|
-
if (stderr) process.stderr.write(stderr)
|
|
1085
|
-
return
|
|
1086
|
-
} catch (error) {
|
|
1087
|
-
const err = error as Error
|
|
1088
|
-
throw new Error(`mysql client failed: ${err.message}`)
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
const args = [
|
|
1093
|
-
'-h',
|
|
1094
|
-
'127.0.0.1',
|
|
1095
|
-
'-P',
|
|
1096
|
-
String(port),
|
|
1097
|
-
'-u',
|
|
1098
|
-
engineDef.superuser,
|
|
1099
|
-
db,
|
|
1100
|
-
]
|
|
1101
|
-
|
|
1102
|
-
if (options.sql) {
|
|
1103
|
-
args.push('-e', options.sql)
|
|
1104
|
-
|
|
1105
|
-
const spawnOptions: SpawnOptions = {
|
|
1106
|
-
stdio: 'inherit',
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
return new Promise((resolve, reject) => {
|
|
1110
|
-
const proc = spawn(mysql, args, spawnOptions)
|
|
1111
|
-
|
|
1112
|
-
proc.on('error', reject)
|
|
1113
|
-
proc.on('close', (code) => {
|
|
1114
|
-
if (code === 0) {
|
|
1115
|
-
resolve()
|
|
1116
|
-
} else {
|
|
1117
|
-
reject(new Error(`mysql client exited with code ${code}`))
|
|
1118
|
-
}
|
|
1119
|
-
})
|
|
1120
|
-
})
|
|
1121
|
-
} else if (options.file) {
|
|
1122
|
-
const spawnOptions: SpawnOptions = {
|
|
1123
|
-
stdio: ['pipe', 'inherit', 'inherit'],
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
return new Promise((resolve, reject) => {
|
|
1127
|
-
const fileStream = createReadStream(options.file!)
|
|
1128
|
-
const proc = spawn(mysql, args, spawnOptions)
|
|
1129
|
-
|
|
1130
|
-
fileStream.pipe(proc.stdin!)
|
|
1131
|
-
|
|
1132
|
-
fileStream.on('error', (err) => {
|
|
1133
|
-
proc.kill()
|
|
1134
|
-
reject(err)
|
|
1135
|
-
})
|
|
1136
|
-
|
|
1137
|
-
proc.on('error', reject)
|
|
1138
|
-
proc.on('close', (code) => {
|
|
1139
|
-
if (code === 0) {
|
|
1140
|
-
resolve()
|
|
1141
|
-
} else {
|
|
1142
|
-
reject(new Error(`mysql client exited with code ${code}`))
|
|
1143
|
-
}
|
|
1144
|
-
})
|
|
1145
|
-
})
|
|
1146
|
-
} else {
|
|
1147
|
-
throw new Error('Either file or sql option must be provided')
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
async executeQuery(
|
|
1152
|
-
container: ContainerConfig,
|
|
1153
|
-
query: string,
|
|
1154
|
-
options?: QueryOptions,
|
|
1155
|
-
): Promise<QueryResult> {
|
|
1156
|
-
const { port } = container
|
|
1157
|
-
const db = options?.database || container.database || 'mysql'
|
|
1158
|
-
assertValidDatabaseName(db)
|
|
1159
|
-
|
|
1160
|
-
const mysql = await this.getMysqlClientPath()
|
|
1161
|
-
|
|
1162
|
-
// Use -B (batch mode) for tab-separated output
|
|
1163
|
-
const args = [
|
|
1164
|
-
'-h',
|
|
1165
|
-
'127.0.0.1',
|
|
1166
|
-
'-P',
|
|
1167
|
-
String(port),
|
|
1168
|
-
'-u',
|
|
1169
|
-
engineDef.superuser,
|
|
1170
|
-
'-B',
|
|
1171
|
-
db,
|
|
1172
|
-
'-e',
|
|
1173
|
-
query,
|
|
1174
|
-
]
|
|
1175
|
-
|
|
1176
|
-
return new Promise((resolve, reject) => {
|
|
1177
|
-
const proc = spawn(mysql, args, {
|
|
1178
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1179
|
-
})
|
|
1180
|
-
|
|
1181
|
-
let stdout = ''
|
|
1182
|
-
let stderr = ''
|
|
1183
|
-
|
|
1184
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
1185
|
-
stdout += data.toString()
|
|
1186
|
-
})
|
|
1187
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
1188
|
-
stderr += data.toString()
|
|
1189
|
-
})
|
|
1190
|
-
|
|
1191
|
-
proc.on('error', reject)
|
|
1192
|
-
|
|
1193
|
-
proc.on('close', (code) => {
|
|
1194
|
-
if (code === 0) {
|
|
1195
|
-
resolve(parseTSVToQueryResult(stdout))
|
|
1196
|
-
} else {
|
|
1197
|
-
reject(new Error(stderr || `mysql exited with code ${code}`))
|
|
1198
|
-
}
|
|
1199
|
-
})
|
|
1200
|
-
})
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
/**
|
|
1204
|
-
* List all user databases, excluding system databases
|
|
1205
|
-
* (information_schema, mysql, performance_schema, sys).
|
|
1206
|
-
*/
|
|
1207
|
-
async listDatabases(container: ContainerConfig): Promise<string[]> {
|
|
1208
|
-
const { port } = container
|
|
1209
|
-
const mysql = await this.getMysqlClientPath()
|
|
1210
|
-
|
|
1211
|
-
// Query for all non-system databases
|
|
1212
|
-
const sql = `SHOW DATABASES WHERE \`Database\` NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')`
|
|
1213
|
-
|
|
1214
|
-
const args = [
|
|
1215
|
-
'-h',
|
|
1216
|
-
'127.0.0.1',
|
|
1217
|
-
'-P',
|
|
1218
|
-
String(port),
|
|
1219
|
-
'-u',
|
|
1220
|
-
engineDef.superuser,
|
|
1221
|
-
'-N', // Skip column names
|
|
1222
|
-
'-B', // Batch mode (no formatting)
|
|
1223
|
-
'-e',
|
|
1224
|
-
sql,
|
|
1225
|
-
]
|
|
1226
|
-
|
|
1227
|
-
return new Promise((resolve, reject) => {
|
|
1228
|
-
const proc = spawn(mysql, args, {
|
|
1229
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1230
|
-
})
|
|
1231
|
-
|
|
1232
|
-
let stdout = ''
|
|
1233
|
-
let stderr = ''
|
|
1234
|
-
|
|
1235
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
1236
|
-
stdout += data.toString()
|
|
1237
|
-
})
|
|
1238
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
1239
|
-
stderr += data.toString()
|
|
1240
|
-
})
|
|
1241
|
-
|
|
1242
|
-
proc.on('error', reject)
|
|
1243
|
-
|
|
1244
|
-
proc.on('close', (code) => {
|
|
1245
|
-
if (code === 0) {
|
|
1246
|
-
const databases = stdout
|
|
1247
|
-
.trim()
|
|
1248
|
-
.split('\n')
|
|
1249
|
-
.map((db) => db.trim())
|
|
1250
|
-
.filter((db) => db.length > 0)
|
|
1251
|
-
resolve(databases)
|
|
1252
|
-
} else {
|
|
1253
|
-
reject(new Error(stderr || `mysql exited with code ${code}`))
|
|
1254
|
-
}
|
|
1255
|
-
})
|
|
1256
|
-
})
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
async createUser(
|
|
1260
|
-
container: ContainerConfig,
|
|
1261
|
-
options: CreateUserOptions,
|
|
1262
|
-
): Promise<UserCredentials> {
|
|
1263
|
-
const { username, password, database } = options
|
|
1264
|
-
assertValidUsername(username)
|
|
1265
|
-
const { port } = container
|
|
1266
|
-
const db = database || container.database
|
|
1267
|
-
if (!db) {
|
|
1268
|
-
throw new Error(
|
|
1269
|
-
'No target database specified. Provide a database name with --database or ensure the container has a default database.',
|
|
1270
|
-
)
|
|
1271
|
-
}
|
|
1272
|
-
assertValidDatabaseName(db)
|
|
1273
|
-
const mysql = await this.getMysqlClientPath()
|
|
1274
|
-
|
|
1275
|
-
// Check if NO_BACKSLASH_ESCAPES is enabled — if so, only escape single quotes
|
|
1276
|
-
let noBackslashEscapes = false
|
|
1277
|
-
try {
|
|
1278
|
-
const modeArgs = [
|
|
1279
|
-
'-h',
|
|
1280
|
-
'127.0.0.1',
|
|
1281
|
-
'-P',
|
|
1282
|
-
String(port),
|
|
1283
|
-
'-u',
|
|
1284
|
-
engineDef.superuser,
|
|
1285
|
-
'-N',
|
|
1286
|
-
'-B',
|
|
1287
|
-
'-e',
|
|
1288
|
-
'SELECT @@sql_mode',
|
|
1289
|
-
]
|
|
1290
|
-
const modeResult = await new Promise<string>((resolve, reject) => {
|
|
1291
|
-
const proc = spawn(mysql, modeArgs, {
|
|
1292
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1293
|
-
})
|
|
1294
|
-
let stdout = ''
|
|
1295
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
1296
|
-
stdout += data.toString()
|
|
1297
|
-
})
|
|
1298
|
-
proc.on('close', (code) => {
|
|
1299
|
-
if (code === 0) resolve(stdout.trim())
|
|
1300
|
-
else reject(new Error(`Failed to query sql_mode`))
|
|
1301
|
-
})
|
|
1302
|
-
proc.on('error', reject)
|
|
1303
|
-
})
|
|
1304
|
-
noBackslashEscapes = modeResult.includes('NO_BACKSLASH_ESCAPES')
|
|
1305
|
-
} catch {
|
|
1306
|
-
// Default to backslash-escaping if query fails
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
const escapedPass = noBackslashEscapes
|
|
1310
|
-
? password.replace(/'/g, "''")
|
|
1311
|
-
: password.replace(/\\/g, '\\\\').replace(/'/g, "''")
|
|
1312
|
-
const escapedDb = db.replace(/`/g, '``')
|
|
1313
|
-
const escapedUser = noBackslashEscapes
|
|
1314
|
-
? username.replace(/'/g, "''")
|
|
1315
|
-
: username.replace(/\\/g, '\\\\').replace(/'/g, "''")
|
|
1316
|
-
const sql = `CREATE USER IF NOT EXISTS '${escapedUser}'@'%' IDENTIFIED BY '${escapedPass}'; CREATE USER IF NOT EXISTS '${escapedUser}'@'localhost' IDENTIFIED BY '${escapedPass}'; ALTER USER '${escapedUser}'@'%' IDENTIFIED BY '${escapedPass}'; ALTER USER '${escapedUser}'@'localhost' IDENTIFIED BY '${escapedPass}'; GRANT ALL ON \`${escapedDb}\`.* TO '${escapedUser}'@'%'; GRANT ALL ON \`${escapedDb}\`.* TO '${escapedUser}'@'localhost'; FLUSH PRIVILEGES;`
|
|
1317
|
-
|
|
1318
|
-
// Send SQL via stdin to avoid leaking password in process argv
|
|
1319
|
-
const args = [
|
|
1320
|
-
'-h',
|
|
1321
|
-
'127.0.0.1',
|
|
1322
|
-
'-P',
|
|
1323
|
-
String(port),
|
|
1324
|
-
'-u',
|
|
1325
|
-
engineDef.superuser,
|
|
1326
|
-
]
|
|
1327
|
-
|
|
1328
|
-
await new Promise<void>((resolve, reject) => {
|
|
1329
|
-
const proc = spawn(mysql, args, {
|
|
1330
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1331
|
-
})
|
|
1332
|
-
|
|
1333
|
-
let stderr = ''
|
|
1334
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
1335
|
-
stderr += data.toString()
|
|
1336
|
-
})
|
|
1337
|
-
|
|
1338
|
-
proc.on('close', (code) => {
|
|
1339
|
-
if (code === 0) resolve()
|
|
1340
|
-
else reject(new Error(`Failed to create user: ${stderr}`))
|
|
1341
|
-
})
|
|
1342
|
-
proc.on('error', reject)
|
|
1343
|
-
|
|
1344
|
-
proc.stdin?.write(sql)
|
|
1345
|
-
proc.stdin?.end()
|
|
1346
|
-
})
|
|
1347
|
-
|
|
1348
|
-
const connectionString = `mysql://${encodeURIComponent(username)}:${encodeURIComponent(password)}@127.0.0.1:${port}/${db}`
|
|
1349
|
-
|
|
1350
|
-
return {
|
|
1351
|
-
username,
|
|
1352
|
-
password,
|
|
1353
|
-
connectionString,
|
|
1354
|
-
engine: container.engine,
|
|
1355
|
-
container: container.name,
|
|
1356
|
-
database: db,
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
export const mysqlEngine = new MySQLEngine()
|