spindb 0.4.1 → 0.5.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/cli/ui/prompts.ts CHANGED
@@ -2,12 +2,13 @@ import inquirer from 'inquirer'
2
2
  import chalk from 'chalk'
3
3
  import ora from 'ora'
4
4
  import { listEngines, getEngine } from '../../engines'
5
- import { defaults } from '../../config/defaults'
5
+ import { defaults, getEngineDefaults } from '../../config/defaults'
6
6
  import { installPostgresBinaries } from '../../core/postgres-binary-manager'
7
7
  import {
8
8
  detectPackageManager,
9
9
  getManualInstallInstructions,
10
10
  getCurrentPlatform,
11
+ installEngineDependencies,
11
12
  } from '../../core/dependency-manager'
12
13
  import { getEngineDependencies } from '../../config/os-dependencies'
13
14
  import type { ContainerConfig } from '../../types'
@@ -36,25 +37,26 @@ export async function promptContainerName(
36
37
  return name
37
38
  }
38
39
 
40
+ /**
41
+ * Engine icons for display
42
+ */
43
+ const engineIcons: Record<string, string> = {
44
+ postgresql: '🐘',
45
+ mysql: '🐬',
46
+ }
47
+
39
48
  /**
40
49
  * Prompt for database engine selection
41
50
  */
