spindb 0.32.2 → 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.
@@ -398,6 +398,10 @@ export function detectLocationType(location: string): {
398
398
  return { type: 'connection', inferredEngine: Engine.Meilisearch }
399
399
  }
400
400
 
401
+ if (location.startsWith('influxdb://')) {
402
+ return { type: 'connection', inferredEngine: Engine.InfluxDB }
403
+ }
404
+
401
405
  if (existsSync(location)) {
402
406
  // Check if it's a SQLite file (case-insensitive)
403
407
  const lowerLocation = location.toLowerCase()
@@ -423,7 +427,7 @@ export const createCommand = new Command('create')
423
427
  .argument('[name]', 'Container name')
424
428
  .option(
425
429
  '-e, --engine <engine>',
426
- 'Database engine (postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch)',
430
+ 'Database engine (postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb)',
427
431
  )
428
432
  .option('--db-version <version>', 'Database version (e.g., 17, 8.0)')
429
433
  .option('-d, --database <database>', 'Database name')
@@ -48,6 +48,7 @@ import {
48
48
  type InstalledSurrealDBEngine,
49
49
  type InstalledQuestDBEngine,
50
50
  type InstalledTypeDBEngine,
51
+ type InstalledInfluxDBEngine,
51
52
  } from '../helpers'
52
53
  import { Engine, Platform } from '../../types'
53
54
  import {
@@ -70,6 +71,7 @@ import { cockroachdbBinaryManager } from '../../engines/cockroachdb/binary-manag
70
71
  import { surrealdbBinaryManager } from '../../engines/surrealdb/binary-manager'
71
72
  import { questdbBinaryManager } from '../../engines/questdb/binary-manager'
72
73
  import { typedbBinaryManager } from '../../engines/typedb/binary-manager'
74
+ import { influxdbBinaryManager } from '../../engines/influxdb/binary-manager'
73
75
  import {
74
76
  DEFAULT_DOCUMENTDB_VERSION,
75
77
  normalizeDocumentDBVersion,
@@ -475,6 +477,9 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
475
477
  const typedbEngines = engines.filter(
476
478
  (e): e is InstalledTypeDBEngine => e.engine === 'typedb',
477
479
  )
480
+ const influxdbEngines = engines.filter(
481
+ (e): e is InstalledInfluxDBEngine => e.engine === 'influxdb',
482
+ )
478
483
 
479
484
  // Calculate total size for PostgreSQL
480
485
  const totalPgSize = pgEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
@@ -699,6 +704,20 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
699
704
  )
700
705
  }
701
706
 
707
+ // InfluxDB rows
708
+ for (const engine of influxdbEngines) {
709
+ const platformInfo = `${engine.platform}-${engine.arch}`
710
+
711
+ console.log(
712
+ chalk.gray(' ') +
713
+ getEngineIcon('influxdb') +
714
+ chalk.cyan('influxdb'.padEnd(13)) +
715
+ chalk.yellow(engine.version.padEnd(12)) +
716
+ chalk.gray(platformInfo.padEnd(18)) +
717
+ chalk.white(formatBytes(engine.sizeBytes)),
718
+ )
719
+ }
720
+
702
721
  console.log(chalk.gray(' ' + '─'.repeat(59)))
703
722
 
704
723
  // Summary
@@ -852,6 +871,17 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
852
871
  ),
853
872
  )
854
873
  }
874
+ if (influxdbEngines.length > 0) {
875
+ const totalInfluxDBSize = influxdbEngines.reduce(
876
+ (acc, e) => acc + e.sizeBytes,
877
+ 0,
878
+ )
879
+ console.log(
880
+ chalk.gray(
881
+ ` InfluxDB: ${influxdbEngines.length} version(s), ${formatBytes(totalInfluxDBSize)}`,
882
+ ),
883
+ )
884
+ }
855
885
  console.log()
856
886
  }
857
887
 
