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
|
@@ -1,1292 +0,0 @@
|
|
|
1
|
-
import { spawn, type SpawnOptions } from 'child_process'
|
|
2
|
-
import { existsSync } from 'fs'
|
|
3
|
-
import { mkdir, writeFile, readFile, unlink } from 'fs/promises'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
import { BaseEngine } from '../base-engine'
|
|
6
|
-
import { paths } from '../../config/paths'
|
|
7
|
-
import { getEngineDefaults } from '../../config/defaults'
|
|
8
|
-
import { platformService, isWindows } from '../../core/platform-service'
|
|
9
|
-
import { configManager } from '../../core/config-manager'
|
|
10
|
-
import {
|
|
11
|
-
logDebug,
|
|
12
|
-
logWarning,
|
|
13
|
-
assertValidUsername,
|
|
14
|
-
UnsupportedOperationError,
|
|
15
|
-
} from '../../core/error-handler'
|
|
16
|
-
import { processManager } from '../../core/process-manager'
|
|
17
|
-
import { portManager } from '../../core/port-manager'
|
|
18
|
-
import { meilisearchBinaryManager } from './binary-manager'
|
|
19
|
-
import { getBinaryUrl } from './binary-urls'
|
|
20
|
-
import { normalizeVersion, SUPPORTED_MAJOR_VERSIONS } from './version-maps'
|
|
21
|
-
import { fetchAvailableVersions as fetchHostdbVersions } from './hostdb-releases'
|
|
22
|
-
import {
|
|
23
|
-
detectBackupFormat as detectBackupFormatImpl,
|
|
24
|
-
restoreBackup,
|
|
25
|
-
} from './restore'
|
|
26
|
-
import { createBackup } from './backup'
|
|
27
|
-
import { meilisearchApiRequest } from './api-client'
|
|
28
|
-
import {
|
|
29
|
-
type Platform,
|
|
30
|
-
type Arch,
|
|
31
|
-
type ContainerConfig,
|
|
32
|
-
type ProgressCallback,
|
|
33
|
-
type BackupFormat,
|
|
34
|
-
type BackupOptions,
|
|
35
|
-
type BackupResult,
|
|
36
|
-
type RestoreResult,
|
|
37
|
-
type DumpResult,
|
|
38
|
-
type StatusResult,
|
|
39
|
-
type QueryResult,
|
|
40
|
-
type QueryOptions,
|
|
41
|
-
type CreateUserOptions,
|
|
42
|
-
type UserCredentials,
|
|
43
|
-
} from '../../types'
|
|
44
|
-
import { parseRESTAPIResult } from '../../core/query-parser'
|
|
45
|
-
|
|
46
|
-
const ENGINE = 'meilisearch'
|
|
47
|
-
const engineDef = getEngineDefaults(ENGINE)
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Initial delay before checking if Meilisearch is ready after spawning.
|
|
51
|
-
* Windows requires a longer delay as process startup is slower.
|
|
52
|
-
*/
|
|
53
|
-
const START_CHECK_DELAY_MS = isWindows() ? 2000 : 500
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Parse a Meilisearch connection string
|
|
57
|
-
* Supported formats:
|
|
58
|
-
* - http://host:port
|
|
59
|
-
* - https://host:port
|
|
60
|
-
* - meilisearch://host:port (converted to http)
|
|
61
|
-
* - http://host:port?api_key=KEY (for API key auth)
|
|
62
|
-
*/
|
|
63
|
-
function parseMeilisearchConnectionString(connectionString: string): {
|
|
64
|
-
baseUrl: string
|
|
65
|
-
headers: Record<string, string>
|
|
66
|
-
} {
|
|
67
|
-
let url: URL
|
|
68
|
-
let scheme = 'http'
|
|
69
|
-
|
|
70
|
-
// Handle meilisearch:// scheme by converting to http://
|
|
71
|
-
let normalized = connectionString.trim()
|
|
72
|
-
if (normalized.startsWith('meilisearch://')) {
|
|
73
|
-
normalized = normalized.replace('meilisearch://', 'http://')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Ensure scheme is present
|
|
77
|
-
if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {
|
|
78
|
-
normalized = `http://${normalized}`
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
url = new URL(normalized)
|
|
83
|
-
scheme = url.protocol.replace(':', '')
|
|
84
|
-
} catch {
|
|
85
|
-
throw new Error(
|
|
86
|
-
`Invalid Meilisearch connection string: ${connectionString}\n` +
|
|
87
|
-
'Expected format: http://host:port or meilisearch://host:port',
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Extract API key if provided
|
|
92
|
-
const apiKey = url.searchParams.get('api_key')
|
|
93
|
-
|
|
94
|
-
const headers: Record<string, string> = {
|
|
95
|
-
'Content-Type': 'application/json',
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (apiKey) {
|
|
99
|
-
headers['Authorization'] = `Bearer ${apiKey}`
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Construct base URL without query params
|
|
103
|
-
const port = url.port || '7700'
|
|
104
|
-
const baseUrl = `${scheme}://${url.hostname}:${port}`
|
|
105
|
-
|
|
106
|
-
return { baseUrl, headers }
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Make an HTTP request to a remote Meilisearch server
|
|
111
|
-
*/
|
|
112
|
-
async function remoteMeilisearchRequest(
|
|
113
|
-
baseUrl: string,
|
|
114
|
-
method: string,
|
|
115
|
-
path: string,
|
|
116
|
-
headers: Record<string, string>,
|
|
117
|
-
body?: Record<string, unknown>,
|
|
118
|
-
timeoutMs = 30000,
|
|
119
|
-
): Promise<{ status: number; data: unknown }> {
|
|
120
|
-
const url = `${baseUrl}${path}`
|
|
121
|
-
|
|
122
|
-
const controller = new AbortController()
|
|
123
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
|
|
124
|
-
|
|
125
|
-
const options: RequestInit = {
|
|
126
|
-
method,
|
|
127
|
-
headers,
|
|
128
|
-
signal: controller.signal,
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (body) {
|
|
132
|
-
options.body = JSON.stringify(body)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
const response = await fetch(url, options)
|
|
137
|
-
|
|
138
|
-
// Try to parse as JSON, fall back to text
|
|
139
|
-
let data: unknown
|
|
140
|
-
const contentType = response.headers.get('content-type') || ''
|
|
141
|
-
if (contentType.includes('application/json')) {
|
|
142
|
-
data = await response.json()
|
|
143
|
-
} else {
|
|
144
|
-
data = await response.text()
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return { status: response.status, data }
|
|
148
|
-
} catch (error) {
|
|
149
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`Remote Meilisearch request timed out after ${timeoutMs / 1000}s: ${method} ${path}`,
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
throw error
|
|
155
|
-
} finally {
|
|
156
|
-
clearTimeout(timeoutId)
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export class MeilisearchEngine extends BaseEngine {
|
|
161
|
-
name = ENGINE
|
|
162
|
-
displayName = 'Meilisearch'
|
|
163
|
-
defaultPort = engineDef.defaultPort
|
|
164
|
-
supportedVersions = SUPPORTED_MAJOR_VERSIONS
|
|
165
|
-
|
|
166
|
-
// Get platform info for binary operations
|
|
167
|
-
getPlatformInfo(): { platform: Platform; arch: Arch } {
|
|
168
|
-
return platformService.getPlatformInfo()
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Fetch available versions from hostdb (dynamically or from cache/fallback)
|
|
172
|
-
async fetchAvailableVersions(): Promise<Record<string, string[]>> {
|
|
173
|
-
return fetchHostdbVersions()
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Get binary download URL from hostdb
|
|
177
|
-
getBinaryUrl(version: string, platform: Platform, arch: Arch): string {
|
|
178
|
-
return getBinaryUrl(version, platform, arch)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Resolves version string to full version (e.g., '1' -> '1.33.1')
|
|
182
|
-
resolveFullVersion(version: string): string {
|
|
183
|
-
// Use normalizeVersion which handles all cases:
|
|
184
|
-
// - Maps known versions (1 -> 1.33.1, 1.33 -> 1.33.1)
|
|
185
|
-
// - Returns full versions as-is (1.33.1 -> 1.33.1)
|
|
186
|
-
// - Returns unknown versions as-is with a warning (avoids invalid 4-part versions)
|
|
187
|
-
return normalizeVersion(version)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Get the path where binaries for a version would be installed
|
|
191
|
-
getBinaryPath(version: string): string {
|
|
192
|
-
const fullVersion = this.resolveFullVersion(version)
|
|
193
|
-
const { platform: p, arch: a } = this.getPlatformInfo()
|
|
194
|
-
return paths.getBinaryPath({
|
|
195
|
-
engine: 'meilisearch',
|
|
196
|
-
version: fullVersion,
|
|
197
|
-
platform: p,
|
|
198
|
-
arch: a,
|
|
199
|
-
})
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Verify that Meilisearch binaries are available
|
|
203
|
-
async verifyBinary(binPath: string): Promise<boolean> {
|
|
204
|
-
const ext = platformService.getExecutableExtension()
|
|
205
|
-
const serverPath = join(binPath, 'bin', `meilisearch${ext}`)
|
|
206
|
-
return existsSync(serverPath)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Check if a specific Meilisearch version is installed (downloaded)
|
|
210
|
-
async isBinaryInstalled(version: string): Promise<boolean> {
|
|
211
|
-
const { platform, arch } = this.getPlatformInfo()
|
|
212
|
-
return meilisearchBinaryManager.isInstalled(version, platform, arch)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Ensure Meilisearch binaries are available for a specific version
|
|
217
|
-
* Downloads from hostdb if not already installed
|
|
218
|
-
* Returns the path to the bin directory
|
|
219
|
-
*/
|
|
220
|
-
async ensureBinaries(
|
|
221
|
-
version: string,
|
|
222
|
-
onProgress?: ProgressCallback,
|
|
223
|
-
): Promise<string> {
|
|
224
|
-
const { platform, arch } = this.getPlatformInfo()
|
|
225
|
-
|
|
226
|
-
const binPath = await meilisearchBinaryManager.ensureInstalled(
|
|
227
|
-
version,
|
|
228
|
-
platform,
|
|
229
|
-
arch,
|
|
230
|
-
onProgress,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
// Register binaries in config
|
|
234
|
-
const ext = platformService.getExecutableExtension()
|
|
235
|
-
const tools = ['meilisearch'] as const
|
|
236
|
-
|
|
237
|
-
for (const tool of tools) {
|
|
238
|
-
const toolPath = join(binPath, 'bin', `${tool}${ext}`)
|
|
239
|
-
if (existsSync(toolPath)) {
|
|
240
|
-
await configManager.setBinaryPath(tool, toolPath, 'bundled')
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return binPath
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Initialize a new Meilisearch data directory
|
|
249
|
-
* Creates the directory structure
|
|
250
|
-
*
|
|
251
|
-
* IMPORTANT: snapshots directory must be a SIBLING of data directory, not inside it.
|
|
252
|
-
* Meilisearch fails to start if --snapshot-dir points inside --db-path.
|
|
253
|
-
*/
|
|
254
|
-
async initDataDir(
|
|
255
|
-
containerName: string,
|
|
256
|
-
_version: string,
|
|
257
|
-
_options: Record<string, unknown> = {},
|
|
258
|
-
): Promise<string> {
|
|
259
|
-
const dataDir = paths.getContainerDataPath(containerName, {
|
|
260
|
-
engine: ENGINE,
|
|
261
|
-
})
|
|
262
|
-
const containerDir = paths.getContainerPath(containerName, {
|
|
263
|
-
engine: ENGINE,
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
// Create container directory if it doesn't exist
|
|
267
|
-
if (!existsSync(containerDir)) {
|
|
268
|
-
await mkdir(containerDir, { recursive: true })
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Create data directory if it doesn't exist
|
|
272
|
-
if (!existsSync(dataDir)) {
|
|
273
|
-
await mkdir(dataDir, { recursive: true })
|
|
274
|
-
logDebug(`Created Meilisearch data directory: ${dataDir}`)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Create snapshots directory as SIBLING of data (not inside it!)
|
|
278
|
-
// Meilisearch fails with "failed to infer the version of the database"
|
|
279
|
-
// if --snapshot-dir points inside --db-path
|
|
280
|
-
const snapshotsDir = join(containerDir, 'snapshots')
|
|
281
|
-
if (!existsSync(snapshotsDir)) {
|
|
282
|
-
await mkdir(snapshotsDir, { recursive: true })
|
|
283
|
-
logDebug(`Created Meilisearch snapshots directory: ${snapshotsDir}`)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return dataDir
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Get the path to meilisearch server for a version
|
|
290
|
-
async getMeilisearchServerPath(version: string): Promise<string> {
|
|
291
|
-
const { platform, arch } = this.getPlatformInfo()
|
|
292
|
-
const fullVersion = normalizeVersion(version)
|
|
293
|
-
const binPath = paths.getBinaryPath({
|
|
294
|
-
engine: 'meilisearch',
|
|
295
|
-
version: fullVersion,
|
|
296
|
-
platform,
|
|
297
|
-
arch,
|
|
298
|
-
})
|
|
299
|
-
const ext = platformService.getExecutableExtension()
|
|
300
|
-
const serverPath = join(binPath, 'bin', `meilisearch${ext}`)
|
|
301
|
-
if (existsSync(serverPath)) {
|
|
302
|
-
return serverPath
|
|
303
|
-
}
|
|
304
|
-
throw new Error(
|
|
305
|
-
`Meilisearch ${version} is not installed. Run: spindb engines download meilisearch ${version}`,
|
|
306
|
-
)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Get the path to meilisearch binary
|
|
310
|
-
async getMeilisearchPath(version?: string): Promise<string> {
|
|
311
|
-
// Check config cache first
|
|
312
|
-
const cached = await configManager.getBinaryPath('meilisearch')
|
|
313
|
-
if (cached && existsSync(cached)) {
|
|
314
|
-
return cached
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// If version provided, use downloaded binary
|
|
318
|
-
if (version) {
|
|
319
|
-
const { platform, arch } = this.getPlatformInfo()
|
|
320
|
-
const fullVersion = normalizeVersion(version)
|
|
321
|
-
const binPath = paths.getBinaryPath({
|
|
322
|
-
engine: 'meilisearch',
|
|
323
|
-
version: fullVersion,
|
|
324
|
-
platform,
|
|
325
|
-
arch,
|
|
326
|
-
})
|
|
327
|
-
const ext = platformService.getExecutableExtension()
|
|
328
|
-
const meilisearchPath = join(binPath, 'bin', `meilisearch${ext}`)
|
|
329
|
-
if (existsSync(meilisearchPath)) {
|
|
330
|
-
return meilisearchPath
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
throw new Error(
|
|
335
|
-
'meilisearch not found. Run: spindb engines download meilisearch <version>',
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Start Meilisearch server
|
|
341
|
-
* CLI: meilisearch --db-path /path/to/data --http-addr 127.0.0.1:PORT --env development
|
|
342
|
-
*/
|
|
343
|
-
async start(
|
|
344
|
-
container: ContainerConfig,
|
|
345
|
-
onProgress?: ProgressCallback,
|
|
346
|
-
): Promise<{ port: number; connectionString: string }> {
|
|
347
|
-
const { name, port, version, binaryPath } = container
|
|
348
|
-
|
|
349
|
-
// Check if already running (idempotent behavior)
|
|
350
|
-
const alreadyRunning = await processManager.isRunning(name, {
|
|
351
|
-
engine: ENGINE,
|
|
352
|
-
})
|
|
353
|
-
if (alreadyRunning) {
|
|
354
|
-
return {
|
|
355
|
-
port,
|
|
356
|
-
connectionString: this.getConnectionString(container),
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Use stored binary path if available (from container creation)
|
|
361
|
-
let meilisearchServer: string | null = null
|
|
362
|
-
|
|
363
|
-
if (binaryPath && existsSync(binaryPath)) {
|
|
364
|
-
const ext = platformService.getExecutableExtension()
|
|
365
|
-
const serverPath = join(binaryPath, 'bin', `meilisearch${ext}`)
|
|
366
|
-
if (existsSync(serverPath)) {
|
|
367
|
-
meilisearchServer = serverPath
|
|
368
|
-
logDebug(`Using stored binary path: ${meilisearchServer}`)
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// If we didn't find the binary above, fall back to normal path
|
|
373
|
-
if (!meilisearchServer) {
|
|
374
|
-
try {
|
|
375
|
-
meilisearchServer = await this.getMeilisearchServerPath(version)
|
|
376
|
-
} catch (error) {
|
|
377
|
-
const originalMessage =
|
|
378
|
-
error instanceof Error ? error.message : String(error)
|
|
379
|
-
throw new Error(
|
|
380
|
-
`Meilisearch ${version} is not installed. Run: spindb engines download meilisearch ${version}\n` +
|
|
381
|
-
` Original error: ${originalMessage}`,
|
|
382
|
-
)
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
logDebug(`Using meilisearch for version ${version}: ${meilisearchServer}`)
|
|
387
|
-
|
|
388
|
-
const containerDir = paths.getContainerPath(name, { engine: ENGINE })
|
|
389
|
-
const dataDir = paths.getContainerDataPath(name, { engine: ENGINE })
|
|
390
|
-
// IMPORTANT: snapshots must be a SIBLING of data, not inside it
|
|
391
|
-
// Meilisearch fails with "failed to infer database version" if --snapshot-dir is inside --db-path
|
|
392
|
-
const snapshotsDir = join(containerDir, 'snapshots')
|
|
393
|
-
const logFile = paths.getContainerLogPath(name, { engine: ENGINE })
|
|
394
|
-
const pidFile = join(containerDir, 'meilisearch.pid')
|
|
395
|
-
|
|
396
|
-
// On Windows, wait longer for ports to be released (TIME_WAIT state can persist)
|
|
397
|
-
const portWaitTimeout = isWindows() ? 60000 : 0
|
|
398
|
-
const portCheckStart = Date.now()
|
|
399
|
-
const portCheckInterval = 1000
|
|
400
|
-
|
|
401
|
-
// Check if HTTP port is available
|
|
402
|
-
while (!(await portManager.isPortAvailable(port))) {
|
|
403
|
-
if (Date.now() - portCheckStart >= portWaitTimeout) {
|
|
404
|
-
throw new Error(`HTTP port ${port} is already in use.`)
|
|
405
|
-
}
|
|
406
|
-
logDebug(`Waiting for HTTP port ${port} to become available...`)
|
|
407
|
-
await new Promise((resolve) => setTimeout(resolve, portCheckInterval))
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Ensure snapshots directory exists
|
|
411
|
-
if (!existsSync(snapshotsDir)) {
|
|
412
|
-
await mkdir(snapshotsDir, { recursive: true })
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Check for pending snapshot import (created by restore operation)
|
|
416
|
-
const importMarkerPath = join(containerDir, 'pending-snapshot-import')
|
|
417
|
-
let pendingSnapshotImport: string | null = null
|
|
418
|
-
if (existsSync(importMarkerPath)) {
|
|
419
|
-
try {
|
|
420
|
-
pendingSnapshotImport = (
|
|
421
|
-
await readFile(importMarkerPath, 'utf-8')
|
|
422
|
-
).trim()
|
|
423
|
-
logDebug(`Found pending snapshot import: ${pendingSnapshotImport}`)
|
|
424
|
-
} catch {
|
|
425
|
-
logDebug('Failed to read pending snapshot import marker')
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
onProgress?.({ stage: 'starting', message: 'Starting Meilisearch...' })
|
|
430
|
-
|
|
431
|
-
// Build command arguments
|
|
432
|
-
// Meilisearch uses --db-path for data directory and --http-addr for binding
|
|
433
|
-
const args = [
|
|
434
|
-
'--db-path',
|
|
435
|
-
dataDir,
|
|
436
|
-
'--http-addr',
|
|
437
|
-
`127.0.0.1:${port}`,
|
|
438
|
-
'--env',
|
|
439
|
-
'development',
|
|
440
|
-
'--no-analytics',
|
|
441
|
-
'--snapshot-dir',
|
|
442
|
-
snapshotsDir,
|
|
443
|
-
]
|
|
444
|
-
|
|
445
|
-
// If there's a pending snapshot import, add the flag
|
|
446
|
-
if (pendingSnapshotImport && existsSync(pendingSnapshotImport)) {
|
|
447
|
-
args.push('--import-snapshot', pendingSnapshotImport)
|
|
448
|
-
logDebug(`Will import snapshot: ${pendingSnapshotImport}`)
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
logDebug(`Starting meilisearch with args: ${args.join(' ')}`)
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Check log file for startup errors
|
|
455
|
-
*/
|
|
456
|
-
const checkLogForError = async (): Promise<string | null> => {
|
|
457
|
-
try {
|
|
458
|
-
const logContent = await readFile(logFile, 'utf-8')
|
|
459
|
-
const recentLog = logContent.slice(-2000) // Last 2KB
|
|
460
|
-
|
|
461
|
-
if (
|
|
462
|
-
recentLog.includes('Address already in use') ||
|
|
463
|
-
recentLog.includes('bind: Address already in use')
|
|
464
|
-
) {
|
|
465
|
-
return `Port ${port} is already in use`
|
|
466
|
-
}
|
|
467
|
-
if (recentLog.includes('Failed to bind')) {
|
|
468
|
-
return `Port ${port} is already in use`
|
|
469
|
-
}
|
|
470
|
-
} catch {
|
|
471
|
-
// Log file might not exist yet
|
|
472
|
-
}
|
|
473
|
-
return null
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Meilisearch runs in foreground, so we need to spawn detached
|
|
477
|
-
if (isWindows()) {
|
|
478
|
-
return new Promise((resolve, reject) => {
|
|
479
|
-
const spawnOpts: SpawnOptions = {
|
|
480
|
-
cwd: containerDir,
|
|
481
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
482
|
-
detached: true,
|
|
483
|
-
windowsHide: true,
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const proc = spawn(meilisearchServer, args, spawnOpts)
|
|
487
|
-
let settled = false
|
|
488
|
-
let stderrOutput = ''
|
|
489
|
-
let stdoutOutput = ''
|
|
490
|
-
|
|
491
|
-
proc.on('error', (err) => {
|
|
492
|
-
if (settled) return
|
|
493
|
-
settled = true
|
|
494
|
-
reject(
|
|
495
|
-
new Error(`Failed to spawn Meilisearch server: ${err.message}`),
|
|
496
|
-
)
|
|
497
|
-
})
|
|
498
|
-
|
|
499
|
-
proc.on('exit', (code, signal) => {
|
|
500
|
-
if (settled) return
|
|
501
|
-
settled = true
|
|
502
|
-
const reason = signal ? `signal ${signal}` : `code ${code}`
|
|
503
|
-
reject(
|
|
504
|
-
new Error(
|
|
505
|
-
`Meilisearch process exited unexpectedly (${reason}).\n` +
|
|
506
|
-
`Stderr: ${stderrOutput || '(none)'}\n` +
|
|
507
|
-
`Stdout: ${stdoutOutput || '(none)'}`,
|
|
508
|
-
),
|
|
509
|
-
)
|
|
510
|
-
})
|
|
511
|
-
|
|
512
|
-
proc.stdout?.on('data', (data: Buffer) => {
|
|
513
|
-
const str = data.toString()
|
|
514
|
-
stdoutOutput += str
|
|
515
|
-
logDebug(`meilisearch stdout: ${str}`)
|
|
516
|
-
})
|
|
517
|
-
proc.stderr?.on('data', (data: Buffer) => {
|
|
518
|
-
const str = data.toString()
|
|
519
|
-
stderrOutput += str
|
|
520
|
-
logDebug(`meilisearch stderr: ${str}`)
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
proc.unref()
|
|
524
|
-
|
|
525
|
-
setTimeout(async () => {
|
|
526
|
-
if (settled) return
|
|
527
|
-
|
|
528
|
-
if (!proc.pid) {
|
|
529
|
-
settled = true
|
|
530
|
-
reject(
|
|
531
|
-
new Error('Meilisearch server process failed to start (no PID)'),
|
|
532
|
-
)
|
|
533
|
-
return
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
try {
|
|
537
|
-
await writeFile(pidFile, String(proc.pid))
|
|
538
|
-
} catch {
|
|
539
|
-
// Non-fatal
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const ready = await this.waitForReady(port)
|
|
543
|
-
if (settled) return
|
|
544
|
-
|
|
545
|
-
if (ready) {
|
|
546
|
-
settled = true
|
|
547
|
-
// Clean up pending snapshot import marker if it exists
|
|
548
|
-
if (existsSync(importMarkerPath)) {
|
|
549
|
-
try {
|
|
550
|
-
await unlink(importMarkerPath)
|
|
551
|
-
logDebug('Cleaned up pending snapshot import marker')
|
|
552
|
-
} catch {
|
|
553
|
-
// Non-fatal
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
resolve({
|
|
557
|
-
port,
|
|
558
|
-
connectionString: this.getConnectionString(container),
|
|
559
|
-
})
|
|
560
|
-
} else {
|
|
561
|
-
settled = true
|
|
562
|
-
|
|
563
|
-
// Clean up the orphaned detached process before rejecting
|
|
564
|
-
if (proc.pid && platformService.isProcessRunning(proc.pid)) {
|
|
565
|
-
try {
|
|
566
|
-
await platformService.terminateProcess(proc.pid, true)
|
|
567
|
-
} catch {
|
|
568
|
-
// Ignore cleanup errors - best effort
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
const portError = await checkLogForError()
|
|
573
|
-
|
|
574
|
-
const errorDetails = [
|
|
575
|
-
portError || 'Meilisearch failed to start within timeout.',
|
|
576
|
-
`Binary: ${meilisearchServer}`,
|
|
577
|
-
`Log file: ${logFile}`,
|
|
578
|
-
stderrOutput ? `Stderr:\n${stderrOutput}` : '',
|
|
579
|
-
stdoutOutput ? `Stdout:\n${stdoutOutput}` : '',
|
|
580
|
-
]
|
|
581
|
-
.filter(Boolean)
|
|
582
|
-
.join('\n')
|
|
583
|
-
|
|
584
|
-
reject(new Error(errorDetails))
|
|
585
|
-
}
|
|
586
|
-
}, START_CHECK_DELAY_MS)
|
|
587
|
-
})
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// macOS/Linux: spawn with ignored stdio so Node.js can exit cleanly
|
|
591
|
-
const proc = spawn(meilisearchServer, args, {
|
|
592
|
-
cwd: containerDir,
|
|
593
|
-
stdio: ['ignore', 'ignore', 'ignore'],
|
|
594
|
-
detached: true,
|
|
595
|
-
})
|
|
596
|
-
proc.unref()
|
|
597
|
-
|
|
598
|
-
if (!proc.pid) {
|
|
599
|
-
throw new Error('Meilisearch server process failed to start (no PID)')
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
try {
|
|
603
|
-
await writeFile(pidFile, String(proc.pid))
|
|
604
|
-
} catch {
|
|
605
|
-
// Non-fatal
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Wait for Meilisearch to be ready
|
|
609
|
-
const ready = await this.waitForReady(port)
|
|
610
|
-
|
|
611
|
-
if (ready) {
|
|
612
|
-
// Clean up pending snapshot import marker if it exists
|
|
613
|
-
if (existsSync(importMarkerPath)) {
|
|
614
|
-
try {
|
|
615
|
-
await unlink(importMarkerPath)
|
|
616
|
-
logDebug('Cleaned up pending snapshot import marker')
|
|
617
|
-
} catch {
|
|
618
|
-
// Non-fatal
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
return {
|
|
622
|
-
port,
|
|
623
|
-
connectionString: this.getConnectionString(container),
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// Clean up the orphaned detached process before throwing
|
|
628
|
-
if (proc.pid) {
|
|
629
|
-
try {
|
|
630
|
-
// Try to kill the process group first (POSIX)
|
|
631
|
-
process.kill(-proc.pid, 'SIGTERM')
|
|
632
|
-
logDebug(`Killed process group ${proc.pid}`)
|
|
633
|
-
} catch {
|
|
634
|
-
// Process group kill failed, try individual process
|
|
635
|
-
try {
|
|
636
|
-
process.kill(proc.pid, 'SIGTERM')
|
|
637
|
-
logDebug(`Killed process ${proc.pid}`)
|
|
638
|
-
} catch {
|
|
639
|
-
// Ignore - process may have already exited
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Clean up PID file
|
|
645
|
-
if (existsSync(pidFile)) {
|
|
646
|
-
try {
|
|
647
|
-
await unlink(pidFile)
|
|
648
|
-
} catch {
|
|
649
|
-
// Non-fatal
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
const portError = await checkLogForError()
|
|
654
|
-
|
|
655
|
-
const errorDetails = [
|
|
656
|
-
portError || 'Meilisearch failed to start within timeout.',
|
|
657
|
-
`Binary: ${meilisearchServer}`,
|
|
658
|
-
`Log file: ${logFile}`,
|
|
659
|
-
]
|
|
660
|
-
.filter(Boolean)
|
|
661
|
-
.join('\n')
|
|
662
|
-
|
|
663
|
-
throw new Error(errorDetails)
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// Wait for Meilisearch to be ready to accept connections
|
|
667
|
-
private async waitForReady(
|
|
668
|
-
port: number,
|
|
669
|
-
timeoutMs = 30000,
|
|
670
|
-
): Promise<boolean> {
|
|
671
|
-
const startTime = Date.now()
|
|
672
|
-
const checkInterval = 500
|
|
673
|
-
|
|
674
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
675
|
-
try {
|
|
676
|
-
// Use REST API health check
|
|
677
|
-
// Meilisearch uses /health (not /healthz like Qdrant)
|
|
678
|
-
const response = await meilisearchApiRequest(port, 'GET', '/health')
|
|
679
|
-
if (response.status === 200) {
|
|
680
|
-
logDebug(`Meilisearch ready on port ${port}`)
|
|
681
|
-
return true
|
|
682
|
-
}
|
|
683
|
-
} catch {
|
|
684
|
-
// Connection failed, wait and retry
|
|
685
|
-
}
|
|
686
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval))
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
logDebug(`Meilisearch did not become ready within ${timeoutMs}ms`)
|
|
690
|
-
return false
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Stop Meilisearch server
|
|
695
|
-
* Uses process termination
|
|
696
|
-
*/
|
|
697
|
-
async stop(container: ContainerConfig): Promise<void> {
|
|
698
|
-
const { name, port } = container
|
|
699
|
-
const containerDir = paths.getContainerPath(name, { engine: ENGINE })
|
|
700
|
-
const pidFile = join(containerDir, 'meilisearch.pid')
|
|
701
|
-
|
|
702
|
-
logDebug(`Stopping Meilisearch container "${name}" on port ${port}`)
|
|
703
|
-
|
|
704
|
-
// Get PID and terminate
|
|
705
|
-
let pid: number | null = null
|
|
706
|
-
|
|
707
|
-
if (existsSync(pidFile)) {
|
|
708
|
-
try {
|
|
709
|
-
const content = await readFile(pidFile, 'utf8')
|
|
710
|
-
pid = parseInt(content.trim(), 10)
|
|
711
|
-
} catch {
|
|
712
|
-
// Ignore
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// Kill process if running
|
|
717
|
-
// On Windows, use force kill immediately (graceful shutdown often doesn't release resources)
|
|
718
|
-
if (pid && platformService.isProcessRunning(pid)) {
|
|
719
|
-
logDebug(`Killing Meilisearch process ${pid}`)
|
|
720
|
-
try {
|
|
721
|
-
// On Windows, skip graceful termination - it often doesn't release file handles
|
|
722
|
-
if (isWindows()) {
|
|
723
|
-
await platformService.terminateProcess(pid, true)
|
|
724
|
-
} else {
|
|
725
|
-
await platformService.terminateProcess(pid, false)
|
|
726
|
-
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
727
|
-
|
|
728
|
-
if (platformService.isProcessRunning(pid)) {
|
|
729
|
-
logWarning(`Graceful termination failed, force killing ${pid}`)
|
|
730
|
-
await platformService.terminateProcess(pid, true)
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
} catch (error) {
|
|
734
|
-
logDebug(`Process termination error: ${error}`)
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// Wait for process to fully terminate
|
|
739
|
-
if (isWindows()) {
|
|
740
|
-
await new Promise((resolve) => setTimeout(resolve, 3000))
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Kill any processes still listening on the port
|
|
744
|
-
const portPids = await platformService.findProcessByPort(port)
|
|
745
|
-
for (const portPid of portPids) {
|
|
746
|
-
if (platformService.isProcessRunning(portPid)) {
|
|
747
|
-
logDebug(`Killing process ${portPid} still on port ${port}`)
|
|
748
|
-
try {
|
|
749
|
-
await platformService.terminateProcess(portPid, true)
|
|
750
|
-
} catch {
|
|
751
|
-
// Ignore
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
// On Windows, wait again after killing port processes
|
|
757
|
-
if (isWindows() && portPids.length > 0) {
|
|
758
|
-
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
// Cleanup PID file
|
|
762
|
-
if (existsSync(pidFile)) {
|
|
763
|
-
try {
|
|
764
|
-
await unlink(pidFile)
|
|
765
|
-
} catch {
|
|
766
|
-
// Ignore
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// On Windows, wait for ports to be released
|
|
771
|
-
if (isWindows()) {
|
|
772
|
-
logDebug(`Waiting for port ${port} to be released...`)
|
|
773
|
-
const portWaitStart = Date.now()
|
|
774
|
-
const portWaitTimeout = 30000 // 30 seconds max
|
|
775
|
-
const checkInterval = 500
|
|
776
|
-
|
|
777
|
-
while (Date.now() - portWaitStart < portWaitTimeout) {
|
|
778
|
-
const httpAvailable = await portManager.isPortAvailable(port)
|
|
779
|
-
|
|
780
|
-
if (httpAvailable) {
|
|
781
|
-
logDebug('Port released successfully')
|
|
782
|
-
break
|
|
783
|
-
}
|
|
784
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval))
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
logDebug('Meilisearch stopped')
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
// Get Meilisearch server status
|
|
792
|
-
async status(container: ContainerConfig): Promise<StatusResult> {
|
|
793
|
-
const { name, port } = container
|
|
794
|
-
const containerDir = paths.getContainerPath(name, { engine: ENGINE })
|
|
795
|
-
const pidFile = join(containerDir, 'meilisearch.pid')
|
|
796
|
-
|
|
797
|
-
// Try health check via REST API
|
|
798
|
-
try {
|
|
799
|
-
const response = await meilisearchApiRequest(port, 'GET', '/health')
|
|
800
|
-
if (response.status === 200) {
|
|
801
|
-
return { running: true, message: 'Meilisearch is running' }
|
|
802
|
-
}
|
|
803
|
-
} catch {
|
|
804
|
-
// Not responding, check PID
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// Check PID file
|
|
808
|
-
if (existsSync(pidFile)) {
|
|
809
|
-
try {
|
|
810
|
-
const content = await readFile(pidFile, 'utf8')
|
|
811
|
-
const pid = parseInt(content.trim(), 10)
|
|
812
|
-
if (!isNaN(pid) && pid > 0 && platformService.isProcessRunning(pid)) {
|
|
813
|
-
return {
|
|
814
|
-
running: true,
|
|
815
|
-
message: `Meilisearch is running (PID: ${pid})`,
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
} catch {
|
|
819
|
-
// Ignore
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
return { running: false, message: 'Meilisearch is not running' }
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
// Detect backup format
|
|
827
|
-
async detectBackupFormat(filePath: string): Promise<BackupFormat> {
|
|
828
|
-
return detectBackupFormatImpl(filePath)
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
/**
|
|
832
|
-
* Restore a backup
|
|
833
|
-
* IMPORTANT: Meilisearch must be stopped before restore
|
|
834
|
-
*/
|
|
835
|
-
async restore(
|
|
836
|
-
container: ContainerConfig,
|
|
837
|
-
backupPath: string,
|
|
838
|
-
_options: { database?: string; flush?: boolean } = {},
|
|
839
|
-
): Promise<RestoreResult> {
|
|
840
|
-
const { name } = container
|
|
841
|
-
|
|
842
|
-
// Check if container is running - Meilisearch must be stopped for snapshot restore
|
|
843
|
-
const statusResult = await this.status(container)
|
|
844
|
-
if (statusResult.running) {
|
|
845
|
-
throw new Error(
|
|
846
|
-
`Meilisearch container "${name}" must be stopped before restore. ` +
|
|
847
|
-
`Run: spindb stop ${name}`,
|
|
848
|
-
)
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const dataDir = paths.getContainerDataPath(name, { engine: ENGINE })
|
|
852
|
-
|
|
853
|
-
return restoreBackup(backupPath, {
|
|
854
|
-
containerName: name,
|
|
855
|
-
dataDir,
|
|
856
|
-
})
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
/**
|
|
860
|
-
* Get connection string
|
|
861
|
-
* Format: http://127.0.0.1:PORT
|
|
862
|
-
*/
|
|
863
|
-
getConnectionString(container: ContainerConfig, _database?: string): string {
|
|
864
|
-
const { port } = container
|
|
865
|
-
return `http://127.0.0.1:${port}`
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// Open HTTP API (Meilisearch uses REST API, no interactive shell)
|
|
869
|
-
async connect(container: ContainerConfig, _database?: string): Promise<void> {
|
|
870
|
-
const { port } = container
|
|
871
|
-
const url = `http://127.0.0.1:${port}`
|
|
872
|
-
|
|
873
|
-
console.log(`Meilisearch REST API available at: ${url}`)
|
|
874
|
-
console.log(`Meilisearch Dashboard: ${url}`)
|
|
875
|
-
console.log('')
|
|
876
|
-
console.log('Example commands:')
|
|
877
|
-
console.log(` curl ${url}/indexes`)
|
|
878
|
-
console.log(` curl ${url}/health`)
|
|
879
|
-
console.log(` curl ${url}/stats`)
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
/**
|
|
883
|
-
* Create a new index
|
|
884
|
-
* Meilisearch uses indexes instead of traditional databases
|
|
885
|
-
*/
|
|
886
|
-
async createDatabase(
|
|
887
|
-
container: ContainerConfig,
|
|
888
|
-
database: string,
|
|
889
|
-
): Promise<void> {
|
|
890
|
-
const { port } = container
|
|
891
|
-
|
|
892
|
-
// Create an index with the given name as the primary key
|
|
893
|
-
const response = await meilisearchApiRequest(port, 'POST', '/indexes', {
|
|
894
|
-
uid: database,
|
|
895
|
-
primaryKey: 'id',
|
|
896
|
-
})
|
|
897
|
-
|
|
898
|
-
// Meilisearch returns 202 Accepted for async operations
|
|
899
|
-
if (response.status !== 202 && response.status !== 200) {
|
|
900
|
-
throw new Error(
|
|
901
|
-
`Failed to create index: ${JSON.stringify(response.data)}`,
|
|
902
|
-
)
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
logDebug(`Created Meilisearch index: ${database}`)
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
/**
|
|
909
|
-
* Drop an index
|
|
910
|
-
*/
|
|
911
|
-
async dropDatabase(
|
|
912
|
-
container: ContainerConfig,
|
|
913
|
-
database: string,
|
|
914
|
-
): Promise<void> {
|
|
915
|
-
const { port } = container
|
|
916
|
-
|
|
917
|
-
const response = await meilisearchApiRequest(
|
|
918
|
-
port,
|
|
919
|
-
'DELETE',
|
|
920
|
-
`/indexes/${database}`,
|
|
921
|
-
)
|
|
922
|
-
|
|
923
|
-
// Meilisearch returns 202 Accepted for async delete
|
|
924
|
-
if (response.status !== 202 && response.status !== 200) {
|
|
925
|
-
throw new Error(
|
|
926
|
-
`Failed to delete index: ${JSON.stringify(response.data)}`,
|
|
927
|
-
)
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
logDebug(`Deleted Meilisearch index: ${database}`)
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
/**
|
|
934
|
-
* Get the storage size of the Meilisearch instance
|
|
935
|
-
*/
|
|
936
|
-
async getDatabaseSize(container: ContainerConfig): Promise<number | null> {
|
|
937
|
-
const { port } = container
|
|
938
|
-
|
|
939
|
-
try {
|
|
940
|
-
const response = await meilisearchApiRequest(port, 'GET', '/stats')
|
|
941
|
-
if (response.status === 200) {
|
|
942
|
-
const stats = response.data as { databaseSize?: number }
|
|
943
|
-
return stats.databaseSize ?? null
|
|
944
|
-
}
|
|
945
|
-
return null
|
|
946
|
-
} catch {
|
|
947
|
-
return null
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
* Dump from a remote Meilisearch connection
|
|
953
|
-
* Uses Meilisearch's REST API to create and download a dump
|
|
954
|
-
*
|
|
955
|
-
* Connection string format: http://host:port or meilisearch://host:port
|
|
956
|
-
* For API key auth: http://host:port?api_key=YOUR_KEY
|
|
957
|
-
*/
|
|
958
|
-
async dumpFromConnectionString(
|
|
959
|
-
connectionString: string,
|
|
960
|
-
outputPath: string,
|
|
961
|
-
): Promise<DumpResult> {
|
|
962
|
-
// Parse connection string
|
|
963
|
-
const { baseUrl, headers } =
|
|
964
|
-
parseMeilisearchConnectionString(connectionString)
|
|
965
|
-
|
|
966
|
-
logDebug(`Connecting to remote Meilisearch at ${baseUrl}`)
|
|
967
|
-
|
|
968
|
-
// Check connectivity and get index count
|
|
969
|
-
const indexesResponse = await remoteMeilisearchRequest(
|
|
970
|
-
baseUrl,
|
|
971
|
-
'GET',
|
|
972
|
-
'/indexes',
|
|
973
|
-
headers,
|
|
974
|
-
)
|
|
975
|
-
if (indexesResponse.status !== 200) {
|
|
976
|
-
throw new Error(
|
|
977
|
-
`Failed to connect to Meilisearch at ${baseUrl}: ${JSON.stringify(indexesResponse.data)}`,
|
|
978
|
-
)
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
const indexesData = indexesResponse.data as {
|
|
982
|
-
results?: Array<{ uid: string }>
|
|
983
|
-
}
|
|
984
|
-
const indexCount = indexesData.results?.length ?? 0
|
|
985
|
-
|
|
986
|
-
logDebug(`Found ${indexCount} indexes on remote server`)
|
|
987
|
-
|
|
988
|
-
// Create a dump on the remote server
|
|
989
|
-
logDebug('Creating dump on remote server...')
|
|
990
|
-
const dumpResponse = await remoteMeilisearchRequest(
|
|
991
|
-
baseUrl,
|
|
992
|
-
'POST',
|
|
993
|
-
'/dumps',
|
|
994
|
-
headers,
|
|
995
|
-
)
|
|
996
|
-
|
|
997
|
-
// Meilisearch returns 202 Accepted
|
|
998
|
-
if (dumpResponse.status !== 202 && dumpResponse.status !== 200) {
|
|
999
|
-
throw new Error(
|
|
1000
|
-
`Failed to create dump on remote Meilisearch: ${JSON.stringify(dumpResponse.data)}`,
|
|
1001
|
-
)
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
const dumpData = dumpResponse.data as { taskUid?: number }
|
|
1005
|
-
const taskUid = dumpData?.taskUid
|
|
1006
|
-
|
|
1007
|
-
if (taskUid === undefined) {
|
|
1008
|
-
throw new Error('Meilisearch dump creation failed: no task UID returned')
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
logDebug(`Remote dump task created: ${taskUid}`)
|
|
1012
|
-
|
|
1013
|
-
// Wait for task to complete
|
|
1014
|
-
const maxWait = 5 * 60 * 1000 // 5 minutes
|
|
1015
|
-
const startTime = Date.now()
|
|
1016
|
-
|
|
1017
|
-
while (Date.now() - startTime < maxWait) {
|
|
1018
|
-
const taskResponse = await remoteMeilisearchRequest(
|
|
1019
|
-
baseUrl,
|
|
1020
|
-
'GET',
|
|
1021
|
-
`/tasks/${taskUid}`,
|
|
1022
|
-
headers,
|
|
1023
|
-
)
|
|
1024
|
-
|
|
1025
|
-
if (taskResponse.status === 200) {
|
|
1026
|
-
const task = taskResponse.data as {
|
|
1027
|
-
status?: string
|
|
1028
|
-
details?: { dumpUid?: string }
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
if (task.status === 'succeeded') {
|
|
1032
|
-
logDebug(`Dump task succeeded: ${task.details?.dumpUid}`)
|
|
1033
|
-
// Note: Meilisearch stores dumps locally on the server
|
|
1034
|
-
// We cannot download them via REST API like Qdrant snapshots
|
|
1035
|
-
// The user needs to access the server's filesystem
|
|
1036
|
-
|
|
1037
|
-
return {
|
|
1038
|
-
filePath: outputPath,
|
|
1039
|
-
warnings: [
|
|
1040
|
-
`Dump created on remote server. Meilisearch does not support downloading dumps via REST API.`,
|
|
1041
|
-
`The dump is stored on the server in the dumps directory.`,
|
|
1042
|
-
indexCount === 0
|
|
1043
|
-
? 'Remote Meilisearch instance has no indexes'
|
|
1044
|
-
: undefined,
|
|
1045
|
-
].filter((w): w is string => w !== undefined),
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
if (task.status === 'failed') {
|
|
1050
|
-
throw new Error(
|
|
1051
|
-
`Meilisearch dump task failed: ${JSON.stringify(task)}`,
|
|
1052
|
-
)
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
await new Promise((r) => setTimeout(r, 1000))
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
throw new Error('Meilisearch dump task did not complete within timeout')
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
// Create a backup
|
|
1063
|
-
async backup(
|
|
1064
|
-
container: ContainerConfig,
|
|
1065
|
-
outputPath: string,
|
|
1066
|
-
options: BackupOptions,
|
|
1067
|
-
): Promise<BackupResult> {
|
|
1068
|
-
return createBackup(container, outputPath, options)
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// Run a command - Meilisearch uses REST API, not command files
|
|
1072
|
-
async runScript(
|
|
1073
|
-
container: ContainerConfig,
|
|
1074
|
-
options: { file?: string; sql?: string; database?: string },
|
|
1075
|
-
): Promise<void> {
|
|
1076
|
-
const { port } = container
|
|
1077
|
-
|
|
1078
|
-
if (options.file) {
|
|
1079
|
-
throw new Error(
|
|
1080
|
-
'Meilisearch does not support command files. Use the REST API directly.\n' +
|
|
1081
|
-
`Example: curl -X POST http://127.0.0.1:${port}/indexes`,
|
|
1082
|
-
)
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
if (options.sql) {
|
|
1086
|
-
// Try to interpret as a simple command (e.g., "LIST INDEXES")
|
|
1087
|
-
const command = options.sql.trim().toUpperCase()
|
|
1088
|
-
|
|
1089
|
-
if (command === 'LIST INDEXES' || command === 'SHOW INDEXES') {
|
|
1090
|
-
const response = await meilisearchApiRequest(port, 'GET', '/indexes')
|
|
1091
|
-
console.log(JSON.stringify(response.data, null, 2))
|
|
1092
|
-
return
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
throw new Error(
|
|
1096
|
-
'Meilisearch uses REST API for operations. Use curl or the Meilisearch client libraries.\n' +
|
|
1097
|
-
`API endpoint: http://127.0.0.1:${port}`,
|
|
1098
|
-
)
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
throw new Error('Either file or sql option must be provided')
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
/**
|
|
1105
|
-
* Execute a query via REST API
|
|
1106
|
-
*
|
|
1107
|
-
* Query format: METHOD /path [JSON body]
|
|
1108
|
-
* Examples:
|
|
1109
|
-
* GET /indexes
|
|
1110
|
-
* POST /indexes/movies/search {"q": "action"}
|
|
1111
|
-
*/
|
|
1112
|
-
async executeQuery(
|
|
1113
|
-
container: ContainerConfig,
|
|
1114
|
-
query: string,
|
|
1115
|
-
options?: QueryOptions,
|
|
1116
|
-
): Promise<QueryResult> {
|
|
1117
|
-
const { port } = container
|
|
1118
|
-
|
|
1119
|
-
// Parse the query string: METHOD /path [body]
|
|
1120
|
-
const trimmed = query.trim()
|
|
1121
|
-
const spaceIdx = trimmed.indexOf(' ')
|
|
1122
|
-
|
|
1123
|
-
if (spaceIdx === -1) {
|
|
1124
|
-
throw new Error(
|
|
1125
|
-
'Invalid query format. Expected: METHOD /path [body]\n' +
|
|
1126
|
-
'Example: GET /indexes',
|
|
1127
|
-
)
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
const method = (options?.method ||
|
|
1131
|
-
trimmed.substring(0, spaceIdx).toUpperCase()) as
|
|
1132
|
-
| 'GET'
|
|
1133
|
-
| 'POST'
|
|
1134
|
-
| 'PUT'
|
|
1135
|
-
| 'DELETE'
|
|
1136
|
-
const rest = trimmed.substring(spaceIdx + 1).trim()
|
|
1137
|
-
|
|
1138
|
-
// Extract path and optional JSON body
|
|
1139
|
-
let path: string
|
|
1140
|
-
let body: Record<string, unknown> | undefined = options?.body
|
|
1141
|
-
|
|
1142
|
-
const bodyStart = rest.indexOf('{')
|
|
1143
|
-
if (bodyStart !== -1) {
|
|
1144
|
-
// Always extract path without the JSON blob
|
|
1145
|
-
path = rest.substring(0, bodyStart).trim()
|
|
1146
|
-
if (options?.body) {
|
|
1147
|
-
// Both inline JSON and options.body provided - error
|
|
1148
|
-
throw new Error(
|
|
1149
|
-
'Cannot specify both inline JSON body in query and options.body. Use one or the other.',
|
|
1150
|
-
)
|
|
1151
|
-
}
|
|
1152
|
-
try {
|
|
1153
|
-
body = JSON.parse(rest.substring(bodyStart)) as Record<string, unknown>
|
|
1154
|
-
} catch {
|
|
1155
|
-
throw new Error('Invalid JSON body in query')
|
|
1156
|
-
}
|
|
1157
|
-
} else {
|
|
1158
|
-
path = rest
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
// Ensure path starts with /
|
|
1162
|
-
if (!path.startsWith('/')) {
|
|
1163
|
-
path = '/' + path
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
const response = await meilisearchApiRequest(port, method, path, body)
|
|
1167
|
-
|
|
1168
|
-
if (response.status >= 400) {
|
|
1169
|
-
throw new Error(
|
|
1170
|
-
`Meilisearch API error (${response.status}): ${JSON.stringify(response.data)}`,
|
|
1171
|
-
)
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
return parseRESTAPIResult(JSON.stringify(response.data))
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
/**
|
|
1178
|
-
* List databases for Meilisearch.
|
|
1179
|
-
* Meilisearch uses indexes, so we query the /indexes endpoint.
|
|
1180
|
-
*/
|
|
1181
|
-
async listDatabases(container: ContainerConfig): Promise<string[]> {
|
|
1182
|
-
const { port } = container
|
|
1183
|
-
|
|
1184
|
-
try {
|
|
1185
|
-
const response = await meilisearchApiRequest(port, 'GET', '/indexes')
|
|
1186
|
-
if (response.status === 200 && response.data) {
|
|
1187
|
-
// Response is { results: [{ uid: "index_name", ... }, ...], ... }
|
|
1188
|
-
const data = response.data as { results?: Array<{ uid: string }> }
|
|
1189
|
-
if (Array.isArray(data.results)) {
|
|
1190
|
-
const indexes = data.results.map((index) => index.uid)
|
|
1191
|
-
return indexes.length > 0 ? indexes : [container.database]
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
// Fall back to configured database
|
|
1195
|
-
return [container.database]
|
|
1196
|
-
} catch {
|
|
1197
|
-
// On error, fall back to configured database
|
|
1198
|
-
return [container.database]
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
async createUser(
|
|
1203
|
-
container: ContainerConfig,
|
|
1204
|
-
options: CreateUserOptions,
|
|
1205
|
-
): Promise<UserCredentials> {
|
|
1206
|
-
const { username } = options
|
|
1207
|
-
assertValidUsername(username)
|
|
1208
|
-
const { port } = container
|
|
1209
|
-
|
|
1210
|
-
// Meilisearch requires a master key to create API keys
|
|
1211
|
-
// Check if the /keys endpoint is available
|
|
1212
|
-
const keysResponse = await meilisearchApiRequest(port, 'GET', '/keys')
|
|
1213
|
-
|
|
1214
|
-
if (keysResponse.status === 403 || keysResponse.status === 401) {
|
|
1215
|
-
throw new UnsupportedOperationError(
|
|
1216
|
-
'createUser',
|
|
1217
|
-
this.displayName,
|
|
1218
|
-
'Meilisearch is running without a master key. API key management requires a master key. ' +
|
|
1219
|
-
'Restart the container with a master key to enable user/key management.',
|
|
1220
|
-
)
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// Derive a deterministic UID from the username so createUser is idempotent.
|
|
1224
|
-
// Meilisearch UIDs are UUIDv4 format; we derive one via a stable hash.
|
|
1225
|
-
const { createHash } = await import('crypto')
|
|
1226
|
-
const hashBuf = createHash('md5').update(`spindb:${username}`).digest()
|
|
1227
|
-
// Set version (4) and variant (RFC 4122) bits for valid UUIDv4
|
|
1228
|
-
hashBuf[6] = (hashBuf[6] & 0x0f) | 0x40
|
|
1229
|
-
hashBuf[8] = (hashBuf[8] & 0x3f) | 0x80
|
|
1230
|
-
const hash = hashBuf.toString('hex')
|
|
1231
|
-
const uid = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`
|
|
1232
|
-
|
|
1233
|
-
// Check if a key with this UID already exists
|
|
1234
|
-
const existingResponse = await meilisearchApiRequest(
|
|
1235
|
-
port,
|
|
1236
|
-
'GET',
|
|
1237
|
-
`/keys/${uid}`,
|
|
1238
|
-
)
|
|
1239
|
-
|
|
1240
|
-
let apiKey: string
|
|
1241
|
-
|
|
1242
|
-
if (existingResponse.status === 200) {
|
|
1243
|
-
// Key already exists — return it
|
|
1244
|
-
const existingData = existingResponse.data as { key?: string }
|
|
1245
|
-
if (!existingData.key) {
|
|
1246
|
-
throw new Error('Existing API key response missing key property')
|
|
1247
|
-
}
|
|
1248
|
-
apiKey = existingData.key
|
|
1249
|
-
logDebug(`Found existing Meilisearch API key: ${username}`)
|
|
1250
|
-
} else if (existingResponse.status !== 404) {
|
|
1251
|
-
// Unexpected error (e.g., 401, 403, 429, 500) — surface it instead of silently creating a new key
|
|
1252
|
-
throw new Error(
|
|
1253
|
-
`Failed to check existing API key (HTTP ${existingResponse.status}): ${JSON.stringify(existingResponse.data)}`,
|
|
1254
|
-
)
|
|
1255
|
-
} else {
|
|
1256
|
-
// Create a new API key with the deterministic UID
|
|
1257
|
-
const response = await meilisearchApiRequest(port, 'POST', '/keys', {
|
|
1258
|
-
uid,
|
|
1259
|
-
description: username,
|
|
1260
|
-
actions: ['*'],
|
|
1261
|
-
indexes: ['*'],
|
|
1262
|
-
expiresAt: null,
|
|
1263
|
-
} as unknown as Record<string, unknown>)
|
|
1264
|
-
|
|
1265
|
-
if (response.status !== 201 && response.status !== 200) {
|
|
1266
|
-
throw new Error(
|
|
1267
|
-
`Failed to create API key: ${JSON.stringify(response.data)}`,
|
|
1268
|
-
)
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
const data = response.data as { key?: string }
|
|
1272
|
-
if (!data.key) {
|
|
1273
|
-
throw new Error('API key creation response missing key property')
|
|
1274
|
-
}
|
|
1275
|
-
apiKey = data.key
|
|
1276
|
-
logDebug(`Created Meilisearch API key: ${username}`)
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
const connectionString = `http://127.0.0.1:${port}`
|
|
1280
|
-
|
|
1281
|
-
return {
|
|
1282
|
-
username,
|
|
1283
|
-
password: '',
|
|
1284
|
-
connectionString,
|
|
1285
|
-
engine: container.engine,
|
|
1286
|
-
container: container.name,
|
|
1287
|
-
apiKey,
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
export const meilisearchEngine = new MeilisearchEngine()
|