42
51
  export async function promptEngine(): Promise<string> {
43
52
  const engines = listEngines()
44
53
 
45
- // Build choices from available engines plus coming soon engines
46
- const choices = [
47
- ...engines.map((e) => ({
48
- name: `🐘 ${e.displayName} ${chalk.gray(`(versions: ${e.supportedVersions.join(', ')})`)}`,
49
- value: e.name,
50
- short: e.displayName,
51
- })),
52
- {
53
- name: chalk.gray('🐬 MySQL (coming soon)'),
54
- value: 'mysql',
55
- disabled: 'Coming soon',
56
- },
57
- ]
54
+ // Build choices from available engines
55
+ const choices = engines.map((e) => ({
56
+ name: `${engineIcons[e.name] || '🗄️'} ${e.displayName} ${chalk.gray(`(versions: ${e.supportedVersions.join(', ')})`)}`,
57
+ value: e.name,
58
+ short: e.displayName,
59
+ }))
58
60
 
59
61
  const { engine } = await inquirer.prompt<{ engine: string }>([
60
62
  {
@@ -69,8 +71,8 @@ export async function promptEngine(): Promise<string> {
69
71
  }
70
72
 
71
73
  /**
72
- * Prompt for PostgreSQL version
73
- * Two-step selection: first major version, then specific minor version
74
+ * Prompt for database version
75
+ * Two-step selection: first major version, then specific minor version (if available)
74
76
  */
75
77
  export async function promptVersion(engineName: string): Promise<string> {
76
78
  const engine = getEngine(engineName)
@@ -112,13 +114,13 @@ export async function promptVersion(engineName: string): Promise<string> {
112
114
  const countLabel =
113
115
  versionCount > 0 ? chalk.gray(`(${versionCount} versions)`) : ''
114
116
  const label = isLatestMajor
115
- ? `PostgreSQL ${major} ${countLabel} ${chalk.green('← latest')}`
116
- : `PostgreSQL ${major} ${countLabel}`
117
+ ? `${engine.displayName} ${major} ${countLabel} ${chalk.green('← latest')}`
118
+ : `${engine.displayName} ${major} ${countLabel}`
117
119
 
118
120
  majorChoices.push({
119
121
  name: label,
120
122
  value: major,
121
- short: `PostgreSQL ${major}`,
123
+ short: `${engine.displayName} ${major}`,
122
124
  })
123
125
  }
124
126
 
@@ -150,7 +152,7 @@ export async function promptVersion(engineName: string): Promise<string> {
150
152
  {
151
153
  type: 'list',
152
154
  name: 'version',
153
- message: `Select PostgreSQL ${majorVersion} version:`,
155
+ message: `Select ${engine.displayName} ${majorVersion} version:`,
154
156
  choices: minorChoices,
155
157
  default: minorVersions[0], // Default to latest
156
158
  },
@@ -225,7 +227,7 @@ export async function promptContainerSelect(
225
227
  name: 'container',
226
228
  message,
227
229
  choices: containers.map((c) => ({
228
- name: `${c.name} ${chalk.gray(`(${c.engine} ${c.version}, port ${c.port})`)} ${
230
+ name: `${c.name} ${chalk.gray(`(${engineIcons[c.engine] || '🗄️'} ${c.engine} ${c.version}, port ${c.port})`)} ${
229
231
  c.status === 'running'
230
232
  ? chalk.green('● running')
231
233
  : chalk.gray('○ stopped')
@@ -279,16 +281,17 @@ export type CreateOptions = {
279
281
  /**
280
282
  * Full interactive create flow
281
283
  */
282
- export async function promptCreateOptions(
283
- defaultPort: number = defaults.port,
284
- ): Promise<CreateOptions> {
284
+ export async function promptCreateOptions(): Promise<CreateOptions> {
285
285
  console.log(chalk.cyan('\n 🗄️ Create New Database Container\n'))
286
286
 
287
287
  const engine = await promptEngine()
288
288
  const version = await promptVersion(engine)
289
289
  const name = await promptContainerName()
290
290
  const database = await promptDatabaseName(name) // Default to container name
291
- const port = await promptPort(defaultPort)
291
+
292
+ // Get engine-specific default port
293
+ const engineDefaults = getEngineDefaults(engine)
294
+ const port = await promptPort(engineDefaults.defaultPort)
292
295
 
293
296
  return { name, engine, version, port, database }
294
297
  }
@@ -393,8 +396,7 @@ export async function promptInstallDependencies(
393
396
 
394
397
  console.log()
395
398
 
396
- // For now, only PostgreSQL has full install support
397
- // Future engines will need their own install functions
399
+ // PostgreSQL has its own install function with extra logic
398
400
  if (engine === 'postgresql') {
399
401
  const success = await installPostgresBinaries()
400
402
 
@@ -410,11 +412,72 @@ export async function promptInstallDependencies(
410
412
  return success
411
413
  }
412
414
 
413
- // For other engines, show manual instructions
415
+ // For other engines (MySQL, etc.), use the generic installer
414
416
  console.log(
415
- chalk.yellow(` Automatic installation for ${engineName} is not yet supported.`),
417
+ chalk.cyan(` Installing ${engineName} with ${packageManager.name}...`),
416
418
  )
417
- console.log(chalk.gray(' Please install manually.'))
419
+ console.log(chalk.gray(' You may be prompted for your password.'))
418
420
  console.log()
419
- return false
421
+
422
+ try {
423
+ const results = await installEngineDependencies(engine, packageManager)
424
+ const allSuccess = results.every((r) => r.success)
425
+
426
+ if (allSuccess) {
427
+ console.log()
428
+ console.log(
429
+ chalk.green(` ${engineName} tools installed successfully!`),
430
+ )
431
+ console.log(chalk.gray(' Continuing with your operation...'))
432
+ console.log()
433
+ return true
434
+ } else {
435
+ const failed = results.filter((r) => !r.success)
436
+ console.log()
437
+ console.log(chalk.red(' Some installations failed:'))
438
+ for (const f of failed) {
439
+ console.log(chalk.red(` ${f.dependency.name}: ${f.error}`))
440
+ }
441
+ console.log()
442
+
443
+ // Show manual install instructions
444
+ if (engineDeps) {
445
+ const instructions = getManualInstallInstructions(
446
+ engineDeps.dependencies[0],
447
+ platform,
448
+ )
449
+ if (instructions.length > 0) {
450
+ console.log(chalk.gray(' To install manually:'))
451
+ for (const instruction of instructions) {
452
+ console.log(chalk.gray(` ${instruction}`))
453
+ }
454
+ console.log()
455
+ }
456
+ }
457
+
458
+ return false
459
+ }
460
+ } catch (err) {
461
+ const e = err as Error
462
+ console.log()
463
+ console.log(chalk.red(` Installation failed: ${e.message}`))
464
+ console.log()
465
+
466
+ // Show manual install instructions on error
467
+ if (engineDeps) {
468
+ const instructions = getManualInstallInstructions(
469
+ engineDeps.dependencies[0],
470
+ platform,
471
+ )
472
+ if (instructions.length > 0) {
473
+ console.log(chalk.gray(' To install manually:'))
474
+ for (const instruction of instructions) {
475
+ console.log(chalk.gray(` ${instruction}`))
476
+ }
477
+ console.log()
478
+ }
479
+ }
480
+
481
+ return false
482
+ }
420
483
  }
@@ -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,84 @@
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
+ /** Default superuser name */
16
+ superuser: string
17
+ /** Connection string scheme (e.g., 'postgresql', 'mysql') */
18
+ connectionScheme: string
19
+ /** Log file name within container directory */
20
+ logFileName: string
21
+ /** PID file name (relative to data directory or container) */
22
+ pidFileName: string
23
+ /** Subdirectory for data files within container */
24
+ dataSubdir: string
25
+ /** Client tools required for this engine */
26
+ clientTools: string[]
27
+ }
28
+
29
+ export const engineDefaults: Record<string, EngineDefaults> = {
30
+ postgresql: {
31
+ defaultVersion: '16',
32
+ defaultPort: 5432,
33
+ portRange: { start: 5432, end: 5500 },
34
+ supportedVersions: ['14', '15', '16', '17'],
35
+ superuser: 'postgres',
36
+ connectionScheme: 'postgresql',
37
+ logFileName: 'postgres.log',
38
+ pidFileName: 'postmaster.pid',
39
+ dataSubdir: 'data',
40
+ clientTools: ['psql', 'pg_dump', 'pg_restore', 'pg_basebackup'],
41
+ },
42
+ mysql: {
43
+ defaultVersion: '9.0',
44
+ defaultPort: 3306,
45
+ portRange: { start: 3306, end: 3400 },
46
+ supportedVersions: ['5.7', '8.0', '8.4', '9.0'],
47
+ superuser: 'root',
48
+ connectionScheme: 'mysql',
49
+ logFileName: 'mysql.log',
50
+ pidFileName: 'mysql.pid',
51
+ dataSubdir: 'data',
52
+ clientTools: ['mysql', 'mysqldump', 'mysqlpump'],
53
+ },
54
+ }
55
+
56
+ /**
57
+ * Get engine defaults by name
58
+ * @throws Error if engine is not found
59
+ */
60
+ export function getEngineDefaults(engine: string): EngineDefaults {
61
+ const normalized = engine.toLowerCase()
62
+ const defaults = engineDefaults[normalized]
63
+ if (!defaults) {
64
+ const available = Object.keys(engineDefaults).join(', ')
65
+ throw new Error(
66
+ `Unknown engine "${engine}". Available engines: ${available}`,
67
+ )
68
+ }
69
+ return defaults
70
+ }
71
+
72
+ /**
73
+ * Check if an engine is supported
74
+ */
75
+ export function isEngineSupported(engine: string): boolean {
76
+ return engine.toLowerCase() in engineDefaults
77
+ }
78
+
79
+ /**
80
+ * Get list of all supported engine names
81
+ */
82
+ export function getSupportedEngines(): string[] {
83
+ return Object.keys(engineDefaults)
84
+ }
@@ -241,28 +241,53 @@ const postgresqlDependencies: EngineDependencies = {
241
241
 
242
242
  const mysqlDependencies: EngineDependencies = {
243
243
  engine: 'mysql',
244
- displayName: 'MySQL',
244
+ displayName: 'MySQL/MariaDB',
245
245
  dependencies: [
246
+ {
247
+ name: 'mysqld',
248
+ binary: 'mysqld',
249
+ description: 'MySQL/MariaDB server daemon',
250
+ packages: {
251
+ brew: { package: 'mysql' },
252
+ // Modern Debian/Ubuntu use mariadb-server (MySQL-compatible)
253
+ apt: { package: 'mariadb-server' },
254
+ yum: { package: 'mariadb-server' },
255
+ dnf: { package: 'mariadb-server' },
256
+ pacman: { package: 'mariadb' },
257
+ },
258
+ manualInstall: {
259
+ darwin: [
260
+ 'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
261
+ 'Then run: brew install mysql',
262
+ ],
263
+ linux: [
264
+ 'Debian/Ubuntu: sudo apt install mariadb-server',
265
+ 'CentOS/RHEL: sudo yum install mariadb-server',
266
+ 'Fedora: sudo dnf install mariadb-server',
267
+ 'Arch: sudo pacman -S mariadb',
268
+ ],
269
+ },
270
+ },
246
271
  {
247
272
  name: 'mysql',
248
273
  binary: 'mysql',
249
- description: 'MySQL command-line client',
274
+ description: 'MySQL/MariaDB command-line client',
250
275
  packages: {
251
- brew: { package: 'mysql-client' },
252
- apt: { package: 'mysql-client' },
253
- yum: { package: 'mysql' },
254
- dnf: { package: 'mysql' },
276
+ brew: { package: 'mysql' },
277
+ apt: { package: 'mariadb-client' },
278
+ yum: { package: 'mariadb' },
279
+ dnf: { package: 'mariadb' },
255
280
  pacman: { package: 'mariadb-clients' },
256
281
  },
257
282
  manualInstall: {
258
283
  darwin: [
259
284
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
260
- 'Then run: brew install mysql-client',
285
+ 'Then run: brew install mysql',
261
286
  ],
262
287
  linux: [
263
- 'Ubuntu/Debian: sudo apt install mysql-client',
264
- 'CentOS/RHEL: sudo yum install mysql',
265
- 'Fedora: sudo dnf install mysql',
288
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
289
+ 'CentOS/RHEL: sudo yum install mariadb',
290
+ 'Fedora: sudo dnf install mariadb',
266
291
  'Arch: sudo pacman -S mariadb-clients',
267
292
  ],
268
293
  },
@@ -270,23 +295,47 @@ const mysqlDependencies: EngineDependencies = {
270
295
  {
271
296
  name: 'mysqldump',
272
297
  binary: 'mysqldump',
273
- description: 'MySQL database backup utility',
298
+ description: 'MySQL/MariaDB database backup utility',
299
+ packages: {
300
+ brew: { package: 'mysql' },
301
+ apt: { package: 'mariadb-client' },
302
+ yum: { package: 'mariadb' },
303
+ dnf: { package: 'mariadb' },
304
+ pacman: { package: 'mariadb-clients' },
305
+ },
306
+ manualInstall: {
307
+ darwin: [
308
+ 'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
309
+ 'Then run: brew install mysql',
310
+ ],
311
+ linux: [
312
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
313
+ 'CentOS/RHEL: sudo yum install mariadb',
314
+ 'Fedora: sudo dnf install mariadb',
315
+ 'Arch: sudo pacman -S mariadb-clients',
316
+ ],
317
+ },
318
+ },
319
+ {
320
+ name: 'mysqladmin',
321
+ binary: 'mysqladmin',
322
+ description: 'MySQL/MariaDB server administration utility',
274
323
  packages: {
275
- brew: { package: 'mysql-client' },
276
- apt: { package: 'mysql-client' },
277
- yum: { package: 'mysql' },
278
- dnf: { package: 'mysql' },
324
+ brew: { package: 'mysql' },
325
+ apt: { package: 'mariadb-client' },
326
+ yum: { package: 'mariadb' },
327
+ dnf: { package: 'mariadb' },
279
328
  pacman: { package: 'mariadb-clients' },
280
329
  },
281
330
  manualInstall: {
282
331
  darwin: [
283
332
  'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
284
- 'Then run: brew install mysql-client',
333
+ 'Then run: brew install mysql',
285
334
  ],
286
335
  linux: [
287
- 'Ubuntu/Debian: sudo apt install mysql-client',
288
- 'CentOS/RHEL: sudo yum install mysql',
289
- 'Fedora: sudo dnf install mysql',
336
+ 'Debian/Ubuntu: sudo apt install mariadb-client',
337
+ 'CentOS/RHEL: sudo yum install mariadb',
338
+ 'Fedora: sudo dnf install mariadb',
290
339
  'Arch: sudo pacman -S mariadb-clients',
291
340
  ],
292
341
  },
package/config/paths.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { homedir } from 'os'
2
2
  import { join } from 'path'
3
3
  import { execSync } from 'child_process'
4
+ import { getEngineDefaults } from './engine-defaults'
4
5
 
5
6
  /**
6
7
  * Get the real user's home directory, even when running under sudo.
@@ -41,6 +42,23 @@ function getRealHomeDir(): string {
41
42
 
42
43
  const SPINDB_HOME = join(getRealHomeDir(), '.spindb')
43
44
 
45
+ /**
46
+ * Options for container path functions
47
+ */
48
+ type ContainerPathOptions = {
49
+ engine: string
50
+ }
51
+
52
+ /**
53
+ * Options for binary path functions
54
+ */
55
+ type BinaryPathOptions = {
56
+ engine: string
57
+ version: string
58
+ platform: string
59
+ arch: string
60
+ }
61
+
44
62
  export const paths = {
45
63
  // Root directory for all spindb data
46
64
  root: SPINDB_HOME,
@@ -54,38 +72,75 @@ export const paths = {
54
72
  // Global config file
55
73
  config: join(SPINDB_HOME, 'config.json'),
56
74
 
57
- // Get path for a specific binary version
58
- getBinaryPath(
59
- engine: string,
60
- version: string,
61
- platform: string,
62
- arch: string,
63
- ): string {
75
+ /**
76
+ * Get path for a specific binary version
77
+ */
78
+ getBinaryPath(options: BinaryPathOptions): string {
79
+ const { engine, version, platform, arch } = options
64
80
  return join(this.bin, `${engine}-${version}-${platform}-${arch}`)
65
81
  },
66
82
 
67
- // Get path for a specific container
68
- getContainerPath(name: string): string {
69
- return join(this.containers, name)
83
+ /**
84
+ * Get path for a specific container
85
+ * New structure: ~/.spindb/containers/{engine}/{name}/
86
+ */
87
+ getContainerPath(name: string, options: ContainerPathOptions): string {
88
+ const { engine } = options
89
+ return join(this.containers, engine, name)
70
90
  },
71
91
 
72
- // Get path for container config
73
- getContainerConfigPath(name: string): string {
74
- return join(this.containers, name, 'container.json')
92
+ /**
93
+ * Get path for container config file
94
+ */
95
+ getContainerConfigPath(name: string, options: ContainerPathOptions): string {
96
+ const { engine } = options
97
+ return join(this.containers, engine, name, 'container.json')
75
98
  },
76
99
 
77
- // Get path for container data directory
78
- getContainerDataPath(name: string): string {
79
- return join(this.containers, name, 'data')
100
+ /**
101
+ * Get path for container data directory
102
+ */
103
+ getContainerDataPath(name: string, options: ContainerPathOptions): string {
104
+ const { engine } = options
105
+ const engineDef = getEngineDefaults(engine)
106
+ return join(this.containers, engine, name, engineDef.dataSubdir)
80
107
  },
81
108
 
82
- // Get path for container log file
83
- getContainerLogPath(name: string): string {
84
- return join(this.containers, name, 'postgres.log')
109
+ /**
110
+ * Get path for container log file
111
+ */
112
+ getContainerLogPath(name: string, options: ContainerPathOptions): string {
113
+ const { engine } = options
114
+ const engineDef = getEngineDefaults(engine)
115
+ return join(this.containers, engine, name, engineDef.logFileName)
116
+ },
117
+
118
+ /**
119
+ * Get path for container PID file
120
+ * Note: For PostgreSQL, PID is inside data dir. For MySQL, it may differ.
121
+ */
122
+ getContainerPidPath(name: string, options: ContainerPathOptions): string {
123
+ const { engine } = options
124
+ const engineDef = getEngineDefaults(engine)
125
+ // PostgreSQL: data/postmaster.pid
126
+ // MySQL: data/mysql.pid (or just mysql.pid depending on config)
127
+ if (engine === 'postgresql') {
128
+ return join(
129
+ this.containers,
130
+ engine,
131
+ name,
132
+ engineDef.dataSubdir,
133
+ engineDef.pidFileName,
134
+ )
135
+ }
136
+ // MySQL and others: PID file at container level
137
+ return join(this.containers, engine, name, engineDef.pidFileName)
85
138
  },
86
139
 
87
- // Get path for container PID file
88
- getContainerPidPath(name: string): string {
89
- return join(this.containers, name, 'data', 'postmaster.pid')
140
+ /**
141
+ * Get path for engine-specific containers directory
142
+ */
143
+ getEngineContainersPath(engine: string): string {
144
+ return join(this.containers, engine)
90
145
  },
91
146
  }