@@ -2013,9 +2043,56 @@ enginesCommand
2013
2043
  return
2014
2044
  }
2015
2045
 
2046
+ if (['influxdb', 'influx'].includes(normalizedEngine)) {
2047
+ if (!version) {
2048
+ console.error(uiError('InfluxDB requires a version (e.g., 3)'))
2049
+ process.exit(1)
2050
+ }
2051
+
2052
+ const engine = getEngine(Engine.InfluxDB)
2053
+
2054
+ const spinner = createSpinner(
2055
+ `Checking InfluxDB ${version} binaries...`,
2056
+ )
2057
+ spinner.start()
2058
+
2059
+ let wasCached = false
2060
+ await engine.ensureBinaries(version, ({ stage, message }) => {
2061
+ if (stage === 'cached') {
2062
+ wasCached = true
2063
+ spinner.text = `InfluxDB ${version} binaries ready (cached)`
2064
+ } else {
2065
+ spinner.text = message
2066
+ }
2067
+ })
2068
+
2069
+ if (wasCached) {
2070
+ spinner.succeed(`InfluxDB ${version} binaries already installed`)
2071
+ } else {
2072
+ spinner.succeed(`InfluxDB ${version} binaries downloaded`)
2073
+ }
2074
+
2075
+ // Show the path for reference
2076
+ const { platform: influxdbPlatform, arch: influxdbArch } =
2077
+ platformService.getPlatformInfo()
2078
+ const influxdbFullVersion =
2079
+ influxdbBinaryManager.getFullVersion(version)
2080
+ const binPath = paths.getBinaryPath({
2081
+ engine: 'influxdb',
2082
+ version: influxdbFullVersion,
2083
+ platform: influxdbPlatform,
2084
+ arch: influxdbArch,
2085
+ })
2086
+ console.log(chalk.gray(` Location: ${binPath}`))
2087
+
2088
+ // Skip client tools check for InfluxDB - it's a REST API server
2089
+ // with no CLI client tools (uses HTTP protocols instead)
2090
+ return
2091
+ }
2092
+
2016
2093
  console.error(
2017
2094
  uiError(
2018
- `Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb`,
2095
+ `Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb`,
2019
2096
  ),
2020
2097
  )
2021
2098
  process.exit(1)
@@ -214,6 +214,15 @@ function validateConnectionString(
214
214
  if (typedbError) return typedbError
215
215
  }
216
216
  break
217
+ case Engine.InfluxDB:
218
+ if (
219
+ !input.startsWith('influxdb://') &&
220
+ !input.startsWith('http://') &&
221
+ !input.startsWith('https://')
222
+ ) {
223
+ return 'Connection string must start with influxdb://, http://, or https://'
224
+ }
225
+ break
217
226
  case Engine.SQLite:
218
227
  case Engine.DuckDB:
219
228
  return 'File-based engines do not support remote connection strings'
@@ -133,6 +133,8 @@ export async function handleCreate(): Promise<'main' | string | void> {
133
133
  database = '0'
134
134
  } else if (engine === 'qdrant' || engine === 'meilisearch') {
135
135
  database = 'default'
136
+ } else if (engine === 'influxdb') {
137
+ database = 'mydb'
136
138
  } else {
137
139
  database = await promptDatabaseName(name, engine)
138
140
  }
@@ -31,6 +31,7 @@ import {
31
31
  type InstalledSurrealDBEngine,
32
32
  type InstalledQuestDBEngine,
33
33
  type InstalledTypeDBEngine,
34
+ type InstalledInfluxDBEngine,
34
35
  } from '../../helpers'
35
36
 
36
37
  import { type MenuChoice } from './shared'
@@ -97,6 +98,9 @@ export async function handleEngines(): Promise<void> {
97
98
  (e): e is InstalledQuestDBEngine => e.engine === 'questdb',
98
99
  ),
99
100
  ...engines.filter((e): e is InstalledTypeDBEngine => e.engine === 'typedb'),
