spindb 0.31.4 → 0.33.1

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 (64) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +107 -826
  3. package/cli/commands/create.ts +5 -1
  4. package/cli/commands/engines.ts +256 -1
  5. package/cli/commands/menu/backup-handlers.ts +16 -0
  6. package/cli/commands/menu/container-handlers.ts +170 -17
  7. package/cli/commands/menu/engine-handlers.ts +6 -0
  8. package/cli/commands/menu/settings-handlers.ts +6 -0
  9. package/cli/commands/menu/shell-handlers.ts +74 -14
  10. package/cli/commands/menu/sql-handlers.ts +8 -50
  11. package/cli/commands/menu/validators.ts +8 -0
  12. package/cli/commands/users.ts +264 -0
  13. package/cli/constants.ts +8 -0
  14. package/cli/helpers.ts +140 -0
  15. package/cli/index.ts +2 -0
  16. package/cli/ui/prompts.ts +24 -20
  17. package/config/backup-formats.ts +28 -0
  18. package/config/engine-defaults.ts +26 -0
  19. package/config/engines-registry.ts +1 -0
  20. package/config/engines.json +50 -0
  21. package/config/engines.schema.json +6 -1
  22. package/core/base-binary-manager.ts +6 -1
  23. package/core/config-manager.ts +20 -0
  24. package/core/credential-manager.ts +257 -0
  25. package/core/dependency-manager.ts +5 -0
  26. package/core/docker-exporter.ts +30 -0
  27. package/core/error-handler.ts +19 -0
  28. package/engines/base-engine.ts +32 -1
  29. package/engines/clickhouse/index.ts +99 -3
  30. package/engines/cockroachdb/index.ts +69 -2
  31. package/engines/couchdb/index.ts +149 -1
  32. package/engines/ferretdb/README.md +4 -0
  33. package/engines/ferretdb/index.ts +342 -13
  34. package/engines/index.ts +8 -0
  35. package/engines/influxdb/README.md +180 -0
  36. package/engines/influxdb/api-client.ts +64 -0
  37. package/engines/influxdb/backup.ts +160 -0
  38. package/engines/influxdb/binary-manager.ts +110 -0
  39. package/engines/influxdb/binary-urls.ts +69 -0
  40. package/engines/influxdb/hostdb-releases.ts +23 -0
  41. package/engines/influxdb/index.ts +1227 -0
  42. package/engines/influxdb/restore.ts +417 -0
  43. package/engines/influxdb/version-maps.ts +75 -0
  44. package/engines/influxdb/version-validator.ts +128 -0
  45. package/engines/mariadb/index.ts +96 -1
  46. package/engines/meilisearch/index.ts +97 -1
  47. package/engines/mongodb/index.ts +82 -0
  48. package/engines/mysql/index.ts +105 -1
  49. package/engines/postgresql/index.ts +92 -0
  50. package/engines/qdrant/index.ts +107 -2
  51. package/engines/redis/index.ts +106 -12
  52. package/engines/surrealdb/index.ts +102 -2
  53. package/engines/typedb/backup.ts +167 -0
  54. package/engines/typedb/binary-manager.ts +200 -0
  55. package/engines/typedb/binary-urls.ts +38 -0
  56. package/engines/typedb/cli-utils.ts +210 -0
  57. package/engines/typedb/hostdb-releases.ts +118 -0
  58. package/engines/typedb/index.ts +1275 -0
  59. package/engines/typedb/restore.ts +377 -0
  60. package/engines/typedb/version-maps.ts +48 -0
  61. package/engines/typedb/version-validator.ts +127 -0
  62. package/engines/valkey/index.ts +70 -2
  63. package/package.json +4 -1
  64. package/types/index.ts +37 -0
package/cli/helpers.ts CHANGED
@@ -224,6 +224,26 @@ export type InstalledQuestDBEngine = {
224
224
  source: 'downloaded'
225
225
  }
226
226
 
