spindb 0.9.1 → 0.9.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/commands/backup.ts +13 -11
- package/cli/commands/clone.ts +14 -10
- package/cli/commands/config.ts +29 -29
- package/cli/commands/connect.ts +51 -39
- package/cli/commands/create.ts +59 -32
- package/cli/commands/delete.ts +8 -8
- package/cli/commands/deps.ts +17 -15
- package/cli/commands/doctor.ts +11 -11
- package/cli/commands/edit.ts +108 -55
- package/cli/commands/engines.ts +17 -15
- package/cli/commands/info.ts +8 -6
- package/cli/commands/list.ts +31 -16
- package/cli/commands/logs.ts +15 -11
- package/cli/commands/menu/backup-handlers.ts +52 -47
- package/cli/commands/menu/container-handlers.ts +120 -78
- package/cli/commands/menu/engine-handlers.ts +21 -11
- package/cli/commands/menu/index.ts +4 -4
- package/cli/commands/menu/shell-handlers.ts +34 -31
- package/cli/commands/menu/sql-handlers.ts +22 -16
- package/cli/commands/menu/update-handlers.ts +19 -17
- package/cli/commands/restore.ts +22 -20
- package/cli/commands/run.ts +20 -18
- package/cli/commands/self-update.ts +5 -5
- package/cli/commands/start.ts +11 -9
- package/cli/commands/stop.ts +9 -9
- package/cli/commands/url.ts +12 -9
- package/cli/helpers.ts +9 -4
- package/cli/ui/prompts.ts +12 -5
- package/cli/ui/spinner.ts +4 -4
- package/cli/ui/theme.ts +4 -4
- package/core/binary-manager.ts +5 -1
- package/core/container-manager.ts +5 -5
- package/core/platform-service.ts +3 -3
- package/core/start-with-retry.ts +6 -6
- package/core/transaction-manager.ts +6 -6
- package/engines/mysql/index.ts +11 -11
- package/engines/mysql/restore.ts +4 -4
- package/engines/mysql/version-validator.ts +2 -2
- package/engines/postgresql/binary-manager.ts +17 -17
- package/engines/postgresql/index.ts +7 -2
- package/engines/postgresql/restore.ts +2 -2
- package/engines/postgresql/version-validator.ts +2 -2
- package/engines/sqlite/index.ts +21 -8
- package/package.json +1 -1
package/engines/mysql/index.ts
CHANGED
|
@@ -450,8 +450,8 @@ export class MySQLEngine extends BaseEngine {
|
|
|
450
450
|
await this.cleanupPidFile(pidFile)
|
|
451
451
|
return null
|
|
452
452
|
}
|
|
453
|
-
} catch (
|
|
454
|
-
const e =
|
|
453
|
+
} catch (error) {
|
|
454
|
+
const e = error as NodeJS.ErrnoException
|
|
455
455
|
if (e.code !== 'ENOENT') {
|
|
456
456
|
logWarning(`Failed to read PID file: ${e.message}`, {
|
|
457
457
|
pidFile,
|
|
@@ -479,8 +479,8 @@ export class MySQLEngine extends BaseEngine {
|
|
|
479
479
|
`"${mysqladmin}" -h 127.0.0.1 -P ${port} -u root shutdown`,
|
|
480
480
|
{ timeout: 5000 },
|
|
481
481
|
)
|
|
482
|
-
} catch (
|
|
483
|
-
const e =
|
|
482
|
+
} catch (error) {
|
|
483
|
+
const e = error as Error
|
|
484
484
|
logDebug(`mysqladmin shutdown failed: ${e.message}`)
|
|
485
485
|
// Continue to wait for process to die or send SIGTERM
|
|
486
486
|
}
|
|
@@ -542,8 +542,8 @@ export class MySQLEngine extends BaseEngine {
|
|
|
542
542
|
await this.cleanupPidFile(pidFile)
|
|
543
543
|
return
|
|
544
544
|
}
|
|
545
|
-
} catch (
|
|
546
|
-
const e =
|
|
545
|
+
} catch (error) {
|
|
546
|
+
const e = error as NodeJS.ErrnoException
|
|
547
547
|
if (e.code === 'ESRCH') {
|
|
548
548
|
// Process already dead
|
|
549
549
|
await this.cleanupPidFile(pidFile)
|
|
@@ -575,9 +575,9 @@ export class MySQLEngine extends BaseEngine {
|
|
|
575
575
|
logDebug(`Process ${pid} terminated after SIGKILL`)
|
|
576
576
|
await this.cleanupPidFile(pidFile)
|
|
577
577
|
}
|
|
578
|
-
} catch (
|
|
579
|
-
if (
|
|
580
|
-
const e =
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (error instanceof SpinDBError) throw error
|
|
580
|
+
const e = error as NodeJS.ErrnoException
|
|
581
581
|
if (e.code === 'ESRCH') {
|
|
582
582
|
// Process already dead
|
|
583
583
|
await this.cleanupPidFile(pidFile)
|
|
@@ -594,8 +594,8 @@ export class MySQLEngine extends BaseEngine {
|
|
|
594
594
|
try {
|
|
595
595
|
await unlink(pidFile)
|
|
596
596
|
logDebug('PID file cleaned up')
|
|
597
|
-
} catch (
|
|
598
|
-
const e =
|
|
597
|
+
} catch (error) {
|
|
598
|
+
const e = error as NodeJS.ErrnoException
|
|
599
599
|
if (e.code !== 'ENOENT') {
|
|
600
600
|
logDebug(`Failed to clean up PID file: ${e.message}`)
|
|
601
601
|
}
|
package/engines/mysql/restore.ts
CHANGED
|
@@ -174,13 +174,13 @@ export async function restoreBackup(
|
|
|
174
174
|
if (validateVersion) {
|
|
175
175
|
try {
|
|
176
176
|
await validateRestoreCompatibility({ dumpPath: backupPath })
|
|
177
|
-
} catch (
|
|
177
|
+
} catch (error) {
|
|
178
178
|
// Re-throw SpinDBError, log and continue for other errors
|
|
179
|
-
if (
|
|
180
|
-
throw
|
|
179
|
+
if (error instanceof Error && error.name === 'SpinDBError') {
|
|
180
|
+
throw error
|
|
181
181
|
}
|
|
182
182
|
logDebug('Version validation failed, proceeding anyway', {
|
|
183
|
-
error:
|
|
183
|
+
error: error instanceof Error ? error.message : String(error),
|
|
184
184
|
})
|
|
185
185
|
}
|
|
186
186
|
}
|
|
@@ -197,10 +197,10 @@ export async function parseDumpVersion(dumpPath: string): Promise<DumpInfo> {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
return { version: null, variant }
|
|
200
|
-
} catch (
|
|
200
|
+
} catch (error) {
|
|
201
201
|
logDebug('Failed to parse dump version', {
|
|
202
202
|
dumpPath,
|
|
203
|
-
error:
|
|
203
|
+
error: error instanceof Error ? error.message : String(error),
|
|
204
204
|
})
|
|
205
205
|
return { version: null, variant: 'unknown' }
|
|
206
206
|
}
|
|
@@ -2,7 +2,7 @@ import { exec } from 'child_process'
|
|
|
2
2
|
import { promisify } from 'util'
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
import { createSpinner } from '../../cli/ui/spinner'
|
|
5
|
-
import {
|
|
5
|
+
import { uiWarning, uiError, uiSuccess } from '../../cli/ui/theme'
|
|
6
6
|
import {
|
|
7
7
|
detectPackageManager as detectPM,
|
|
8
8
|
installEngineDependencies,
|
|
@@ -311,7 +311,7 @@ export async function installPostgresBinaries(): Promise<boolean> {
|
|
|
311
311
|
const packageManager = await detectPM()
|
|
312
312
|
if (!packageManager) {
|
|
313
313
|
spinner.fail('No supported package manager found')
|
|
314
|
-
console.log(
|
|
314
|
+
console.log(uiError('Please install PostgreSQL client tools manually:'))
|
|
315
315
|
|
|
316
316
|
// Show platform-specific instructions from the registry
|
|
317
317
|
const platform = getCurrentPlatform()
|
|
@@ -348,21 +348,21 @@ export async function installPostgresBinaries(): Promise<boolean> {
|
|
|
348
348
|
|
|
349
349
|
if (allSuccess) {
|
|
350
350
|
console.log()
|
|
351
|
-
console.log(
|
|
351
|
+
console.log(uiSuccess('PostgreSQL client tools installed successfully'))
|
|
352
352
|
return true
|
|
353
353
|
} else {
|
|
354
354
|
const failed = results.filter((r) => !r.success)
|
|
355
355
|
console.log()
|
|
356
|
-
console.log(
|
|
356
|
+
console.log(uiError('Some installations failed:'))
|
|
357
357
|
for (const f of failed) {
|
|
358
|
-
console.log(
|
|
358
|
+
console.log(uiError(` ${f.dependency.name}: ${f.error}`))
|
|
359
359
|
}
|
|
360
360
|
return false
|
|
361
361
|
}
|
|
362
362
|
} catch (error: unknown) {
|
|
363
363
|
console.log()
|
|
364
|
-
console.log(
|
|
365
|
-
console.log(
|
|
364
|
+
console.log(uiError('Failed to install PostgreSQL client tools'))
|
|
365
|
+
console.log(uiWarning('Please install manually'))
|
|
366
366
|
if (error instanceof Error) {
|
|
367
367
|
console.log(chalk.gray(`Error details: ${error.message}`))
|
|
368
368
|
}
|
|
@@ -408,7 +408,7 @@ export async function updatePostgresClientTools(): Promise<boolean> {
|
|
|
408
408
|
|
|
409
409
|
spinner.succeed('PostgreSQL client tools updated')
|
|
410
410
|
console.log(
|
|
411
|
-
|
|
411
|
+
uiSuccess(
|
|
412
412
|
`Client tools successfully linked to PostgreSQL ${latestMajor}`,
|
|
413
413
|
),
|
|
414
414
|
)
|
|
@@ -418,13 +418,13 @@ export async function updatePostgresClientTools(): Promise<boolean> {
|
|
|
418
418
|
// For other package managers, use the standard update
|
|
419
419
|
await execWithTimeout(packageManager.updateCommand('postgresql'), 120000)
|
|
420
420
|
spinner.succeed('PostgreSQL client tools updated')
|
|
421
|
-
console.log(
|
|
421
|
+
console.log(uiSuccess('Update completed successfully'))
|
|
422
422
|
return true
|
|
423
423
|
}
|
|
424
424
|
} catch (error: unknown) {
|
|
425
425
|
spinner.fail('Update failed')
|
|
426
|
-
console.log(
|
|
427
|
-
console.log(
|
|
426
|
+
console.log(uiError('Failed to update PostgreSQL client tools'))
|
|
427
|
+
console.log(uiWarning('Please update manually:'))
|
|
428
428
|
|
|
429
429
|
if (packageManager.name === 'brew') {
|
|
430
430
|
const olderVersions = ['14', '15', '16'].filter((v) => v !== latestMajor)
|
|
@@ -473,12 +473,12 @@ export async function updatePostgresBinaries(): Promise<boolean> {
|
|
|
473
473
|
try {
|
|
474
474
|
await execWithTimeout(packageManager.updateCommand('postgresql'), 120000) // 2 minute timeout
|
|
475
475
|
updateSpinner.succeed('PostgreSQL client tools updated')
|
|
476
|
-
console.log(
|
|
476
|
+
console.log(uiSuccess('Update completed successfully'))
|
|
477
477
|
return true
|
|
478
478
|
} catch (error: unknown) {
|
|
479
479
|
updateSpinner.fail('Update failed')
|
|
480
|
-
console.log(
|
|
481
|
-
console.log(
|
|
480
|
+
console.log(uiError('Failed to update PostgreSQL client tools'))
|
|
481
|
+
console.log(uiWarning('Please update manually:'))
|
|
482
482
|
console.log(` ${packageManager.updateCommand('postgresql')}`)
|
|
483
483
|
if (error instanceof Error) {
|
|
484
484
|
console.log(chalk.gray(`Error details: ${error.message}`))
|
|
@@ -505,7 +505,7 @@ export async function ensurePostgresBinary(
|
|
|
505
505
|
return { success: false, info: null, action: 'install_required' }
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
-
console.log(
|
|
508
|
+
console.log(uiWarning(`${binary} not found on your system`))
|
|
509
509
|
const success = await installPostgresBinaries()
|
|
510
510
|
if (!success) {
|
|
511
511
|
return { success: false, info: null, action: 'install_failed' }
|
|
@@ -527,13 +527,13 @@ export async function ensurePostgresBinary(
|
|
|
527
527
|
}
|
|
528
528
|
|
|
529
529
|
console.log(
|
|
530
|
-
|
|
530
|
+
uiWarning(
|
|
531
531
|
`Your ${binary} version (${info.version}) is incompatible with the dump file`,
|
|
532
532
|
),
|
|
533
533
|
)
|
|
534
534
|
if (info.requiredVersion) {
|
|
535
535
|
console.log(
|
|
536
|
-
|
|
536
|
+
uiWarning(`Required version: ${info.requiredVersion} or compatible`),
|
|
537
537
|
)
|
|
538
538
|
}
|
|
539
539
|
|
|
@@ -155,8 +155,13 @@ export class PostgreSQLEngine extends BaseEngine {
|
|
|
155
155
|
|
|
156
156
|
// Configure max_connections after initdb creates postgresql.conf
|
|
157
157
|
const maxConnections =
|
|
158
|
-
(options.maxConnections as number) ||
|
|
159
|
-
|
|
158
|
+
(options.maxConnections as number) ||
|
|
159
|
+
getEngineDefaults('postgresql').maxConnections
|
|
160
|
+
await this.setConfigValue(
|
|
161
|
+
dataDir,
|
|
162
|
+
'max_connections',
|
|
163
|
+
String(maxConnections),
|
|
164
|
+
)
|
|
160
165
|
|
|
161
166
|
return dataDir
|
|
162
167
|
}
|
|
@@ -219,8 +219,8 @@ export async function restoreBackup(
|
|
|
219
219
|
format: detectedFormat,
|
|
220
220
|
...result,
|
|
221
221
|
}
|
|
222
|
-
} catch (
|
|
223
|
-
const e =
|
|
222
|
+
} catch (error) {
|
|
223
|
+
const e = error as Error & { stdout?: string; stderr?: string }
|
|
224
224
|
// pg_restore often returns non-zero even on partial success
|
|
225
225
|
return {
|
|
226
226
|
format: detectedFormat,
|
|
@@ -135,11 +135,11 @@ export async function parseDumpVersion(
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
} catch (
|
|
138
|
+
} catch (error) {
|
|
139
139
|
logDebug('Failed to parse dump version', {
|
|
140
140
|
dumpPath,
|
|
141
141
|
format,
|
|
142
|
-
error:
|
|
142
|
+
error: error instanceof Error ? error.message : String(error),
|
|
143
143
|
})
|
|
144
144
|
}
|
|
145
145
|
|
package/engines/sqlite/index.ts
CHANGED
|
@@ -538,15 +538,28 @@ export class SQLiteEngine extends BaseEngine {
|
|
|
538
538
|
* Download a file from HTTP/HTTPS URL
|
|
539
539
|
*/
|
|
540
540
|
private async downloadFile(url: string, destPath: string): Promise<void> {
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
541
|
+
const controller = new AbortController()
|
|
542
|
+
const timeoutMs = 5 * 60 * 1000 // 5 minutes
|
|
543
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs)
|
|
544
|
+
|
|
545
|
+
try {
|
|
546
|
+
const response = await fetch(url, { signal: controller.signal })
|
|
547
|
+
if (!response.ok) {
|
|
548
|
+
throw new Error(
|
|
549
|
+
`Failed to download: ${response.status} ${response.statusText}`,
|
|
550
|
+
)
|
|
551
|
+
}
|
|
547
552
|
|
|
548
|
-
|
|
549
|
-
|
|
553
|
+
const buffer = await response.arrayBuffer()
|
|
554
|
+
await writeFile(destPath, Buffer.from(buffer))
|
|
555
|
+
} catch (error) {
|
|
556
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
557
|
+
throw new Error('Download timed out after 5 minutes')
|
|
558
|
+
}
|
|
559
|
+
throw error
|
|
560
|
+
} finally {
|
|
561
|
+
clearTimeout(timeout)
|
|
562
|
+
}
|
|
550
563
|
}
|
|
551
564
|
|
|
552
565
|
/**
|