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/cli/ui/prompts.ts
DELETED
|
@@ -1,1525 +0,0 @@
|
|
|
1
|
-
import inquirer from 'inquirer'
|
|
2
|
-
import inquirerAutocomplete from 'inquirer-autocomplete-prompt'
|
|
3
|
-
import chalk from 'chalk'
|
|
4
|
-
|
|
5
|
-
// Register the autocomplete prompt type
|
|
6
|
-
inquirer.registerPrompt('autocomplete', inquirerAutocomplete)
|
|
7
|
-
import ora from 'ora'
|
|
8
|
-
import { existsSync, statSync } from 'fs'
|
|
9
|
-
import { resolve, join } from 'path'
|
|
10
|
-
import { homedir } from 'os'
|
|
11
|
-
import { listEngines, getEngine } from '../../engines'
|
|
12
|
-
import { defaults, getEngineDefaults } from '../../config/defaults'
|
|
13
|
-
import { portManager } from '../../core/port-manager'
|
|
14
|
-
import { containerManager } from '../../core/container-manager'
|
|
15
|
-
import {
|
|
16
|
-
detectPackageManager,
|
|
17
|
-
getManualInstallInstructions,
|
|
18
|
-
getCurrentPlatform,
|
|
19
|
-
installEngineDependencies,
|
|
20
|
-
} from '../../core/dependency-manager'
|
|
21
|
-
import { getEngineDependencies } from '../../config/os-dependencies'
|
|
22
|
-
import { getEngineIcon, getPageSize } from '../constants'
|
|
23
|
-
import {
|
|
24
|
-
BACKUP_FORMATS,
|
|
25
|
-
supportsFormatChoice,
|
|
26
|
-
getDefaultFormat,
|
|
27
|
-
} from '../../config/backup-formats'
|
|
28
|
-
import {
|
|
29
|
-
type ContainerConfig,
|
|
30
|
-
type Engine,
|
|
31
|
-
type BackupFormatType,
|
|
32
|
-
} from '../../types'
|
|
33
|
-
|
|
34
|
-
// Navigation sentinel values for menu navigation
|
|
35
|
-
export const BACK_VALUE = '__back__'
|
|
36
|
-
export const MAIN_MENU_VALUE = '__main__'
|
|
37
|
-
export const ESCAPE_VALUE = '__escape__'
|
|
38
|
-
export const TOGGLE_PREFIX = '__toggle__:'
|
|
39
|
-
|
|
40
|
-
// Global escape handler state
|
|
41
|
-
let globalEscapeEnabled = false
|
|
42
|
-
let escapeTriggered = false
|
|
43
|
-
let escapeReject: ((error: Error) => void) | null = null
|
|
44
|
-
// Store the raw UI object so we can access activePrompt dynamically
|
|
45
|
-
// (activePrompt may not be set at capture time due to async initialization)
|
|
46
|
-
let currentPromptUi: Record<string, unknown> | null = null
|
|
47
|
-
|
|
48
|
-
// Toggle handler state (Shift+Tab to toggle container start/stop)
|
|
49
|
-
let toggleEnabled = false
|
|
50
|
-
// Set of values that are valid toggle targets (container names)
|
|
51
|
-
let toggleValidTargets: Set<string> = new Set()
|
|
52
|
-
|
|
53
|
-
// Custom error class for escape
|
|
54
|
-
export class EscapeError extends Error {
|
|
55
|
-
constructor() {
|
|
56
|
-
super('Escape pressed')
|
|
57
|
-
this.name = 'EscapeError'
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Custom error class for toggle (Shift+Tab)
|
|
62
|
-
export class ToggleError extends Error {
|
|
63
|
-
targetValue: string
|
|
64
|
-
constructor(targetValue: string) {
|
|
65
|
-
super('Toggle pressed')
|
|
66
|
-
this.name = 'ToggleError'
|
|
67
|
-
this.targetValue = targetValue
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Module-scoped stdin data handler for escape key and special key detection
|
|
72
|
-
// Defined at module scope so disableGlobalEscape() can remove it
|
|
73
|
-
function onEscapeData(data: Buffer): void {
|
|
74
|
-
// Ctrl+C is byte 3 - handle graceful exit
|
|
75
|
-
if (data.length === 1 && data[0] === 3) {
|
|
76
|
-
console.log(chalk.gray('\n Goodbye!\n'))
|
|
77
|
-
process.exit(0)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Handle multi-byte escape sequences (arrow keys, Shift+Tab)
|
|
81
|
-
// These start with ESC (27) followed by '[' (91) and a letter
|
|
82
|
-
if (data.length === 3 && data[0] === 27 && data[1] === 91) {
|
|
83
|
-
const keyCode = data[2]
|
|
84
|
-
|
|
85
|
-
// Shift+Tab: \x1b[Z (27, 91, 90)
|
|
86
|
-
// Access inquirer's internal state to get the currently highlighted value
|
|
87
|
-
if (keyCode === 90 && toggleEnabled && currentPromptUi) {
|
|
88
|
-
try {
|
|
89
|
-
// Access activePrompt dynamically (it may not be set at capture time)
|
|
90
|
-
// inquirer-autocomplete-prompt uses 'selected' for cursor index
|
|
91
|
-
// and currentChoices.getChoice(index) to get the choice object
|
|
92
|
-
const activePrompt = currentPromptUi.activePrompt as
|
|
93
|
-
| {
|
|
94
|
-
selected?: number
|
|
95
|
-
currentChoices?: {
|
|
96
|
-
getChoice?: (
|
|
97
|
-
index: number,
|
|
98
|
-
) => { value?: string; type?: string } | undefined
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
| undefined
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
activePrompt?.currentChoices?.getChoice &&
|
|
105
|
-
activePrompt.selected !== undefined
|
|
106
|
-
) {
|
|
107
|
-
const currentChoice = activePrompt.currentChoices.getChoice(
|
|
108
|
-
activePrompt.selected,
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
// Check if the highlighted item is a valid toggle target (a container)
|
|
112
|
-
// Skip separators (type === 'separator') and non-container items
|
|
113
|
-
if (
|
|
114
|
-
currentChoice &&
|
|
115
|
-
currentChoice.value &&
|
|
116
|
-
currentChoice.type !== 'separator' &&
|
|
117
|
-
toggleValidTargets.has(currentChoice.value)
|
|
118
|
-
) {
|
|
119
|
-
// Reject the prompt with the container value to toggle
|
|
120
|
-
if (escapeReject) {
|
|
121
|
-
const reject = escapeReject
|
|
122
|
-
escapeReject = null
|
|
123
|
-
reject(new ToggleError(currentChoice.value))
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Close the prompt UI
|
|
127
|
-
if (typeof currentPromptUi.close === 'function') {
|
|
128
|
-
try {
|
|
129
|
-
currentPromptUi.close()
|
|
130
|
-
} catch {
|
|
131
|
-
// Swallow errors from inquirer internals
|
|
132
|
-
}
|
|
133
|
-
currentPromptUi = null
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
} catch {
|
|
138
|
-
// Ignore errors accessing inquirer internals - the prompt state
|
|
139
|
-
// may be inconsistent during filtering or other operations
|
|
140
|
-
}
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return // Don't process other escape sequences as standalone escape
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Escape key is byte 27 (0x1b) by itself
|
|
148
|
-
// Arrow keys and other sequences start with 27 but have more bytes
|
|
149
|
-
if (data.length === 1 && data[0] === 27) {
|
|
150
|
-
escapeTriggered = true
|
|
151
|
-
// First reject the escape promise to interrupt the prompt
|
|
152
|
-
if (escapeReject) {
|
|
153
|
-
const reject = escapeReject
|
|
154
|
-
escapeReject = null
|
|
155
|
-
reject(new EscapeError())
|
|
156
|
-
}
|
|
157
|
-
// Then close the prompt UI to stop it from rendering
|
|
158
|
-
// Do this after rejecting so the error propagates first
|
|
159
|
-
// Wrap in try/catch as inquirer internals may change between versions
|
|
160
|
-
if (currentPromptUi && typeof currentPromptUi.close === 'function') {
|
|
161
|
-
try {
|
|
162
|
-
currentPromptUi.close()
|
|
163
|
-
} catch {
|
|
164
|
-
// Swallow errors from inquirer internals - close() behavior may vary
|
|
165
|
-
}
|
|
166
|
-
currentPromptUi = null
|
|
167
|
-
}
|
|
168
|
-
// Clear the screen
|
|
169
|
-
console.clear()
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Enable global escape key handling for the interactive menu.
|
|
175
|
-
* When escape is pressed, the current prompt is closed and escapeTriggered flag is set.
|
|
176
|
-
* Call this once at the start of the interactive menu session.
|
|
177
|
-
*/
|
|
178
|
-
export function enableGlobalEscape(): void {
|
|
179
|
-
if (globalEscapeEnabled) return
|
|
180
|
-
globalEscapeEnabled = true
|
|
181
|
-
process.stdin.on('data', onEscapeData)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Disable global escape key handling and clean up state.
|
|
186
|
-
* Call this when exiting interactive mode or in tests to remove the stdin listener.
|
|
187
|
-
*/
|
|
188
|
-
export function disableGlobalEscape(): void {
|
|
189
|
-
if (!globalEscapeEnabled) return
|
|
190
|
-
process.stdin.off('data', onEscapeData)
|
|
191
|
-
globalEscapeEnabled = false
|
|
192
|
-
escapeTriggered = false
|
|
193
|
-
escapeReject = null
|
|
194
|
-
currentPromptUi = null
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Check if escape was triggered and reset the flag.
|
|
199
|
-
* Call this at the start of main menu to handle escape from anywhere.
|
|
200
|
-
*/
|
|
201
|
-
export function checkAndResetEscape(): boolean {
|
|
202
|
-
const wasTriggered = escapeTriggered
|
|
203
|
-
escapeTriggered = false
|
|
204
|
-
return wasTriggered
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Enable toggle tracking for the container list.
|
|
209
|
-
* @param validTargets - Set of values that are valid toggle targets (container names)
|
|
210
|
-
*/
|
|
211
|
-
export function enableToggleTracking(validTargets: Set<string>): void {
|
|
212
|
-
toggleEnabled = true
|
|
213
|
-
toggleValidTargets = validTargets
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Disable toggle tracking and clean up state.
|
|
218
|
-
*/
|
|
219
|
-
export function disableToggleTracking(): void {
|
|
220
|
-
toggleEnabled = false
|
|
221
|
-
toggleValidTargets = new Set()
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Wrapper around inquirer.prompt that registers/unregisters with global escape handler.
|
|
226
|
-
* Use this instead of inquirer.prompt() directly for escape key support.
|
|
227
|
-
*
|
|
228
|
-
* Automatically detects non-interactive mode (piped input, scripts, CI) and throws
|
|
229
|
-
* a clear error instead of hanging on user input that can never come.
|
|
230
|
-
*/
|
|
231
|
-
export async function escapeablePrompt<T extends Record<string, unknown>>(
|
|
232
|
-
questions: Parameters<typeof inquirer.prompt>[0],
|
|
233
|
-
): Promise<T> {
|
|
234
|
-
// Detect non-interactive mode (piped input, scripts, CI environments)
|
|
235
|
-
if (!process.stdin.isTTY) {
|
|
236
|
-
throw new Error(
|
|
237
|
-
'Cannot prompt in non-interactive mode. Use appropriate flags (--force, --yes, --json) or provide required arguments.',
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Create a promise that rejects when escape is pressed
|
|
242
|
-
const escapePromise = new Promise<never>((_, reject) => {
|
|
243
|
-
escapeReject = reject
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
const p = inquirer.prompt(questions)
|
|
248
|
-
// Register the prompt UI so we can close it on escape
|
|
249
|
-
// Use runtime guard to safely access inquirer's internal ui property
|
|
250
|
-
// which may change between versions.
|
|
251
|
-
// Validated against inquirer@9.3.7 - the prompt object exposes a .ui
|
|
252
|
-
// property with a .close() method for programmatic prompt termination.
|
|
253
|
-
const promptWithUi = p as unknown as Record<string, unknown>
|
|
254
|
-
if (
|
|
255
|
-
promptWithUi.ui &&
|
|
256
|
-
typeof promptWithUi.ui === 'object' &&
|
|
257
|
-
promptWithUi.ui !== null &&
|
|
258
|
-
typeof (promptWithUi.ui as Record<string, unknown>).close === 'function'
|
|
259
|
-
) {
|
|
260
|
-
currentPromptUi = promptWithUi.ui as Record<string, unknown>
|
|
261
|
-
} else {
|
|
262
|
-
currentPromptUi = null
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Race the prompt against the escape promise
|
|
266
|
-
const result = (await Promise.race([p, escapePromise])) as T
|
|
267
|
-
return result
|
|
268
|
-
} finally {
|
|
269
|
-
escapeReject = null
|
|
270
|
-
currentPromptUi = null
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Type for autocomplete choices - must have name and value
|
|
276
|
-
*/
|
|
277
|
-
export type FilterableChoice = {
|
|
278
|
-
name: string
|
|
279
|
-
value: string
|
|
280
|
-
short?: string
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Filterable list prompt using inquirer-autocomplete-prompt.
|
|
285
|
-
* Allows typing to filter items while still using arrow keys to navigate.
|
|
286
|
-
*
|
|
287
|
-
* @param choices - Array of choices (items to filter + navigation items)
|
|
288
|
-
* @param message - Prompt message
|
|
289
|
-
* @param options.filterableCount - Number of items at the start that should be filterable
|
|
290
|
-
* (remaining items like Back/separators are always shown)
|
|
291
|
-
* @param options.pageSize - Number of items to show at once
|
|
292
|
-
* @param options.emptyText - Text to show when filter matches nothing
|
|
293
|
-
* @param options.enableToggle - Enable Shift+Tab to toggle items (returns TOGGLE_PREFIX + value)
|
|
294
|
-
*/
|
|
295
|
-
export async function filterableListPrompt(
|
|
296
|
-
choices: (FilterableChoice | inquirer.Separator)[],
|
|
297
|
-
message: string,
|
|
298
|
-
options: {
|
|
299
|
-
filterableCount: number
|
|
300
|
-
pageSize?: number
|
|
301
|
-
emptyText?: string
|
|
302
|
-
enableToggle?: boolean
|
|
303
|
-
defaultValue?: string // Pre-select this value (cursor starts here)
|
|
304
|
-
headerItems?: (FilterableChoice | inquirer.Separator)[] // Shown above filterable items
|
|
305
|
-
},
|
|
306
|
-
): Promise<string> {
|
|
307
|
-
// Split choices into filterable items and static footer (separators, back buttons, etc.)
|
|
308
|
-
const filterableItems = choices.slice(
|
|
309
|
-
0,
|
|
310
|
-
options.filterableCount,
|
|
311
|
-
) as FilterableChoice[]
|
|
312
|
-
const footerItems = choices.slice(options.filterableCount)
|
|
313
|
-
|
|
314
|
-
// Enable toggle tracking if requested
|
|
315
|
-
// Build a set of valid toggle targets (the container values from filterable items)
|
|
316
|
-
if (options.enableToggle) {
|
|
317
|
-
const validTargets = new Set(filterableItems.map((item) => item.value))
|
|
318
|
-
enableToggleTracking(validTargets)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Source function for autocomplete - filters items based on input
|
|
322
|
-
const header = options.headerItems || []
|
|
323
|
-
async function source(
|
|
324
|
-
_answers: Record<string, unknown>,
|
|
325
|
-
input: string | undefined,
|
|
326
|
-
): Promise<(FilterableChoice | inquirer.Separator)[]> {
|
|
327
|
-
const searchTerm = (input || '').toLowerCase().trim()
|
|
328
|
-
|
|
329
|
-
let result: (FilterableChoice | inquirer.Separator)[]
|
|
330
|
-
|
|
331
|
-
if (!searchTerm) {
|
|
332
|
-
// No filter - show all items
|
|
333
|
-
result = [...header, ...filterableItems, ...footerItems]
|
|
334
|
-
} else {
|
|
335
|
-
// Filter items by matching search term against the display name
|
|
336
|
-
// Strip ANSI codes for matching but keep them for display
|
|
337
|
-
// eslint-disable-next-line no-control-regex
|
|
338
|
-
const ansiPattern = /\x1b\[[0-9;]*m/g
|
|
339
|
-
const filtered = filterableItems.filter((item) => {
|
|
340
|
-
// Strip ANSI escape codes for matching
|
|
341
|
-
const plainName = item.name.replace(ansiPattern, '')
|
|
342
|
-
return plainName.toLowerCase().includes(searchTerm)
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
if (filtered.length === 0) {
|
|
346
|
-
// No matches - show empty message and footer
|
|
347
|
-
result = [
|
|
348
|
-
new inquirer.Separator(
|
|
349
|
-
chalk.gray(options.emptyText || `No matches for "${input}"`),
|
|
350
|
-
),
|
|
351
|
-
...footerItems,
|
|
352
|
-
]
|
|
353
|
-
} else {
|
|
354
|
-
result = [...header, ...filtered, ...footerItems]
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return result
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Create escape promise for escape key handling
|
|
362
|
-
const escapePromise = new Promise<never>((_, reject) => {
|
|
363
|
-
escapeReject = reject
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
const p = inquirer.prompt([
|
|
368
|
-
{
|
|
369
|
-
type: 'autocomplete',
|
|
370
|
-
name: 'selection',
|
|
371
|
-
message,
|
|
372
|
-
source,
|
|
373
|
-
pageSize: options.pageSize || getPageSize(),
|
|
374
|
-
emptyText: options.emptyText || 'No matches',
|
|
375
|
-
suggestOnly: false,
|
|
376
|
-
// Suppress the default "(Use arrow keys or type to search)" suffix
|
|
377
|
-
// since we include custom instructions in the message
|
|
378
|
-
suffix: '',
|
|
379
|
-
// Pre-select a value (cursor starts on this item)
|
|
380
|
-
default: options.defaultValue,
|
|
381
|
-
},
|
|
382
|
-
])
|
|
383
|
-
|
|
384
|
-
// Register the prompt UI for escape and toggle handling
|
|
385
|
-
// Store the raw UI object so we can access activePrompt dynamically
|
|
386
|
-
// (activePrompt contains selected and currentChoices for the highlighted item)
|
|
387
|
-
const promptWithUi = p as unknown as Record<string, unknown>
|
|
388
|
-
if (
|
|
389
|
-
promptWithUi.ui &&
|
|
390
|
-
typeof promptWithUi.ui === 'object' &&
|
|
391
|
-
promptWithUi.ui !== null &&
|
|
392
|
-
typeof (promptWithUi.ui as Record<string, unknown>).close === 'function'
|
|
393
|
-
) {
|
|
394
|
-
currentPromptUi = promptWithUi.ui as Record<string, unknown>
|
|
395
|
-
} else {
|
|
396
|
-
currentPromptUi = null
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const result = (await Promise.race([p, escapePromise])) as {
|
|
400
|
-
selection: string
|
|
401
|
-
}
|
|
402
|
-
return result.selection
|
|
403
|
-
} catch (error) {
|
|
404
|
-
// Handle toggle (Shift+Tab) - return special value so caller can handle it
|
|
405
|
-
if (error instanceof ToggleError) {
|
|
406
|
-
return TOGGLE_PREFIX + error.targetValue
|
|
407
|
-
}
|
|
408
|
-
throw error
|
|
409
|
-
} finally {
|
|
410
|
-
escapeReject = null
|
|
411
|
-
currentPromptUi = null
|
|
412
|
-
if (options.enableToggle) {
|
|
413
|
-
disableToggleTracking()
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Check if a prompt result indicates escape was pressed
|
|
420
|
-
*/
|
|
421
|
-
export function wasEscapePressed(result: unknown): boolean {
|
|
422
|
-
if (typeof result === 'string') return result === ESCAPE_VALUE
|
|
423
|
-
if (typeof result === 'object' && result !== null) {
|
|
424
|
-
return Object.values(result).some((v) => v === ESCAPE_VALUE)
|
|
425
|
-
}
|
|
426
|
-
return false
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Prompt for container name
|
|
431
|
-
* @param defaultName - Default value for the container name
|
|
432
|
-
* @param options.allowBack - Allow empty input to go back (returns null)
|
|
433
|
-
*/
|
|
434
|
-
export function promptContainerName(
|
|
435
|
-
defaultName?: string,
|
|
436
|
-
options?: { allowBack?: false },
|
|
437
|
-
): Promise<string>
|
|
438
|
-
export function promptContainerName(
|
|
439
|
-
defaultName: string | undefined,
|
|
440
|
-
options: { allowBack: true },
|
|
441
|
-
): Promise<string | null>
|
|
442
|
-
export async function promptContainerName(
|
|
443
|
-
defaultName?: string,
|
|
444
|
-
options?: { allowBack?: boolean },
|
|
445
|
-
): Promise<string | null> {
|
|
446
|
-
const { name } = await escapeablePrompt<{ name: string }>([
|
|
447
|
-
{
|
|
448
|
-
type: 'input',
|
|
449
|
-
name: 'name',
|
|
450
|
-
message: 'Container name:',
|
|
451
|
-
default: options?.allowBack ? undefined : defaultName,
|
|
452
|
-
validate: (input: string) => {
|
|
453
|
-
if (options?.allowBack && !input) return true // Allow empty for back
|
|
454
|
-
if (!input) return 'Name is required'
|
|
455
|
-
if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(input)) {
|
|
456
|
-
return 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores'
|
|
457
|
-
}
|
|
458
|
-
return true
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
])
|
|
462
|
-
|
|
463
|
-
if (options?.allowBack && !name) return null
|
|
464
|
-
return name
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Prompt for database engine selection
|
|
469
|
-
* @param options.includeBack - Include back/main menu navigation options
|
|
470
|
-
* @returns Engine name, or BACK_VALUE/MAIN_MENU_VALUE for navigation
|
|
471
|
-
*/
|
|
472
|
-
export async function promptEngine(options?: {
|
|
473
|
-
includeBack?: boolean
|
|
474
|
-
}): Promise<string> {
|
|
475
|
-
const engines = listEngines()
|
|
476
|
-
|
|
477
|
-
const engineChoices: FilterableChoice[] = engines.map((e) => ({
|
|
478
|
-
name: `${getEngineIcon(e.name)} ${e.displayName} ${chalk.gray(`(versions: ${e.supportedVersions.join(', ')})`)}`,
|
|
479
|
-
value: e.name,
|
|
480
|
-
short: e.displayName,
|
|
481
|
-
}))
|
|
482
|
-
|
|
483
|
-
const footerChoices: (FilterableChoice | inquirer.Separator)[] = [
|
|
484
|
-
new inquirer.Separator(),
|
|
485
|
-
new inquirer.Separator(
|
|
486
|
-
chalk.gray(` ${engines.length} engines — type to filter`),
|
|
487
|
-
),
|
|
488
|
-
]
|
|
489
|
-
|
|
490
|
-
if (options?.includeBack) {
|
|
491
|
-
footerChoices.push(new inquirer.Separator())
|
|
492
|
-
footerChoices.push({
|
|
493
|
-
name: `${chalk.blue('←')} Back`,
|
|
494
|
-
value: BACK_VALUE,
|
|
495
|
-
})
|
|
496
|
-
footerChoices.push({
|
|
497
|
-
name: `${chalk.blue('⌂')} Back to main menu ${chalk.gray('(esc)')}`,
|
|
498
|
-
value: MAIN_MENU_VALUE,
|
|
499
|
-
})
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
footerChoices.push(new inquirer.Separator())
|
|
503
|
-
|
|
504
|
-
const allChoices = [...engineChoices, ...footerChoices]
|
|
505
|
-
|
|
506
|
-
const engine = await filterableListPrompt(
|
|
507
|
-
allChoices,
|
|
508
|
-
'Select database engine:',
|
|
509
|
-
{
|
|
510
|
-
filterableCount: engineChoices.length,
|
|
511
|
-
pageSize: getPageSize(),
|
|
512
|
-
emptyText: 'No engines match filter',
|
|
513
|
-
},
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
return engine
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* Prompt for database version
|
|
521
|
-
* Two-step selection: first major version, then specific minor version (if available)
|
|
522
|
-
* @param options.includeBack - Include back/main menu navigation options
|
|
523
|
-
* @returns Version string, or BACK_VALUE/MAIN_MENU_VALUE for navigation
|
|
524
|
-
*/
|
|
525
|
-
export async function promptVersion(
|
|
526
|
-
engineName: string,
|
|
527
|
-
options?: { includeBack?: boolean },
|
|
528
|
-
): Promise<string> {
|
|
529
|
-
const engine = getEngine(engineName)
|
|
530
|
-
const majorVersions = engine.supportedVersions
|
|
531
|
-
|
|
532
|
-
// Fetch available versions with a loading indicator
|
|
533
|
-
const spinner = ora({
|
|
534
|
-
text: 'Fetching available versions...',
|
|
535
|
-
color: 'cyan',
|
|
536
|
-
}).start()
|
|
537
|
-
|
|
538
|
-
let availableVersions: Record<string, string[]>
|
|
539
|
-
try {
|
|
540
|
-
availableVersions = await engine.fetchAvailableVersions()
|
|
541
|
-
spinner.stop()
|
|
542
|
-
} catch {
|
|
543
|
-
spinner.stop()
|
|
544
|
-
// Fall back to major versions only
|
|
545
|
-
availableVersions = {}
|
|
546
|
-
for (const v of majorVersions) {
|
|
547
|
-
availableVersions[v] = []
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// Step 1: Select major version
|
|
552
|
-
type Choice =
|
|
553
|
-
| { name: string; value: string; short?: string }
|
|
554
|
-
| inquirer.Separator
|
|
555
|
-
|
|
556
|
-
const majorChoices: Choice[] = []
|
|
557
|
-
const engineDefs = getEngineDefaults(engineName)
|
|
558
|
-
|
|
559
|
-
for (let i = 0; i < majorVersions.length; i++) {
|
|
560
|
-
const major = majorVersions[i]
|
|
561
|
-
const fullVersions = availableVersions[major] || []
|
|
562
|
-
const versionCount = fullVersions.length
|
|
563
|
-
const isLatestMajor = major === engineDefs.latestVersion
|
|
564
|
-
|
|
565
|
-
const countLabel =
|
|
566
|
-
versionCount > 0 ? chalk.gray(`(${versionCount} versions)`) : ''
|
|
567
|
-
const label = isLatestMajor
|
|
568
|
-
? `${engine.displayName} ${major} ${countLabel} ${chalk.green('← latest')}`
|
|
569
|
-
: `${engine.displayName} ${major} ${countLabel}`
|
|
570
|
-
|
|
571
|
-
majorChoices.push({
|
|
572
|
-
name: label,
|
|
573
|
-
value: major,
|
|
574
|
-
short: `${engine.displayName} ${major}`,
|
|
575
|
-
})
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (options?.includeBack) {
|
|
579
|
-
majorChoices.push(new inquirer.Separator())
|
|
580
|
-
majorChoices.push({ name: `${chalk.blue('←')} Back`, value: BACK_VALUE })
|
|
581
|
-
majorChoices.push({
|
|
582
|
-
name: `${chalk.blue('⌂')} Back to main menu ${chalk.gray('(esc)')}`,
|
|
583
|
-
value: MAIN_MENU_VALUE,
|
|
584
|
-
})
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
const { majorVersion } = await escapeablePrompt<{ majorVersion: string }>([
|
|
588
|
-
{
|
|
589
|
-
type: 'list',
|
|
590
|
-
name: 'majorVersion',
|
|
591
|
-
message: 'Select major version:',
|
|
592
|
-
choices: majorChoices,
|
|
593
|
-
default: engineDefs.latestVersion, // Default to latest major
|
|
594
|
-
},
|
|
595
|
-
])
|
|
596
|
-
|
|
597
|
-
// Handle navigation (including escape)
|
|
598
|
-
if (
|
|
599
|
-
majorVersion === ESCAPE_VALUE ||
|
|
600
|
-
majorVersion === BACK_VALUE ||
|
|
601
|
-
majorVersion === MAIN_MENU_VALUE
|
|
602
|
-
) {
|
|
603
|
-
return majorVersion === ESCAPE_VALUE ? MAIN_MENU_VALUE : majorVersion
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Step 2: Select specific version within the major version
|
|
607
|
-
const minorVersions = availableVersions[majorVersion] || []
|
|
608
|
-
|
|
609
|
-
if (minorVersions.length === 0) {
|
|
610
|
-
// No versions fetched, return major version (will use fallback)
|
|
611
|
-
return majorVersion
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const minorChoices: Choice[] = minorVersions.map((v, i) => ({
|
|
615
|
-
name: i === 0 ? `${v} ${chalk.green('← latest')}` : v,
|
|
616
|
-
value: v,
|
|
617
|
-
short: v,
|
|
618
|
-
}))
|
|
619
|
-
|
|
620
|
-
if (options?.includeBack) {
|
|
621
|
-
minorChoices.push(new inquirer.Separator())
|
|
622
|
-
minorChoices.push({
|
|
623
|
-
name: `${chalk.blue('←')} Back to major versions`,
|
|
624
|
-
value: BACK_VALUE,
|
|
625
|
-
})
|
|
626
|
-
minorChoices.push({
|
|
627
|
-
name: `${chalk.blue('⌂')} Back to main menu ${chalk.gray('(esc)')}`,
|
|
628
|
-
value: MAIN_MENU_VALUE,
|
|
629
|
-
})
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
const { version } = await escapeablePrompt<{ version: string }>([
|
|
633
|
-
{
|
|
634
|
-
type: 'list',
|
|
635
|
-
name: 'version',
|
|
636
|
-
message: `Select ${engine.displayName} ${majorVersion} version:`,
|
|
637
|
-
choices: minorChoices,
|
|
638
|
-
default: minorVersions[0], // Default to latest
|
|
639
|
-
},
|
|
640
|
-
])
|
|
641
|
-
|
|
642
|
-
// Handle navigation from minor version selection (including escape)
|
|
643
|
-
if (version === ESCAPE_VALUE) {
|
|
644
|
-
return MAIN_MENU_VALUE
|
|
645
|
-
}
|
|
646
|
-
if (version === BACK_VALUE) {
|
|
647
|
-
// Go back to major version selection (recursive call)
|
|
648
|
-
return promptVersion(engineName, options)
|
|
649
|
-
}
|
|
650
|
-
if (version === MAIN_MENU_VALUE) {
|
|
651
|
-
return MAIN_MENU_VALUE
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
return version
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* Prompt for port with conflict detection
|
|
659
|
-
* @param defaultPort - Default port number
|
|
660
|
-
* @param engine - Engine name for port range lookup
|
|
661
|
-
*/
|
|
662
|
-
export async function promptPort(
|
|
663
|
-
defaultPort: number = defaults.port,
|
|
664
|
-
engine?: string,
|
|
665
|
-
): Promise<number> {
|
|
666
|
-
// Get engine-specific port range
|
|
667
|
-
const portRange = engine
|
|
668
|
-
? getEngineDefaults(engine).portRange
|
|
669
|
-
: defaults.portRange
|
|
670
|
-
|
|
671
|
-
// Get running container ports for conflict detection
|
|
672
|
-
// Stopped containers don't block ports - users can manage conflicts themselves
|
|
673
|
-
const existingContainers = await containerManager.list()
|
|
674
|
-
const containerPorts = new Map<number, string>()
|
|
675
|
-
for (const c of existingContainers) {
|
|
676
|
-
if (c.port > 0 && c.status === 'running') {
|
|
677
|
-
containerPorts.set(c.port, c.name)
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Check if default port has a conflict and find a better default
|
|
682
|
-
let suggestedPort = defaultPort
|
|
683
|
-
const defaultPortContainer = containerPorts.get(defaultPort)
|
|
684
|
-
const defaultPortInUse =
|
|
685
|
-
!defaultPortContainer && !(await portManager.isPortAvailable(defaultPort))
|
|
686
|
-
|
|
687
|
-
if (defaultPortContainer || defaultPortInUse) {
|
|
688
|
-
// Find next available port in the engine's port range
|
|
689
|
-
try {
|
|
690
|
-
const result = await portManager.findAvailablePortExcludingContainers({
|
|
691
|
-
preferredPort: defaultPort,
|
|
692
|
-
portRange,
|
|
693
|
-
})
|
|
694
|
-
suggestedPort = result.port
|
|
695
|
-
} catch {
|
|
696
|
-
// Fall back to default if no ports available
|
|
697
|
-
suggestedPort = defaultPort
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
const { port } = await escapeablePrompt<{ port: number }>([
|
|
702
|
-
{
|
|
703
|
-
type: 'input',
|
|
704
|
-
name: 'port',
|
|
705
|
-
message: 'Port:',
|
|
706
|
-
default: String(suggestedPort),
|
|
707
|
-
validate: (input: string) => {
|
|
708
|
-
const num = parseInt(input, 10)
|
|
709
|
-
if (isNaN(num) || num < 1 || num > 65535) {
|
|
710
|
-
return 'Port must be a number between 1 and 65535'
|
|
711
|
-
}
|
|
712
|
-
return true
|
|
713
|
-
},
|
|
714
|
-
filter: (input: string) => parseInt(input, 10),
|
|
715
|
-
},
|
|
716
|
-
])
|
|
717
|
-
|
|
718
|
-
// Check for conflicts after selection
|
|
719
|
-
const conflictContainer = containerPorts.get(port)
|
|
720
|
-
if (conflictContainer) {
|
|
721
|
-
console.log()
|
|
722
|
-
console.log(
|
|
723
|
-
chalk.yellow(
|
|
724
|
-
` ⚠ Warning: Port ${port} is already assigned to container "${conflictContainer}"`,
|
|
725
|
-
),
|
|
726
|
-
)
|
|
727
|
-
console.log(
|
|
728
|
-
chalk.gray(' Only one container can run on this port at a time.'),
|
|
729
|
-
)
|
|
730
|
-
console.log()
|
|
731
|
-
|
|
732
|
-
const { proceed } = await escapeablePrompt<{ proceed: string }>([
|
|
733
|
-
{
|
|
734
|
-
type: 'list',
|
|
735
|
-
name: 'proceed',
|
|
736
|
-
message: 'What would you like to do?',
|
|
737
|
-
choices: [
|
|
738
|
-
{ name: `Use port ${port} anyway`, value: 'continue' },
|
|
739
|
-
{ name: 'Choose a different port', value: 'retry' },
|
|
740
|
-
],
|
|
741
|
-
},
|
|
742
|
-
])
|
|
743
|
-
|
|
744
|
-
if (proceed === 'retry') {
|
|
745
|
-
return promptPort(defaultPort, engine)
|
|
746
|
-
}
|
|
747
|
-
} else {
|
|
748
|
-
// Check if port is in use by something else
|
|
749
|
-
const portAvailable = await portManager.isPortAvailable(port)
|
|
750
|
-
if (!portAvailable) {
|
|
751
|
-
console.log()
|
|
752
|
-
console.log(
|
|
753
|
-
chalk.yellow(` ⚠ Warning: Port ${port} is currently in use`),
|
|
754
|
-
)
|
|
755
|
-
console.log(
|
|
756
|
-
chalk.gray(
|
|
757
|
-
' The container will be created but may fail to start until the port is freed.',
|
|
758
|
-
),
|
|
759
|
-
)
|
|
760
|
-
console.log()
|
|
761
|
-
|
|
762
|
-
const { proceed } = await escapeablePrompt<{ proceed: string }>([
|
|
763
|
-
{
|
|
764
|
-
type: 'list',
|
|
765
|
-
name: 'proceed',
|
|
766
|
-
message: 'What would you like to do?',
|
|
767
|
-
choices: [
|
|
768
|
-
{ name: `Use port ${port} anyway`, value: 'continue' },
|
|
769
|
-
{ name: 'Choose a different port', value: 'retry' },
|
|
770
|
-
],
|
|
771
|
-
},
|
|
772
|
-
])
|
|
773
|
-
|
|
774
|
-
if (proceed === 'retry') {
|
|
775
|
-
return promptPort(defaultPort, engine)
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
return port
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// Prompt for confirmation using arrow-key selection
|
|
784
|
-
export async function promptConfirm(
|
|
785
|
-
message: string,
|
|
786
|
-
defaultValue: boolean = true,
|
|
787
|
-
): Promise<boolean> {
|
|
788
|
-
const { confirmed } = await escapeablePrompt<{ confirmed: string }>([
|
|
789
|
-
{
|
|
790
|
-
type: 'list',
|
|
791
|
-
name: 'confirmed',
|
|
792
|
-
message,
|
|
793
|
-
choices: [
|
|
794
|
-
{ name: 'Yes', value: 'yes' },
|
|
795
|
-
{ name: 'No', value: 'no' },
|
|
796
|
-
],
|
|
797
|
-
default: defaultValue ? 'yes' : 'no',
|
|
798
|
-
},
|
|
799
|
-
])
|
|
800
|
-
|
|
801
|
-
return confirmed === 'yes'
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
/**
|
|
805
|
-
* Prompt for container selection from a list with type-to-filter support
|
|
806
|
-
* @param containers - List of containers to choose from
|
|
807
|
-
* @param message - Prompt message
|
|
808
|
-
* @param options - Optional settings
|
|
809
|
-
* @param options.includeBack - Include back/main menu navigation options (returns null when selected)
|
|
810
|
-
*/
|
|
811
|
-
export async function promptContainerSelect(
|
|
812
|
-
containers: ContainerConfig[],
|
|
813
|
-
message: string = 'Select container:',
|
|
814
|
-
options: { includeBack?: boolean } = {},
|
|
815
|
-
): Promise<string | null> {
|
|
816
|
-
if (containers.length === 0) {
|
|
817
|
-
return null
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
// Build filterable container choices
|
|
821
|
-
const containerChoices: FilterableChoice[] = containers.map((c) => ({
|
|
822
|
-
name: `${c.name} ${chalk.gray(`(${getEngineIcon(c.engine)}${c.engine} ${c.version}, port ${c.port})`)} ${
|
|
823
|
-
c.status === 'running'
|
|
824
|
-
? chalk.green('● running')
|
|
825
|
-
: chalk.gray('○ stopped')
|
|
826
|
-
}`,
|
|
827
|
-
value: c.name,
|
|
828
|
-
short: c.name,
|
|
829
|
-
}))
|
|
830
|
-
|
|
831
|
-
// Build footer with navigation options
|
|
832
|
-
const footerChoices: (FilterableChoice | inquirer.Separator)[] = []
|
|
833
|
-
if (options.includeBack) {
|
|
834
|
-
footerChoices.push(new inquirer.Separator())
|
|
835
|
-
footerChoices.push({ name: `${chalk.blue('←')} Back`, value: BACK_VALUE })
|
|
836
|
-
footerChoices.push({
|
|
837
|
-
name: `${chalk.blue('⌂')} Back to main menu ${chalk.gray('(esc)')}`,
|
|
838
|
-
value: MAIN_MENU_VALUE,
|
|
839
|
-
})
|
|
840
|
-
footerChoices.push(new inquirer.Separator())
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
const allChoices = [...containerChoices, ...footerChoices]
|
|
844
|
-
|
|
845
|
-
const container = await filterableListPrompt(allChoices, message, {
|
|
846
|
-
filterableCount: containerChoices.length,
|
|
847
|
-
pageSize: getPageSize(),
|
|
848
|
-
emptyText: 'No containers match filter',
|
|
849
|
-
})
|
|
850
|
-
|
|
851
|
-
// Handle navigation (including escape)
|
|
852
|
-
if (
|
|
853
|
-
container === ESCAPE_VALUE ||
|
|
854
|
-
container === BACK_VALUE ||
|
|
855
|
-
container === MAIN_MENU_VALUE
|
|
856
|
-
) {
|
|
857
|
-
return null
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
return container
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
/**
|
|
864
|
-
* Sanitize a string to be a valid database name
|
|
865
|
-
* Replaces invalid characters with underscores
|
|
866
|
-
*/
|
|
867
|
-
function sanitizeDatabaseName(name: string): string {
|
|
868
|
-
// Replace invalid characters with underscores
|
|
869
|
-
// Note: hyphens are excluded because they require quoting in SQL
|
|
870
|
-
let sanitized = name.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
871
|
-
// Ensure it starts with a letter or underscore
|
|
872
|
-
if (sanitized && !/^[a-zA-Z_]/.test(sanitized)) {
|
|
873
|
-
sanitized = '_' + sanitized
|
|
874
|
-
}
|
|
875
|
-
// Collapse multiple underscores
|
|
876
|
-
sanitized = sanitized.replace(/_+/g, '_')
|
|
877
|
-
// Trim trailing underscores
|
|
878
|
-
sanitized = sanitized.replace(/_+$/, '')
|
|
879
|
-
// Fallback if result is empty (e.g., input was "---")
|
|
880
|
-
if (!sanitized) {
|
|
881
|
-
sanitized = 'db'
|
|
882
|
-
}
|
|
883
|
-
return sanitized
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
/**
|
|
887
|
-
* Prompt for database name
|
|
888
|
-
* @param defaultName - Default value for the database name
|
|
889
|
-
* @param engine - Database engine (mysql shows "schema" terminology)
|
|
890
|
-
* @param options.allowBack - Allow empty input to go back (returns null)
|
|
891
|
-
* @param options.existingDatabases - List of existing database names for context
|
|
892
|
-
* @param options.disallowExisting - Validate that name is not in existingDatabases
|
|
893
|
-
*/
|
|
894
|
-
export function promptDatabaseName(
|
|
895
|
-
defaultName?: string,
|
|
896
|
-
engine?: string,
|
|
897
|
-
options?: {
|
|
898
|
-
allowBack?: false
|
|
899
|
-
existingDatabases?: string[]
|
|
900
|
-
disallowExisting?: boolean
|
|
901
|
-
},
|
|
902
|
-
): Promise<string>
|
|
903
|
-
export function promptDatabaseName(
|
|
904
|
-
defaultName: string | undefined,
|
|
905
|
-
engine: string | undefined,
|
|
906
|
-
options: {
|
|
907
|
-
allowBack: true
|
|
908
|
-
existingDatabases?: string[]
|
|
909
|
-
disallowExisting?: boolean
|
|
910
|
-
},
|
|
911
|
-
): Promise<string | null>
|
|
912
|
-
export async function promptDatabaseName(
|
|
913
|
-
defaultName?: string,
|
|
914
|
-
engine?: string,
|
|
915
|
-
options?: {
|
|
916
|
-
allowBack?: boolean
|
|
917
|
-
existingDatabases?: string[]
|
|
918
|
-
disallowExisting?: boolean
|
|
919
|
-
},
|
|
920
|
-
): Promise<string | null> {
|
|
921
|
-
// MySQL uses "schema" terminology (database and schema are synonymous)
|
|
922
|
-
const baseLabel =
|
|
923
|
-
engine === 'mysql' ? 'Database (schema) name' : 'Database name'
|
|
924
|
-
|
|
925
|
-
// Sanitize the default name to ensure it's valid
|
|
926
|
-
const sanitizedDefault = defaultName
|
|
927
|
-
? sanitizeDatabaseName(defaultName)
|
|
928
|
-
: undefined
|
|
929
|
-
|
|
930
|
-
// When allowBack is true, show the default in the message (since we can't use inquirer's default)
|
|
931
|
-
const label =
|
|
932
|
-
options?.allowBack && sanitizedDefault
|
|
933
|
-
? `${baseLabel} [${sanitizedDefault}]:`
|
|
934
|
-
: `${baseLabel}:`
|
|
935
|
-
|
|
936
|
-
const { database } = await escapeablePrompt<{ database: string }>([
|
|
937
|
-
{
|
|
938
|
-
type: 'input',
|
|
939
|
-
name: 'database',
|
|
940
|
-
message: label,
|
|
941
|
-
default: options?.allowBack ? undefined : sanitizedDefault,
|
|
942
|
-
validate: (input: string) => {
|
|
943
|
-
if (options?.allowBack && !input) return true // Allow empty for back
|
|
944
|
-
if (!input) return 'Database name is required'
|
|
945
|
-
// PostgreSQL database naming rules (also valid for MySQL)
|
|
946
|
-
// Hyphens excluded to avoid requiring quoted identifiers in SQL
|
|
947
|
-
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input)) {
|
|
948
|
-
return 'Database name must start with a letter or underscore and contain only letters, numbers, and underscores'
|
|
949
|
-
}
|
|
950
|
-
if (input.length > 63) {
|
|
951
|
-
return 'Database name must be 63 characters or less'
|
|
952
|
-
}
|
|
953
|
-
if (
|
|
954
|
-
options?.disallowExisting &&
|
|
955
|
-
options.existingDatabases?.includes(input)
|
|
956
|
-
) {
|
|
957
|
-
return `Database "${input}" already exists. Choose a different name.`
|
|
958
|
-
}
|
|
959
|
-
return true
|
|
960
|
-
},
|
|
961
|
-
},
|
|
962
|
-
])
|
|
963
|
-
|
|
964
|
-
if (options?.allowBack && !database) return null
|
|
965
|
-
return database
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* Prompt to select a database from a list of databases in a container
|
|
970
|
-
* @param options.includeBack - Include a back option (returns null when selected)
|
|
971
|
-
*/
|
|
972
|
-
export function promptDatabaseSelect(
|
|
973
|
-
databases: string[],
|
|
974
|
-
message?: string,
|
|
975
|
-
options?: { includeBack?: false },
|
|
976
|
-
): Promise<string>
|
|
977
|
-
export function promptDatabaseSelect(
|
|
978
|
-
databases: string[],
|
|
979
|
-
message: string | undefined,
|
|
980
|
-
options: { includeBack: true },
|
|
981
|
-
): Promise<string | null>
|
|
982
|
-
export async function promptDatabaseSelect(
|
|
983
|
-
databases: string[],
|
|
984
|
-
message: string = 'Select database:',
|
|
985
|
-
options?: { includeBack?: boolean },
|
|
986
|
-
): Promise<string | null> {
|
|
987
|
-
if (databases.length === 0) {
|
|
988
|
-
throw new Error('No databases available to select')
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
if (databases.length === 1 && !options?.includeBack) {
|
|
992
|
-
return databases[0]
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
type Choice =
|
|
996
|
-
| { name: string; value: string; short?: string }
|
|
997
|
-
| inquirer.Separator
|
|
998
|
-
|
|
999
|
-
const choices: Choice[] = databases.map((db, index) => ({
|
|
1000
|
-
name: index === 0 ? `${db} ${chalk.gray('(primary)')}` : db,
|
|
1001
|
-
value: db,
|
|
1002
|
-
short: db,
|
|
1003
|
-
}))
|
|
1004
|
-
|
|
1005
|
-
if (options?.includeBack) {
|
|
1006
|
-
choices.push(new inquirer.Separator())
|
|
1007
|
-
choices.push({ name: `${chalk.blue('←')} Back`, value: BACK_VALUE })
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
const { database } = await escapeablePrompt<{ database: string }>([
|
|
1011
|
-
{
|
|
1012
|
-
type: 'list',
|
|
1013
|
-
name: 'database',
|
|
1014
|
-
message,
|
|
1015
|
-
choices,
|
|
1016
|
-
},
|
|
1017
|
-
])
|
|
1018
|
-
|
|
1019
|
-
if (database === BACK_VALUE) return null
|
|
1020
|
-
return database
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
* Prompt for backup format selection
|
|
1025
|
-
* Uses centralized format configuration from config/backup-formats.ts
|
|
1026
|
-
* Dynamically builds choices from engine-specific format definitions
|
|
1027
|
-
* @param options.includeBack - Include a back option (returns null when selected)
|
|
1028
|
-
*/
|
|
1029
|
-
export function promptBackupFormat(
|
|
1030
|
-
engine: Engine,
|
|
1031
|
-
options?: { includeBack?: false },
|
|
1032
|
-
): Promise<BackupFormatType>
|
|
1033
|
-
export function promptBackupFormat(
|
|
1034
|
-
engine: Engine,
|
|
1035
|
-
options: { includeBack: true },
|
|
1036
|
-
): Promise<BackupFormatType | null>
|
|
1037
|
-
export async function promptBackupFormat(
|
|
1038
|
-
engine: Engine,
|
|
1039
|
-
options?: { includeBack?: boolean },
|
|
1040
|
-
): Promise<BackupFormatType | null> {
|
|
1041
|
-
// If engine doesn't support format choice (e.g., ClickHouse), return default
|
|
1042
|
-
if (!supportsFormatChoice(engine)) {
|
|
1043
|
-
return getDefaultFormat(engine)
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
const engineFormats = BACKUP_FORMATS[engine]
|
|
1047
|
-
|
|
1048
|
-
type Choice =
|
|
1049
|
-
| { name: string; value: string; short?: string }
|
|
1050
|
-
| inquirer.Separator
|
|
1051
|
-
|
|
1052
|
-
// Build choices dynamically from the engine's format definitions
|
|
1053
|
-
const choices: Choice[] = Object.entries(engineFormats.formats).map(
|
|
1054
|
-
([key, info]) => ({
|
|
1055
|
-
name: `${info.label} ${chalk.gray(`- ${info.description}`)}`,
|
|
1056
|
-
value: key,
|
|
1057
|
-
}),
|
|
1058
|
-
)
|
|
1059
|
-
|
|
1060
|
-
if (options?.includeBack) {
|
|
1061
|
-
choices.push(new inquirer.Separator())
|
|
1062
|
-
choices.push({ name: `${chalk.blue('←')} Back`, value: BACK_VALUE })
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
const { format } = await escapeablePrompt<{ format: string }>([
|
|
1066
|
-
{
|
|
1067
|
-
type: 'list',
|
|
1068
|
-
name: 'format',
|
|
1069
|
-
message: 'Select backup format:',
|
|
1070
|
-
choices,
|
|
1071
|
-
default: engineFormats.defaultFormat,
|
|
1072
|
-
},
|
|
1073
|
-
])
|
|
1074
|
-
|
|
1075
|
-
if (format === BACK_VALUE) return null
|
|
1076
|
-
return format as BackupFormatType
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
/**
|
|
1080
|
-
* Prompt for backup output directory
|
|
1081
|
-
* @returns Directory path or null if cancelled
|
|
1082
|
-
*/
|
|
1083
|
-
export async function promptBackupDirectory(): Promise<string | null> {
|
|
1084
|
-
const cwd = process.cwd()
|
|
1085
|
-
|
|
1086
|
-
const { choice } = await escapeablePrompt<{ choice: string }>([
|
|
1087
|
-
{
|
|
1088
|
-
type: 'list',
|
|
1089
|
-
name: 'choice',
|
|
1090
|
-
message: 'Where to save the backup?',
|
|
1091
|
-
choices: [
|
|
1092
|
-
{
|
|
1093
|
-
name: `${chalk.cyan('.')} Current directory ${chalk.gray(`(${cwd})`)}`,
|
|
1094
|
-
value: 'cwd',
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
name: `${chalk.yellow('...')} Choose different directory`,
|
|
1098
|
-
value: 'custom',
|
|
1099
|
-
},
|
|
1100
|
-
new inquirer.Separator(),
|
|
1101
|
-
{ name: `${chalk.blue('←')} Back`, value: BACK_VALUE },
|
|
1102
|
-
],
|
|
1103
|
-
},
|
|
1104
|
-
])
|
|
1105
|
-
|
|
1106
|
-
if (choice === BACK_VALUE) return null
|
|
1107
|
-
if (choice === 'cwd') return cwd
|
|
1108
|
-
|
|
1109
|
-
const { customPath } = await escapeablePrompt<{ customPath: string }>([
|
|
1110
|
-
{
|
|
1111
|
-
type: 'input',
|
|
1112
|
-
name: 'customPath',
|
|
1113
|
-
message: 'Enter directory path:',
|
|
1114
|
-
default: cwd,
|
|
1115
|
-
validate: (input: string) => {
|
|
1116
|
-
if (!input.trim()) return 'Directory path is required'
|
|
1117
|
-
const resolved = resolve(input.replace(/^~/, process.env.HOME || ''))
|
|
1118
|
-
if (existsSync(resolved)) {
|
|
1119
|
-
if (!statSync(resolved).isDirectory()) {
|
|
1120
|
-
return 'Path is not a directory'
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
// Directory will be created if it doesn't exist
|
|
1124
|
-
return true
|
|
1125
|
-
},
|
|
1126
|
-
},
|
|
1127
|
-
])
|
|
1128
|
-
|
|
1129
|
-
return resolve(customPath.replace(/^~/, process.env.HOME || ''))
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
/**
|
|
1133
|
-
* Prompt for backup filename
|
|
1134
|
-
* @param options.allowBack - Allow empty input to go back (returns null)
|
|
1135
|
-
*/
|
|
1136
|
-
export function promptBackupFilename(
|
|
1137
|
-
defaultName: string,
|
|
1138
|
-
options?: { allowBack?: false },
|
|
1139
|
-
): Promise<string>
|
|
1140
|
-
export function promptBackupFilename(
|
|
1141
|
-
defaultName: string,
|
|
1142
|
-
options: { allowBack: true },
|
|
1143
|
-
): Promise<string | null>
|
|
1144
|
-
export async function promptBackupFilename(
|
|
1145
|
-
defaultName: string,
|
|
1146
|
-
options?: { allowBack?: boolean },
|
|
1147
|
-
): Promise<string | null> {
|
|
1148
|
-
// Show the default in the message when allowBack is true
|
|
1149
|
-
const message = options?.allowBack
|
|
1150
|
-
? `Backup filename [${defaultName}]:`
|
|
1151
|
-
: 'Backup filename:'
|
|
1152
|
-
|
|
1153
|
-
const { filename } = await escapeablePrompt<{ filename: string }>([
|
|
1154
|
-
{
|
|
1155
|
-
type: 'input',
|
|
1156
|
-
name: 'filename',
|
|
1157
|
-
message,
|
|
1158
|
-
default: options?.allowBack ? undefined : defaultName,
|
|
1159
|
-
validate: (input: string) => {
|
|
1160
|
-
if (options?.allowBack && !input) return true // Allow empty for back
|
|
1161
|
-
if (!input) return 'Filename is required'
|
|
1162
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(input)) {
|
|
1163
|
-
return 'Filename must contain only letters, numbers, underscores, and hyphens'
|
|
1164
|
-
}
|
|
1165
|
-
return true
|
|
1166
|
-
},
|
|
1167
|
-
},
|
|
1168
|
-
])
|
|
1169
|
-
|
|
1170
|
-
if (options?.allowBack && !filename) return null
|
|
1171
|
-
return filename
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
export type CreateOptions = {
|
|
1175
|
-
name: string
|
|
1176
|
-
engine: string
|
|
1177
|
-
version: string
|
|
1178
|
-
port: number
|
|
1179
|
-
database: string
|
|
1180
|
-
path?: string // SQLite file path
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
/**
|
|
1184
|
-
* Prompt for file-based database (SQLite/DuckDB) file location
|
|
1185
|
-
* Similar to the relocate logic in container-handlers.ts
|
|
1186
|
-
*/
|
|
1187
|
-
export async function promptFileDatabasePath(
|
|
1188
|
-
containerName: string,
|
|
1189
|
-
extension: string = '.sqlite',
|
|
1190
|
-
): Promise<string | undefined> {
|
|
1191
|
-
const defaultPath = `./${containerName}${extension}`
|
|
1192
|
-
const dbType = extension === '.duckdb' ? 'DuckDB' : 'SQLite'
|
|
1193
|
-
|
|
1194
|
-
console.log(
|
|
1195
|
-
chalk.gray(
|
|
1196
|
-
` ${dbType} databases are stored as files in your project directory.`,
|
|
1197
|
-
),
|
|
1198
|
-
)
|
|
1199
|
-
console.log(chalk.gray(` Default: ${defaultPath}`))
|
|
1200
|
-
console.log()
|
|
1201
|
-
|
|
1202
|
-
const { useDefault } = await escapeablePrompt<{ useDefault: string }>([
|
|
1203
|
-
{
|
|
1204
|
-
type: 'list',
|
|
1205
|
-
name: 'useDefault',
|
|
1206
|
-
message: 'Where should the database file be created?',
|
|
1207
|
-
choices: [
|
|
1208
|
-
{ name: `Use default location (${defaultPath})`, value: 'default' },
|
|
1209
|
-
{ name: 'Specify custom path', value: 'custom' },
|
|
1210
|
-
],
|
|
1211
|
-
},
|
|
1212
|
-
])
|
|
1213
|
-
|
|
1214
|
-
if (useDefault === 'default') {
|
|
1215
|
-
return undefined // Use default
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
const { inputPath } = await escapeablePrompt<{ inputPath: string }>([
|
|
1219
|
-
{
|
|
1220
|
-
type: 'input',
|
|
1221
|
-
name: 'inputPath',
|
|
1222
|
-
message: 'File path:',
|
|
1223
|
-
default: defaultPath,
|
|
1224
|
-
validate: (input: string) => {
|
|
1225
|
-
if (!input) return 'Path is required'
|
|
1226
|
-
return true
|
|
1227
|
-
},
|
|
1228
|
-
},
|
|
1229
|
-
])
|
|
1230
|
-
|
|
1231
|
-
// Expand ~ to home directory
|
|
1232
|
-
let expandedPath = inputPath
|
|
1233
|
-
if (inputPath === '~') {
|
|
1234
|
-
expandedPath = homedir()
|
|
1235
|
-
} else if (inputPath.startsWith('~/')) {
|
|
1236
|
-
expandedPath = join(homedir(), inputPath.slice(2))
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
// Convert relative paths to absolute
|
|
1240
|
-
if (!expandedPath.startsWith('/')) {
|
|
1241
|
-
expandedPath = resolve(process.cwd(), expandedPath)
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
// Check if path looks like a file (has db extension) or directory
|
|
1245
|
-
const hasDbExtension = /\.(sqlite3?|db|duckdb|ddb)$/i.test(expandedPath)
|
|
1246
|
-
|
|
1247
|
-
// Treat as directory if:
|
|
1248
|
-
// - ends with /
|
|
1249
|
-
// - exists and is a directory
|
|
1250
|
-
// - doesn't have a database file extension (assume it's a directory path)
|
|
1251
|
-
const isDirectory =
|
|
1252
|
-
expandedPath.endsWith('/') ||
|
|
1253
|
-
(existsSync(expandedPath) && statSync(expandedPath).isDirectory()) ||
|
|
1254
|
-
!hasDbExtension
|
|
1255
|
-
|
|
1256
|
-
let finalPath: string
|
|
1257
|
-
if (isDirectory) {
|
|
1258
|
-
// Remove trailing slash if present, then append filename
|
|
1259
|
-
const dirPath = expandedPath.endsWith('/')
|
|
1260
|
-
? expandedPath.slice(0, -1)
|
|
1261
|
-
: expandedPath
|
|
1262
|
-
finalPath = join(dirPath, `${containerName}${extension}`)
|
|
1263
|
-
} else {
|
|
1264
|
-
finalPath = expandedPath
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// Check if file already exists
|
|
1268
|
-
if (existsSync(finalPath)) {
|
|
1269
|
-
console.log(chalk.yellow(` Warning: File already exists: ${finalPath}`))
|
|
1270
|
-
const { overwrite } = await escapeablePrompt<{ overwrite: string }>([
|
|
1271
|
-
{
|
|
1272
|
-
type: 'list',
|
|
1273
|
-
name: 'overwrite',
|
|
1274
|
-
message:
|
|
1275
|
-
'A file already exists at this location. What would you like to do?',
|
|
1276
|
-
choices: [
|
|
1277
|
-
{ name: 'Choose a different path', value: 'different' },
|
|
1278
|
-
{ name: 'Cancel', value: 'cancel' },
|
|
1279
|
-
],
|
|
1280
|
-
},
|
|
1281
|
-
])
|
|
1282
|
-
|
|
1283
|
-
if (overwrite === 'cancel') {
|
|
1284
|
-
throw new Error('Creation cancelled')
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
// Recursively prompt again
|
|
1288
|
-
return promptFileDatabasePath(containerName, extension)
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
return finalPath
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
// Full interactive create flow
|
|
1295
|
-
export async function promptCreateOptions(): Promise<CreateOptions> {
|
|
1296
|
-
console.log(chalk.cyan('\n ▣ Create New Database Container\n'))
|
|
1297
|
-
|
|
1298
|
-
const engine = await promptEngine()
|
|
1299
|
-
const version = await promptVersion(engine)
|
|
1300
|
-
const name = await promptContainerName()
|
|
1301
|
-
const database = await promptDatabaseName(name, engine) // Default to container name
|
|
1302
|
-
|
|
1303
|
-
// File-based databases (SQLite/DuckDB) don't need a port but need a path
|
|
1304
|
-
let port = 0
|
|
1305
|
-
let path: string | undefined
|
|
1306
|
-
if (engine === 'sqlite') {
|
|
1307
|
-
path = await promptFileDatabasePath(name, '.sqlite')
|
|
1308
|
-
} else if (engine === 'duckdb') {
|
|
1309
|
-
path = await promptFileDatabasePath(name, '.duckdb')
|
|
1310
|
-
} else {
|
|
1311
|
-
const engineDefaults = getEngineDefaults(engine)
|
|
1312
|
-
port = await promptPort(engineDefaults.defaultPort, engine)
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
return { name, engine, version, port, database, path }
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
/**
|
|
1319
|
-
* Prompt user to install missing database client tools
|
|
1320
|
-
*
|
|
1321
|
-
* @param missingTool - The name of the missing tool (e.g., 'psql', 'pg_dump', 'mysql')
|
|
1322
|
-
* @param engine - The database engine (defaults to 'postgresql')
|
|
1323
|
-
* @returns true if installation was successful, false otherwise.
|
|
1324
|
-
*
|
|
1325
|
-
* Note: For PostgreSQL, this function always returns false because PostgreSQL
|
|
1326
|
-
* client tools (psql, pg_dump, etc.) are bundled with the engine binaries from
|
|
1327
|
-
* hostdb. Callers should treat this as "use bundled tools via spindb engines
|
|
1328
|
-
* download postgresql" rather than an installation failure.
|
|
1329
|
-
*/
|
|
1330
|
-
export async function promptInstallDependencies(
|
|
1331
|
-
missingTool: string,
|
|
1332
|
-
engine: string = 'postgresql',
|
|
1333
|
-
): Promise<boolean> {
|
|
1334
|
-
const platform = getCurrentPlatform()
|
|
1335
|
-
|
|
1336
|
-
console.log()
|
|
1337
|
-
console.log(
|
|
1338
|
-
chalk.yellow(` Database client tool "${missingTool}" is not installed.`),
|
|
1339
|
-
)
|
|
1340
|
-
console.log()
|
|
1341
|
-
|
|
1342
|
-
// Check what package manager is available
|
|
1343
|
-
const packageManager = await detectPackageManager()
|
|
1344
|
-
|
|
1345
|
-
if (!packageManager) {
|
|
1346
|
-
console.log(chalk.red(' No supported package manager found.'))
|
|
1347
|
-
console.log()
|
|
1348
|
-
|
|
1349
|
-
// Get instructions from the dependency registry
|
|
1350
|
-
const engineDeps = getEngineDependencies(engine)
|
|
1351
|
-
if (engineDeps) {
|
|
1352
|
-
// Find the specific dependency or use the first one for general instructions
|
|
1353
|
-
const dep =
|
|
1354
|
-
engineDeps.dependencies.find((d) => d.binary === missingTool) ||
|
|
1355
|
-
engineDeps.dependencies[0]
|
|
1356
|
-
|
|
1357
|
-
if (dep) {
|
|
1358
|
-
const instructions = getManualInstallInstructions(dep, platform)
|
|
1359
|
-
console.log(
|
|
1360
|
-
chalk.gray(
|
|
1361
|
-
` Please install ${engineDeps.displayName} client tools:`,
|
|
1362
|
-
),
|
|
1363
|
-
)
|
|
1364
|
-
console.log()
|
|
1365
|
-
for (const instruction of instructions) {
|
|
1366
|
-
console.log(chalk.gray(` ${instruction}`))
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
console.log()
|
|
1371
|
-
return false
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
console.log(
|
|
1375
|
-
chalk.gray(
|
|
1376
|
-
` Detected package manager: ${chalk.white(packageManager.name)}`,
|
|
1377
|
-
),
|
|
1378
|
-
)
|
|
1379
|
-
console.log()
|
|
1380
|
-
|
|
1381
|
-
// Get engine display name
|
|
1382
|
-
const engineDeps = getEngineDependencies(engine)
|
|
1383
|
-
const engineName = engineDeps?.displayName || engine
|
|
1384
|
-
|
|
1385
|
-
// In CI environments (no TTY or CI env var), auto-install without prompting
|
|
1386
|
-
const isCI = !!(
|
|
1387
|
-
process.env.CI ||
|
|
1388
|
-
process.env.GITHUB_ACTIONS ||
|
|
1389
|
-
!process.stdin.isTTY
|
|
1390
|
-
)
|
|
1391
|
-
|
|
1392
|
-
let shouldInstall = 'yes'
|
|
1393
|
-
|
|
1394
|
-
if (!isCI) {
|
|
1395
|
-
const response = await escapeablePrompt<{ shouldInstall: string }>([
|
|
1396
|
-
{
|
|
1397
|
-
type: 'list',
|
|
1398
|
-
name: 'shouldInstall',
|
|
1399
|
-
message: `Would you like to install ${engineName} client tools now?`,
|
|
1400
|
-
choices: [
|
|
1401
|
-
{ name: 'Yes, install now', value: 'yes' },
|
|
1402
|
-
{ name: 'No, I will install manually', value: 'no' },
|
|
1403
|
-
],
|
|
1404
|
-
default: 'yes',
|
|
1405
|
-
},
|
|
1406
|
-
])
|
|
1407
|
-
shouldInstall = response.shouldInstall
|
|
1408
|
-
} else {
|
|
1409
|
-
console.log(
|
|
1410
|
-
chalk.gray(
|
|
1411
|
-
` CI environment detected - auto-installing ${engineName} client tools...`,
|
|
1412
|
-
),
|
|
1413
|
-
)
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
if (shouldInstall === 'no') {
|
|
1417
|
-
console.log()
|
|
1418
|
-
console.log(chalk.gray(' To install manually, run:'))
|
|
1419
|
-
|
|
1420
|
-
// Get the specific dependency and build install command info
|
|
1421
|
-
if (engineDeps) {
|
|
1422
|
-
const dep = engineDeps.dependencies.find((d) => d.binary === missingTool)
|
|
1423
|
-
if (dep) {
|
|
1424
|
-
const pkgDef = dep.packages[packageManager.id]
|
|
1425
|
-
if (pkgDef) {
|
|
1426
|
-
const installCmd = packageManager.config.installTemplate.replace(
|
|
1427
|
-
'{package}',
|
|
1428
|
-
pkgDef.package,
|
|
1429
|
-
)
|
|
1430
|
-
console.log(chalk.cyan(` ${installCmd}`))
|
|
1431
|
-
if (pkgDef.postInstall) {
|
|
1432
|
-
for (const postCmd of pkgDef.postInstall) {
|
|
1433
|
-
console.log(chalk.cyan(` ${postCmd}`))
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
console.log()
|
|
1440
|
-
return false
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
console.log()
|
|
1444
|
-
|
|
1445
|
-
// PostgreSQL client tools are bundled with hostdb binaries
|
|
1446
|
-
if (engine === 'postgresql') {
|
|
1447
|
-
console.log(
|
|
1448
|
-
chalk.cyan(
|
|
1449
|
-
' PostgreSQL client tools are bundled with the engine binaries.',
|
|
1450
|
-
),
|
|
1451
|
-
)
|
|
1452
|
-
console.log(
|
|
1453
|
-
chalk.cyan(' Download them with: spindb engines download postgresql'),
|
|
1454
|
-
)
|
|
1455
|
-
console.log()
|
|
1456
|
-
return false
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
// For other engines, use the generic installer
|
|
1460
|
-
console.log(
|
|
1461
|
-
chalk.cyan(` Installing ${engineName} with ${packageManager.name}...`),
|
|
1462
|
-
)
|
|
1463
|
-
console.log(chalk.gray(' You may be prompted for your password.'))
|
|
1464
|
-
console.log()
|
|
1465
|
-
|
|
1466
|
-
try {
|
|
1467
|
-
const results = await installEngineDependencies(engine, packageManager)
|
|
1468
|
-
const allSuccess = results.every((r) => r.success)
|
|
1469
|
-
|
|
1470
|
-
if (allSuccess) {
|
|
1471
|
-
console.log()
|
|
1472
|
-
console.log(chalk.green(` ${engineName} tools installed successfully!`))
|
|
1473
|
-
console.log(chalk.gray(' Continuing with your operation...'))
|
|
1474
|
-
console.log()
|
|
1475
|
-
return true
|
|
1476
|
-
} else {
|
|
1477
|
-
const failed = results.filter((r) => !r.success)
|
|
1478
|
-
console.log()
|
|
1479
|
-
console.log(chalk.red(' Some installations failed:'))
|
|
1480
|
-
for (const f of failed) {
|
|
1481
|
-
console.log(chalk.red(` ${f.dependency.name}: ${f.error}`))
|
|
1482
|
-
}
|
|
1483
|
-
console.log()
|
|
1484
|
-
|
|
1485
|
-
// Show manual install instructions
|
|
1486
|
-
if (engineDeps) {
|
|
1487
|
-
const instructions = getManualInstallInstructions(
|
|
1488
|
-
engineDeps.dependencies[0],
|
|
1489
|
-
platform,
|
|
1490
|
-
)
|
|
1491
|
-
if (instructions.length > 0) {
|
|
1492
|
-
console.log(chalk.gray(' To install manually:'))
|
|
1493
|
-
for (const instruction of instructions) {
|
|
1494
|
-
console.log(chalk.gray(` ${instruction}`))
|
|
1495
|
-
}
|
|
1496
|
-
console.log()
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
return false
|
|
1501
|
-
}
|
|
1502
|
-
} catch (error) {
|
|
1503
|
-
const e = error as Error
|
|
1504
|
-
console.log()
|
|
1505
|
-
console.log(chalk.red(` Installation failed: ${e.message}`))
|
|
1506
|
-
console.log()
|
|
1507
|
-
|
|
1508
|
-
// Show manual install instructions on error
|
|
1509
|
-
if (engineDeps) {
|
|
1510
|
-
const instructions = getManualInstallInstructions(
|
|
1511
|
-
engineDeps.dependencies[0],
|
|
1512
|
-
platform,
|
|
1513
|
-
)
|
|
1514
|
-
if (instructions.length > 0) {
|
|
1515
|
-
console.log(chalk.gray(' To install manually:'))
|
|
1516
|
-
for (const instruction of instructions) {
|
|
1517
|
-
console.log(chalk.gray(` ${instruction}`))
|
|
1518
|
-
}
|
|
1519
|
-
console.log()
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
return false
|
|
1524
|
-
}
|
|
1525
|
-
}
|