spindb 0.35.4 → 0.36.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/README.md +20 -9
- package/cli/commands/engines.ts +89 -435
- package/cli/commands/menu/backup-handlers.ts +5 -0
- package/cli/commands/menu/settings-handlers.ts +3 -0
- package/cli/commands/menu/shell-handlers.ts +40 -0
- package/cli/constants.ts +4 -0
- package/cli/helpers.ts +74 -0
- package/config/backup-formats.ts +14 -0
- package/config/engine-defaults.ts +13 -0
- package/config/engines.json +17 -0
- package/core/config-manager.ts +10 -0
- package/core/credential-manager.ts +2 -0
- package/core/dependency-manager.ts +2 -0
- package/core/docker-exporter.ts +7 -0
- package/core/library-env.ts +120 -0
- package/engines/index.ts +5 -0
- package/engines/mariadb/index.ts +45 -14
- package/engines/redis/index.ts +39 -0
- package/engines/valkey/index.ts +40 -0
- package/engines/weaviate/README.md +302 -0
- package/engines/weaviate/api-client.ts +61 -0
- package/engines/weaviate/backup.ts +145 -0
- package/engines/weaviate/binary-manager.ts +80 -0
- package/engines/weaviate/binary-urls.ts +115 -0
- package/engines/weaviate/cli-utils.ts +43 -0
- package/engines/weaviate/hostdb-releases.ts +23 -0
- package/engines/weaviate/index.ts +1139 -0
- package/engines/weaviate/restore.ts +235 -0
- package/engines/weaviate/version-maps.ts +78 -0
- package/engines/weaviate/version-validator.ts +128 -0
- package/package.json +2 -1
- package/types/index.ts +9 -0
|
@@ -48,6 +48,7 @@ function generatePreviewLine(mode: IconMode): string {
|
|
|
48
48
|
[Engine.QuestDB]: '[QS]',
|
|
49
49
|
[Engine.TypeDB]: '[TB]',
|
|
50
50
|
[Engine.InfluxDB]: '[IX]',
|
|
51
|
+
[Engine.Weaviate]: '[WV]',
|
|
51
52
|
}
|
|
52
53
|
const icons = PREVIEW_ENGINES.map((engine) => {
|
|
53
54
|
const icon = ASCII_ICONS[engine] || '[??]'
|
|
@@ -77,6 +78,7 @@ function generatePreviewLine(mode: IconMode): string {
|
|
|
77
78
|
[Engine.QuestDB]: '\ued2f',
|
|
78
79
|
[Engine.TypeDB]: '\ue706',
|
|
79
80
|
[Engine.InfluxDB]: '\udb85\udf95',
|
|
81
|
+
[Engine.Weaviate]: '\uf0e8',
|
|
80
82
|
}
|
|
81
83
|
const icons = PREVIEW_ENGINES.map((engine) => {
|
|
82
84
|
const icon = NERD_ICONS[engine] || '\ue706'
|
|
@@ -106,6 +108,7 @@ function generatePreviewLine(mode: IconMode): string {
|
|
|
106
108
|
[Engine.QuestDB]: '\u23F1',
|
|
107
109
|
[Engine.TypeDB]: '\u{1F916}',
|
|
108
110
|
[Engine.InfluxDB]: '\u{1F4C8}',
|
|
111
|
+
[Engine.Weaviate]: '\u{1F52E}',
|
|
109
112
|
}
|
|
110
113
|
const icons = PREVIEW_ENGINES.map((engine) => EMOJI_ICONS[engine] || '\u25A3')
|
|
111
114
|
return icons.join(' ')
|
|
@@ -244,6 +244,13 @@ export async function handleOpenShell(
|
|
|
244
244
|
engineSpecificInstalled = false
|
|
245
245
|
engineSpecificValue = null
|
|
246
246
|
engineSpecificInstallValue = null
|
|
247
|
+
} else if (config.engine === 'weaviate') {
|
|
248
|
+
// Weaviate uses REST API, open web dashboard in browser
|
|
249
|
+
defaultShellName = 'REST API'
|
|
250
|
+
engineSpecificCli = null
|
|
251
|
+
engineSpecificInstalled = false
|
|
252
|
+
engineSpecificValue = null
|
|
253
|
+
engineSpecificInstallValue = null
|
|
247
254
|
} else if (config.engine === 'couchdb') {
|
|
248
255
|
// CouchDB uses REST API, open Fauxton dashboard in browser
|
|
249
256
|
defaultShellName = 'Fauxton Dashboard'
|
|
@@ -344,6 +351,16 @@ export async function handleOpenShell(
|
|
|
344
351
|
name: `ℹ Show API info`,
|
|
345
352
|
value: 'api-info',
|
|
346
353
|
})
|
|
354
|
+
} else if (config.engine === 'weaviate') {
|
|
355
|
+
// Weaviate: REST API dashboard + API info
|
|
356
|
+
choices.push({
|
|
357
|
+
name: `◎ Open Dashboard in browser`,
|
|
358
|
+
value: 'default',
|
|
359
|
+
})
|
|
360
|
+
choices.push({
|
|
361
|
+
name: `ℹ Show API info`,
|
|
362
|
+
value: 'api-info',
|
|
363
|
+
})
|
|
347
364
|
} else if (config.engine === 'couchdb') {
|
|
348
365
|
// CouchDB: Fauxton dashboard is built-in at /_utils
|
|
349
366
|
choices.push({
|
|
@@ -597,6 +614,20 @@ export async function handleOpenShell(
|
|
|
597
614
|
` curl -H "Content-Type: application/json" http://127.0.0.1:${config.port}/api/v3/query_sql -d '{"db":"mydb","q":"SELECT 1"}'`,
|
|
598
615
|
),
|
|
599
616
|
)
|
|
617
|
+
} else if (config.engine === 'weaviate') {
|
|
618
|
+
console.log(chalk.cyan('Weaviate REST API:'))
|
|
619
|
+
console.log(chalk.white(` HTTP: http://127.0.0.1:${config.port}`))
|
|
620
|
+
console.log(chalk.white(` gRPC: 127.0.0.1:${config.port + 1}`))
|
|
621
|
+
console.log()
|
|
622
|
+
console.log(chalk.gray('Example curl commands:'))
|
|
623
|
+
console.log(
|
|
624
|
+
chalk.gray(
|
|
625
|
+
` curl http://127.0.0.1:${config.port}/v1/.well-known/ready`,
|
|
626
|
+
),
|
|
627
|
+
)
|
|
628
|
+
console.log(
|
|
629
|
+
chalk.gray(` curl http://127.0.0.1:${config.port}/v1/schema`),
|
|
630
|
+
)
|
|
600
631
|
} else if (config.engine === 'couchdb') {
|
|
601
632
|
console.log(chalk.cyan('CouchDB REST API:'))
|
|
602
633
|
console.log(chalk.white(` HTTP: http://127.0.0.1:${config.port}`))
|
|
@@ -1505,6 +1536,15 @@ async function launchShell(
|
|
|
1505
1536
|
openInBrowser(dashboardUrl)
|
|
1506
1537
|
await pressEnterToContinue()
|
|
1507
1538
|
return
|
|
1539
|
+
} else if (config.engine === 'weaviate') {
|
|
1540
|
+
// Weaviate: Open REST API root in browser
|
|
1541
|
+
const dashboardUrl = `http://127.0.0.1:${config.port}`
|
|
1542
|
+
console.log(uiInfo(`Opening Weaviate in browser...`))
|
|
1543
|
+
console.log(chalk.gray(` ${dashboardUrl}`))
|
|
1544
|
+
console.log()
|
|
1545
|
+
openInBrowser(dashboardUrl)
|
|
1546
|
+
await pressEnterToContinue()
|
|
1547
|
+
return
|
|
1508
1548
|
} else if (config.engine === 'influxdb') {
|
|
1509
1549
|
// InfluxDB: influxdb3 query is one-shot (no REPL), use interactive loop
|
|
1510
1550
|
const engine = getEngine(config.engine)
|
package/cli/constants.ts
CHANGED
|
@@ -77,6 +77,7 @@ export const ENGINE_BRAND_COLORS: Record<Engine, BrandColor> = {
|
|
|
77
77
|
[Engine.QuestDB]: { foreground: '#000000', background: '#02FC04' }, // Black on green
|
|
78
78
|
[Engine.TypeDB]: { foreground: '#FFFFFF', background: '#7B2D8E' }, // White on purple
|
|
79
79
|
[Engine.InfluxDB]: { foreground: '#FFFFFF', background: '#9394FF' }, // White on indigo/purple
|
|
80
|
+
[Engine.Weaviate]: { foreground: '#FFFFFF', background: '#00D1A8' }, // White on green
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
// ASCII fallback icons - work in any terminal
|
|
@@ -99,6 +100,7 @@ const ASCII_ICONS: Record<Engine, string> = {
|
|
|
99
100
|
[Engine.QuestDB]: '[QS]',
|
|
100
101
|
[Engine.TypeDB]: '[TB]',
|
|
101
102
|
[Engine.InfluxDB]: '[IX]',
|
|
103
|
+
[Engine.Weaviate]: '[WV]',
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
// Nerd Font icons - require a patched font
|
|
@@ -122,6 +124,7 @@ const NERD_ICONS: Record<Engine, string> = {
|
|
|
122
124
|
[Engine.QuestDB]: '\ued2f', // nf-fa-gauge-high (time-series performance)
|
|
123
125
|
[Engine.TypeDB]: '\ue706', // nf-dev-database (knowledge graph)
|
|
124
126
|
[Engine.InfluxDB]: '\udb85\udf95', // nf-md-chart-line (time-series)
|
|
127
|
+
[Engine.Weaviate]: '\uf0e8', // nf-fa-sitemap (vector graph)
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
// Emoji icons - original icons, inconsistent width across terminals
|
|
@@ -144,6 +147,7 @@ const EMOJI_ICONS: Record<Engine, string> = {
|
|
|
144
147
|
[Engine.QuestDB]: '⏱',
|
|
145
148
|
[Engine.TypeDB]: '🤖',
|
|
146
149
|
[Engine.InfluxDB]: '📈',
|
|
150
|
+
[Engine.Weaviate]: '🔮',
|
|
147
151
|
}
|
|
148
152
|
|
|
149
153
|
const DEFAULT_ICONS: Record<IconMode, string> = {
|
package/cli/helpers.ts
CHANGED
|
@@ -244,6 +244,16 @@ export type InstalledInfluxDBEngine = {
|
|
|
244
244
|
source: 'downloaded'
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
export type InstalledWeaviateEngine = {
|
|
248
|
+
engine: 'weaviate'
|
|
249
|
+
version: string
|
|
250
|
+
platform: string
|
|
251
|
+
arch: string
|
|
252
|
+
path: string
|
|
253
|
+
sizeBytes: number
|
|
254
|
+
source: 'downloaded'
|
|
255
|
+
}
|
|
256
|
+
|
|
247
257
|
export type InstalledEngine =
|
|
248
258
|
| InstalledPostgresEngine
|
|
249
259
|
| InstalledMariadbEngine
|
|
@@ -263,6 +273,7 @@ export type InstalledEngine =
|
|
|
263
273
|
| InstalledQuestDBEngine
|
|
264
274
|
| InstalledTypeDBEngine
|
|
265
275
|
| InstalledInfluxDBEngine
|
|
276
|
+
| InstalledWeaviateEngine
|
|
266
277
|
|
|
267
278
|
async function getPostgresVersion(binPath: string): Promise<string | null> {
|
|
268
279
|
const ext = platformService.getExecutableExtension()
|
|
@@ -1278,6 +1289,64 @@ async function getInstalledFerretDBEngines(): Promise<
|
|
|
1278
1289
|
return engines
|
|
1279
1290
|
}
|
|
1280
1291
|
|
|
1292
|
+
// Get Weaviate version from binary path
|
|
1293
|
+
async function getWeaviateVersion(binPath: string): Promise<string | null> {
|
|
1294
|
+
const ext = platformService.getExecutableExtension()
|
|
1295
|
+
const weaviatePath = join(binPath, 'bin', `weaviate${ext}`)
|
|
1296
|
+
if (!existsSync(weaviatePath)) {
|
|
1297
|
+
return null
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
try {
|
|
1301
|
+
const { stdout } = await execFileAsync(weaviatePath, ['--version'])
|
|
1302
|
+
// Parse output like "weaviate v1.35.7" or "1.35.7"
|
|
1303
|
+
const match = stdout.match(/(?:weaviate\s+)?v?(\d+\.\d+\.\d+)/)
|
|
1304
|
+
return match ? match[1] : null
|
|
1305
|
+
} catch {
|
|
1306
|
+
return null
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Get installed Weaviate engines from downloaded binaries
|
|
1311
|
+
async function getInstalledWeaviateEngines(): Promise<
|
|
1312
|
+
InstalledWeaviateEngine[]
|
|
1313
|
+
> {
|
|
1314
|
+
const binDir = paths.bin
|
|
1315
|
+
|
|
1316
|
+
if (!existsSync(binDir)) {
|
|
1317
|
+
return []
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
const entries = await readdir(binDir, { withFileTypes: true })
|
|
1321
|
+
const engines: InstalledWeaviateEngine[] = []
|
|
1322
|
+
|
|
1323
|
+
for (const entry of entries) {
|
|
1324
|
+
if (!entry.isDirectory()) continue
|
|
1325
|
+
if (!entry.name.startsWith('weaviate-')) continue
|
|
1326
|
+
|
|
1327
|
+
const parsed = parseEngineDirectory(entry.name, 'weaviate-', binDir)
|
|
1328
|
+
if (!parsed) continue
|
|
1329
|
+
|
|
1330
|
+
const actualVersion =
|
|
1331
|
+
(await getWeaviateVersion(parsed.path)) || parsed.version
|
|
1332
|
+
const sizeBytes = await calculateDirectorySize(parsed.path)
|
|
1333
|
+
|
|
1334
|
+
engines.push({
|
|
1335
|
+
engine: 'weaviate',
|
|
1336
|
+
version: actualVersion,
|
|
1337
|
+
platform: parsed.platform,
|
|
1338
|
+
arch: parsed.arch,
|
|
1339
|
+
path: parsed.path,
|
|
1340
|
+
sizeBytes,
|
|
1341
|
+
source: 'downloaded',
|
|
1342
|
+
})
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
engines.sort((a, b) => compareVersions(b.version, a.version))
|
|
1346
|
+
|
|
1347
|
+
return engines
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1281
1350
|
export function compareVersions(a: string, b: string): number {
|
|
1282
1351
|
const partsA = a.split('.').map((p) => parseInt(p, 10) || 0)
|
|
1283
1352
|
const partsB = b.split('.').map((p) => parseInt(p, 10) || 0)
|
|
@@ -1314,6 +1383,7 @@ const ENGINE_PREFIXES = [
|
|
|
1314
1383
|
'questdb-',
|
|
1315
1384
|
'typedb-',
|
|
1316
1385
|
'influxdb-',
|
|
1386
|
+
'weaviate-',
|
|
1317
1387
|
] as const
|
|
1318
1388
|
|
|
1319
1389
|
/**
|
|
@@ -1362,6 +1432,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
|
|
|
1362
1432
|
questdbEngines,
|
|
1363
1433
|
typedbEngines,
|
|
1364
1434
|
influxdbEngines,
|
|
1435
|
+
weaviateEngines,
|
|
1365
1436
|
] = await Promise.all([
|
|
1366
1437
|
getInstalledPostgresEngines(),
|
|
1367
1438
|
getInstalledMariadbEngines(),
|
|
@@ -1381,6 +1452,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
|
|
|
1381
1452
|
getInstalledQuestDBEngines(),
|
|
1382
1453
|
getInstalledTypeDBEngines(),
|
|
1383
1454
|
getInstalledInfluxDBEngines(),
|
|
1455
|
+
getInstalledWeaviateEngines(),
|
|
1384
1456
|
])
|
|
1385
1457
|
|
|
1386
1458
|
return [
|
|
@@ -1402,6 +1474,7 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
|
|
|
1402
1474
|
...questdbEngines,
|
|
1403
1475
|
...typedbEngines,
|
|
1404
1476
|
...influxdbEngines,
|
|
1477
|
+
...weaviateEngines,
|
|
1405
1478
|
]
|
|
1406
1479
|
}
|
|
1407
1480
|
|
|
@@ -1423,4 +1496,5 @@ export {
|
|
|
1423
1496
|
getInstalledQuestDBEngines,
|
|
1424
1497
|
getInstalledTypeDBEngines,
|
|
1425
1498
|
getInstalledInfluxDBEngines,
|
|
1499
|
+
getInstalledWeaviateEngines,
|
|
1426
1500
|
}
|
package/config/backup-formats.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
type QuestDBFormat,
|
|
29
29
|
type TypeDBFormat,
|
|
30
30
|
type InfluxDBFormat,
|
|
31
|
+
type WeaviateFormat,
|
|
31
32
|
type BackupFormatType,
|
|
32
33
|
} from '../types'
|
|
33
34
|
|
|
@@ -65,6 +66,7 @@ export const BACKUP_FORMATS: {
|
|
|
65
66
|
[Engine.QuestDB]: EngineBackupFormats<QuestDBFormat>
|
|
66
67
|
[Engine.TypeDB]: EngineBackupFormats<TypeDBFormat>
|
|
67
68
|
[Engine.InfluxDB]: EngineBackupFormats<InfluxDBFormat>
|
|
69
|
+
[Engine.Weaviate]: EngineBackupFormats<WeaviateFormat>
|
|
68
70
|
} = {
|
|
69
71
|
[Engine.PostgreSQL]: {
|
|
70
72
|
formats: {
|
|
@@ -336,6 +338,18 @@ export const BACKUP_FORMATS: {
|
|
|
336
338
|
supportsFormatChoice: false, // Only SQL format supported
|
|
337
339
|
defaultFormat: 'sql',
|
|
338
340
|
},
|
|
341
|
+
[Engine.Weaviate]: {
|
|
342
|
+
formats: {
|
|
343
|
+
snapshot: {
|
|
344
|
+
extension: '.snapshot',
|
|
345
|
+
label: '.snapshot',
|
|
346
|
+
description: 'Weaviate snapshot - full database backup',
|
|
347
|
+
spinnerLabel: 'snapshot',
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
supportsFormatChoice: false, // Only snapshot format supported
|
|
351
|
+
defaultFormat: 'snapshot',
|
|
352
|
+
},
|
|
339
353
|
}
|
|
340
354
|
|
|
341
355
|
/**
|
|
@@ -265,6 +265,19 @@ export const engineDefaults: Record<Engine, EngineDefaults> = {
|
|
|
265
265
|
clientTools: [], // InfluxDB uses REST API, no separate CLI tools
|
|
266
266
|
maxConnections: 0, // Not applicable for time-series DB
|
|
267
267
|
},
|
|
268
|
+
[Engine.Weaviate]: {
|
|
269
|
+
defaultVersion: '1',
|
|
270
|
+
defaultPort: 8080, // Weaviate HTTP REST API port (gRPC is port + 1)
|
|
271
|
+
portRange: { start: 8080, end: 8180 },
|
|
272
|
+
latestVersion: '1',
|
|
273
|
+
superuser: '', // No auth by default for local dev
|
|
274
|
+
connectionScheme: 'http',
|
|
275
|
+
logFileName: 'weaviate.log',
|
|
276
|
+
pidFileName: 'weaviate.pid',
|
|
277
|
+
dataSubdir: 'data',
|
|
278
|
+
clientTools: [], // Weaviate uses REST/GraphQL API, no separate CLI tools
|
|
279
|
+
maxConnections: 0, // Not applicable for vector DB
|
|
280
|
+
},
|
|
268
281
|
}
|
|
269
282
|
|
|
270
283
|
/**
|
package/config/engines.json
CHANGED
|
@@ -309,6 +309,23 @@
|
|
|
309
309
|
"clientTools": ["influxdb3"],
|
|
310
310
|
"licensing": ["Apache-2.0", "MIT"],
|
|
311
311
|
"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."
|
|
312
|
+
},
|
|
313
|
+
"weaviate": {
|
|
314
|
+
"displayName": "Weaviate",
|
|
315
|
+
"icon": "🔮",
|
|
316
|
+
"status": "integrated",
|
|
317
|
+
"binarySource": "hostdb",
|
|
318
|
+
"supportedVersions": ["1.35.7"],
|
|
319
|
+
"defaultVersion": "1.35.7",
|
|
320
|
+
"defaultPort": 8080,
|
|
321
|
+
"runtime": "server",
|
|
322
|
+
"queryLanguage": "rest",
|
|
323
|
+
"scriptFileLabel": null,
|
|
324
|
+
"connectionScheme": "http",
|
|
325
|
+
"superuser": null,
|
|
326
|
+
"clientTools": ["weaviate"],
|
|
327
|
+
"licensing": "BSD-3-Clause",
|
|
328
|
+
"notes": "AI-native vector database. REST API on port 8080, gRPC on port+1. Uses classes/collections instead of databases."
|
|
312
329
|
}
|
|
313
330
|
}
|
|
314
331
|
}
|
package/core/config-manager.ts
CHANGED
|
@@ -82,6 +82,8 @@ const TYPEDB_TOOLS: BinaryTool[] = ['typedb', 'typedb_console_bin']
|
|
|
82
82
|
|
|
83
83
|
const INFLUXDB_TOOLS: BinaryTool[] = ['influxdb3']
|
|
84
84
|
|
|
85
|
+
const WEAVIATE_TOOLS: BinaryTool[] = ['weaviate']
|
|
86
|
+
|
|
85
87
|
const PGWEB_TOOLS: BinaryTool[] = ['pgweb']
|
|
86
88
|
|
|
87
89
|
const DBLAB_TOOLS: BinaryTool[] = ['dblab']
|
|
@@ -110,6 +112,7 @@ const ALL_TOOLS: BinaryTool[] = [
|
|
|
110
112
|
...QUESTDB_TOOLS,
|
|
111
113
|
...TYPEDB_TOOLS,
|
|
112
114
|
...INFLUXDB_TOOLS,
|
|
115
|
+
...WEAVIATE_TOOLS,
|
|
113
116
|
...PGWEB_TOOLS,
|
|
114
117
|
...DBLAB_TOOLS,
|
|
115
118
|
...SQLITE_TOOLS,
|
|
@@ -135,6 +138,7 @@ const ENGINE_BINARY_MAP: Partial<Record<Engine, BinaryTool[]>> = {
|
|
|
135
138
|
[Engine.QuestDB]: QUESTDB_TOOLS,
|
|
136
139
|
[Engine.TypeDB]: TYPEDB_TOOLS,
|
|
137
140
|
[Engine.InfluxDB]: INFLUXDB_TOOLS,
|
|
141
|
+
[Engine.Weaviate]: WEAVIATE_TOOLS,
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
export class ConfigManager {
|
|
@@ -368,6 +372,7 @@ export class ConfigManager {
|
|
|
368
372
|
meilisearch: { found: BinaryTool[]; missing: BinaryTool[] }
|
|
369
373
|
typedb: { found: BinaryTool[]; missing: BinaryTool[] }
|
|
370
374
|
influxdb: { found: BinaryTool[]; missing: BinaryTool[] }
|
|
375
|
+
weaviate: { found: BinaryTool[]; missing: BinaryTool[] }
|
|
371
376
|
enhanced: { found: BinaryTool[]; missing: BinaryTool[] }
|
|
372
377
|
}> {
|
|
373
378
|
// First, scan ~/.spindb/bin/ for downloaded (bundled) binaries
|
|
@@ -429,6 +434,10 @@ export class ConfigManager {
|
|
|
429
434
|
found: found.filter((t) => INFLUXDB_TOOLS.includes(t)),
|
|
430
435
|
missing: missing.filter((t) => INFLUXDB_TOOLS.includes(t)),
|
|
431
436
|
},
|
|
437
|
+
weaviate: {
|
|
438
|
+
found: found.filter((t) => WEAVIATE_TOOLS.includes(t)),
|
|
439
|
+
missing: missing.filter((t) => WEAVIATE_TOOLS.includes(t)),
|
|
440
|
+
},
|
|
432
441
|
enhanced: {
|
|
433
442
|
found: found.filter((t) => ENHANCED_SHELLS.includes(t)),
|
|
434
443
|
missing: missing.filter((t) => ENHANCED_SHELLS.includes(t)),
|
|
@@ -627,6 +636,7 @@ export {
|
|
|
627
636
|
QUESTDB_TOOLS,
|
|
628
637
|
TYPEDB_TOOLS,
|
|
629
638
|
INFLUXDB_TOOLS,
|
|
639
|
+
WEAVIATE_TOOLS,
|
|
630
640
|
PGWEB_TOOLS,
|
|
631
641
|
DBLAB_TOOLS,
|
|
632
642
|
SQLITE_TOOLS,
|
package/core/docker-exporter.ts
CHANGED
|
@@ -72,6 +72,7 @@ function getEngineDisplayName(engine: Engine): string {
|
|
|
72
72
|
[Engine.QuestDB]: 'QuestDB',
|
|
73
73
|
[Engine.TypeDB]: 'TypeDB',
|
|
74
74
|
[Engine.InfluxDB]: 'InfluxDB',
|
|
75
|
+
[Engine.Weaviate]: 'Weaviate',
|
|
75
76
|
}
|
|
76
77
|
return displayNames[engine] || engine
|
|
77
78
|
}
|
|
@@ -145,6 +146,9 @@ const _ENGINE_BINARY_CONFIG: Record<
|
|
|
145
146
|
[Engine.InfluxDB]: {
|
|
146
147
|
primaryBinaries: [], // REST API only, no CLI tools
|
|
147
148
|
},
|
|
149
|
+
[Engine.Weaviate]: {
|
|
150
|
+
primaryBinaries: [], // REST/GraphQL API only, no CLI tools
|
|
151
|
+
},
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
/**
|
|
@@ -198,6 +202,7 @@ function getConnectionStringTemplate(
|
|
|
198
202
|
|
|
199
203
|
case Engine.Meilisearch:
|
|
200
204
|
case Engine.InfluxDB:
|
|
205
|
+
case Engine.Weaviate:
|
|
201
206
|
return useTLS ? `https://<host>:${port}` : `http://<host>:${port}`
|
|
202
207
|
|
|
203
208
|
case Engine.CouchDB:
|
|
@@ -494,6 +499,7 @@ echo "User configured via server settings"
|
|
|
494
499
|
|
|
495
500
|
case Engine.Qdrant:
|
|
496
501
|
case Engine.Meilisearch:
|
|
502
|
+
case Engine.Weaviate:
|
|
497
503
|
userCreationCommands = `
|
|
498
504
|
# API key is configured at server start
|
|
499
505
|
echo "API key configured via server settings"
|
|
@@ -1297,6 +1303,7 @@ export async function getDockerConnectionString(
|
|
|
1297
1303
|
|
|
1298
1304
|
case Engine.Meilisearch:
|
|
1299
1305
|
case Engine.InfluxDB:
|
|
1306
|
+
case Engine.Weaviate:
|
|
1300
1307
|
return `http://${host}:${port}`
|
|
1301
1308
|
|
|
1302
1309
|
case Engine.CouchDB:
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library environment utilities for dynamically-linked engine binaries.
|
|
3
|
+
*
|
|
4
|
+
* MariaDB, Redis, and Valkey hostdb binaries are linked against Homebrew's
|
|
5
|
+
* OpenSSL at absolute paths (e.g. /opt/homebrew/opt/openssl@3/lib/libssl.3.dylib).
|
|
6
|
+
* On systems without that library, they fail with cryptic dyld errors.
|
|
7
|
+
*
|
|
8
|
+
* This module provides:
|
|
9
|
+
* - getLibraryEnv(): sets DYLD_FALLBACK_LIBRARY_PATH / LD_LIBRARY_PATH so
|
|
10
|
+
* the dynamic linker checks {binPath}/lib first (preparing for when hostdb
|
|
11
|
+
* bundles dylibs alongside binaries).
|
|
12
|
+
* - detectLibraryError(): scans process output for library-loading patterns
|
|
13
|
+
* and returns an actionable error message.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { platform as osPlatform } from 'os'
|
|
17
|
+
import { join } from 'path'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns env vars that point the dynamic linker at {binPath}/lib.
|
|
21
|
+
* On macOS: DYLD_FALLBACK_LIBRARY_PATH
|
|
22
|
+
* On Linux: LD_LIBRARY_PATH
|
|
23
|
+
* On Windows: returns undefined (not applicable).
|
|
24
|
+
*
|
|
25
|
+
* Usage: spread into spawn env: `{ ...process.env, ...getLibraryEnv(binPath) }`
|
|
26
|
+
*/
|
|
27
|
+
export function getLibraryEnv(
|
|
28
|
+
binPath: string,
|
|
29
|
+
): Record<string, string> | undefined {
|
|
30
|
+
const plat = osPlatform()
|
|
31
|
+
const libDir = join(binPath, 'lib')
|
|
32
|
+
|
|
33
|
+
if (plat === 'darwin') {
|
|
34
|
+
return { DYLD_FALLBACK_LIBRARY_PATH: libDir }
|
|
35
|
+
}
|
|
36
|
+
if (plat === 'linux') {
|
|
37
|
+
return { LD_LIBRARY_PATH: libDir }
|
|
38
|
+
}
|
|
39
|
+
return undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Scans stderr/log output for dynamic library loading errors and returns
|
|
44
|
+
* an actionable message, or null if no library error was detected.
|
|
45
|
+
*/
|
|
46
|
+
export function detectLibraryError(
|
|
47
|
+
output: string,
|
|
48
|
+
engineName: string,
|
|
49
|
+
): string | null {
|
|
50
|
+
if (!output) return null
|
|
51
|
+
|
|
52
|
+
const plat = osPlatform()
|
|
53
|
+
const lower = output.toLowerCase()
|
|
54
|
+
|
|
55
|
+
// macOS dyld errors
|
|
56
|
+
if (
|
|
57
|
+
lower.includes('library not loaded') ||
|
|
58
|
+
lower.includes('dyld:') ||
|
|
59
|
+
lower.includes('dyld[')
|
|
60
|
+
) {
|
|
61
|
+
const needsOpenssl =
|
|
62
|
+
lower.includes('libssl') || lower.includes('libcrypto')
|
|
63
|
+
|
|
64
|
+
if (needsOpenssl && plat === 'darwin') {
|
|
65
|
+
return (
|
|
66
|
+
`${engineName} failed to start: missing OpenSSL libraries.\n` +
|
|
67
|
+
`The downloaded binary requires OpenSSL 3 which is not installed.\n` +
|
|
68
|
+
`Fix: brew install openssl@3\n` +
|
|
69
|
+
`Alternatively, re-download binaries after hostdb ships relocatable builds.`
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
`${engineName} failed to start: a required dynamic library could not be loaded.\n` +
|
|
75
|
+
`This typically means the hostdb binary was built against libraries not present on this system.\n` +
|
|
76
|
+
(plat === 'darwin'
|
|
77
|
+
? `Try: brew install openssl@3\n`
|
|
78
|
+
: `Try: sudo apt-get install libssl-dev (or the equivalent for your distro)\n`) +
|
|
79
|
+
`See: https://github.com/robertjbass/hostdb/issues`
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Linux GLIBC version errors
|
|
84
|
+
if (lower.includes('glibc') || lower.includes('libc.so')) {
|
|
85
|
+
return (
|
|
86
|
+
`${engineName} failed to start: incompatible system C library (GLIBC).\n` +
|
|
87
|
+
`The downloaded binary requires a newer GLIBC version than is installed.\n` +
|
|
88
|
+
`Options:\n` +
|
|
89
|
+
` - Upgrade your OS to a newer version\n` +
|
|
90
|
+
` - Use Docker: spindb can run inside containers with newer GLIBC\n` +
|
|
91
|
+
`See: https://github.com/robertjbass/hostdb/issues`
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Generic shared library errors on Linux
|
|
96
|
+
if (
|
|
97
|
+
lower.includes('error while loading shared libraries') ||
|
|
98
|
+
lower.includes('cannot open shared object file')
|
|
99
|
+
) {
|
|
100
|
+
const needsOpenssl =
|
|
101
|
+
lower.includes('libssl') || lower.includes('libcrypto')
|
|
102
|
+
|
|
103
|
+
if (needsOpenssl) {
|
|
104
|
+
return (
|
|
105
|
+
`${engineName} failed to start: missing OpenSSL libraries.\n` +
|
|
106
|
+
`Fix: sudo apt-get install libssl-dev (Debian/Ubuntu)\n` +
|
|
107
|
+
` sudo dnf install openssl-devel (Fedora/RHEL)\n` +
|
|
108
|
+
`See: https://github.com/robertjbass/hostdb/issues`
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
`${engineName} failed to start: a required shared library is missing.\n` +
|
|
114
|
+
`Check the error output above for the specific library name and install it.\n` +
|
|
115
|
+
`See: https://github.com/robertjbass/hostdb/issues`
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return null
|
|
120
|
+
}
|
package/engines/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { surrealdbEngine } from './surrealdb'
|
|
|
16
16
|
import { questdbEngine } from './questdb'
|
|
17
17
|
import { typedbEngine } from './typedb'
|
|
18
18
|
import { influxdbEngine } from './influxdb'
|
|
19
|
+
import { weaviateEngine } from './weaviate'
|
|
19
20
|
import { platformService } from '../core/platform-service'
|
|
20
21
|
import { Engine, Platform } from '../types'
|
|
21
22
|
import type { BaseEngine } from './base-engine'
|
|
@@ -83,6 +84,9 @@ export const engines: Record<string, BaseEngine> = {
|
|
|
83
84
|
// InfluxDB and aliases
|
|
84
85
|
[Engine.InfluxDB]: influxdbEngine,
|
|
85
86
|
influx: influxdbEngine,
|
|
87
|
+
// Weaviate and aliases
|
|
88
|
+
[Engine.Weaviate]: weaviateEngine,
|
|
89
|
+
wv: weaviateEngine,
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
// Get an engine by name
|
|
@@ -119,4 +123,5 @@ export function listEngines(): EngineInfo[] {
|
|
|
119
123
|
defaultPort: engine.defaultPort,
|
|
120
124
|
supportedVersions: engine.supportedVersions,
|
|
121
125
|
}))
|
|
126
|
+
.sort((a, b) => a.displayName.localeCompare(b.displayName))
|
|
122
127
|
}
|