@ouim/vectoriadb-server 0.1.2 → 0.1.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 +0 -9
- package/index.js +17 -17
- package/listen-race-test.js +28 -0
- package/package.json +2 -3
- package/vectoriadb-server.js +74 -48
package/README.md
CHANGED
|
@@ -189,15 +189,6 @@ A: The client SDK stringifies your filter function. The server then reconstructs
|
|
|
189
189
|
|
|
190
190
|
---
|
|
191
191
|
|
|
192
|
-
## Future Roadmap
|
|
193
|
-
|
|
194
|
-
- [ ] **JWT Authentication**: Add more robust auth options.
|
|
195
|
-
- [ ] **Data Encryption**: Support for end-to-end encryption of metadata.
|
|
196
|
-
- [ ] **Multi-Instance**: Support for multiple VectoriaDB instances managed by one server.
|
|
197
|
-
- [ ] **Python Client**: A compatible SDK for Python applications.
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
192
|
## Credits
|
|
202
193
|
|
|
203
194
|
This SDK builds on and integrates with [VectoriaDB](https://github.com/agentfront/vectoriadb). See the Vectoria product website at [https://agentfront.dev/vectoria](https://agentfront.dev/vectoria) for more information and additional resources.
|
package/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import VectoriaDBServer from './vectoriadb-server.js'
|
|
2
2
|
import { FileStorageAdapter } from 'vectoriadb'
|
|
3
3
|
|
|
4
|
-
// If run directly, start a demo server
|
|
5
|
-
if (process.argv[1] && process.argv[1].endsWith('index.js')) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
// // If run directly, start a demo server
|
|
5
|
+
// if (process.argv[1] && process.argv[1].endsWith('index.js')) {
|
|
6
|
+
// const server = new VectoriaDBServer({
|
|
7
|
+
// port: process.env.PORT ? Number(process.env.PORT) : 3001,
|
|
8
|
+
// host: '0.0.0.0',
|
|
9
|
+
// vectoriadbConfig: {
|
|
10
|
+
// // default storage / model - user should override for production
|
|
11
|
+
// storageAdapter: new FileStorageAdapter({ cacheDir: '/data/vectoriadb', namespace: 'default' }),
|
|
12
|
+
// },
|
|
13
|
+
// cors: ['http://localhost:3000'],
|
|
14
|
+
// })
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
16
|
+
// server.listen().catch(err => {
|
|
17
|
+
// console.error(err)
|
|
18
|
+
// process.exit(1)
|
|
19
|
+
// })
|
|
20
|
+
// }
|
|
21
21
|
|
|
22
|
-
export { VectoriaDBServer }
|
|
22
|
+
export { VectoriaDBServer, FileStorageAdapter }
|
|
23
23
|
export default VectoriaDBServer
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import VectoriaDBServer from './vectoriadb-server.js'
|
|
2
|
+
import { FileStorageAdapter } from 'vectoriadb'
|
|
3
|
+
|
|
4
|
+
async function run() {
|
|
5
|
+
const server = new VectoriaDBServer({
|
|
6
|
+
port: 3002,
|
|
7
|
+
vectoriadbConfig: {
|
|
8
|
+
storageAdapter: new FileStorageAdapter({ cacheDir: './.cache/test-vectoriadb', namespace: 'test' }),
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// call listen() twice concurrently to reproduce the race if present
|
|
14
|
+
const results = await Promise.all([server.listen(), server.listen()])
|
|
15
|
+
console.log('listen() calls resolved, same instance:', results[0] === results[1])
|
|
16
|
+
console.log('server._started =', server._started)
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error('concurrent listen failed:', err)
|
|
19
|
+
process.exitCode = 1
|
|
20
|
+
} finally {
|
|
21
|
+
await server.close()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
run().catch(err => {
|
|
26
|
+
console.error(err)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
})
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouim/vectoriadb-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "node index.js",
|
|
8
|
-
"demo": "node demo.js"
|
|
9
|
-
"publish": "npm publish --access public"
|
|
8
|
+
"demo": "node demo.js"
|
|
10
9
|
},
|
|
11
10
|
"dependencies": {
|
|
12
11
|
"@huggingface/transformers": "^3.8.1",
|
package/vectoriadb-server.js
CHANGED
|
@@ -19,63 +19,89 @@ export default class VectoriaDBServer {
|
|
|
19
19
|
this._vectoria = null
|
|
20
20
|
this._sockets = new Set()
|
|
21
21
|
this._started = false
|
|
22
|
+
this._startPromise = null
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
async listen() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this._vectoria = new VectoriaDB(this.vectoriadbConfig)
|
|
28
|
-
if (typeof this._vectoria.initialize === 'function') {
|
|
29
|
-
await this._vectoria.initialize()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this._http = http.createServer((req, res) => {
|
|
33
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' })
|
|
34
|
-
res.end('VectoriaDB Server')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
this._io = new IOServer(this._http, {
|
|
38
|
-
cors: { origin: this.cors.length ? this.cors : '*', methods: ['GET', 'POST'] },
|
|
39
|
-
maxHttpBufferSize: 1e7,
|
|
40
|
-
})
|
|
26
|
+
// fast-path: already started
|
|
27
|
+
if (this._started) return this
|
|
41
28
|
|
|
42
|
-
|
|
29
|
+
// if a start is already in progress, return the same promise
|
|
30
|
+
if (this._startPromise) return this._startPromise
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
32
|
+
this._startPromise = (async () => {
|
|
33
|
+
try {
|
|
34
|
+
// Initialize VectoriaDB (loads models / storage as configured)
|
|
35
|
+
this._vectoria = new VectoriaDB(this.vectoriadbConfig)
|
|
36
|
+
if (typeof this._vectoria.initialize === 'function') {
|
|
37
|
+
await this._vectoria.initialize()
|
|
50
38
|
}
|
|
51
|
-
}
|
|
52
|
-
next()
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
nsp.on('connection', socket => {
|
|
56
|
-
this._sockets.add(socket)
|
|
57
|
-
socket.on('disconnect', () => this._sockets.delete(socket))
|
|
58
39
|
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
this._http = http.createServer((req, res) => {
|
|
41
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' })
|
|
42
|
+
res.end('VectoriaDB Server')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
this._io = new IOServer(this._http, {
|
|
46
|
+
cors: { origin: this.cors.length ? this.cors : '*', methods: ['GET', 'POST'] },
|
|
47
|
+
maxHttpBufferSize: 1e7,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const nsp = this._io.of('/vectoriadb')
|
|
51
|
+
|
|
52
|
+
nsp.use((socket, next) => {
|
|
53
|
+
// simple API key auth if configured
|
|
54
|
+
if (this.apiKey) {
|
|
55
|
+
const provided = socket.handshake.auth?.apiKey || socket.handshake.query?.apiKey
|
|
56
|
+
if (!provided || provided !== this.apiKey) {
|
|
57
|
+
return next(new Error('Unauthorized'))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
next()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
nsp.on('connection', socket => {
|
|
64
|
+
this._sockets.add(socket)
|
|
65
|
+
socket.on('disconnect', () => this._sockets.delete(socket))
|
|
66
|
+
|
|
67
|
+
socket.on('request', async payload => {
|
|
68
|
+
// payload: { id, method, params, collection, timestamp }
|
|
69
|
+
try {
|
|
70
|
+
await this._handleRequest(socket, payload)
|
|
71
|
+
} catch (err) {
|
|
72
|
+
socket.emit('response', { id: payload?.id ?? null, result: null, error: { message: err.message }, took: 0 })
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// allow ping from client
|
|
77
|
+
socket.on('health', cb => cb && cb({ ok: true, ts: Date.now() }))
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await new Promise((res, rej) => {
|
|
81
|
+
this._http.listen(this.port, this.host, err => (err ? rej(err) : res()))
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
this._started = true
|
|
85
|
+
console.log(`VectoriaDB Server listening on ${this.host}:${this.port}`)
|
|
86
|
+
return this
|
|
87
|
+
} catch (err) {
|
|
88
|
+
// cleanup partial resources on failure
|
|
61
89
|
try {
|
|
62
|
-
await this.
|
|
63
|
-
} catch (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
await new Promise((res, rej) => {
|
|
73
|
-
this._http.listen(this.port, this.host, err => (err ? rej(err) : res()))
|
|
74
|
-
})
|
|
90
|
+
if (this._io) await this._io.close()
|
|
91
|
+
} catch (e) {}
|
|
92
|
+
try {
|
|
93
|
+
if (this._http) this._http.close(() => {})
|
|
94
|
+
} catch (e) {}
|
|
95
|
+
throw err
|
|
96
|
+
}
|
|
97
|
+
})()
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
try {
|
|
100
|
+
return await this._startPromise
|
|
101
|
+
} finally {
|
|
102
|
+
// ensure the in-progress marker is cleared after attempt completes
|
|
103
|
+
this._startPromise = null
|
|
104
|
+
}
|
|
79
105
|
}
|
|
80
106
|
|
|
81
107
|
async _handleRequest(socket, payload) {
|