spindb 0.4.1 → 0.5.3

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 (44) hide show
  1. package/README.md +207 -101
  2. package/cli/commands/clone.ts +3 -1
  3. package/cli/commands/connect.ts +54 -24
  4. package/cli/commands/create.ts +309 -189
  5. package/cli/commands/delete.ts +3 -1
  6. package/cli/commands/deps.ts +19 -4
  7. package/cli/commands/edit.ts +245 -0
  8. package/cli/commands/engines.ts +434 -0
  9. package/cli/commands/info.ts +279 -0
  10. package/cli/commands/list.ts +14 -3
  11. package/cli/commands/menu.ts +510 -198
  12. package/cli/commands/restore.ts +66 -43
  13. package/cli/commands/start.ts +50 -19
  14. package/cli/commands/stop.ts +3 -1
  15. package/cli/commands/url.ts +79 -0
  16. package/cli/index.ts +9 -3
  17. package/cli/ui/prompts.ts +99 -34
  18. package/config/defaults.ts +40 -15
  19. package/config/engine-defaults.ts +107 -0
  20. package/config/os-dependencies.ts +119 -124
  21. package/config/paths.ts +82 -56
  22. package/core/binary-manager.ts +44 -6
  23. package/core/config-manager.ts +17 -5
  24. package/core/container-manager.ts +124 -60
  25. package/core/dependency-manager.ts +9 -15
  26. package/core/error-handler.ts +336 -0
  27. package/core/platform-service.ts +634 -0
  28. package/core/port-manager.ts +51 -32
  29. package/core/process-manager.ts +26 -8
  30. package/core/start-with-retry.ts +167 -0
  31. package/core/transaction-manager.ts +170 -0
  32. package/engines/index.ts +7 -2
  33. package/engines/mysql/binary-detection.ts +325 -0
  34. package/engines/mysql/index.ts +808 -0
  35. package/engines/mysql/restore.ts +257 -0
  36. package/engines/mysql/version-validator.ts +373 -0
  37. package/{core/postgres-binary-manager.ts → engines/postgresql/binary-manager.ts} +63 -23
  38. package/engines/postgresql/binary-urls.ts +5 -3
  39. package/engines/postgresql/index.ts +17 -9
  40. package/engines/postgresql/restore.ts +54 -5
  41. package/engines/postgresql/version-validator.ts +262 -0
  42. package/package.json +9 -3
  43. package/types/index.ts +29 -5
  44. package/cli/commands/postgres-tools.ts +0 -216
@@ -1,3 +1,20 @@
1
+ import {
2
+ engineDefaults,
3
+ getEngineDefaults,
4
+ isEngineSupported,
5
+ getSupportedEngines,
6
+ type EngineDefaults,
7
+ } from './engine-defaults'
8
+
9
+ // Re-export engine-related functions and types
10
+ export {
11
+ engineDefaults,
12
+ getEngineDefaults,
13
+ isEngineSupported,
14
+ getSupportedEngines,
15
+ type EngineDefaults,
16
+ }
17
+
1
18
  export type PlatformMappings = {
2
19
  [key: string]: string
3
20
  }
@@ -7,42 +24,50 @@ export type PortRange = {
7
24
  end: number
8
25
  }
9
26
 
27
+ /**
28
+ * Legacy Defaults type - kept for backward compatibility
29
+ * New code should use getEngineDefaults(engine) instead
30
+ */
10
31
  export type Defaults = {
32
+ /** @deprecated Use getEngineDefaults(engine).defaultVersion instead */
11
33
  postgresVersion: string
12
34
  port: number
13
35
  portRange: PortRange
14
36
  engine: string
37
+ /** @deprecated Use getEngineDefaults(engine).supportedVersions instead */
15
38
  supportedPostgresVersions: string[]
16
39
  superuser: string
17
40
  platformMappings: PlatformMappings
18
41
  }
19
42
 