227
+ export type InstalledTypeDBEngine = {
228
+ engine: 'typedb'
229
+ version: string
230
+ platform: string
231
+ arch: string
232
+ path: string
233
+ sizeBytes: number
234
+ source: 'downloaded'
235
+ }
236
+
237
+ export type InstalledInfluxDBEngine = {
238
+ engine: 'influxdb'
239
+ version: string
240
+ platform: string
241
+ arch: string
242
+ path: string
243
+ sizeBytes: number
244
+ source: 'downloaded'
245
+ }
246
+
227
247
  export type InstalledEngine =
228
248
  | InstalledPostgresEngine
229
249
  | InstalledMariadbEngine
@@ -241,6 +261,8 @@ export type InstalledEngine =
241
261
  | InstalledCockroachDBEngine
242
262
  | InstalledSurrealDBEngine
243
263
  | InstalledQuestDBEngine
264
+ | InstalledTypeDBEngine
265
+ | InstalledInfluxDBEngine
244
266
 
245
267
  async function getPostgresVersion(binPath: string): Promise<string | null> {
246
268
  const ext = platformService.getExecutableExtension()
@@ -1088,6 +1110,114 @@ async function getInstalledQuestDBEngines(): Promise<InstalledQuestDBEngine[]> {
1088
1110
  return engines
1089
1111
  }
1090
1112
 
1113
+ // Get TypeDB version from binary path
1114
+ // TypeDB is a Rust binary but uses a launcher script. Check for server binary existence.
1115
+ async function getTypeDBVersion(binPath: string): Promise<string | null> {
1116
+ const ext = platformService.getExecutableExtension()
1117
+ const serverPath = join(binPath, 'bin', 'server', `typedb_server_bin${ext}`)
1118
+ if (!existsSync(serverPath)) {
1119
+ return null
1120
+ }
1121
+ // TypeDB server binary doesn't have a simple --version flag
1122
+ // Return null to use directory-parsed version
1123
+ return null
1124
+ }
1125
+
1126
+ // Get installed TypeDB engines from downloaded binaries
1127
+ async function getInstalledTypeDBEngines(): Promise<InstalledTypeDBEngine[]> {
1128
+ const binDir = paths.bin
1129
+
1130
+ if (!existsSync(binDir)) {
1131
+ return []
1132
+ }
1133
+
1134
+ const entries = await readdir(binDir, { withFileTypes: true })
1135
+ const engines: InstalledTypeDBEngine[] = []
1136
+
1137
+ for (const entry of entries) {
1138
+ if (!entry.isDirectory()) continue
1139
+ if (!entry.name.startsWith('typedb-')) continue
1140
+
1141
+ const parsed = parseEngineDirectory(entry.name, 'typedb-', binDir)
1142
+ if (!parsed) continue
1143
+
1144
+ const actualVersion =
1145
+ (await getTypeDBVersion(parsed.path)) || parsed.version
1146
+ const sizeBytes = await calculateDirectorySize(parsed.path)
1147
+
1148
+ engines.push({
1149
+ engine: 'typedb',
1150
+ version: actualVersion,
1151
+ platform: parsed.platform,
1152
+ arch: parsed.arch,
1153
+ path: parsed.path,
1154
+ sizeBytes,
1155
+ source: 'downloaded',
1156
+ })
1157
+ }
1158
+
1159
+ engines.sort((a, b) => compareVersions(b.version, a.version))
1160
+
1161
+ return engines
1162
+ }
1163
+
1164
+ // Get InfluxDB version from binary path
1165
+ async function getInfluxDBVersion(binPath: string): Promise<string | null> {
1166
+ const ext = platformService.getExecutableExtension()
1167
+ const influxdbPath = join(binPath, 'bin', `influxdb3${ext}`)
1168
+ if (!existsSync(influxdbPath)) {
1169
+ return null
1170
+ }
1171
+
1172
+ try {
1173
+ const { stdout } = await execFileAsync(influxdbPath, ['--version'])
1174
+ const match = stdout.match(/v?(\d+\.\d+\.\d+)/)
1175
+ return match ? match[1] : null
1176
+ } catch {
1177
+ return null
1178
+ }
1179
+ }
1180
+
1181
+ // Get installed InfluxDB engines from downloaded binaries
1182
+ async function getInstalledInfluxDBEngines(): Promise<
1183
+ InstalledInfluxDBEngine[]
1184
+ > {
1185
+ const binDir = paths.bin
1186
+
1187
+ if (!existsSync(binDir)) {
1188
+ return []
1189
+ }
1190
+
1191
+ const entries = await readdir(binDir, { withFileTypes: true })
1192
+ const engines: InstalledInfluxDBEngine[] = []
1193
+
1194
+ for (const entry of entries) {
1195
+ if (!entry.isDirectory()) continue
1196
+ if (!entry.name.startsWith('influxdb-')) continue
1197
+
1198
+ const parsed = parseEngineDirectory(entry.name, 'influxdb-', binDir)
1199
+ if (!parsed) continue
1200
+
1201
+ const actualVersion =
1202
+ (await getInfluxDBVersion(parsed.path)) || parsed.version
1203
+ const sizeBytes = await calculateDirectorySize(parsed.path)
1204
+
1205
+ engines.push({
1206
+ engine: 'influxdb',
1207
+ version: actualVersion,
1208
+ platform: parsed.platform,
1209
+ arch: parsed.arch,
1210
+ path: parsed.path,
1211
+ sizeBytes,
1212
+ source: 'downloaded',
1213
+ })
1214
+ }
1215
+
1216
+ engines.sort((a, b) => compareVersions(b.version, a.version))
1217
+
1218
+ return engines
1219
+ }
1220
+
1091
1221
  // Get FerretDB version from binary path
1092
1222
  async function getFerretDBVersion(binPath: string): Promise<string | null> {
1093
1223
  const ext = platformService.getExecutableExtension()
@@ -1182,6 +1312,8 @@ const ENGINE_PREFIXES = [
1182
1312
  'cockroachdb-',
1183
1313
  'surrealdb-',
1184
1314
  'questdb-',
1315
+ 'typedb-',
1316
+ 'influxdb-',
1185
1317
  ] as const
1186
1318
 
1187
1319
  /**
@@ -1228,6 +1360,8 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1228
1360
  cockroachdbEngines,
1229
1361
  surrealdbEngines,
1230
1362
  questdbEngines,
1363
+ typedbEngines,
1364
+ influxdbEngines,
1231
1365
  ] = await Promise.all([
1232
1366
  getInstalledPostgresEngines(),
1233
1367
  getInstalledMariadbEngines(),
@@ -1245,6 +1379,8 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1245
1379
  getInstalledCockroachDBEngines(),
1246
1380
  getInstalledSurrealDBEngines(),
1247
1381
  getInstalledQuestDBEngines(),
1382
+ getInstalledTypeDBEngines(),
1383
+ getInstalledInfluxDBEngines(),
1248
1384
  ])
1249
1385
 
1250
1386
  return [
@@ -1264,6 +1400,8 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1264
1400
  ...cockroachdbEngines,
1265
1401
  ...surrealdbEngines,
1266
1402
  ...questdbEngines,
1403
+ ...typedbEngines,
1404
+ ...influxdbEngines,
1267
1405
  ]
1268
1406
  }
1269
1407
 
@@ -1283,4 +1421,6 @@ export {
1283
1421
  getInstalledCockroachDBEngines,
1284
1422
  getInstalledSurrealDBEngines,
1285
1423
  getInstalledQuestDBEngines,
1424
+ getInstalledTypeDBEngines,
1425
+ getInstalledInfluxDBEngines,
1286
1426
  }
package/cli/index.ts CHANGED
@@ -31,6 +31,7 @@ import { pullCommand } from './commands/pull'
31
31
  import { whichCommand } from './commands/which'
32
32
  import { exportCommand } from './commands/export'
33
33
  import { queryCommand } from './commands/query'
34
+ import { usersCommand } from './commands/users'
34
35
  import { updateManager } from '../core/update-manager'
35
36
  import { configManager } from '../core/config-manager'
36
37
  import { setCachedIconMode } from './constants'
@@ -144,6 +145,7 @@ export async function run(): Promise<void> {
144
145
  program.addCommand(whichCommand)
145
146
  program.addCommand(exportCommand)
146
147
  program.addCommand(queryCommand)
148
+ program.addCommand(usersCommand)
147
149
 
148
150
  if (process.argv.length <= 2) {
149
151
  // Only show update notification in interactive menu mode (once at startup)
package/cli/ui/prompts.ts CHANGED
@@ -472,40 +472,44 @@ export async function promptEngine(options?: {
472
472
  }): Promise<string> {
473
473
  const engines = listEngines()
474
474
 
475
- type Choice =
476
- | { name: string; value: string; short?: string }
477
- | inquirer.Separator
478
-
479
- const choices: Choice[] = engines.map((e) => ({
475
+ const engineChoices: FilterableChoice[] = engines.map((e) => ({
480
476
  name: `${getEngineIcon(e.name)} ${e.displayName} ${chalk.gray(`(versions: ${e.supportedVersions.join(', ')})`)}`,
481
477
  value: e.name,
482
478
  short: e.displayName,
483
479
  }))
484
480
 
481
+ const footerChoices: (FilterableChoice | inquirer.Separator)[] = [
482
+ new inquirer.Separator(),
483
+ new inquirer.Separator(
484
+ chalk.gray(` ${engines.length} engines — type to filter`),
485
+ ),
486
+ ]
487
+
485
488
  if (options?.includeBack) {
486
- choices.push(new inquirer.Separator())
487
- choices.push({ name: `${chalk.blue('←')} Back`, value: BACK_VALUE })
488
- choices.push({
489
+ footerChoices.push(new inquirer.Separator())
490
+ footerChoices.push({
491
+ name: `${chalk.blue('←')} Back`,
492
+ value: BACK_VALUE,
493
+ })
494
+ footerChoices.push({
489
495
  name: `${chalk.blue('⌂')} Back to main menu ${chalk.gray('(esc)')}`,
490
496
  value: MAIN_MENU_VALUE,
491
497
  })
492
- choices.push(new inquirer.Separator())
493
498
  }
494
499
 
495
- const { engine } = await escapeablePrompt<{ engine: string }>([
500
+ footerChoices.push(new inquirer.Separator())
501
+
502
+ const allChoices = [...engineChoices, ...footerChoices]
503
+
504
+ const engine = await filterableListPrompt(
505
+ allChoices,
506
+ 'Select database engine:',
496
507
  {
497
- type: 'list',
498
- name: 'engine',
499
- message: 'Select database engine:',
500
- choices,
508
+ filterableCount: engineChoices.length,
501
509
  pageSize: getPageSize(),
510
+ emptyText: 'No engines match filter',
502
511
  },
503
- ])
504
-
505
- // Escape returns to main menu
506
- if (engine === ESCAPE_VALUE) {
507
- return MAIN_MENU_VALUE
508
- }
512
+ )
509
513
 
510
514
  return engine
511
515
  }
@@ -26,6 +26,8 @@ import {
26
26
  type CockroachDBFormat,
27
27
  type SurrealDBFormat,
28
28
  type QuestDBFormat,
29
+ type TypeDBFormat,
30
+ type InfluxDBFormat,
29
31
  type BackupFormatType,
30
32
  } from '../types'
31
33
 
@@ -61,6 +63,8 @@ export const BACKUP_FORMATS: {
61
63
  [Engine.CockroachDB]: EngineBackupFormats<CockroachDBFormat>
62
64
  [Engine.SurrealDB]: EngineBackupFormats<SurrealDBFormat>
63
65
  [Engine.QuestDB]: EngineBackupFormats<QuestDBFormat>
66
+ [Engine.TypeDB]: EngineBackupFormats<TypeDBFormat>
67
+ [Engine.InfluxDB]: EngineBackupFormats<InfluxDBFormat>
64
68
  } = {
65
69
  [Engine.PostgreSQL]: {
66
70
  formats: {
@@ -308,6 +312,30 @@ export const BACKUP_FORMATS: {
308
312
  supportsFormatChoice: false, // Only SQL format supported
309
313
  defaultFormat: 'sql',
310
314
  },
315
+ [Engine.TypeDB]: {
316
+ formats: {
317
+ typeql: {
318
+ extension: '.typeql',
319
+ label: '.typeql',
320
+ description: 'TypeQL dump - schema and data as TypeQL statements',
321
+ spinnerLabel: 'TypeQL',
322
+ },
323
+ },
324
+ supportsFormatChoice: false, // Only TypeQL format supported
325
+ defaultFormat: 'typeql',
326
+ },
327
+ [Engine.InfluxDB]: {
328
+ formats: {
329
+ sql: {
330
+ extension: '.sql',
331
+ label: '.sql',
332
+ description: 'SQL dump - time-series data as SQL statements',
333
+ spinnerLabel: 'SQL',
334
+ },
335
+ },
336
+ supportsFormatChoice: false, // Only SQL format supported
337
+ defaultFormat: 'sql',
338
+ },
311
339
  }
312
340
 
313
341
  /**
@@ -239,6 +239,32 @@ export const engineDefaults: Record<Engine, EngineDefaults> = {
239
239
  clientTools: ['questdb'],
240
240
  maxConnections: 0, // Not applicable - managed internally
241
241
  },
242
+ [Engine.TypeDB]: {
243
+ defaultVersion: '3',
244
+ defaultPort: 1729, // TypeDB main port (gRPC protocol)
245
+ portRange: { start: 1729, end: 1829 },
246
+ latestVersion: '3',
247
+ superuser: 'admin', // Default admin user (password: 'password')
248
+ connectionScheme: 'typedb', // TypeDB proprietary protocol
249
+ logFileName: 'typedb.log',
250
+ pidFileName: 'typedb.pid',
251
+ dataSubdir: 'data',
252
+ clientTools: ['typedb', 'typedb_console_bin'],
253
+ maxConnections: 0, // Not applicable - managed internally
254
+ },
255
+ [Engine.InfluxDB]: {
256
+ defaultVersion: '3',
257
+ defaultPort: 8086, // InfluxDB HTTP API port
258
+ portRange: { start: 8086, end: 8186 },
259
+ latestVersion: '3',
260
+ superuser: '', // No auth by default for local dev
261
+ connectionScheme: 'http',
262
+ logFileName: 'influxdb.log',
263
+ pidFileName: 'influxdb.pid',
264
+ dataSubdir: 'data',
265
+ clientTools: [], // InfluxDB uses REST API, no separate CLI tools
266
+ maxConnections: 0, // Not applicable for time-series DB
267
+ },
242
268
  }
243
269
 
244
270
  /**
@@ -13,6 +13,7 @@ export type EngineConfig = {
13
13
  defaultPort: number | null
14
14
  runtime: 'server' | 'embedded'
15
15
  queryLanguage: string
16
+ scriptFileLabel: string | null
16
17
  connectionScheme: string
17
18
  superuser: string | null
18
19
  clientTools: string[]
@@ -11,6 +11,7 @@
11
11
  "defaultPort": 5432,
12
12
  "runtime": "server",
13
13
  "queryLanguage": "sql",
14
+ "scriptFileLabel": "Run SQL file",
14
15
  "connectionScheme": "postgresql",
15
16
  "superuser": "postgres",
16
17
  "clientTools": ["psql", "pg_dump", "pg_restore"],
@@ -26,6 +27,7 @@
26
27
  "defaultPort": 3306,
27
28
  "runtime": "server",
28
29
  "queryLanguage": "sql",
30
+ "scriptFileLabel": "Run SQL file",
29
31
  "connectionScheme": "mysql",
30
32
  "superuser": "root",
31
33
  "clientTools": ["mysql", "mysqldump", "mysqladmin"],
@@ -41,6 +43,7 @@
41
43
  "defaultPort": 3307,
42
44
  "runtime": "server",
43
45
  "queryLanguage": "sql",
46
+ "scriptFileLabel": "Run SQL file",
44
47
  "connectionScheme": "mysql",
45
48
  "superuser": "root",
46
49
  "clientTools": ["mariadb", "mariadb-dump", "mariadb-admin"]
@@ -55,6 +58,7 @@
55
58
  "defaultPort": null,
56
59
  "runtime": "embedded",
57
60
  "queryLanguage": "sql",
61
+ "scriptFileLabel": "Run SQL file",
58
62
  "connectionScheme": "sqlite",
59
63
  "superuser": null,
60
64
  "clientTools": ["sqlite3", "sqldiff", "sqlite3_analyzer", "sqlite3_rsync"]
@@ -69,6 +73,7 @@
69
73
  "defaultPort": null,
70
74
  "runtime": "embedded",
71
75
  "queryLanguage": "sql",
76
+ "scriptFileLabel": "Run SQL file",
72
77
  "connectionScheme": "duckdb",
73
78
  "superuser": null,
74
79
  "clientTools": ["duckdb"],
@@ -85,6 +90,7 @@
85
90
  "defaultPort": 27017,
86
91
  "runtime": "server",
87
92
  "queryLanguage": "javascript",
93
+ "scriptFileLabel": "Run script file",
88
94
  "connectionScheme": "mongodb",
89
95
  "superuser": null,
90
96
  "clientTools": ["mongod", "mongosh", "mongodump", "mongorestore"],
@@ -100,6 +106,7 @@
100
106
  "defaultPort": 6379,
101
107
  "runtime": "server",
102
108
  "queryLanguage": "redis",
109
+ "scriptFileLabel": "Run command file",
103
110
  "connectionScheme": "redis",
104
111
  "superuser": null,
105
112
  "clientTools": ["redis-server", "redis-cli"],
@@ -115,6 +122,7 @@
115
122
  "defaultPort": 6379,
116
123
  "runtime": "server",
117
124
  "queryLanguage": "redis",
125
+ "scriptFileLabel": "Run command file",
118
126
  "connectionScheme": "redis",
119
127
  "superuser": null,
120
128
  "clientTools": ["valkey-server", "valkey-cli"],
@@ -131,6 +139,7 @@
131
139
  "defaultPort": 9000,
132
140
  "runtime": "server",
133
141
  "queryLanguage": "sql",
142
+ "scriptFileLabel": "Run SQL file",
134
143
  "connectionScheme": "clickhouse",
135
144
  "superuser": "default",
136
145
  "clientTools": ["clickhouse"],
@@ -147,6 +156,7 @@
147
156
  "defaultPort": 6333,
148
157
  "runtime": "server",
149
158
  "queryLanguage": "rest",
159
+ "scriptFileLabel": null,
150
160
  "connectionScheme": "http",
151
161
  "superuser": null,
152
162
  "clientTools": ["qdrant"],
@@ -163,6 +173,7 @@
163
173
  "defaultPort": 7700,
164
174
  "runtime": "server",
165
175
  "queryLanguage": "rest",
176
+ "scriptFileLabel": null,
166
177
  "connectionScheme": "http",
167
178
  "superuser": null,
168
179
  "clientTools": ["meilisearch"],
@@ -179,6 +190,7 @@
179
190
  "defaultPort": 27017,
180
191
  "runtime": "server",
181
192
  "queryLanguage": "javascript",
193
+ "scriptFileLabel": "Run script file",
182
194
  "connectionScheme": "mongodb",
183
195
  "superuser": null,
184
196
  "clientTools": ["ferretdb", "mongosh", "mongodump", "mongorestore"],
@@ -195,6 +207,7 @@
195
207
  "defaultPort": 5984,
196
208
  "runtime": "server",
197
209
  "queryLanguage": "rest",
210
+ "scriptFileLabel": null,
198
211
  "connectionScheme": "http",
199
212
  "superuser": null,
200
213
  "clientTools": ["couchdb"],
@@ -211,6 +224,7 @@
211
224
  "defaultPort": 26257,
212
225
  "runtime": "server",
213
226
  "queryLanguage": "sql",
227
+ "scriptFileLabel": "Run SQL file",
214
228
  "connectionScheme": "postgresql",
215
229
  "superuser": "root",
216
230
  "clientTools": ["cockroach"],
@@ -227,6 +241,7 @@
227
241
  "defaultPort": 8000,
228
242
  "runtime": "server",
229
243
  "queryLanguage": "surrealql",
244
+ "scriptFileLabel": "Run SurrealQL file",
230
245
  "connectionScheme": "ws",
231
246
  "superuser": "root",
232
247
  "clientTools": ["surreal"],
@@ -243,11 +258,46 @@
243
258
  "defaultPort": 8812,
244
259
  "runtime": "server",
245
260
  "queryLanguage": "sql",
261
+ "scriptFileLabel": "Run SQL file",
246
262
  "connectionScheme": "postgresql",
247
263
  "superuser": "admin",
248
264
  "clientTools": ["questdb"],
249
265
  "licensing": "Apache-2.0",
250
266
  "notes": "High-performance time-series database. PostgreSQL wire protocol on port 8812. Web Console at port+188. Bundled JRE (no Java required)."
267
+ },
268
+ "typedb": {
269
+ "displayName": "TypeDB",
270
+ "icon": "🤖",
271
+ "status": "integrated",
272
+ "binarySource": "hostdb",
273
+ "supportedVersions": ["3.8.0"],
274
+ "defaultVersion": "3.8.0",
275
+ "defaultPort": 1729,
276
+ "runtime": "server",
277
+ "queryLanguage": "typeql",
278
+ "scriptFileLabel": "Run TypeQL file",
279
+ "connectionScheme": "typedb",
280
+ "superuser": "admin",
281
+ "clientTools": ["typedb", "typedb-console"],
282
+ "licensing": "MPL-2.0",
283
+ "notes": "Strongly-typed database for knowledge representation and reasoning. TypeQL query language. Main port 1729, HTTP port 8000. Default credentials: admin/password."
284
+ },
285
+ "influxdb": {
286
+ "displayName": "InfluxDB",
287
+ "icon": "📈",
288
+ "status": "integrated",
289
+ "binarySource": "hostdb",
290
+ "supportedVersions": ["3.8.0"],
291
+ "defaultVersion": "3.8.0",
292
+ "defaultPort": 8086,
293
+ "runtime": "server",
294
+ "queryLanguage": "sql",
295
+ "scriptFileLabel": null,
296
+ "connectionScheme": "http",
297
+ "superuser": null,
298
+ "clientTools": ["influxdb3"],
299
+ "licensing": ["Apache-2.0", "MIT"],
300
+ "notes": "Purpose-built time-series database with SQL support. InfluxDB 3.x is a Rust rewrite using Apache Arrow/DataFusion. HTTP API on port 8086."
251
301
  }
252
302
  }
253
303
  }
@@ -27,6 +27,7 @@
27
27
  "defaultPort",
28
28
  "runtime",
29
29
  "queryLanguage",
30
+ "scriptFileLabel",
30
31
  "connectionScheme",
31
32
  "superuser",
32
33
  "clientTools"
@@ -72,9 +73,13 @@
72
73
  },
73
74
  "queryLanguage": {
74
75
  "type": "string",
75
- "enum": ["sql", "javascript", "redis", "rest"],
76
+ "enum": ["sql", "javascript", "redis", "rest", "surrealql", "typeql"],
76
77
  "description": "Query language used by the engine"
77
78
  },
79
+ "scriptFileLabel": {
80
+ "type": ["string", "null"],
81
+ "description": "Menu label for running script files (e.g., 'Run SQL file', 'Run TypeQL file'). Null for REST API engines that don't support script files."
82
+ },
78
83
  "connectionScheme": {
79
84
  "type": "string",
80
85
  "description": "URI scheme for connection strings"
@@ -44,6 +44,9 @@ export type BinaryManagerConfig = {
44
44
  export abstract class BaseBinaryManager {
45
45
  protected abstract readonly config: BinaryManagerConfig
46
46
 
47
+ /** Timeout for `--version` verification after download (ms). Override in subclass if needed. */
48
+ protected verifyTimeoutMs = 30_000
49
+
47
50
  /**
48
51
  * Get the download URL for a version.
49
52
  * Must be implemented by subclass to use engine-specific binary-urls module.
@@ -446,7 +449,9 @@ export abstract class BaseBinaryManager {
446
449
  }
447
450
 
448
451
  try {
449
- const { stdout, stderr } = await spawnAsync(serverPath, ['--version'])
452
+ const { stdout, stderr } = await spawnAsync(serverPath, ['--version'], {
453
+ timeout: this.verifyTimeoutMs,
454
+ })
450
455
  // Log stderr if present (may contain warnings)
451
456
  if (stderr && stderr.trim()) {
452
457
  logDebug(`${this.config.serverBinary} stderr`, {
@@ -78,6 +78,10 @@ const SURREALDB_TOOLS: BinaryTool[] = ['surreal']
78
78
 
79
79
  const QUESTDB_TOOLS: BinaryTool[] = ['questdb']
80
80
 
81
+ const TYPEDB_TOOLS: BinaryTool[] = ['typedb', 'typedb_console_bin']
82
+
83
+ const INFLUXDB_TOOLS: BinaryTool[] = ['influxdb3']
84
+
81
85
  const ENHANCED_SHELLS: BinaryTool[] = [
82
86
  'pgcli',
83
87
  'mycli',
@@ -100,6 +104,8 @@ const ALL_TOOLS: BinaryTool[] = [
100
104
  ...COCKROACHDB_TOOLS,
101
105
  ...SURREALDB_TOOLS,
102
106
  ...QUESTDB_TOOLS,
107
+ ...TYPEDB_TOOLS,
108
+ ...INFLUXDB_TOOLS,
103
109
  ...SQLITE_TOOLS,
104
110
  ...DUCKDB_TOOLS,
105
111
  ...ENHANCED_SHELLS,
@@ -121,6 +127,8 @@ const ENGINE_BINARY_MAP: Partial<Record<Engine, BinaryTool[]>> = {
121
127
  [Engine.CockroachDB]: COCKROACHDB_TOOLS,
122
128
  [Engine.SurrealDB]: SURREALDB_TOOLS,
123
129
  [Engine.QuestDB]: QUESTDB_TOOLS,
130
+ [Engine.TypeDB]: TYPEDB_TOOLS,
131
+ [Engine.InfluxDB]: INFLUXDB_TOOLS,
124
132
  }
125
133
 
126
134
  export class ConfigManager {
@@ -352,6 +360,8 @@ export class ConfigManager {
352
360
  redis: { found: BinaryTool[]; missing: BinaryTool[] }
353
361
  valkey: { found: BinaryTool[]; missing: BinaryTool[] }
354
362
  meilisearch: { found: BinaryTool[]; missing: BinaryTool[] }
363
+ typedb: { found: BinaryTool[]; missing: BinaryTool[] }
364
+ influxdb: { found: BinaryTool[]; missing: BinaryTool[] }
355
365
  enhanced: { found: BinaryTool[]; missing: BinaryTool[] }
356
366
  }> {
357
367
  // First, scan ~/.spindb/bin/ for downloaded (bundled) binaries
@@ -405,6 +415,14 @@ export class ConfigManager {
405
415
  found: found.filter((t) => MEILISEARCH_TOOLS.includes(t)),
406
416
  missing: missing.filter((t) => MEILISEARCH_TOOLS.includes(t)),
407
417
  },
418
+ typedb: {
419
+ found: found.filter((t) => TYPEDB_TOOLS.includes(t)),
420
+ missing: missing.filter((t) => TYPEDB_TOOLS.includes(t)),
421
+ },
422
+ influxdb: {
423
+ found: found.filter((t) => INFLUXDB_TOOLS.includes(t)),
424
+ missing: missing.filter((t) => INFLUXDB_TOOLS.includes(t)),
425
+ },
408
426
  enhanced: {
409
427
  found: found.filter((t) => ENHANCED_SHELLS.includes(t)),
410
428
  missing: missing.filter((t) => ENHANCED_SHELLS.includes(t)),
@@ -601,6 +619,8 @@ export {
601
619
  COCKROACHDB_TOOLS,
602
620
  SURREALDB_TOOLS,
603
621
  QUESTDB_TOOLS,
622
+ TYPEDB_TOOLS,
623
+ INFLUXDB_TOOLS,
604
624
  SQLITE_TOOLS,
605
625
  DUCKDB_TOOLS,
606
626
  ENHANCED_SHELLS,