101
+ ...engines.filter(
102
+ (e): e is InstalledInfluxDBEngine => e.engine === 'influxdb',
103
+ ),
100
104
  ]
101
105
 
102
106
  // Calculate total size
@@ -47,6 +47,7 @@ function generatePreviewLine(mode: IconMode): string {
47
47
  [Engine.SurrealDB]: '[SR]',
48
48
  [Engine.QuestDB]: '[QS]',
49
49
  [Engine.TypeDB]: '[TB]',
50
+ [Engine.InfluxDB]: '[IX]',
50
51
  }
51
52
  const icons = PREVIEW_ENGINES.map((engine) => {
52
53
  const icon = ASCII_ICONS[engine] || '[??]'
@@ -75,6 +76,7 @@ function generatePreviewLine(mode: IconMode): string {
75
76
  [Engine.SurrealDB]: '\uedfe',
76
77
  [Engine.QuestDB]: '\ued2f',
77
78
  [Engine.TypeDB]: '\ue706',
79
+ [Engine.InfluxDB]: '\udb85\udf95',
78
80
  }
79
81
  const icons = PREVIEW_ENGINES.map((engine) => {
80
82
  const icon = NERD_ICONS[engine] || '\ue706'
@@ -103,6 +105,7 @@ function generatePreviewLine(mode: IconMode): string {
103
105
  [Engine.SurrealDB]: '\u{1F300}',
104
106
  [Engine.QuestDB]: '\u23F1',
105
107
  [Engine.TypeDB]: '\u{1F916}',
108
+ [Engine.InfluxDB]: '\u{1F4C8}',
106
109
  }
107
110
  const icons = PREVIEW_ENGINES.map((engine) => EMOJI_ICONS[engine] || '\u25A3')
108
111
  return icons.join(' ')
@@ -218,6 +218,13 @@ export async function handleOpenShell(
218
218
  engineSpecificInstalled = false
219
219
  engineSpecificValue = null
220
220
  engineSpecificInstallValue = null
221
+ } else if (config.engine === 'influxdb') {
222
+ // InfluxDB uses REST API, no interactive shell
223
+ defaultShellName = 'Web Dashboard'
224
+ engineSpecificCli = null
225
+ engineSpecificInstalled = false
226
+ engineSpecificValue = null
227
+ engineSpecificInstallValue = null
221
228
  } else if (config.engine === 'couchdb') {
222
229
  // CouchDB uses REST API, open Fauxton dashboard in browser
223
230
  defaultShellName = 'Fauxton Dashboard'
@@ -308,6 +315,12 @@ export async function handleOpenShell(
308
315
  name: `ℹ Show API info`,
309
316
  value: 'api-info',
310
317
  })
318
+ } else if (config.engine === 'influxdb') {
319
+ // InfluxDB: REST API only, no web dashboard or interactive shell
320
+ choices.push({
321
+ name: `ℹ Show API info`,
322
+ value: 'api-info',
323
+ })
311
324
  } else if (config.engine === 'couchdb') {
312
325
  // CouchDB: Fauxton dashboard is built-in at /_utils
313
326
  choices.push({
@@ -320,7 +333,7 @@ export async function handleOpenShell(
320
333
  value: 'api-info',
321
334
  })
322
335
  } else {
323
- // Non-Qdrant/Meilisearch/CouchDB engines: show default shell option
336
+ // Non-REST-API engines: show default shell option
324
337
  choices.push({
325
338
  name: `>_ Use default shell (${defaultShellName})`,
326
339
  value: 'default',
@@ -424,6 +437,17 @@ export async function handleOpenShell(
424
437
  console.log(chalk.gray(` curl http://127.0.0.1:${config.port}/indexes`))
425
438
  console.log(chalk.gray(` curl http://127.0.0.1:${config.port}/health`))
426
439
  console.log(chalk.gray(` curl http://127.0.0.1:${config.port}/stats`))
440
+ } else if (config.engine === 'influxdb') {
441
+ console.log(chalk.cyan('InfluxDB REST API:'))
442
+ console.log(chalk.white(` HTTP: http://127.0.0.1:${config.port}`))
443
+ console.log()
444
+ console.log(chalk.gray('Example curl commands:'))
445
+ console.log(chalk.gray(` curl http://127.0.0.1:${config.port}/health`))
446
+ console.log(
447
+ chalk.gray(
448
+ ` curl -H "Content-Type: application/json" http://127.0.0.1:${config.port}/api/v3/query_sql -d '{"db":"mydb","q":"SELECT 1"}'`,
449
+ ),
450
+ )
427
451
  } else if (config.engine === 'couchdb') {
428
452
  console.log(chalk.cyan('CouchDB REST API:'))
429
453
  console.log(chalk.white(` HTTP: http://127.0.0.1:${config.port}`))
@@ -919,6 +943,24 @@ async function launchShell(
919
943
  openInBrowser(dashboardUrl)
920
944
  await pressEnterToContinue()
921
945
  return
946
+ } else if (config.engine === 'influxdb') {
947
+ // InfluxDB: REST API only, no web dashboard
948
+ // This branch shouldn't be reached since we removed the 'default' choice,
949
+ // but handle gracefully just in case
950
+ console.log()
951
+ console.log(chalk.cyan('InfluxDB REST API:'))
952
+ console.log(chalk.white(` HTTP: http://127.0.0.1:${config.port}`))
953
+ console.log()
954
+ console.log(chalk.gray('Example curl commands:'))
955
+ console.log(chalk.gray(` curl http://127.0.0.1:${config.port}/health`))
956
+ console.log(
957
+ chalk.gray(
958
+ ` curl -H "Content-Type: application/json" http://127.0.0.1:${config.port}/api/v3/query_sql -d '{"db":"mydb","q":"SELECT 1"}'`,
959
+ ),
960
+ )
961
+ console.log()
962
+ await pressEnterToContinue()
963
+ return
922
964
  } else if (config.engine === 'couchdb') {
923
965
  // CouchDB: Open Fauxton dashboard in browser (served at /_utils)
924
966
  const dashboardUrl = `http://127.0.0.1:${config.port}/_utils`
package/cli/constants.ts CHANGED
@@ -76,6 +76,7 @@ export const ENGINE_BRAND_COLORS: Record<Engine, BrandColor> = {
76
76
  [Engine.SurrealDB]: { foreground: '#FFFFFF', background: '#FF00A0' }, // White on pink
77
77
  [Engine.QuestDB]: { foreground: '#000000', background: '#02FC04' }, // Black on green
78
78
  [Engine.TypeDB]: { foreground: '#FFFFFF', background: '#7B2D8E' }, // White on purple
79
+ [Engine.InfluxDB]: { foreground: '#FFFFFF', background: '#9394FF' }, // White on indigo/purple
79
80
  }
80
81
 
81
82
  // ASCII fallback icons - work in any terminal
@@ -97,6 +98,7 @@ const ASCII_ICONS: Record<Engine, string> = {
97
98
  [Engine.SurrealDB]: '[SR]',
98
99
  [Engine.QuestDB]: '[QS]',
99
100
  [Engine.TypeDB]: '[TB]',
101
+ [Engine.InfluxDB]: '[IX]',
100
102
  }
101
103
 
102
104
  // Nerd Font icons - require a patched font
@@ -119,6 +121,7 @@ const NERD_ICONS: Record<Engine, string> = {
119
121
  [Engine.SurrealDB]: '\uedfe', // nf-fa-infinity (multi-model)
120
122
  [Engine.QuestDB]: '\ued2f', // nf-fa-gauge-high (time-series performance)
121
123
  [Engine.TypeDB]: '\ue706', // nf-dev-database (knowledge graph)
124
+ [Engine.InfluxDB]: '\udb85\udf95', // nf-md-chart-line (time-series)
122
125
  }
123
126
 
124
127
  // Emoji icons - original icons, inconsistent width across terminals
@@ -140,6 +143,7 @@ const EMOJI_ICONS: Record<Engine, string> = {
140
143
  [Engine.SurrealDB]: '🌀',
141
144
  [Engine.QuestDB]: '⏱',
142
145
  [Engine.TypeDB]: '🤖',
146
+ [Engine.InfluxDB]: '📈',
143
147
  }
144
148
 
145
149
  const DEFAULT_ICONS: Record<IconMode, string> = {
package/cli/helpers.ts CHANGED
@@ -234,6 +234,16 @@ export type InstalledTypeDBEngine = {
234
234
  source: 'downloaded'
235
235
  }
236
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
+
237
247
  export type InstalledEngine =
238
248
  | InstalledPostgresEngine
239
249
  | InstalledMariadbEngine
@@ -252,6 +262,7 @@ export type InstalledEngine =
252
262
  | InstalledSurrealDBEngine
253
263
  | InstalledQuestDBEngine
254
264
  | InstalledTypeDBEngine
265
+ | InstalledInfluxDBEngine
255
266
 
256
267
  async function getPostgresVersion(binPath: string): Promise<string | null> {
257
268
  const ext = platformService.getExecutableExtension()
@@ -1150,6 +1161,63 @@ async function getInstalledTypeDBEngines(): Promise<InstalledTypeDBEngine[]> {
1150
1161
  return engines
1151
1162
  }
1152
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
+
1153
1221
  // Get FerretDB version from binary path
1154
1222
  async function getFerretDBVersion(binPath: string): Promise<string | null> {
1155
1223
  const ext = platformService.getExecutableExtension()
@@ -1245,6 +1313,7 @@ const ENGINE_PREFIXES = [
1245
1313
  'surrealdb-',
1246
1314
  'questdb-',
1247
1315
  'typedb-',
1316
+ 'influxdb-',
1248
1317
  ] as const
1249
1318
 
1250
1319
  /**
@@ -1292,6 +1361,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1292
1361
  surrealdbEngines,
1293
1362
  questdbEngines,
1294
1363
  typedbEngines,
1364
+ influxdbEngines,
1295
1365
  ] = await Promise.all([
1296
1366
  getInstalledPostgresEngines(),
1297
1367
  getInstalledMariadbEngines(),
@@ -1310,6 +1380,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1310
1380
  getInstalledSurrealDBEngines(),
1311
1381
  getInstalledQuestDBEngines(),
1312
1382
  getInstalledTypeDBEngines(),
1383
+ getInstalledInfluxDBEngines(),
1313
1384
  ])
1314
1385
 
1315
1386
  return [
@@ -1330,6 +1401,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
1330
1401
  ...surrealdbEngines,
1331
1402
  ...questdbEngines,
1332
1403
  ...typedbEngines,
1404
+ ...influxdbEngines,
1333
1405
  ]
1334
1406
  }
1335
1407
 
@@ -1350,4 +1422,5 @@ export {
1350
1422
  getInstalledSurrealDBEngines,
1351
1423
  getInstalledQuestDBEngines,
1352
1424
  getInstalledTypeDBEngines,
1425
+ getInstalledInfluxDBEngines,
1353
1426
  }
@@ -27,6 +27,7 @@ import {
27
27
  type SurrealDBFormat,
28
28
  type QuestDBFormat,
29
29
  type TypeDBFormat,
30
+ type InfluxDBFormat,
30
31
  type BackupFormatType,
31
32
  } from '../types'
32
33
 
@@ -63,6 +64,7 @@ export const BACKUP_FORMATS: {
63
64
  [Engine.SurrealDB]: EngineBackupFormats<SurrealDBFormat>
64
65
  [Engine.QuestDB]: EngineBackupFormats<QuestDBFormat>
65
66
  [Engine.TypeDB]: EngineBackupFormats<TypeDBFormat>
67
+ [Engine.InfluxDB]: EngineBackupFormats<InfluxDBFormat>
66
68
  } = {
67
69
  [Engine.PostgreSQL]: {
68
70
  formats: {
@@ -322,6 +324,18 @@ export const BACKUP_FORMATS: {
322
324
  supportsFormatChoice: false, // Only TypeQL format supported
323
325
  defaultFormat: 'typeql',
324
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
+ },
325
339
  }
326
340
 
327
341
  /**
@@ -252,6 +252,19 @@ export const engineDefaults: Record<Engine, EngineDefaults> = {
252
252
  clientTools: ['typedb', 'typedb_console_bin'],
253
253
  maxConnections: 0, // Not applicable - managed internally
254
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
+ },
255
268
  }
256
269
 
257
270
  /**
@@ -281,6 +281,23 @@
281
281
  "clientTools": ["typedb", "typedb-console"],
282
282
  "licensing": "MPL-2.0",
283
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."
284
301
  }
285
302
  }
286
303
  }
@@ -80,6 +80,8 @@ const QUESTDB_TOOLS: BinaryTool[] = ['questdb']
80
80
 
81
81
  const TYPEDB_TOOLS: BinaryTool[] = ['typedb', 'typedb_console_bin']
82
82
 
83
+ const INFLUXDB_TOOLS: BinaryTool[] = ['influxdb3']
84
+
83
85
  const ENHANCED_SHELLS: BinaryTool[] = [
84
86
  'pgcli',
85
87
  'mycli',
@@ -103,6 +105,7 @@ const ALL_TOOLS: BinaryTool[] = [
103
105
  ...SURREALDB_TOOLS,
104
106
  ...QUESTDB_TOOLS,
105
107
  ...TYPEDB_TOOLS,
108
+ ...INFLUXDB_TOOLS,
106
109
  ...SQLITE_TOOLS,
107
110
  ...DUCKDB_TOOLS,
108
111
  ...ENHANCED_SHELLS,
@@ -125,6 +128,7 @@ const ENGINE_BINARY_MAP: Partial<Record<Engine, BinaryTool[]>> = {
125
128
  [Engine.SurrealDB]: SURREALDB_TOOLS,
126
129
  [Engine.QuestDB]: QUESTDB_TOOLS,
127
130
  [Engine.TypeDB]: TYPEDB_TOOLS,
131
+ [Engine.InfluxDB]: INFLUXDB_TOOLS,
128
132
  }
129
133
 
130
134
  export class ConfigManager {
@@ -357,6 +361,7 @@ export class ConfigManager {
357
361
  valkey: { found: BinaryTool[]; missing: BinaryTool[] }
358
362
  meilisearch: { found: BinaryTool[]; missing: BinaryTool[] }
359
363
  typedb: { found: BinaryTool[]; missing: BinaryTool[] }
364
+ influxdb: { found: BinaryTool[]; missing: BinaryTool[] }
360
365
  enhanced: { found: BinaryTool[]; missing: BinaryTool[] }
361
366
  }> {
362
367
  // First, scan ~/.spindb/bin/ for downloaded (bundled) binaries
@@ -414,6 +419,10 @@ export class ConfigManager {
414
419
  found: found.filter((t) => TYPEDB_TOOLS.includes(t)),
415
420
  missing: missing.filter((t) => TYPEDB_TOOLS.includes(t)),
416
421
  },
422
+ influxdb: {
423
+ found: found.filter((t) => INFLUXDB_TOOLS.includes(t)),
424
+ missing: missing.filter((t) => INFLUXDB_TOOLS.includes(t)),
425
+ },
417
426
  enhanced: {
418
427
  found: found.filter((t) => ENHANCED_SHELLS.includes(t)),
419
428
  missing: missing.filter((t) => ENHANCED_SHELLS.includes(t)),
@@ -611,6 +620,7 @@ export {
611
620
  SURREALDB_TOOLS,
612
621
  QUESTDB_TOOLS,
613
622
  TYPEDB_TOOLS,
623
+ INFLUXDB_TOOLS,
614
624
  SQLITE_TOOLS,
615
625
  DUCKDB_TOOLS,
616
626
  ENHANCED_SHELLS,
@@ -84,6 +84,8 @@ const KNOWN_BINARY_TOOLS: readonly BinaryTool[] = [
84
84
  // TypeDB
85
85
  'typedb',
86
86
  'typedb_console_bin',
87
+ // InfluxDB
88
+ 'influxdb3',
87
89
  // Enhanced shells (optional)
88
90
  'pgcli',
89
91
  'mycli',
@@ -71,6 +71,7 @@ function getEngineDisplayName(engine: Engine): string {
71
71
  [Engine.SurrealDB]: 'SurrealDB',
72
72
  [Engine.QuestDB]: 'QuestDB',
73
73
  [Engine.TypeDB]: 'TypeDB',
74
+ [Engine.InfluxDB]: 'InfluxDB',
74
75
  }
75
76
  return displayNames[engine] || engine
76
77
  }
@@ -141,6 +142,9 @@ const _ENGINE_BINARY_CONFIG: Record<
141
142
  [Engine.TypeDB]: {
142
143
  primaryBinaries: ['typedb', 'typedb_console_bin'],
143
144
  },
145
+ [Engine.InfluxDB]: {
146
+ primaryBinaries: [], // REST API only, no CLI tools
147
+ },
144
148
  }
145
149
 
146
150
  /**
@@ -193,6 +197,7 @@ function getConnectionStringTemplate(
193
197
  return useTLS ? `https://<host>:${port}` : `http://<host>:${port}`
194
198
 
195
199
  case Engine.Meilisearch:
200
+ case Engine.InfluxDB:
196
201
  return useTLS ? `https://<host>:${port}` : `http://<host>:${port}`
197
202
 
198
203
  case Engine.CouchDB:
@@ -492,6 +497,13 @@ echo "User configured via server settings"
492
497
  userCreationCommands = `
493
498
  # API key is configured at server start
494
499
  echo "API key configured via server settings"
500
+ `
501
+ break
502
+
503
+ case Engine.InfluxDB:
504
+ userCreationCommands = `
505
+ # InfluxDB 3.x local dev runs without authentication
506
+ echo "No authentication required for local InfluxDB 3.x"
495
507
  `
496
508
  break
497
509
 
@@ -1284,6 +1296,7 @@ export async function getDockerConnectionString(
1284
1296
  return `http://${host}:${port}`
1285
1297
 
1286
1298
  case Engine.Meilisearch:
1299
+ case Engine.InfluxDB:
1287
1300
  return `http://${host}:${port}`
1288
1301
 
1289
1302
  case Engine.CouchDB:
package/engines/index.ts CHANGED
@@ -15,6 +15,7 @@ import { cockroachdbEngine } from './cockroachdb'
15
15
  import { surrealdbEngine } from './surrealdb'
16
16
  import { questdbEngine } from './questdb'
17
17
  import { typedbEngine } from './typedb'
18
+ import { influxdbEngine } from './influxdb'
18
19
  import { platformService } from '../core/platform-service'
19
20
  import { Engine, Platform } from '../types'
20
21
  import type { BaseEngine } from './base-engine'
@@ -80,6 +81,9 @@ export const engines: Record<string, BaseEngine> = {
80
81
  // TypeDB and aliases
81
82
  [Engine.TypeDB]: typedbEngine,
82
83
  tdb: typedbEngine,
84
+ // InfluxDB and aliases
85
+ [Engine.InfluxDB]: influxdbEngine,
86
+ influx: influxdbEngine,
83
87
  }
84
88
 
85
89
  // Get an engine by name