spindb 0.15.1 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +176 -81
  2. package/bin/cli.js +39 -10
  3. package/cli/commands/backup.ts +4 -1
  4. package/cli/commands/backups.ts +17 -23
  5. package/cli/commands/config.ts +1 -3
  6. package/cli/commands/connect.ts +16 -2
  7. package/cli/commands/create.ts +18 -9
  8. package/cli/commands/deps.ts +1 -3
  9. package/cli/commands/doctor.ts +29 -16
  10. package/cli/commands/edit.ts +4 -12
  11. package/cli/commands/engines.ts +730 -52
  12. package/cli/commands/list.ts +1 -3
  13. package/cli/commands/menu/backup-handlers.ts +36 -39
  14. package/cli/commands/menu/container-handlers.ts +6 -10
  15. package/cli/commands/menu/engine-handlers.ts +71 -639
  16. package/cli/commands/menu/shared.ts +2 -6
  17. package/cli/commands/menu/shell-handlers.ts +63 -16
  18. package/cli/commands/menu/sql-handlers.ts +10 -7
  19. package/cli/commands/run.ts +7 -2
  20. package/cli/commands/start.ts +10 -7
  21. package/cli/commands/stop.ts +9 -4
  22. package/cli/constants.ts +2 -1
  23. package/cli/helpers.ts +358 -357
  24. package/cli/ui/prompts.ts +8 -16
  25. package/cli/ui/spinner.ts +3 -9
  26. package/cli/utils/file-follower.ts +1 -3
  27. package/config/backup-formats.ts +42 -27
  28. package/config/engine-defaults.ts +25 -15
  29. package/config/engines-registry.ts +93 -0
  30. package/config/engines.json +109 -0
  31. package/config/engines.schema.json +117 -0
  32. package/config/os-dependencies.ts +72 -30
  33. package/config/paths.ts +7 -21
  34. package/core/backup-restore.ts +16 -32
  35. package/core/binary-manager.ts +165 -19
  36. package/core/config-manager.ts +187 -14
  37. package/core/dependency-manager.ts +13 -46
  38. package/core/error-handler.ts +1 -3
  39. package/core/homebrew-version-manager.ts +22 -22
  40. package/core/hostdb-client.ts +173 -0
  41. package/core/hostdb-metadata.ts +325 -0
  42. package/core/platform-service.ts +16 -72
  43. package/core/process-manager.ts +3 -1
  44. package/core/spawn-utils.ts +120 -0
  45. package/core/start-with-retry.ts +1 -3
  46. package/core/transaction-manager.ts +2 -6
  47. package/core/update-manager.ts +5 -15
  48. package/core/version-utils.ts +77 -0
  49. package/engines/base-engine.ts +29 -42
  50. package/engines/index.ts +6 -9
  51. package/engines/mariadb/backup.ts +8 -10
  52. package/engines/mariadb/binary-manager.ts +58 -138
  53. package/engines/mariadb/binary-urls.ts +3 -12
  54. package/engines/mariadb/hostdb-releases.ts +95 -180
  55. package/engines/mariadb/index.ts +24 -17
  56. package/engines/mariadb/restore.ts +10 -8
  57. package/engines/mariadb/version-maps.ts +21 -15
  58. package/engines/mariadb/version-validator.ts +12 -24
  59. package/engines/mongodb/backup.ts +2 -6
  60. package/engines/mongodb/binary-manager.ts +435 -0
  61. package/engines/mongodb/binary-urls.ts +71 -0
  62. package/engines/mongodb/cli-utils.ts +78 -0
  63. package/engines/mongodb/hostdb-releases.ts +182 -0
  64. package/engines/mongodb/index.ts +217 -152
  65. package/engines/mongodb/restore.ts +8 -16
  66. package/engines/mongodb/version-maps.ts +89 -0
  67. package/engines/mongodb/version-validator.ts +2 -6
  68. package/engines/mysql/backup.ts +13 -11
  69. package/engines/mysql/binary-detection.ts +116 -108
  70. package/engines/mysql/binary-manager.ts +395 -0
  71. package/engines/mysql/binary-urls.ts +122 -0
  72. package/engines/mysql/hostdb-releases.ts +199 -0
  73. package/engines/mysql/index.ts +356 -507
  74. package/engines/mysql/restore.ts +47 -13
  75. package/engines/mysql/version-maps.ts +88 -0
  76. package/engines/mysql/version-validator.ts +2 -6
  77. package/engines/postgresql/backup.ts +1 -3
  78. package/engines/postgresql/binary-manager.ts +63 -36
  79. package/engines/postgresql/binary-urls.ts +4 -15
  80. package/engines/postgresql/hostdb-releases.ts +101 -170
  81. package/engines/postgresql/index.ts +45 -70
  82. package/engines/postgresql/remote-version.ts +1 -3
  83. package/engines/postgresql/restore.ts +4 -12
  84. package/engines/postgresql/version-maps.ts +31 -8
  85. package/engines/postgresql/version-validator.ts +1 -3
  86. package/engines/redis/backup.ts +131 -100
  87. package/engines/redis/binary-manager.ts +471 -0
  88. package/engines/redis/binary-urls.ts +140 -0
  89. package/engines/redis/cli-utils.ts +44 -0
  90. package/engines/redis/hostdb-releases.ts +177 -0
  91. package/engines/redis/index.ts +285 -197
  92. package/engines/redis/restore.ts +54 -23
  93. package/engines/redis/version-maps.ts +80 -0
  94. package/engines/redis/version-validator.ts +1 -3
  95. package/engines/sqlite/binary-manager.ts +431 -0
  96. package/engines/sqlite/binary-urls.ts +120 -0
  97. package/engines/sqlite/index.ts +165 -64
  98. package/engines/sqlite/registry.ts +9 -27
  99. package/engines/sqlite/version-maps.ts +63 -0
  100. package/engines/valkey/backup.ts +389 -0
  101. package/engines/valkey/binary-manager.ts +473 -0
  102. package/engines/valkey/binary-urls.ts +143 -0
  103. package/engines/valkey/cli-utils.ts +44 -0
  104. package/engines/valkey/hostdb-releases.ts +182 -0
  105. package/engines/valkey/index.ts +1022 -0
  106. package/engines/valkey/restore.ts +415 -0
  107. package/engines/valkey/version-maps.ts +80 -0
  108. package/engines/valkey/version-validator.ts +131 -0
  109. package/package.json +11 -2
  110. package/types/index.ts +103 -21
  111. package/engines/mongodb/binary-detection.ts +0 -314
  112. package/engines/redis/binary-detection.ts +0 -442
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  **The first npm CLI for running local databases without Docker.**
9
9
 
