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.
- package/README.md +207 -101
- package/cli/commands/clone.ts +3 -1
- package/cli/commands/connect.ts +54 -24
- package/cli/commands/create.ts +309 -189
- package/cli/commands/delete.ts +3 -1
- package/cli/commands/deps.ts +19 -4
- package/cli/commands/edit.ts +245 -0
- package/cli/commands/engines.ts +434 -0
- package/cli/commands/info.ts +279 -0
- package/cli/commands/list.ts +14 -3
- package/cli/commands/menu.ts +510 -198
- package/cli/commands/restore.ts +66 -43
- package/cli/commands/start.ts +50 -19
- package/cli/commands/stop.ts +3 -1
- package/cli/commands/url.ts +79 -0
- package/cli/index.ts +9 -3
- package/cli/ui/prompts.ts +99 -34
- package/config/defaults.ts +40 -15
- package/config/engine-defaults.ts +107 -0
- package/config/os-dependencies.ts +119 -124
- package/config/paths.ts +82 -56
- package/core/binary-manager.ts +44 -6
- package/core/config-manager.ts +17 -5
- package/core/container-manager.ts +124 -60
- package/core/dependency-manager.ts +9 -15
- package/core/error-handler.ts +336 -0
- package/core/platform-service.ts +634 -0
- package/core/port-manager.ts +51 -32
- package/core/process-manager.ts +26 -8
- package/core/start-with-retry.ts +167 -0
- package/core/transaction-manager.ts +170 -0
- package/engines/index.ts +7 -2
- package/engines/mysql/binary-detection.ts +325 -0
- package/engines/mysql/index.ts +808 -0
- package/engines/mysql/restore.ts +257 -0
- package/engines/mysql/version-validator.ts +373 -0
- package/{core/postgres-binary-manager.ts → engines/postgresql/binary-manager.ts} +63 -23
- package/engines/postgresql/binary-urls.ts +5 -3
- package/engines/postgresql/index.ts +17 -9
- package/engines/postgresql/restore.ts +54 -5
- package/engines/postgresql/version-validator.ts +262 -0
- package/package.json +9 -3
- package/types/index.ts +29 -5
- package/cli/commands/postgres-tools.ts +0 -216
package/cli/commands/deps.ts
CHANGED
|
@@ -188,7 +188,11 @@ depsCommand
|
|
|
188
188
|
|
|
189
189
|
if (succeeded.length > 0) {
|
|
190
190
|
console.log()
|
|
191
|
-
console.log(
|
|
191
|
+
console.log(
|
|
192
|
+
success(
|
|
193
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
194
|
+
),
|
|
195
|
+
)
|
|
192
196
|
}
|
|
193
197
|
} else if (options.engine) {
|
|
194
198
|
// Install dependencies for specific engine
|
|
@@ -254,7 +258,11 @@ depsCommand
|
|
|
254
258
|
|
|
255
259
|
if (succeeded.length > 0) {
|
|
256
260
|
console.log()
|
|
257
|
-
console.log(
|
|
261
|
+
console.log(
|
|
262
|
+
success(
|
|
263
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
264
|
+
),
|
|
265
|
+
)
|
|
258
266
|
}
|
|
259
267
|
} else {
|
|
260
268
|
// Default: install PostgreSQL dependencies (most common use case)
|
|
@@ -278,7 +286,10 @@ depsCommand
|
|
|
278
286
|
const spinner = createSpinner('Installing PostgreSQL dependencies...')
|
|
279
287
|
spinner.start()
|
|
280
288
|
|
|
281
|
-
const results = await installEngineDependencies(
|
|
289
|
+
const results = await installEngineDependencies(
|
|
290
|
+
'postgresql',
|
|
291
|
+
packageManager,
|
|
292
|
+
)
|
|
282
293
|
|
|
283
294
|
const succeeded = results.filter((r) => r.success)
|
|
284
295
|
const failed = results.filter((r) => !r.success)
|
|
@@ -295,7 +306,11 @@ depsCommand
|
|
|
295
306
|
|
|
296
307
|
if (succeeded.length > 0) {
|
|
297
308
|
console.log()
|
|
298
|
-
console.log(
|
|
309
|
+
console.log(
|
|
310
|
+
success(
|
|
311
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
312
|
+
),
|
|
313
|
+
)
|
|
299
314
|
}
|
|
300
315
|
}
|
|
301
316
|
})
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import inquirer from 'inquirer'
|
|
4
|
+
import { containerManager } from '../../core/container-manager'
|
|
5
|
+
import { processManager } from '../../core/process-manager'
|
|
6
|
+
import { portManager } from '../../core/port-manager'
|
|
7
|
+
import { promptContainerSelect } from '../ui/prompts'
|
|
8
|
+
import { createSpinner } from '../ui/spinner'
|
|
9
|
+
import { error, warning, success } from '../ui/theme'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Validate container name format
|
|
13
|
+
*/
|
|
14
|
+
function isValidName(name: string): boolean {
|
|
15
|
+
return /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Prompt for what to edit when no options provided
|
|
20
|
+
*/
|
|
21
|
+
async function promptEditAction(): Promise<'name' | 'port' | null> {
|
|
22
|
+
const { action } = await inquirer.prompt<{ action: string }>([
|
|
23
|
+
{
|
|
24
|
+
type: 'list',
|
|
25
|
+
name: 'action',
|
|
26
|
+
message: 'What would you like to edit?',
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: 'Rename container', value: 'name' },
|
|
29
|
+
{ name: 'Change port', value: 'port' },
|
|
30
|
+
{ name: chalk.gray('Cancel'), value: 'cancel' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
])
|
|
34
|
+
|
|
35
|
+
if (action === 'cancel') return null
|
|
36
|
+
return action as 'name' | 'port'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Prompt for new container name
|
|
41
|
+
*/
|
|
42
|
+
async function promptNewName(currentName: string): Promise<string | null> {
|
|
43
|
+
const { newName } = await inquirer.prompt<{ newName: string }>([
|
|
44
|
+
{
|
|
45
|
+
type: 'input',
|
|
46
|
+
name: 'newName',
|
|
47
|
+
message: 'New container name:',
|
|
48
|
+
default: currentName,
|
|
49
|
+
validate: (input: string) => {
|
|
50
|
+
if (!input) return 'Name is required'
|
|
51
|
+
if (!isValidName(input)) {
|
|
52
|
+
return 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores'
|
|
53
|
+
}
|
|
54
|
+
return true
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
if (newName === currentName) {
|
|
60
|
+
console.log(warning('Name unchanged'))
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return newName
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Prompt for new port
|
|
69
|
+
*/
|
|
70
|
+
async function promptNewPort(currentPort: number): Promise<number | null> {
|
|
71
|
+
const { newPort } = await inquirer.prompt<{ newPort: number }>([
|
|
72
|
+
{
|
|
73
|
+
type: 'input',
|
|
74
|
+
name: 'newPort',
|
|
75
|
+
message: 'New port:',
|
|
76
|
+
default: String(currentPort),
|
|
77
|
+
validate: (input: string) => {
|
|
78
|
+
const num = parseInt(input, 10)
|
|
79
|
+
if (isNaN(num) || num < 1 || num > 65535) {
|
|
80
|
+
return 'Port must be a number between 1 and 65535'
|
|
81
|
+
}
|
|
82
|
+
return true
|
|
83
|
+
},
|
|
84
|
+
filter: (input: string) => parseInt(input, 10),
|
|
85
|
+
},
|
|
86
|
+
])
|
|
87
|
+
|
|
88
|
+
if (newPort === currentPort) {
|
|
89
|
+
console.log(warning('Port unchanged'))
|
|
90
|
+
return null
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return newPort
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const editCommand = new Command('edit')
|
|
97
|
+
.description('Edit container properties (rename or change port)')
|
|
98
|
+
.argument('[name]', 'Container name')
|
|
99
|
+
.option('-n, --name <newName>', 'New container name')
|
|
100
|
+
.option('-p, --port <port>', 'New port number', parseInt)
|
|
101
|
+
.action(
|
|
102
|
+
async (
|
|
103
|
+
name: string | undefined,
|
|
104
|
+
options: { name?: string; port?: number },
|
|
105
|
+
) => {
|
|
106
|
+
try {
|
|
107
|
+
let containerName = name
|
|
108
|
+
|
|
109
|
+
// Interactive selection if no name provided
|
|
110
|
+
if (!containerName) {
|
|
111
|
+
const containers = await containerManager.list()
|
|
112
|
+
|
|
113
|
+
if (containers.length === 0) {
|
|
114
|
+
console.log(warning('No containers found'))
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const selected = await promptContainerSelect(
|
|
119
|
+
containers,
|
|
120
|
+
'Select container to edit:',
|
|
121
|
+
)
|
|
122
|
+
if (!selected) return
|
|
123
|
+
containerName = selected
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Get container config
|
|
127
|
+
const config = await containerManager.getConfig(containerName)
|
|
128
|
+
if (!config) {
|
|
129
|
+
console.error(error(`Container "${containerName}" not found`))
|
|
130
|
+
process.exit(1)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// If no options provided, prompt for what to edit
|
|
134
|
+
if (options.name === undefined && options.port === undefined) {
|
|
135
|
+
const action = await promptEditAction()
|
|
136
|
+
if (!action) return
|
|
137
|
+
|
|
138
|
+
if (action === 'name') {
|
|
139
|
+
const newName = await promptNewName(containerName)
|
|
140
|
+
if (newName) {
|
|
141
|
+
options.name = newName
|
|
142
|
+
} else {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
} else if (action === 'port') {
|
|
146
|
+
const newPort = await promptNewPort(config.port)
|
|
147
|
+
if (newPort) {
|
|
148
|
+
options.port = newPort
|
|
149
|
+
} else {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Handle rename
|
|
156
|
+
if (options.name) {
|
|
157
|
+
// Validate new name
|
|
158
|
+
if (!isValidName(options.name)) {
|
|
159
|
+
console.error(
|
|
160
|
+
error(
|
|
161
|
+
'Name must start with a letter and contain only letters, numbers, hyphens, and underscores',
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
process.exit(1)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if new name already exists
|
|
168
|
+
const exists = await containerManager.exists(options.name, {
|
|
169
|
+
engine: config.engine,
|
|
170
|
+
})
|
|
171
|
+
if (exists) {
|
|
172
|
+
console.error(error(`Container "${options.name}" already exists`))
|
|
173
|
+
process.exit(1)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Check if container is running
|
|
177
|
+
const running = await processManager.isRunning(containerName, {
|
|
178
|
+
engine: config.engine,
|
|
179
|
+
})
|
|
180
|
+
if (running) {
|
|
181
|
+
console.error(
|
|
182
|
+
error(
|
|
183
|
+
`Container "${containerName}" is running. Stop it first to rename.`,
|
|
184
|
+
),
|
|
185
|
+
)
|
|
186
|
+
process.exit(1)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Rename the container
|
|
190
|
+
const spinner = createSpinner(
|
|
191
|
+
`Renaming "${containerName}" to "${options.name}"...`,
|
|
192
|
+
)
|
|
193
|
+
spinner.start()
|
|
194
|
+
|
|
195
|
+
await containerManager.rename(containerName, options.name)
|
|
196
|
+
|
|
197
|
+
spinner.succeed(`Renamed "${containerName}" to "${options.name}"`)
|
|
198
|
+
|
|
199
|
+
// Update containerName for subsequent operations
|
|
200
|
+
containerName = options.name
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Handle port change
|
|
204
|
+
if (options.port !== undefined) {
|
|
205
|
+
// Validate port
|
|
206
|
+
if (options.port < 1 || options.port > 65535) {
|
|
207
|
+
console.error(error('Port must be between 1 and 65535'))
|
|
208
|
+
process.exit(1)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check port availability (warning only)
|
|
212
|
+
const portAvailable = await portManager.isPortAvailable(options.port)
|
|
213
|
+
if (!portAvailable) {
|
|
214
|
+
console.log(
|
|
215
|
+
warning(
|
|
216
|
+
`Port ${options.port} is currently in use. The container will use this port on next start.`,
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Update the config
|
|
222
|
+
const spinner = createSpinner(`Changing port to ${options.port}...`)
|
|
223
|
+
spinner.start()
|
|
224
|
+
|
|
225
|
+
await containerManager.updateConfig(containerName, {
|
|
226
|
+
port: options.port,
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
spinner.succeed(`Port changed to ${options.port}`)
|
|
230
|
+
console.log(
|
|
231
|
+
chalk.gray(
|
|
232
|
+
' Note: Port change takes effect on next container start.',
|
|
233
|
+
),
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
console.log()
|
|
238
|
+
console.log(success('Container updated successfully'))
|
|
239
|
+
} catch (err) {
|
|
240
|
+
const e = err as Error
|
|
241
|
+
console.error(error(e.message))
|
|
242
|
+
process.exit(1)
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
)
|