20
- // TODO - make defaults configurable via env vars or config file
21
- // TODO - make defaults generic so it supports multiple engines
22
- // TODO - consider using a configuration file or environment variables for overrides
43
+ // Get PostgreSQL defaults from engine-defaults
44
+ const pgDefaults = engineDefaults.postgresql
45
+
46
+ /**
47
+ * Default configuration values
48
+ * For backward compatibility, this defaults to PostgreSQL settings.
49
+ * New code should use getEngineDefaults(engine) for engine-specific defaults.
50
+ */
23
51
  export const defaults: Defaults = {
24
- // Default PostgreSQL version
25
- postgresVersion: '16',
52
+ // Default PostgreSQL version (from engine defaults)
53
+ postgresVersion: pgDefaults.defaultVersion,
26
54
 
27
55
  // Default port (standard PostgreSQL port)
28
- port: 5432,
56
+ port: pgDefaults.defaultPort,
29
57
 
30
58
  // Port range to scan if default is busy
31
- portRange: {
32
- start: 5432,
33
- end: 5500,
34
- },
59
+ portRange: pgDefaults.portRange,
35
60
 
36
61
  // Default engine
37
62
  engine: 'postgresql',
38
63
 
39
- // Supported PostgreSQL versions
40
- supportedPostgresVersions: ['14', '15', '16', '17'],
64
+ // Supported PostgreSQL versions (from engine defaults)
65
+ supportedPostgresVersions: pgDefaults.supportedVersions,
41
66
 
42
- // Default superuser
43
- superuser: 'postgres',
67
+ // Default superuser (from engine defaults)
68
+ superuser: pgDefaults.superuser,
44
69
 
45
- // Platform mappings for zonky.io binaries
70
+ // Platform mappings for zonky.io binaries (PostgreSQL specific)
46
71
  platformMappings: {
47
72
  'darwin-arm64': 'darwin-arm64v8',
48
73
  'darwin-x64': 'darwin-amd64',
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Engine-specific default configurations
3
+ * Extracted for dependency injection pattern - allows each engine to define its own defaults
4
+ */
5
+
6
+ export type EngineDefaults = {
7
+ /** Default version to use when not specified */
8
+ defaultVersion: string
9
+ /** Default port for this engine */
10
+ defaultPort: number
11
+ /** Port range to scan if default is busy */
12
+ portRange: { start: number; end: number }
13
+ /** Supported major versions */
14
+ supportedVersions: string[]
15
+ /** Latest major version (used for Homebrew package names like postgresql@17) */
16
+ latestVersion: string
17
+ /** Default superuser name */
18
+ superuser: string
19
+ /** Connection string scheme (e.g., 'postgresql', 'mysql') */
20
+ connectionScheme: string
21
+ /** Log file name within container directory */
22
+ logFileName: string
23
+ /** PID file name (relative to data directory or container) */
24
+ pidFileName: string
25
+ /** Subdirectory for data files within container */
26
+ dataSubdir: string
27
+ /** Client tools required for this engine */
28
+ clientTools: string[]
29
+ }
30
+
31
+ export const engineDefaults: Record<string, EngineDefaults> = {
32
+ postgresql: {
33
+ defaultVersion: '17',
34
+ defaultPort: 5432,
35
+ portRange: { start: 5432, end: 5500 },
36
+ supportedVersions: ['14', '15', '16', '17'],
37
+ latestVersion: '17', // Update when PostgreSQL 18 is released
38
+ superuser: 'postgres',
39
+ connectionScheme: 'postgresql',
40
+ logFileName: 'postgres.log',
41
+ pidFileName: 'postmaster.pid',
42
+ dataSubdir: 'data',
43
+ clientTools: ['psql', 'pg_dump', 'pg_restore', 'pg_basebackup'],
44
+ },
45
+ mysql: {
46
+ defaultVersion: '9.0',
47
+ defaultPort: 3306,
48
+ portRange: { start: 3306, end: 3400 },
49
+ supportedVersions: ['5.7', '8.0', '8.4', '9.0'],
50
+ latestVersion: '9.0', // MySQL doesn't use versioned Homebrew packages, but kept for consistency
51
+ superuser: 'root',
52
+ connectionScheme: 'mysql',
53
+ logFileName: 'mysql.log',
54
+ pidFileName: 'mysql.pid',
55
+ dataSubdir: 'data',
56
+ clientTools: ['mysql', 'mysqldump', 'mysqlpump'],
57
+ },
58
+ }
59
+
60
+ /**
61
+ * Get engine defaults by name
62
+ * @throws Error if engine is not found
63
+ */
64
+ export function getEngineDefaults(engine: string): EngineDefaults {
65
+ const normalized = engine.toLowerCase()
66
+ const defaults = engineDefaults[normalized]
67
+ if (!defaults) {
68
+ const available = Object.keys(engineDefaults).join(', ')
69
+ throw new Error(
70
+ `Unknown engine "${engine}". Available engines: ${available}`,
71
+ )
72
+ }
73
+ return defaults
74
+ }
75
+
76
+ /**
77
+ * Check if an engine is supported
78
+ */
79
+ export function isEngineSupported(engine: string): boolean {
80
+ return engine.toLowerCase() in engineDefaults
81
+ }
82
+
83
+ /**
84
+ * Get list of all supported engine names
85
+ */
86
+ export function getSupportedEngines(): string[] {
87
+ return Object.keys(engineDefaults)
88
+ }
89
+
90
+ /**
91
+ * Get Homebrew package name for PostgreSQL client tools
92
+ * Returns 'postgresql@17' format for versioned installs
93
+ */
94
+ export function getPostgresHomebrewPackage(): string {
95
+ const version = engineDefaults.postgresql.latestVersion
96
+ return `postgresql@${version}`
97
+ }
98
+
99
+ /**
100
+ * Get the PostgreSQL Homebrew bin path for a given architecture
101
+ * @param arch - 'arm64' or 'x64'
102
+ */
103
+ export function getPostgresHomebrewBinPath(arch: 'arm64' | 'x64'): string {
104
+ const pkg = getPostgresHomebrewPackage()
105
+ const prefix = arch === 'arm64' ? '/opt/homebrew' : '/usr/local'
106
+ return `${prefix}/opt/${pkg}/bin`
107
+ }
@@ -5,9 +5,11 @@
5
5
  * across different operating systems and package managers.
6
6
  */
7
7
 
8
+ import { getPostgresHomebrewPackage } from './engine-defaults'
9
+
8
10
  export type PackageManagerId = 'brew' | 'apt' | 'yum' | 'dnf' | 'pacman'
9
11
 
10
- export type Platform = 'darwin' | 'linux'
12
+ export type Platform = 'darwin' | 'linux' | 'win32'
11
13
 
12
14
  /**
13
15
  * Package definition for a specific package manager
@@ -116,177 +118,170 @@ export const packageManagers: PackageManagerConfig[] = [
116
118
  // PostgreSQL Dependencies
117
119
  // =============================================================================
118
120
 
121
+ /**
122
+ * Helper to create PostgreSQL client tool dependency
123
+ * Uses getPostgresHomebrewPackage() to get the current latest version
124
+ */
125
+ function createPostgresDependency(
126
+ name: string,
127
+ binary: string,
128
+ description: string,
129
+ ): Dependency {
130
+ const pgPackage = getPostgresHomebrewPackage()
131
+ return {
132
+ name,
133
+ binary,
134
+ description,
135
+ packages: {
136
+ brew: {
137
+ package: pgPackage,
138
+ postInstall: [`brew link --overwrite ${pgPackage}`],
139
+ },
140
+ apt: { package: 'postgresql-client' },
141
+ yum: { package: 'postgresql' },
142
+ dnf: { package: 'postgresql' },
143
+ pacman: { package: 'postgresql-libs' },
144
+ },
145
+ manualInstall: {
146
+ darwin: [
147
+ 'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
148
+ `Then run: brew install ${pgPackage} && brew link --overwrite ${pgPackage}`,
149
+ 'Or install Postgres.app: https://postgresapp.com/downloads.html',
150
+ ],
151
+ linux: [
152
+ 'Ubuntu/Debian: sudo apt install postgresql-client',
153
+ 'CentOS/RHEL: sudo yum install postgresql',
154
+ 'Fedora: sudo dnf install postgresql',
155
+ 'Arch: sudo pacman -S postgresql-libs',
156
+ ],
157
+ },
158
+ }
159
+ }
160
+
119
161
  const postgresqlDependencies: EngineDependencies = {
120
162
  engine: 'postgresql',
121
163
  displayName: 'PostgreSQL',
164
+ dependencies: [
165
+ createPostgresDependency('psql', 'psql', 'PostgreSQL interactive terminal'),
166
+ createPostgresDependency(
167
+ 'pg_dump',
168
+ 'pg_dump',
169
+ 'PostgreSQL database backup utility',
170
+ ),
171
+ createPostgresDependency(
172
+ 'pg_restore',
173
+ 'pg_restore',
174
+ 'PostgreSQL database restore utility',
175
+ ),
176
+ createPostgresDependency(
177
+ 'pg_basebackup',
178
+ 'pg_basebackup',
179
+ 'PostgreSQL base backup utility for physical backups',
180
+ ),
181
+ ],
182
+ }
183
+
184
+ // =============================================================================
185
+ // MySQL Dependencies (placeholder for future)
186
+ // =============================================================================
187
+
188
+ const mysqlDependencies: EngineDependencies = {
189
+ engine: 'mysql',
190
+ displayName: 'MySQL/MariaDB',
122
191
  dependencies: [
123
192
  {
124
- name: 'psql',
125
- binary: 'psql',
126
- description: 'PostgreSQL interactive terminal',
127
- packages: {
128
- brew: {
129
- package: 'postgresql@17',
130
- postInstall: ['brew link --overwrite postgresql@17'],
131
- },
132
- apt: { package: 'postgresql-client' },
133
- yum: { package: 'postgresql' },
134
- dnf: { package: 'postgresql' },
135
- pacman: { package: 'postgresql-libs' },
136
- },
137
- manualInstall: {
138
- darwin: [
139
- 'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
140
- 'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
141
- 'Or install Postgres.app: https://postgresapp.com/downloads.html',
142
- ],
143
- linux: [
144
- 'Ubuntu/Debian: sudo apt install postgresql-client',
145
- 'CentOS/RHEL: sudo yum install postgresql',
146
- 'Fedora: sudo dnf install postgresql',
147
- 'Arch: sudo pacman -S postgresql-libs',
148
- ],
149
- },
150
- },
151
- {
152
- name: 'pg_dump',
153
- binary: 'pg_dump',
154
- description: 'PostgreSQL database backup utility',
155
- packages: {
156
- brew: {
157
- package: 'postgresql@17',
158
- postInstall: ['brew link --overwrite postgresql@17'],
159
- },
160
- apt: { package: 'postgresql-client' },
161
- yum: { package: 'postgresql' },
162
- dnf: { package: 'postgresql' },
163
- pacman: { package: 'postgresql-libs' },
164
- },
165
- manualInstall: {
166
- darwin: [
167
- 'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
168
- 'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
169
- 'Or install Postgres.app: https://postgresapp.com/downloads.html',
170
- ],
171
- linux: [
172
- 'Ubuntu/Debian: sudo apt install postgresql-client',
173
- 'CentOS/RHEL: sudo yum install postgresql',
174
- 'Fedora: sudo dnf install postgresql',
175
- 'Arch: sudo pacman -S postgresql-libs',
176
- ],
177
- },
178
- },
179
- {
180
- name: 'pg_restore',
181
- binary: 'pg_restore',
182
- description: 'PostgreSQL database restore utility',
193
+ name: 'mysqld',
194
+ binary: 'mysqld',
195
+ description: 'MySQL/MariaDB server daemon',
183
196
  packages: {
184
- brew: {
185
- package: 'postgresql@17',
186
- postInstall: ['brew link --overwrite postgresql@17'],
187
- },
188
- apt: { package: 'postgresql-client' },
189
- yum: { package: 'postgresql' },
190
- dnf: { package: 'postgresql' },
191
- pacman: { package: 'postgresql-libs' },
197
+ brew: { package: 'mysql' },
198
+ // Modern Debian/Ubuntu use mariadb-server (MySQL-compatible)
199
+ apt: { package: 'mariadb-server' },
200
+ yum: { package: 'mariadb-server' },
201
+ dnf: { package: 'mariadb-server' },
202
+ pacman: { package: 'mariadb' },
192
203
  },
193
204
  manualInstall: {
194
205
  darwin: [
195
206
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
196
- 'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
197
- 'Or install Postgres.app: https://postgresapp.com/downloads.html',
207
+ 'Then run: brew install mysql',
198
208
  ],
199
209
  linux: [
200
- 'Ubuntu/Debian: sudo apt install postgresql-client',
201
- 'CentOS/RHEL: sudo yum install postgresql',
202
- 'Fedora: sudo dnf install postgresql',
203
- 'Arch: sudo pacman -S postgresql-libs',
210
+ 'Debian/Ubuntu: sudo apt install mariadb-server',
211
+ 'CentOS/RHEL: sudo yum install mariadb-server',
212
+ 'Fedora: sudo dnf install mariadb-server',
213
+ 'Arch: sudo pacman -S mariadb',
204
214
  ],
205
215
  },
206
216
  },
207
217
  {
208
- name: 'pg_basebackup',
209
- binary: 'pg_basebackup',
210
- description: 'PostgreSQL base backup utility for physical backups',
218
+ name: 'mysql',
219
+ binary: 'mysql',
220
+ description: 'MySQL/MariaDB command-line client',
211
221
  packages: {
212
- brew: {
213
- package: 'postgresql@17',
214
- postInstall: ['brew link --overwrite postgresql@17'],
215
- },
216
- apt: { package: 'postgresql-client' },
217
- yum: { package: 'postgresql' },
218
- dnf: { package: 'postgresql' },
219
- pacman: { package: 'postgresql-libs' },
222
+ brew: { package: 'mysql' },
223
+ apt: { package: 'mariadb-client' },
224
+ yum: { package: 'mariadb' },
225
+ dnf: { package: 'mariadb' },
226
+ pacman: { package: 'mariadb-clients' },
220
227
  },
221
228
  manualInstall: {
222
229
  darwin: [
223
230
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
224
- 'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
225
- 'Or install Postgres.app: https://postgresapp.com/downloads.html',
231
+ 'Then run: brew install mysql',
226
232
  ],
227
233
  linux: [
228
- 'Ubuntu/Debian: sudo apt install postgresql-client',
229
- 'CentOS/RHEL: sudo yum install postgresql',
230
- 'Fedora: sudo dnf install postgresql',
231
- 'Arch: sudo pacman -S postgresql-libs',
234
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
235
+ 'CentOS/RHEL: sudo yum install mariadb',
236
+ 'Fedora: sudo dnf install mariadb',
237
+ 'Arch: sudo pacman -S mariadb-clients',
232
238
  ],
233
239
  },
234
240
  },
235
- ],
236
- }
237
-
238
- // =============================================================================
239
- // MySQL Dependencies (placeholder for future)
240
- // =============================================================================
241
-
242
- const mysqlDependencies: EngineDependencies = {
243
- engine: 'mysql',
244
- displayName: 'MySQL',
245
- dependencies: [
246
241
  {
247
- name: 'mysql',
248
- binary: 'mysql',
249
- description: 'MySQL command-line client',
242
+ name: 'mysqldump',
243
+ binary: 'mysqldump',
244
+ description: 'MySQL/MariaDB database backup utility',
250
245
  packages: {
251
- brew: { package: 'mysql-client' },
252
- apt: { package: 'mysql-client' },
253
- yum: { package: 'mysql' },
254
- dnf: { package: 'mysql' },
246
+ brew: { package: 'mysql' },
247
+ apt: { package: 'mariadb-client' },
248
+ yum: { package: 'mariadb' },
249
+ dnf: { package: 'mariadb' },
255
250
  pacman: { package: 'mariadb-clients' },
256
251
  },
257
252
  manualInstall: {
258
253
  darwin: [
259
254
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
260
- 'Then run: brew install mysql-client',
255
+ 'Then run: brew install mysql',
261
256
  ],
262
257
  linux: [
263
- 'Ubuntu/Debian: sudo apt install mysql-client',
264
- 'CentOS/RHEL: sudo yum install mysql',
265
- 'Fedora: sudo dnf install mysql',
258
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
259
+ 'CentOS/RHEL: sudo yum install mariadb',
260
+ 'Fedora: sudo dnf install mariadb',
266
261
  'Arch: sudo pacman -S mariadb-clients',
267
262
  ],
268
263
  },
269
264
  },
270
265
  {
271
- name: 'mysqldump',
272
- binary: 'mysqldump',
273
- description: 'MySQL database backup utility',
266
+ name: 'mysqladmin',
267
+ binary: 'mysqladmin',
268
+ description: 'MySQL/MariaDB server administration utility',
274
269
  packages: {
275
- brew: { package: 'mysql-client' },
276
- apt: { package: 'mysql-client' },
277
- yum: { package: 'mysql' },
278
- dnf: { package: 'mysql' },
270
+ brew: { package: 'mysql' },
271
+ apt: { package: 'mariadb-client' },
272
+ yum: { package: 'mariadb' },
273
+ dnf: { package: 'mariadb' },
279
274
  pacman: { package: 'mariadb-clients' },
280
275
  },
281
276
  manualInstall: {
282
277
  darwin: [
283
278
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
284
- 'Then run: brew install mysql-client',
279
+ 'Then run: brew install mysql',
285
280
  ],
286
281
  linux: [
287
- 'Ubuntu/Debian: sudo apt install mysql-client',
288
- 'CentOS/RHEL: sudo yum install mysql',
289
- 'Fedora: sudo dnf install mysql',
282
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
283
+ 'CentOS/RHEL: sudo yum install mariadb',
284
+ 'Fedora: sudo dnf install mariadb',
290
285
  'Arch: sudo pacman -S mariadb-clients',
291
286
  ],
292
287
  },
package/config/paths.ts CHANGED
@@ -1,45 +1,34 @@
1
- import { homedir } from 'os'
2
1
  import { join } from 'path'
3
- import { execSync } from 'child_process'
2
+ import { getEngineDefaults } from './engine-defaults'
3
+ import { platformService } from '../core/platform-service'
4
4
 
5
5
  /**
6
- * Get the real user's home directory, even when running under sudo.
7
- * When a user runs `sudo spindb`, we want to use their home directory,
8
- * not root's home directory.
6
+ * Get the SpinDB home directory using the platform service.
7
+ * This handles sudo detection and platform-specific home directories.
9
8
  */
10
- function getRealHomeDir(): string {
11
- // Check if running under sudo
12
- const sudoUser = process.env.SUDO_USER
9
+ function getSpinDBHome(): string {
10
+ const platformInfo = platformService.getPlatformInfo()
11
+ return join(platformInfo.homeDir, '.spindb')
12
+ }
13
13
 
14
- if (sudoUser) {
15
- // Get the original user's home directory
16
- try {
17
- // Use getent to reliably get the home directory for the sudo user
18
- const result = execSync(`getent passwd ${sudoUser}`, {
19
- encoding: 'utf-8',
20
- })
21
- const parts = result.trim().split(':')
22
- if (parts.length >= 6 && parts[5]) {
23
- return parts[5]
24
- }
25
- } catch {
26
- // Fall back to constructing the path
27
- // On most Linux systems, home dirs are /home/username
28
- // On macOS, they're /Users/username
29
- const platform = process.platform
30
- if (platform === 'darwin') {
31
- return `/Users/${sudoUser}`
32
- } else {
33
- return `/home/${sudoUser}`
34
- }
35
- }
36
- }
14
+ const SPINDB_HOME = getSpinDBHome()
37
15
 
38
- // Not running under sudo, use normal homedir
39
- return homedir()
16
+ /**
17
+ * Options for container path functions
18
+ */
19
+ type ContainerPathOptions = {
20
+ engine: string
40
21
  }
41
22
 
42
- const SPINDB_HOME = join(getRealHomeDir(), '.spindb')
23
+ /**
24
+ * Options for binary path functions
25
+ */
26
+ type BinaryPathOptions = {
27
+ engine: string
28
+ version: string
29
+ platform: string
30
+ arch: string
31
+ }
43
32
 
44
33
  export const paths = {
45
34
  // Root directory for all spindb data
@@ -54,38 +43,75 @@ export const paths = {
54
43
  // Global config file
55
44
  config: join(SPINDB_HOME, 'config.json'),
56
45
 
57
- // Get path for a specific binary version
58
- getBinaryPath(
59
- engine: string,
60
- version: string,
61
- platform: string,
62
- arch: string,
63
- ): string {
46
+ /**
47
+ * Get path for a specific binary version
48
+ */
49
+ getBinaryPath(options: BinaryPathOptions): string {
50
+ const { engine, version, platform, arch } = options
64
51
  return join(this.bin, `${engine}-${version}-${platform}-${arch}`)
65
52
  },
66
53
 
67
- // Get path for a specific container
68
- getContainerPath(name: string): string {
69
- return join(this.containers, name)
54
+ /**
55
+ * Get path for a specific container
56
+ * New structure: ~/.spindb/containers/{engine}/{name}/
57
+ */
58
+ getContainerPath(name: string, options: ContainerPathOptions): string {
59
+ const { engine } = options
60
+ return join(this.containers, engine, name)
70
61
  },
71
62
 
72
- // Get path for container config
73
- getContainerConfigPath(name: string): string {
74
- return join(this.containers, name, 'container.json')
63
+ /**
64
+ * Get path for container config file
65
+ */
66
+ getContainerConfigPath(name: string, options: ContainerPathOptions): string {
67
+ const { engine } = options
68
+ return join(this.containers, engine, name, 'container.json')
75
69
  },
76
70
 
77
- // Get path for container data directory
78
- getContainerDataPath(name: string): string {
79
- return join(this.containers, name, 'data')
71
+ /**
72
+ * Get path for container data directory
73
+ */
74
+ getContainerDataPath(name: string, options: ContainerPathOptions): string {
75
+ const { engine } = options
76
+ const engineDef = getEngineDefaults(engine)
77
+ return join(this.containers, engine, name, engineDef.dataSubdir)
80
78
  },
81
79
 
82
- // Get path for container log file
83
- getContainerLogPath(name: string): string {
84
- return join(this.containers, name, 'postgres.log')
80
+ /**
81
+ * Get path for container log file
82
+ */
83
+ getContainerLogPath(name: string, options: ContainerPathOptions): string {
84
+ const { engine } = options
85
+ const engineDef = getEngineDefaults(engine)
86
+ return join(this.containers, engine, name, engineDef.logFileName)
87
+ },
88
+
89
+ /**
90
+ * Get path for container PID file
91
+ * Note: For PostgreSQL, PID is inside data dir. For MySQL, it may differ.
92
+ */
93
+ getContainerPidPath(name: string, options: ContainerPathOptions): string {
94
+ const { engine } = options
95
+ const engineDef = getEngineDefaults(engine)
96
+ // PostgreSQL: data/postmaster.pid
97
+ // MySQL: data/mysql.pid (or just mysql.pid depending on config)
98
+ if (engine === 'postgresql') {
99
+ return join(
100
+ this.containers,
101
+ engine,
102
+ name,
103
+ engineDef.dataSubdir,
104
+ engineDef.pidFileName,
105
+ )
106
+ }
107
+ // MySQL and others: PID file at container level
108
+ return join(this.containers, engine, name, engineDef.pidFileName)
85
109
  },
86
110
 
87
- // Get path for container PID file
88
- getContainerPidPath(name: string): string {
89
- return join(this.containers, name, 'data', 'postmaster.pid')
111
+ /**
112
+ * Get path for engine-specific containers directory
113
+ */
114
+ getEngineContainersPath(engine: string): string {
115
+ return join(this.containers, engine)
90
116
  },
91
117
  }