10
- Spin up PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, and Redis instances for local development. No Docker daemon, no container networking, no volume mounts. Just databases running on localhost, ready in seconds.
10
+ Spin up PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, Redis, and Valkey instances for local development. No Docker daemon, no container networking, no volume mounts. Just databases running on localhost, ready in seconds.
11
11
 
12
12
  ---
13
13
 
@@ -136,7 +136,7 @@ You'll get an interactive menu with arrow-key navigation:
136
136
 
137
137
  | | |
138
138
  |---|---|
139
- | Versions | 14, 15, 16, 17, 18 |
139
+ | Versions | 15, 16, 17, 18 |
140
140
  | Default port | 5432 |
141
141
  | Default user | `postgres` |
142
142
  | Binary source | [hostdb](https://github.com/robertjbass/hostdb) (macOS/Linux), [EDB](https://www.enterprisedb.com/) (Windows) |
@@ -177,43 +177,39 @@ MariaDB is MySQL-compatible, so most MySQL tools and clients work seamlessly. If
177
177
 
178
178
  | | |
179
179
  |---|---|
180
- | Versions | Depends on system installation |
180
+ | Versions | 8.0, 8.4, 9 |
181
181
  | Default port | 3306 |
182
182
  | Default user | `root` |
183
- | Binary source | System installation |
183
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
184
184
 
185
- Unlike PostgreSQL, SpinDB uses your system's MySQL installation. While Oracle provides MySQL binary downloads, they require system libraries and configurationthere's no "unzip and run" distribution like zonky.io provides for PostgreSQL. For most local development, a single system-installed MySQL version works well.
185
+ SpinDB downloads MySQL server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releasesjust like PostgreSQL and MariaDB. This provides multi-version support and works across all platforms.
186
186
 
187
187
  ```bash
188
- # macOS
189
- brew install mysql
190
-
191
- # Ubuntu/Debian
192
- sudo apt install mysql-server
193
-
194
- # Windows (Chocolatey)
195
- choco install mysql
188
+ # Create a MySQL container
189
+ spindb create mydb --engine mysql
196
190
 
197
- # Windows (winget)
198
- winget install Oracle.MySQL
191
+ # Create with specific version
192
+ spindb create mydb --engine mysql --version 8.0
199
193
 
200
- # Check if SpinDB can find MySQL
194
+ # Check what's available
201
195
  spindb deps check --engine mysql
202
196
  ```
203
197
 
204
- **Linux users:** MariaDB is also available as a standalone engine with downloadable binaries. Use `spindb create mydb --engine mariadb` for the dedicated MariaDB engine.
198
+ **Client tools included:** MySQL binaries include `mysql`, `mysqldump`, and `mysqladmin` for all operations. No system installation required.
205
199
 
206
200
  #### SQLite
207
201
 
208
202
  | | |
209
203
  |---|---|
210
- | Version | 3 (system) |
204
+ | Version | 3 |
211
205
  | Default port | N/A (file-based) |
212
206
  | Data location | Project directory (CWD) |
213
- | Binary source | System installation |
207
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
214
208
 
215
209
  SQLite is a file-based database—no server process, no ports. Databases are stored in your project directory by default, not `~/.spindb/`. SpinDB tracks registered SQLite databases in a registry file.
216
210
 
211
+ **Tools included:** SQLite binaries include `sqlite3`, `sqldiff`, `sqlite3_analyzer`, and `sqlite3_rsync`. No system installation required.
212
+
217
213
  ```bash
218
214
  # Create in current directory
219
215
  spindb create mydb --engine sqlite
@@ -234,25 +230,21 @@ spindb connect mydb --litecli
234
230
 
235
231
  | | |
236
232
  |---|---|
237
- | Versions | 6.0, 7.0, 8.0 |
233
+ | Versions | 7.0, 8.0, 8.2 |
238
234
  | Default port | 27017 |
239
235
  | Default user | None (no auth by default) |
240
- | Binary source | System installation |
236
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
241
237
 
242
- Like MySQL, SpinDB uses your system's MongoDB installation. While MongoDB provides official binary downloads, they require additional configuration and system dependencies. SpinDB relies on your package manager to handle this setup.
238
+ SpinDB downloads MongoDB server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases—just like PostgreSQL, MariaDB, and MySQL. This provides multi-version support on all platforms.
243
239
 
244
240
  ```bash
245
- # macOS
246
- brew tap mongodb/brew
247
- brew install mongodb-community mongosh mongodb-database-tools
241
+ # Create a MongoDB container (downloads binaries automatically)
242
+ spindb create mydb --engine mongodb
248
243
 
249
- # Ubuntu/Debian (follow MongoDB's official guide)
250
- # https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/
244
+ # Create with specific version
245
+ spindb create mydb --engine mongodb --version 8.0
251
246
 
252
- # Windows (Chocolatey)
253
- choco install mongodb mongodb-shell mongodb-database-tools
254
-
255
- # Check if SpinDB can find MongoDB
247
+ # Check what's available
256
248
  spindb deps check --engine mongodb
257
249
  ```
258
250
 
@@ -273,24 +265,21 @@ spindb run mydb --file ./scripts/seed.js
273
265
 
274
266
  | | |
275
267
  |---|---|
276
- | Versions | 6, 7, 8 |
268
+ | Versions | 7, 8 |
277
269
  | Default port | 6379 |
278
270
  | Default user | None (no auth by default) |
279
- | Binary source | System installation |
271
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
280
272
 
281
- Like MySQL and MongoDB, SpinDB uses your system's Redis installation. Redis provides embeddable binaries, but system packages are more reliable for handling dependencies and platform-specific setup.
273
+ SpinDB downloads Redis server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases—just like PostgreSQL, MariaDB, MySQL, and MongoDB. This provides multi-version support on all platforms.
282
274
 
283
275
  ```bash
284
- # macOS
285
- brew install redis
286
-
287
- # Ubuntu/Debian
288
- sudo apt install redis-server redis-tools
276
+ # Create a Redis container (downloads binaries automatically)
277
+ spindb create mydb --engine redis
289
278
 
290
- # Windows (Chocolatey)
291
- choco install redis
279
+ # Create with specific version
280
+ spindb create mydb --engine redis --version 8
292
281
 
293
- # Check if SpinDB can find Redis
282
+ # Check what's available
294
283
  spindb deps check --engine redis
295
284
  ```
296
285
 
@@ -312,6 +301,97 @@ spindb connect myredis --iredis
312
301
 
313
302
  **Note:** Redis doesn't support remote dump/restore. Creating containers from remote Redis connection strings is not supported. Use `backup` and `restore` commands for data migration.
314
303
 
304
+ #### Valkey
305
+
306
+ | | |
307
+ |---|---|
308
+ | Versions | 8, 9 |
309
+ | Default port | 6379 |
310
+ | Default user | None (no auth by default) |
311
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
312
+
313
+ Valkey is a Redis fork created after Redis changed its license (RSALv2/SSPLv1). It's fully API-compatible with Redis, making it a drop-in replacement with permissive BSD-3 licensing.
314
+
315
+ SpinDB downloads Valkey server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases. This provides multi-version support on all platforms.
316
+
317
+ ```bash
318
+ # Create a Valkey container (downloads binaries automatically)
319
+ spindb create mydb --engine valkey
320
+
321
+ # Create with specific version
322
+ spindb create mydb --engine valkey --version 9
323
+
324
+ # Check what's available
325
+ spindb deps check --engine valkey
326
+ ```
327
+
328
+ Valkey uses the same commands as Redis:
329
+
330
+ ```bash
331
+ # Set a key
332
+ spindb run myvalkey -c "SET mykey myvalue"
333
+
334
+ # Get a key
335
+ spindb run myvalkey -c "GET mykey"
336
+
337
+ # Run a command file
338
+ spindb run myvalkey --file ./scripts/seed.valkey
339
+
340
+ # Use iredis for enhanced shell experience (Redis-protocol compatible)
341
+ spindb connect myvalkey --iredis
342
+ ```
343
+
344
+ **Note:** Valkey uses `redis://` connection scheme for client compatibility since it's wire-compatible with Redis.
345
+
346
+ ### hostdb Platform Coverage
347
+
348
+ SpinDB downloads database binaries from [hostdb](https://github.com/robertjbass/hostdb), a repository of pre-built database binaries for all major platforms. The following table shows current platform support and integration status:
349
+
350
+ | Icon | Meaning |
351
+ |:----:|---------|
352
+ | ✅ | Integrated with SpinDB |
353
+ | 🟦 | Pending SpinDB integration (hostdb ready) |
354
+ | 🟪 | Planned for hostdb (pending/in-progress) |
355
+
356
+ | Database | macOS ARM64 | macOS Intel | Linux x64 | Linux ARM64 | Windows x64 |
357
+ |----------|:-----------:|:-----------:|:---------:|:-----------:|:-----------:|
358
+ | **Integrated** |||||
359
+ | PostgreSQL | ✅ | ✅ | ✅ | ✅ | ✅ |
360
+ | MySQL | ✅ | ✅ | ✅ | ✅ | ✅ |
361
+ | MariaDB | ✅ | ✅ | ✅ | ✅ | ✅ |
362
+ | SQLite | ✅ | ✅ | ✅ | ✅ | ✅ |
363
+ | MongoDB* | ✅ | ✅ | ✅ | ✅ | ✅ |
364
+ | Redis* | ✅ | ✅ | ✅ | ✅ | ✅ |
365
+ | Valkey | ✅ | ✅ | ✅ | ✅ | ✅ |
366
+ | **Planned for hostdb** |||||
367
+ | CockroachDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
368
+ | TimescaleDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
369
+ | DuckDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
370
+ | Meilisearch | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
371
+ | OpenSearch | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
372
+ | QuestDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
373
+ | FerretDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
374
+ | TiDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
375
+ | ArangoDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
376
+ | Qdrant | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
377
+ | Apache Cassandra | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
378
+ | ClickHouse | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
379
+ | InfluxDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
380
+ | CouchDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
381
+ | KeyDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
382
+ | libSQL | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
383
+ | FoundationDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
384
+ | RocksDB | 🟪 | 🟪 | 🟪 | 🟪 | 🟪 |
385
+
386
+ **Notes:**
387
+ - **\*** Licensing considerations for commercial use — consider Valkey (Redis) or FerretDB (MongoDB) as alternatives
388
+ - **PostgreSQL** uses [EDB](https://www.enterprisedb.com/) binaries on Windows instead of hostdb
389
+ - **Valkey** is a Redis-compatible drop-in replacement with permissive licensing
390
+ - **CockroachDB** is planned for both hostdb and SpinDB (see [roadmap](TODO.md))
391
+ - All databases under "Planned for hostdb" have permissive open-source licenses (Apache 2.0, MIT, or BSD)
392
+
393
+ For the latest platform support, see the [hostdb databases.json](https://github.com/robertjbass/hostdb/blob/main/databases.json).
394
+
315
395
  ---
316
396
 
317
397
  ## Commands
@@ -349,8 +429,8 @@ spindb create mydb --from "postgresql://user:pass@host:5432/production"
349
429
 
350
430
  | Option | Description |
351
431
  |--------|-------------|
352
- | `--engine`, `-e` | Database engine (`postgresql`, `mariadb`, `mysql`, `sqlite`, `mongodb`, `redis`) |
353
- | `--db-version` | Engine version (e.g., 17 for PostgreSQL, 11.8 for MariaDB, 8 for Redis) |
432
+ | `--engine`, `-e` | Database engine (`postgresql`, `mariadb`, `mysql`, `sqlite`, `mongodb`, `redis`, `valkey`) |
433
+ | `--db-version` | Engine version (e.g., 17 for PostgreSQL, 11.8 for MariaDB, 8 for Redis, 9 for Valkey) |
354
434
  | `--port`, `-p` | Port number (not applicable for SQLite) |
355
435
  | `--database`, `-d` | Primary database name (Redis uses 0-15) |
356
436
  | `--path` | File path for SQLite databases |
@@ -468,6 +548,7 @@ Format by engine:
468
548
  - SQLite: `.sql` (plain SQL) / `.sqlite` (binary copy)
469
549
  - MongoDB: `.bson` (BSON dump) / `.archive` (compressed archive)
470
550
  - Redis: `.redis` (text commands) / `.rdb` (RDB snapshot)
551
+ - Valkey: `.valkey` (text commands) / `.rdb` (RDB snapshot)
471
552
 
472
553
  <details>
473
554
  <summary>All options</summary>
@@ -622,6 +703,26 @@ Each engine has specific backup formats and restore behaviors:
622
703
 
623
704
  </details>
624
705
 
706
+ <details>
707
+ <summary>Valkey</summary>
708
+
709
+ | Format | Extension | Tool | Notes |
710
+ |--------|-----------|------|-------|
711
+ | RDB | `.rdb` | BGSAVE | Binary snapshot, requires restart |
712
+ | Text | `.valkey` | Custom | Human-readable Redis-compatible commands |
713
+
714
+ **Text format detection:** Files are detected as Valkey text commands if they contain valid Redis commands (SET, HSET, DEL, etc.), regardless of file extension.
715
+
716
+ **Restore behavior:** Same as Redis (Valkey is Redis-compatible).
717
+ - **RDB (`.rdb`):** Requires stopping Valkey, copies file to data directory, restart loads data
718
+ - **Text (`.valkey`):** Pipes commands to running Valkey instance. Prompts for:
719
+ - **Replace all:** Runs `FLUSHDB` first (clean slate)
720
+ - **Merge:** Adds/updates keys, keeps existing keys not in backup
721
+
722
+ **Note:** Valkey uses numbered databases (0-15) that always exist. "Create new database" is not applicable.
723
+
724
+ </details>
725
+
625
726
  ### Container Management
626
727
 
627
728
  #### `list` - List all containers
@@ -672,6 +773,10 @@ spindb logs mydb --editor # Open in $EDITOR
672
773
 
673
774
  ```bash
674
775
  spindb engines # List installed engines
776
+ spindb engines list --json # JSON output
777
+ spindb engines supported # List all supported engines
778
+ spindb engines supported --json # Full engine config as JSON
779
+ spindb engines supported --all # Include pending/planned engines
675
780
  spindb engines delete postgresql 16 # Delete a version (frees ~45MB)
676
781
  ```
677
782
 
@@ -682,13 +787,25 @@ ENGINE VERSION SOURCE SIZE
682
787
  ────────────────────────────────────────────────────────
683
788
  🐘 postgresql 18.1 darwin-arm64 46.0 MB
684
789
  🐘 postgresql 17.7 darwin-arm64 45.2 MB
685
- 🐬 mysql 8.0.35 system (system-installed)
686
- 🪶 sqlite 3.43.2 system (system-installed)
790
+ 🐬 mysql 9.0.1 darwin-arm64 150.0 MB
791
+ 🪶 sqlite 3.51.2 darwin-arm64 5.0 MB
687
792
  ────────────────────────────────────────────────────────
688
793
 
689
794
  PostgreSQL: 2 version(s), 90.0 MB
690
- MySQL: system-installed at /opt/homebrew/bin/mysqld
691
- SQLite: system-installed at /usr/bin/sqlite3
795
+ MySQL: 1 version(s), 150.0 MB
796
+ SQLite: 1 version(s), 5.0 MB
797
+ ```
798
+
799
+ `spindb engines supported` output:
800
+
801
+ ```
802
+ 🐘 postgresql
803
+ 🐬 mysql
804
+ 🦭 mariadb
805
+ 🪶 sqlite
806
+ 🍃 mongodb
807
+ 🔴 redis
808
+ 🔷 valkey
692
809
  ```
693
810
 
694
811
  #### `deps` - Manage client tools
@@ -773,6 +890,7 @@ SpinDB supports enhanced database shells that provide features like auto-complet
773
890
  | SQLite | `sqlite3` | `litecli` | `usql` |
774
891
  | MongoDB | `mongosh` | - | `usql` |
775
892
  | Redis | `redis-cli` | `iredis` | - |
893
+ | Valkey | `valkey-cli` | `iredis` | - |
776
894
 
777
895
  **pgcli / mycli** provide:
778
896
  - Intelligent auto-completion (tables, columns, keywords)
@@ -879,42 +997,27 @@ This means Redis may lose up to ~60 seconds of writes on an unexpected crash. Fo
879
997
  ### Binary Sources
880
998
 
881
999
  **PostgreSQL:** Server binaries are downloaded automatically:
882
- - **All platforms (macOS/Linux/Windows for macOS/Linux via hostdb, Windows via EDB):** From [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases (macOS/Linux) or [EnterpriseDB (EDB)](https://www.enterprisedb.com/download-postgresql-binaries) (Windows)
883
-
884
- **MariaDB:** Server binaries are downloaded automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases for all platforms.
1000
+ - **macOS/Linux:** From [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases
1001
+ - **Windows:** From [EnterpriseDB (EDB)](https://www.enterprisedb.com/download-postgresql-binaries)
885
1002
 
886
- **MySQL/MongoDB/Redis:** Uses your system installation. SpinDB detects binaries from Homebrew (macOS), apt/pacman (Linux), or Chocolatey/winget/Scoop (Windows).
1003
+ **MariaDB, MySQL, MongoDB, Redis, Valkey:** Server binaries are downloaded automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases for all platforms.
887
1004
 
888
- ### Why Precompiled Binaries for PostgreSQL and MariaDB, but System Installs for Others?
1005
+ ### Why Precompiled Binaries?
889
1006
 
890
- This isn't a preference—it's a practical reality of what's available.
1007
+ The [hostdb](https://github.com/robertjbass/hostdb) project provides pre-compiled, portable database binaries:
891
1008
 
892
- **PostgreSQL and MariaDB have excellent embedded binary distributions.** The [hostdb](https://github.com/robertjbass/hostdb) project provides pre-compiled, portable database binaries:
893
-
894
- - Cross-platform (macOS Intel/ARM, Linux x64/ARM, Windows)
1009
+ - Cross-platform (macOS Intel/ARM, Linux x64/ARM, Windows x64)
895
1010
  - Hosted on GitHub Releases (highly reliable CDN)
896
- - ~45-100 MB per version
1011
+ - ~45-200 MB per version depending on engine
897
1012
  - Actively maintained with new database releases
898
1013
 
899
- This makes multi-version support trivial: need PostgreSQL 14 for a legacy project and 18 for a new one? Need MariaDB 11.8? SpinDB downloads them all, and they run side-by-side without conflicts.
900
-
901
- **No equivalent exists for MySQL, MongoDB, or Redis (yet).** None of these databases have a comparable embedded binary distribution:
902
-
903
- - **MySQL:** Oracle distributes MySQL as large installers with system dependencies, not embeddable binaries.
904
- - **MongoDB:** Server binaries are several hundred MB and aren't designed for portable distribution.
905
- - **Redis:** While Redis is small (~6-12 MB), there's no official portable distribution. Community Windows ports exist, but macOS/Linux rely on system packages.
906
-
907
- For these databases, system packages (Homebrew, apt, choco) are the most reliable option. They handle dependencies, platform quirks, and security updates. SpinDB simply orchestrates what's already installed.
908
-
909
- **Does this limit multi-version support?** Yes, for MySQL/MongoDB/Redis you get whatever version your package manager provides. In practice, this is rarely a problem—developers seldom need multiple versions of these databases simultaneously. As hostdb expands to support more databases, SpinDB will adopt them for multi-version support.
1014
+ This makes multi-version support trivial: need PostgreSQL 14 for a legacy project and 18 for a new one? Need MongoDB 7.0 and 8.0? Redis 7 and 8? SpinDB downloads them all, and they run side-by-side without conflicts.
910
1015
 
911
1016
  ---
912
1017
 
913
1018
  ## Limitations
914
1019
 
915
- - **Client tools required** - `mysql`, `mongosh`, and `redis-cli` must be installed separately for some operations (connecting, backups, restores) for system-installed engines
916
1020
  - **Local only** - Databases bind to `127.0.0.1`; remote connections planned for v1.1
917
- - **Single version for MySQL/MongoDB/Redis** - Unlike PostgreSQL and MariaDB, MySQL, MongoDB, and Redis use system installations, so you're limited to one version per machine (see [Why Precompiled Binaries for PostgreSQL and MariaDB?](#why-precompiled-binaries-for-postgresql-and-mariadb-but-system-installs-for-others))
918
1021
  - **Redis remote dump not supported** - Redis doesn't support creating containers from remote connection strings. Use backup/restore for data migration.
919
1022
 
920
1023
  ---
@@ -938,6 +1041,7 @@ See [TODO.md](TODO.md) for the full roadmap.
938
1041
 
939
1042
  ### Future Infrastructure
940
1043
  - **hostdb npm package**: Available database versions will be published as an npm package from [hostdb](https://github.com/robertjbass/hostdb) and imported into SpinDB, eliminating the need to manually sync version-maps.ts with releases.json
1044
+ - **pnpm 10 upgrade**: Currently pinned to pnpm 9.x (`packageManager` in package.json and Docker). Consider upgrading to pnpm 10.x when stable—requires updating package.json, Dockerfile, regenerating pnpm-lock.yaml, and testing for lockfile format changes
941
1045
 
942
1046
  ### Possible Future Engines
943
1047
 
@@ -947,7 +1051,6 @@ These engines are under consideration but not yet on the roadmap. Community inte
947
1051
  |--------|------|-------|
948
1052
  | **DuckDB** | Embedded analytical | File-based like SQLite, popular for data/analytics work |
949
1053
  | **libSQL** | Embedded relational | SQLite fork by Turso with replication and edge support |
950
- | **Valkey** | Key-value store | Redis fork (post-license change), growing adoption |
951
1054
  | **Meilisearch** | Search engine | Developer-friendly search, good binary distribution |
952
1055
  | **Elasticsearch/OpenSearch** | Search engine | Full-text search, common in web applications |
953
1056
  | **Neo4j** | Graph database | Most popular graph database |
@@ -1011,15 +1114,7 @@ See [ENGINES.md](ENGINES.md) for detailed engine documentation (backup formats,
1011
1114
 
1012
1115
  SpinDB wouldn't be possible without:
1013
1116
 
1014
- - **[zonky.io/embedded-postgres-binaries](https://github.com/zonkyio/embedded-postgres-binaries)** - Pre-compiled PostgreSQL binaries that make Docker-free PostgreSQL possible. These binaries are extracted from official PostgreSQL distributions and hosted on Maven Central.
1015
-
1016
- ---
1017
-
1018
- ## Related Work
1019
-
1020
- We're actively contributing to the broader embedded database ecosystem:
1021
-
1022
- - **[hostdb](https://github.com/robertjbass/hostdb)** - A companion project providing downloadable database binaries (Redis, MySQL/MariaDB, etc.) as GitHub releases. This will enable SpinDB to offer multi-version support for additional engines beyond PostgreSQL.
1117
+ - **[hostdb](https://github.com/robertjbass/hostdb)** - Pre-compiled database binaries (PostgreSQL, MySQL, MariaDB, MongoDB, Redis, Valkey, SQLite) that make Docker-free local databases possible. Hosted on GitHub Releases for reliable, fast downloads.
1023
1118
 
1024
1119
  ---
1025
1120
 
package/bin/cli.js CHANGED
@@ -1,24 +1,53 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { fileURLToPath } from 'node:url'
3
+ import { fileURLToPath, pathToFileURL } from 'node:url'
4
4
  import { dirname, join } from 'node:path'
5
5
  import { spawn } from 'node:child_process'
6
+ import { existsSync } from 'node:fs'
6
7
 
7
8
  // Get the directory of this file
8
9
  const __filename = fileURLToPath(import.meta.url)
9
10
  const __dirname = dirname(__filename)
10
11
 
11
- // Path to the main TypeScript entry point
12
- const mainScript = join(__dirname, '..', 'cli', 'bin.ts')
12
+ // Path to the main TypeScript entry point and package root
13
+ const packageRoot = join(__dirname, '..')
14
+ const mainScript = join(packageRoot, 'cli', 'bin.ts')
13
15
 
14
- // Use tsx to execute the TypeScript file
15
- const tsxPath = join(__dirname, '..', 'node_modules', '.bin', 'tsx')
16
+ // Use Node.js with tsx as ESM loader
17
+ // This approach works reliably on all platforms because:
18
+ // 1. We use process.execPath (always the current Node.js executable)
19
+ // 2. We use --import with tsx's ESM loader module
20
+ // 3. Arguments pass through without shell interpretation (shell: false)
21
+ // 4. Works on Windows without needing to spawn .cmd files
16
22
 
17
- // Spawn tsx process with the main script and pass through all arguments
18
- const child = spawn(tsxPath, [mainScript, ...process.argv.slice(2)], {
19
- stdio: 'inherit',
20
- shell: false,
21
- })
23
+ // Find tsx ESM loader - check common paths
24
+ const tsxLoaderPaths = [
25
+ join(packageRoot, 'node_modules', 'tsx', 'dist', 'esm', 'index.mjs'),
26
+ join(packageRoot, 'node_modules', 'tsx', 'dist', 'loader.mjs'),
27
+ ]
28
+
29
+ const tsxLoader = tsxLoaderPaths.find((p) => existsSync(p))
30
+
31
+ if (!tsxLoader) {
32
+ console.error('Error: tsx loader not found.')
33
+ console.error('Searched paths:')
34
+ tsxLoaderPaths.forEach((p) => console.error(` - ${p}`))
35
+ console.error('\nTry running: pnpm install')
36
+ process.exit(1)
37
+ }
38
+
39
+ // Convert to file URL for --import (required on Windows)
40
+ const tsxLoaderUrl = pathToFileURL(tsxLoader).href
41
+
42
+ const child = spawn(
43
+ process.execPath,
44
+ ['--import', tsxLoaderUrl, mainScript, ...process.argv.slice(2)],
45
+ {
46
+ stdio: 'inherit',
47
+ shell: false,
48
+ cwd: packageRoot,
49
+ },
50
+ )
22
51
 
23
52
  // Forward exit code
24
53
  child.on('exit', (code) => {
@@ -252,7 +252,10 @@ export const backupCommand = new Command('backup')
252
252
  console.log(uiSuccess('Backup complete'))
253
253
  console.log()
254
254
  console.log(chalk.gray(' Saved to:'), chalk.cyan(result.path))
255
- console.log(chalk.gray(' Size:'), chalk.white(formatBytes(result.size)))
255
+ console.log(
256
+ chalk.gray(' Size:'),
257
+ chalk.white(formatBytes(result.size)),
258
+ )
256
259
  console.log(chalk.gray(' Format:'), chalk.white(result.format))
257
260
  console.log()
258
261
  }
@@ -8,6 +8,7 @@
8
8
  import { Command } from 'commander'
9
9
  import { readdirSync, statSync } from 'fs'
10
10
  import { join, extname } from 'path'
11
+ import { homedir } from 'os'
11
12
  import chalk from 'chalk'
12
13
  import { formatBytes } from '../ui/theme'
13
14
 
@@ -20,10 +21,11 @@ type BackupInfo = {
20
21
  format: string
21
22
  }
22
23
 
23
- /**
24
- * Detect engine and format from file extension
25
- */
26
- function detectBackupType(filename: string): { engine: string | null; format: string } {
24
+ // Detect engine and format from file extension
25
+ function detectBackupType(filename: string): {
26
+ engine: string | null
27
+ format: string
28
+ } {
27
29
  const ext = extname(filename).toLowerCase()
28
30
 
29
31
  // Check for double extensions like .sql.gz
@@ -54,9 +56,7 @@ function detectBackupType(filename: string): { engine: string | null; format: st
54
56
  }
55
57
  }
56
58
 
57
- /**
58
- * Check if a file looks like a backup file
59
- */
59
+ // Check if a file looks like a backup file
60
60
  function isBackupFile(filename: string): boolean {
61
61
  const backupExtensions = [
62
62
  '.sql',
@@ -77,9 +77,7 @@ function isBackupFile(filename: string): boolean {
77
77
  return backupExtensions.includes(ext)
78
78
  }
79
79
 
80
- /**
81
- * Scan directory for backup files
82
- */
80
+ // Scan directory for backup files
83
81
  function findBackups(directory: string): BackupInfo[] {
84
82
  const backups: BackupInfo[] = []
85
83
 
@@ -118,9 +116,7 @@ function findBackups(directory: string): BackupInfo[] {
118
116
  return backups
119
117
  }
120
118
 
121
- /**
122
- * Format a relative time string
123
- */
119
+ // Format a relative time string
124
120
  function formatRelativeTime(date: Date): string {
125
121
  const now = new Date()
126
122
  const diffMs = now.getTime() - date.getTime()
@@ -136,9 +132,7 @@ function formatRelativeTime(date: Date): string {
136
132
  return date.toLocaleDateString()
137
133
  }
138
134
 
139
- /**
140
- * Get engine icon
141
- */
135
+ // Get engine icon
142
136
  function getEngineIcon(engine: string | null): string {
143
137
  switch (engine) {
144
138
  case 'postgresql':
@@ -174,11 +168,7 @@ export const backupsCommand = new Command('backups')
174
168
  const searchDirs = [directory || process.cwd()]
175
169
 
176
170
  if (options.all) {
177
- const homeBackups = join(
178
- process.env.HOME || '',
179
- '.spindb',
180
- 'backups',
181
- )
171
+ const homeBackups = join(homedir(), '.spindb', 'backups')
182
172
  searchDirs.push(homeBackups)
183
173
  }
184
174
 
@@ -219,7 +209,9 @@ export const backupsCommand = new Command('backups')
219
209
  console.log(chalk.gray(' No backup files found'))
220
210
  console.log()
221
211
  console.log(chalk.gray(' Backup files are identified by extensions:'))
222
- console.log(chalk.gray(' .sql, .dump, .sqlite, .archive, .rdb, .sql.gz'))
212
+ console.log(
213
+ chalk.gray(' .sql, .dump, .sqlite, .archive, .rdb, .sql.gz'),
214
+ )
223
215
  console.log()
224
216
  return
225
217
  }
@@ -248,7 +240,9 @@ export const backupsCommand = new Command('backups')
248
240
  const time = formatRelativeTime(backup.modified).padStart(10)
249
241
  const format = chalk.gray(backup.format)
250
242
 
251
- console.log(` ${icon} ${chalk.cyan(filename)} ${chalk.white(size)} ${chalk.gray(time)} ${format}`)
243
+ console.log(
244
+ ` ${icon} ${chalk.cyan(filename)} ${chalk.white(size)} ${chalk.gray(time)} ${format}`,
245
+ )
252
246
  }
253
247
 
254
248
  console.log()
@@ -13,9 +13,7 @@ import { uiError, uiSuccess, header, uiInfo } from '../ui/theme'
13
13
  import { createSpinner } from '../ui/spinner'
14
14
  import type { BinaryTool } from '../../types'
15
15
 
16
- /**
17
- * Helper to display a tool's config
18
- */
16
+ // Helper to display a tool's config
19
17
  function displayToolConfig(
20
18
  tool: BinaryTool,
21
19
  binaryConfig: { path: string; version?: string; source: string } | undefined,
@@ -467,7 +467,14 @@ export const connectCommand = new Command('connect')
467
467
  clientArgs = [config.database]
468
468
  } else if (useIredis) {
469
469
  clientCmd = 'iredis'
470
- clientArgs = ['-h', '127.0.0.1', '-p', String(config.port), '-n', database]
470
+ clientArgs = [
471
+ '-h',
472
+ '127.0.0.1',
473
+ '-p',
474
+ String(config.port),
475
+ '-n',
476
+ database,
477
+ ]
471
478
  } else if (usePgcli) {
472
479
  clientCmd = 'pgcli'
473
480
  clientArgs = [connectionString]
@@ -490,7 +497,14 @@ export const connectCommand = new Command('connect')
490
497
  clientArgs = [config.database]
491
498
  } else if (engineName === Engine.Redis) {
492
499
  clientCmd = 'redis-cli'
493
- clientArgs = ['-h', '127.0.0.1', '-p', String(config.port), '-n', database]
500
+ clientArgs = [
501
+ '-h',
502
+ '127.0.0.1',
503
+ '-p',
504
+ String(config.port),
505
+ '-n',
506
+ database,
507
+ ]
494
508
  } else if (engineName === 'mysql') {
495
509
  clientCmd = 'mysql'
496
510
  clientArgs = [