spindb 0.14.0 → 0.15.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.
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, 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, and Redis 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
 
@@ -139,20 +139,40 @@ You'll get an interactive menu with arrow-key navigation:
139
139
  | Versions | 14, 15, 16, 17, 18 |
140
140
  | Default port | 5432 |
141
141
  | Default user | `postgres` |
142
- | Binary source | [zonky.io](https://github.com/zonkyio/embedded-postgres-binaries) (macOS/Linux), [EDB](https://www.enterprisedb.com/) (Windows) |
142
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) (macOS/Linux), [EDB](https://www.enterprisedb.com/) (Windows) |
143
143
 
144
144
  SpinDB downloads PostgreSQL server binaries automatically:
145
- - **macOS/Linux:** Pre-compiled binaries from the zonky.io project, hosted on Maven Central
145
+ - **macOS/Linux:** Pre-compiled binaries from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases
146
146
  - **Windows:** Official binaries from EnterpriseDB (EDB)
147
147
 
148
- **Why download binaries instead of using system PostgreSQL?** The [zonky.io project](https://github.com/zonkyio/embedded-postgres-binaries) provides pre-configured, portable PostgreSQL binaries—just extract and run. This lets you run PostgreSQL 14 for one project and 18 for another, side-by-side, without conflicts. No other database engine has an equivalent portable distribution.
148
+ **Why download binaries instead of using system PostgreSQL?** The hostdb project provides pre-configured, portable PostgreSQL binaries—just extract and run. This lets you run PostgreSQL 14 for one project and 18 for another, side-by-side, without conflicts.
149
149
 
150
- **Client tools required:** You still need `psql`, `pg_dump`, and `pg_restore` installed on your system for some operations (connecting, backups, restores). SpinDB can install these for you:
150
+ **Client tools included:** PostgreSQL binaries include `psql`, `pg_dump`, and `pg_restore` for all operations.
151
+
152
+ #### MariaDB
153
+
154
+ | | |
155
+ |---|---|
156
+ | Versions | 10.11, 11.4, 11.8 |
157
+ | Default port | 3307 |
158
+ | Default user | `root` |
159
+ | Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
160
+
161
+ SpinDB downloads MariaDB server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases—just like PostgreSQL. This provides multi-version support and works across all platforms.
151
162
 
152
163
  ```bash
153
- spindb deps install --engine postgresql
164
+ # Create a MariaDB container
165
+ spindb create mydb --engine mariadb
166
+
167
+ # Or using the alias
168
+ spindb create mydb -e maria
169
+
170
+ # Check what's available
171
+ spindb deps check --engine mariadb
154
172
  ```
155
173
 
174
+ MariaDB is MySQL-compatible, so most MySQL tools and clients work seamlessly. If you need MySQL-specific features, use the `mysql` engine instead.
175
+
156
176
  #### MySQL
157
177
 
158
178
  | | |
@@ -181,7 +201,7 @@ winget install Oracle.MySQL
181
201
  spindb deps check --engine mysql
182
202
  ```
183
203
 
184
- **Linux users:** MariaDB works as a drop-in replacement for MySQL. If you have MariaDB installed, SpinDB will detect and use it automatically. In a future release, MariaDB will be available as its own engine with support for MariaDB-specific features.
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.
185
205
 
186
206
  #### SQLite
187
207
 
@@ -302,6 +322,7 @@ spindb connect myredis --iredis
302
322
 
303
323
  ```bash
304
324
  spindb create mydb # PostgreSQL (default)
325
+ spindb create mydb --engine mariadb # MariaDB
305
326
  spindb create mydb --engine mysql # MySQL
306
327
  spindb create mydb --engine sqlite # SQLite (file-based)
307
328
  spindb create mydb --db-version 16 # Specific PostgreSQL version
@@ -328,8 +349,8 @@ spindb create mydb --from "postgresql://user:pass@host:5432/production"
328
349
 
329
350
  | Option | Description |
330
351
  |--------|-------------|
331
- | `--engine`, `-e` | Database engine (`postgresql`, `mysql`, `sqlite`, `mongodb`, `redis`) |
332
- | `--db-version` | Engine version (e.g., 17 for PostgreSQL, 8 for Redis) |
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) |
333
354
  | `--port`, `-p` | Port number (not applicable for SQLite) |
334
355
  | `--database`, `-d` | Primary database name (Redis uses 0-15) |
335
356
  | `--path` | File path for SQLite databases |
@@ -442,6 +463,7 @@ spindb backup mydb --dump
442
463
 
443
464
  Format by engine:
444
465
  - PostgreSQL: `.sql` (plain SQL) / `.dump` (pg_dump custom)
466
+ - MariaDB: `.sql` (plain SQL) / `.sql.gz` (compressed SQL)
445
467
  - MySQL: `.sql` (plain SQL) / `.sql.gz` (compressed SQL)
446
468
  - SQLite: `.sql` (plain SQL) / `.sqlite` (binary copy)
447
469
  - MongoDB: `.bson` (BSON dump) / `.archive` (compressed archive)
@@ -532,6 +554,18 @@ Each engine has specific backup formats and restore behaviors:
532
554
 
533
555
  </details>
534
556
 
557
+ <details>
558
+ <summary>MariaDB</summary>
559
+
560
+ | Format | Extension | Tool | Notes |
561
+ |--------|-----------|------|-------|
562
+ | SQL | `.sql` | mariadb-dump | Plain text SQL |
563
+ | Compressed | `.sql.gz` | mariadb-dump + gzip | Gzip compressed SQL |
564
+
565
+ **Restore behavior:** Creates new database or replaces existing. Pipes to `mariadb` client.
566
+
567
+ </details>
568
+
535
569
  <details>
536
570
  <summary>MySQL</summary>
537
571
 
@@ -734,6 +768,7 @@ SpinDB supports enhanced database shells that provide features like auto-complet
734
768
  | Engine | Standard | Enhanced | Universal |
735
769
  |--------|----------|----------|-----------|
736
770
  | PostgreSQL | `psql` | `pgcli` | `usql` |
771
+ | MariaDB | `mariadb` | `mycli` | `usql` |
737
772
  | MySQL | `mysql` | `mycli` | `usql` |
738
773
  | SQLite | `sqlite3` | `litecli` | `usql` |
739
774
  | MongoDB | `mongosh` | - | `usql` |
@@ -824,12 +859,13 @@ Each database engine has its own persistence mechanism:
824
859
  | Engine | Mechanism | Durability |
825
860
  |--------|-----------|------------|
826
861
  | PostgreSQL | Write-Ahead Logging (WAL) | Every commit is immediately durable |
862
+ | MariaDB | InnoDB transaction logs | Every commit is immediately durable |
827
863
  | MySQL | InnoDB transaction logs | Every commit is immediately durable |
828
864
  | SQLite | File-based transactions | Every commit is immediately durable |
829
865
  | MongoDB | WiredTiger with journaling | Writes journaled before acknowledged |
830
866
  | Redis | RDB snapshots | Periodic snapshots (see below) |
831
867
 
832
- **PostgreSQL, MySQL, MongoDB:** These engines use transaction logs or journaling. Every committed write is guaranteed to survive a crash or unexpected shutdown.
868
+ **PostgreSQL, MariaDB, MySQL, MongoDB:** These engines use transaction logs or journaling. Every committed write is guaranteed to survive a crash or unexpected shutdown.
833
869
 
834
870
  **SQLite:** As a file-based database, SQLite writes directly to disk on each commit. No server process means no risk of losing in-flight data.
835
871
 
@@ -843,41 +879,42 @@ This means Redis may lose up to ~60 seconds of writes on an unexpected crash. Fo
843
879
  ### Binary Sources
844
880
 
845
881
  **PostgreSQL:** Server binaries are downloaded automatically:
846
- - **macOS/Linux:** From [zonky.io/embedded-postgres-binaries](https://github.com/zonkyio/embedded-postgres-binaries), hosted on Maven Central
847
- - **Windows:** From [EnterpriseDB (EDB)](https://www.enterprisedb.com/download-postgresql-binaries), official PostgreSQL distributions
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.
848
885
 
849
886
  **MySQL/MongoDB/Redis:** Uses your system installation. SpinDB detects binaries from Homebrew (macOS), apt/pacman (Linux), or Chocolatey/winget/Scoop (Windows).
850
887
 
851
- ### Why Precompiled Binaries for PostgreSQL, but System Installs for Others?
888
+ ### Why Precompiled Binaries for PostgreSQL and MariaDB, but System Installs for Others?
852
889
 
853
890
  This isn't a preference—it's a practical reality of what's available.
854
891
 
855
- **PostgreSQL has an excellent embedded binary distribution.** The [zonky.io](https://github.com/zonkyio/embedded-postgres-binaries) project maintains minimal, self-contained PostgreSQL server binaries specifically designed for embedding:
892
+ **PostgreSQL and MariaDB have excellent embedded binary distributions.** The [hostdb](https://github.com/robertjbass/hostdb) project provides pre-compiled, portable database binaries:
856
893
 
857
894
  - Cross-platform (macOS Intel/ARM, Linux x64/ARM, Windows)
858
- - Hosted on Maven Central (highly reliable CDN)
859
- - ~45 MB per version
860
- - Actively maintained with new PostgreSQL releases
895
+ - Hosted on GitHub Releases (highly reliable CDN)
896
+ - ~45-100 MB per version
897
+ - Actively maintained with new database releases
861
898
 
862
- This makes multi-version support trivial: need PostgreSQL 14 for a legacy project and 18 for a new one? SpinDB downloads both, and they run side-by-side without conflicts.
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.
863
900
 
864
- **No equivalent exists for MySQL, MongoDB, or Redis.** None of these databases have a comparable embedded binary project:
901
+ **No equivalent exists for MySQL, MongoDB, or Redis (yet).** None of these databases have a comparable embedded binary distribution:
865
902
 
866
- - **MySQL:** Oracle distributes MySQL as large installers with system dependencies, not embeddable binaries. There's no "zonky.io for MySQL."
903
+ - **MySQL:** Oracle distributes MySQL as large installers with system dependencies, not embeddable binaries.
867
904
  - **MongoDB:** Server binaries are several hundred MB and aren't designed for portable distribution.
868
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.
869
906
 
870
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.
871
908
 
872
- **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. If zonky.io-style distributions emerged for other databases, SpinDB could adopt them.
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.
873
910
 
874
911
  ---
875
912
 
876
913
  ## Limitations
877
914
 
878
- - **Client tools required** - `psql`, `mysql`, `mongosh`, and `redis-cli` must be installed separately for some operations (connecting, backups, restores)
915
+ - **Client tools required** - `mysql`, `mongosh`, and `redis-cli` must be installed separately for some operations (connecting, backups, restores) for system-installed engines
879
916
  - **Local only** - Databases bind to `127.0.0.1`; remote connections planned for v1.1
880
- - **Single version for MySQL/MongoDB/Redis** - Unlike PostgreSQL, MySQL, MongoDB, and Redis use system installations, so you're limited to one version per machine (see [Why Precompiled Binaries for PostgreSQL?](#why-precompiled-binaries-for-postgresql-but-system-installs-for-others))
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))
881
918
  - **Redis remote dump not supported** - Redis doesn't support creating containers from remote connection strings. Use backup/restore for data migration.
882
919
 
883
920
  ---
@@ -892,7 +929,6 @@ See [TODO.md](TODO.md) for the full roadmap.
892
929
  - Secrets management (macOS Keychain)
893
930
 
894
931
  ### v1.2 - Additional Engines
895
- - MariaDB as standalone engine
896
932
  - CockroachDB (distributed SQL)
897
933
 
898
934
  ### v1.3 - Advanced Features
@@ -900,6 +936,9 @@ See [TODO.md](TODO.md) for the full roadmap.
900
936
  - Scheduled backups
901
937
  - Import from Docker
902
938
 
939
+ ### Future Infrastructure
940
+ - **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
941
+
903
942
  ### Possible Future Engines
904
943
 
905
944
  These engines are under consideration but not yet on the roadmap. Community interest and feasibility will determine priority:
@@ -11,6 +11,7 @@ import { getEngineIcon, ENGINE_ICONS } from '../../constants'
11
11
  import {
12
12
  getInstalledEngines,
13
13
  type InstalledPostgresEngine,
14
+ type InstalledMariadbEngine,
14
15
  type InstalledMysqlEngine,
15
16
  type InstalledSqliteEngine,
16
17
  type InstalledMongodbEngine,
@@ -54,6 +55,9 @@ export async function handleEngines(): Promise<void> {
54
55
  const pgEngines = engines.filter(
55
56
  (e): e is InstalledPostgresEngine => e.engine === 'postgresql',
56
57
  )
58
+ const mariadbEngines = engines.filter(
59
+ (e): e is InstalledMariadbEngine => e.engine === 'mariadb',
60
+ )
57
61
  const mysqlEngines = engines.filter(
58
62
  (e): e is InstalledMysqlEngine => e.engine === 'mysql',
59
63
  )
@@ -68,6 +72,7 @@ export async function handleEngines(): Promise<void> {
68
72
  )
69
73
 
70
74
  const totalPgSize = pgEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
75
+ const totalMariadbSize = mariadbEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
71
76
 
72
77
  const COL_ENGINE = 14
73
78
  const COL_VERSION = 12
@@ -97,6 +102,20 @@ export async function handleEngines(): Promise<void> {
97
102
  )
98
103
  }
99
104
 
105
+ for (const engine of mariadbEngines) {
106
+ const icon = getEngineIcon(engine.engine)
107
+ const platformInfo = `${engine.platform}-${engine.arch}`
108
+ const engineDisplay = `${icon} ${engine.engine}`
109
+
110
+ console.log(
111
+ chalk.gray(' ') +
112
+ chalk.cyan(padToWidth(engineDisplay, COL_ENGINE)) +
113
+ chalk.yellow(engine.version.padEnd(COL_VERSION)) +
114
+ chalk.gray(platformInfo.padEnd(COL_SOURCE)) +
115
+ chalk.white(formatBytes(engine.sizeBytes)),
116
+ )
117
+ }
118
+
100
119
  for (const mysqlEngine of mysqlEngines) {
101
120
  const icon = ENGINE_ICONS.mysql
102
121
  const displayName = mysqlEngine.isMariaDB ? 'mariadb' : 'mysql'
@@ -113,8 +132,7 @@ export async function handleEngines(): Promise<void> {
113
132
 
114
133
  if (sqliteEngine) {
115
134
  const icon = ENGINE_ICONS.sqlite
116
- // double space to align with other engines
117
- const engineDisplay = `${icon} sqlite`
135
+ const engineDisplay = `${icon} sqlite`
118
136
 
119
137
  console.log(
120
138
  chalk.gray(' ') +
@@ -161,6 +179,13 @@ export async function handleEngines(): Promise<void> {
161
179
  ),
162
180
  )
163
181
  }
182
+ if (mariadbEngines.length > 0) {
183
+ console.log(
184
+ chalk.gray(
185
+ ` MariaDB: ${mariadbEngines.length} version(s), ${formatBytes(totalMariadbSize)}`,
186
+ ),
187
+ )
188
+ }
164
189
  if (mysqlEngines.length > 0) {
165
190
  const versionCount = mysqlEngines.length
166
191
  const versionText = versionCount === 1 ? 'version' : 'versions'
@@ -198,6 +223,13 @@ export async function handleEngines(): Promise<void> {
198
223
  })
199
224
  }
200
225
 
226
+ for (const e of mariadbEngines) {
227
+ choices.push({
228
+ name: `${chalk.red('✕')} Delete ${e.engine} ${e.version} ${chalk.gray(`(${formatBytes(e.sizeBytes)})`)}`,
229
+ value: `delete:${e.path}:${e.engine}:${e.version}`,
230
+ })
231
+ }
232
+
201
233
  for (const mysqlEngine of mysqlEngines) {
202
234
  const displayName = mysqlEngine.isMariaDB ? 'MariaDB' : 'MySQL'
203
235
  // Show formula name if it's a versioned install
@@ -21,6 +21,7 @@ import {
21
21
  getIredisManualInstructions,
22
22
  } from '../../../core/dependency-manager'
23
23
  import { platformService } from '../../../core/platform-service'
24
+ import { configManager } from '../../../core/config-manager'
24
25
  import { getEngine } from '../../../engines'
25
26
  import { createSpinner } from '../../ui/spinner'
26
27
  import { uiError, uiWarning, uiInfo, uiSuccess } from '../../ui/theme'
@@ -118,6 +119,12 @@ export async function handleOpenShell(containerName: string): Promise<void> {
118
119
  engineSpecificInstalled = mycliInstalled
119
120
  engineSpecificValue = 'mycli'
120
121
  engineSpecificInstallValue = 'install-mycli'
122
+ } else if (config.engine === 'mariadb') {
123
+ defaultShellName = 'mariadb'
124
+ engineSpecificCli = 'mycli'
125
+ engineSpecificInstalled = mycliInstalled
126
+ engineSpecificValue = 'mycli'
127
+ engineSpecificInstallValue = 'install-mycli'
121
128
  } else if (config.engine === 'mongodb') {
122
129
  defaultShellName = 'mongosh'
123
130
  // mongosh IS the enhanced shell for MongoDB (no separate enhanced CLI like pgcli/mycli)
@@ -425,6 +432,20 @@ async function launchShell(
425
432
  config.database,
426
433
  ]
427
434
  installHint = 'brew install mysql-client'
435
+ } else if (config.engine === 'mariadb') {
436
+ // MariaDB uses downloaded binaries, not system PATH - get the actual path
437
+ const mariadbPath = await configManager.getBinaryPath('mariadb')
438
+ shellCmd = mariadbPath || 'mariadb'
439
+ shellArgs = [
440
+ '-u',
441
+ 'root',
442
+ '-h',
443
+ '127.0.0.1',
444
+ '-P',
445
+ String(config.port),
446
+ config.database,
447
+ ]
448
+ installHint = 'spindb engines download mariadb'
428
449
  } else if (config.engine === 'mongodb') {
429
450
  shellCmd = 'mongosh'
430
451
  shellArgs = [connectionString]
package/cli/constants.ts CHANGED
@@ -1,7 +1,10 @@
1
+ // Note: Some emojis render narrower than others in terminals.
2
+ // Add extra space after narrow emojis (🦭, 🪶) for visual alignment.
1
3
  export const ENGINE_ICONS: Record<string, string> = {
2
4
  postgresql: '🐘',
3
5
  mysql: '🐬',
4
- sqlite: '🪶',
6
+ mariadb: '🦭 ', // Extra space - seal emoji renders narrow
7
+ sqlite: '🪶 ', // Extra space - feather emoji renders narrow
5
8
  mongodb: '🍃',
6
9
  redis: '🔴',
7
10
  }
package/cli/helpers.ts CHANGED
@@ -30,6 +30,16 @@ export type InstalledPostgresEngine = {
30
30
  source: 'downloaded'
31
31
  }
32
32
 
33
+ export type InstalledMariadbEngine = {
34
+ engine: 'mariadb'
35
+ version: string
36
+ platform: string
37
+ arch: string
38
+ path: string
39
+ sizeBytes: number
40
+ source: 'downloaded'
41
+ }
42
+
33
43
  export type InstalledMysqlEngine = {
34
44
  engine: 'mysql'
35
45
  version: string
@@ -64,6 +74,7 @@ export type InstalledRedisEngine = {
64
74
 
65
75
  export type InstalledEngine =
66
76
  | InstalledPostgresEngine
77
+ | InstalledMariadbEngine
67
78
  | InstalledMysqlEngine
68
79
  | InstalledSqliteEngine
69
80
  | InstalledMongodbEngine
@@ -143,6 +154,86 @@ export async function getInstalledPostgresEngines(): Promise<
143
154
  return engines
144
155
  }
145
156
 
157
+ async function getMariadbVersion(binPath: string): Promise<string | null> {
158
+ const ext = platformService.getExecutableExtension()
159
+ // Try mariadbd first, then mysqld
160
+ let serverPath = join(binPath, 'bin', `mariadbd${ext}`)
161
+ if (!existsSync(serverPath)) {
162
+ serverPath = join(binPath, 'bin', `mysqld${ext}`)
163
+ }
164
+ if (!existsSync(serverPath)) {
165
+ return null
166
+ }
167
+
168
+ try {
169
+ const { stdout } = await execFileAsync(serverPath, ['--version'])
170
+ // Parse output like "mariadbd Ver 11.8.5-MariaDB"
171
+ const match = stdout.match(/Ver\s+([\d.]+)/)
172
+ return match ? match[1] : null
173
+ } catch {
174
+ return null
175
+ }
176
+ }
177
+
178
+ export async function getInstalledMariadbEngines(): Promise<
179
+ InstalledMariadbEngine[]
180
+ > {
181
+ const binDir = paths.bin
182
+
183
+ if (!existsSync(binDir)) {
184
+ return []
185
+ }
186
+
187
+ const entries = await readdir(binDir, { withFileTypes: true })
188
+ const engines: InstalledMariadbEngine[] = []
189
+
190
+ for (const entry of entries) {
191
+ if (entry.isDirectory()) {
192
+ // Match mariadb-{version}-{platform}-{arch} directories
193
+ const match = entry.name.match(/^(\w+)-([\d.]+)-(\w+)-(\w+)$/)
194
+ if (match && match[1] === 'mariadb') {
195
+ const [, , majorVersion, platform, arch] = match
196
+ const dirPath = join(binDir, entry.name)
197
+
198
+ const actualVersion =
199
+ (await getMariadbVersion(dirPath)) || majorVersion
200
+
201
+ let sizeBytes = 0
202
+ try {
203
+ const files = await readdir(dirPath, { recursive: true })
204
+ for (const file of files) {
205
+ try {
206
+ const filePath = join(dirPath, file.toString())
207
+ const fileStat = await lstat(filePath)
208
+ if (fileStat.isFile()) {
209
+ sizeBytes += fileStat.size
210
+ }
211
+ } catch {
212
+ // Skip files we can't stat
213
+ }
214
+ }
215
+ } catch {
216
+ // Skip directories we can't read
217
+ }
218
+
219
+ engines.push({
220
+ engine: 'mariadb',
221
+ version: actualVersion,
222
+ platform,
223
+ arch,
224
+ path: dirPath,
225
+ sizeBytes,
226
+ source: 'downloaded',
227
+ })
228
+ }
229
+ }
230
+ }
231
+
232
+ engines.sort((a, b) => compareVersions(b.version, a.version))
233
+
234
+ return engines
235
+ }
236
+
146
237
  /**
147
238
  * Extract Homebrew formula name from a binary path by resolving symlinks
148
239
  */
@@ -468,6 +559,9 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
468
559
  const pgEngines = await getInstalledPostgresEngines()
469
560
  engines.push(...pgEngines)
470
561
 
562
+ const mariadbEngines = await getInstalledMariadbEngines()
563
+ engines.push(...mariadbEngines)
564
+
471
565
  const mysqlEngines = await getInstalledMysqlEngines()
472
566
  engines.push(...mysqlEngines)
473
567
 
@@ -35,7 +35,7 @@ export const engineDefaults: Record<string, EngineDefaults> = {
35
35
  defaultVersion: '18',
36
36
  defaultPort: 5432,
37
37
  portRange: { start: 5432, end: 5500 },
38
- supportedVersions: ['14', '15', '16', '17', '18'], // update edb-binary-urls.ts when adding new versions
38
+ supportedVersions: ['15', '16', '17', '18'], // keep in sync with engines/postgresql/version-maps.ts
39
39
  latestVersion: '18',
40
40
  superuser: 'postgres',
41
41
  connectionScheme: 'postgresql',
@@ -59,6 +59,20 @@ export const engineDefaults: Record<string, EngineDefaults> = {
59
59
  clientTools: ['mysql', 'mysqldump', 'mysqlpump'],
60
60
  maxConnections: 200, // Higher than default 151 for parallel builds
61
61
  },
62
+ mariadb: {
63
+ defaultVersion: '11.8',
64
+ defaultPort: 3307, // Different from MySQL to allow side-by-side
65
+ portRange: { start: 3307, end: 3400 },
66
+ supportedVersions: ['10.11', '11.4', '11.8'], // Keep in sync with engines/mariadb/version-maps.ts
67
+ latestVersion: '11.8',
68
+ superuser: 'root',
69
+ connectionScheme: 'mysql', // MariaDB uses MySQL protocol
70
+ logFileName: 'mariadb.log',
71
+ pidFileName: 'mariadb.pid',
72
+ dataSubdir: 'data',
73
+ clientTools: ['mysql', 'mysqldump', 'mysqladmin'],
74
+ maxConnections: 200, // Higher than default 151 for parallel builds
75
+ },
62
76
  sqlite: {
63
77
  defaultVersion: '3',
64
78
  defaultPort: 0, // File-based, no port
@@ -16,7 +16,7 @@ export type RollbackAction = {
16
16
  * Manages a stack of rollback actions for transactional operations.
17
17
  *
18
18
  * Usage:
19
- * ```typescript
19
+ * ```ts
20
20
  * const tx = new TransactionManager()
21
21
  *
22
22
  * try {
@@ -134,7 +134,7 @@ export class TransactionManager {
134
134
  * Helper function to execute an operation with automatic rollback on failure.
135
135
  *
136
136
  * Usage:
137
- * ```typescript
137
+ * ```ts
138
138
  * await withTransaction(async (tx) => {
139
139
  * await step1()
140
140
  * tx.addRollback({ description: 'Undo step1', execute: undoStep1 })
@@ -96,6 +96,14 @@ export abstract class BaseEngine {
96
96
  throw new Error('mysql client not found')
97
97
  }
98
98
 
99
+ /**
100
+ * Get the path to the mariadb client if available
101
+ * Default implementation throws; MariaDB engine overrides this method.
102
+ */
103
+ async getMariadbClientPath(): Promise<string> {
104
+ throw new Error('mariadb client not found')
105
+ }
106
+
99
107
  /**
100
108
  * Get the path to the mysqladmin client if available
101
109
  * Default implementation throws; engines that can provide a bundled or
package/engines/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { postgresqlEngine } from './postgresql'
2
2
  import { mysqlEngine } from './mysql'
3
+ import { mariadbEngine } from './mariadb'
3
4
  import { sqliteEngine } from './sqlite'
4
5
  import { mongodbEngine } from './mongodb'
5
6
  import { redisEngine } from './redis'
@@ -16,7 +17,9 @@ export const engines: Record<string, BaseEngine> = {
16
17
  pg: postgresqlEngine,
17
18
  // MySQL and aliases
18
19
  mysql: mysqlEngine,
19
- mariadb: mysqlEngine, // MariaDB is MySQL-compatible
20
+ // MariaDB (standalone engine with downloadable binaries)
21
+ mariadb: mariadbEngine,
22
+ maria: mariadbEngine,
20
23
  // SQLite and aliases
21
24
  sqlite: sqliteEngine,
22
25
  lite: sqliteEngine,