@ouim/vectoriadb-server 0.1.1 → 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 ADDED
@@ -0,0 +1,200 @@
1
+ # VectoriaDB SDK
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)]()
4
+
5
+ A lightweight, JavaScript-only client/server SDK for [VectoriaDB](https://github.com/agentfront/vectoriadb). Forward vector database operations from client applications to a centralized server instance with ease.
6
+
7
+ > ⚠️ **Not for large production deployments.** This SDK is primarily intended for small applications, prototypes, demos, and hobby projects where quick setup and simplicity are priorities. For mission‑critical or large-scale production use, consider a hardened, production-grade solution.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Mirror API**: Client SDK replicates the full VectoriaDB API surface.
14
+ - **Remote Execution**: Perform heavy vector operations on the server; keep your client light.
15
+ - **Smart Filtering**: Send JavaScript functions as filters; they are automatically serialized and executed on the server.
16
+ - **Streaming Support**: Smoothly handle large result sets with built-in chunking.
17
+ - **Robust Connection**: Automatic reconnection, request queueing, and configurable timeouts.
18
+ - **Collection Helpers**: High-level abstractions for simplified document management.
19
+
20
+ ## Project Structure
21
+
22
+ ```text
23
+ vectoriadb-sdk/
24
+ ├── server/ # Server implementation (hosts VectoriaDB instance)
25
+ └── client/ # Client implementation (forwards requests via Socket.io)
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### 1. Start the Server
31
+
32
+ The server requires `vectoriadb` to be installed.
33
+
34
+ ```bash
35
+ cd server
36
+ npm install
37
+ npm start
38
+ ```
39
+
40
+ **Basic Server Configuration (`server/index.js`):**
41
+
42
+ ```javascript
43
+ import VectoriaDBServer from '@ouim/vectoriadb-server'
44
+
45
+ const server = new VectoriaDBServer({
46
+ port: 3001,
47
+ cors: ['http://localhost:3000'],
48
+ // apiKey: 'your-secure-key' // Optional authentication
49
+ })
50
+
51
+ await server.listen()
52
+ ```
53
+
54
+ ### 2. Connect the Client
55
+
56
+ ```bash
57
+ npm install @ouim/vectoriadb-client
58
+ ```
59
+
60
+ **Basic Usage:**
61
+
62
+ ```javascript
63
+ import VectoriaDB from '@ouim/vectoriadb-client'
64
+
65
+ const db = new VectoriaDB({
66
+ serverUrl: 'http://localhost:3001',
67
+ // apiKey: 'your-secure-key'
68
+ })
69
+
70
+ await db.initialize()
71
+
72
+ // Add documents
73
+ await db.add('doc1', 'Vector databases are awesome!', { category: 'tech' })
74
+
75
+ // Search with semantic similarity
76
+ const results = await db.search('vector database', { topK: 5 })
77
+ console.log(results)
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Advanced Search & Filtering
83
+
84
+ ### Remote Function Filtering
85
+
86
+ One of the most powerful features is the ability to filter results server-side using client-defined functions:
87
+
88
+ ```javascript
89
+ const results = await db.search('cloud computing', {
90
+ filter: metadata => metadata.category === 'tech' && metadata.priority > 5,
91
+ threshold: 0.7, // Strict similarity matching
92
+ })
93
+ ```
94
+
95
+ ### Collection-Style API
96
+
97
+ Use `insert` and `query` for a more traditional database feel:
98
+
99
+ ```javascript
100
+ await db.insert('my-collection', [
101
+ { text: 'Hello World', metadata: { author: 'Alice' } },
102
+ { text: 'Goodbye World', metadata: { author: 'Bob' } },
103
+ ])
104
+
105
+ const bobDocs = await db.query('my-collection', 'farewell', {
106
+ filter: m => m.author === 'Bob',
107
+ })
108
+ ```
109
+
110
+ ---
111
+
112
+ ## ⚙️ Configuration
113
+
114
+ ### Server Options
115
+
116
+ | Option | Description | Default |
117
+ | :---------------- | :------------------------------------- | :--------- |
118
+ | `port` | Server listening port | `3001` |
119
+ | `host` | Server host address | `0.0.0.0` |
120
+ | `apiKey` | Optional key for client authentication | `null` |
121
+ | `cors` | Allowed origins (array) | `[]` (All) |
122
+ | `streamChunkSize` | Max results per chunk for streaming | `500` |
123
+
124
+ ### Client Options
125
+
126
+ | Option | Description | Default |
127
+ | :--------------- | :--------------------------- | :----------- |
128
+ | `serverUrl` | URL of the VectoriaDB server | **Required** |
129
+ | `apiKey` | Authentication key | `null` |
130
+ | `requestTimeout` | API request timeout in ms | `30000` |
131
+
132
+ ---
133
+
134
+ ## Large Datasets & Streaming
135
+
136
+ The SDK automatically handles large result sets by chunking data on the server and assembling it on the client. This prevents memory issues and payload limits when retrieving thousands of vectors.
137
+
138
+ - **Automatic assembly**: You don't need to worry about chunks; the `Promise` resolves only when all data has arrived.
139
+ - **Configurable limits**: Set `streamChunkSize` on the server to tune the chunking behavior.
140
+
141
+ ## Connection Resilience
142
+
143
+ Built for real-world networks, the client includes:
144
+
145
+ - **Offline Queueing**: Requests made while the connection is down are queued and sent automatically upon reconnection.
146
+ - **Heartbeat & Health Checks**: Monitors connection status to ensure reliable delivery.
147
+ - **Configurable Timeouts**: Each request can have its own timeout, or use a global default.
148
+
149
+ ---
150
+
151
+ ## Security Note
152
+
153
+ > [!WARNING] Filter functions passed from the client are serialized and evaluated on the server using `new Function()`. **Never** expose the server to untrusted clients without strict network controls or additional sandboxing.
154
+
155
+ ---
156
+
157
+ ## Docker Integration
158
+
159
+ When deploying with Docker, ensure you persist the database state:
160
+
161
+ ```yaml
162
+ services:
163
+ vectoriadb-server:
164
+ image: node:18
165
+ # ... other config
166
+ volumes:
167
+ - vectoria-data:/app/server/.cache/vectoriadb
168
+
169
+ volumes:
170
+ vectoria-data:
171
+ ```
172
+
173
+ ## Best Practices
174
+
175
+ - **Intended use**: Not recommended for large production systems — best suited for prototypes, demos, and hobby projects where quick setup matters.
176
+ - **Batching**: Use `addMany` instead of repeated `add` calls for efficiency.
177
+ - **Timeouts**: Adjust `requestTimeout` for large-scale operations.
178
+ - **Shutdown**: Always call `db.close()` on the client and `server.close()` on the server for graceful termination.
179
+
180
+ ---
181
+
182
+ ## FAQ
183
+
184
+ **Q: Do I need `vectoriadb` on the client?**
185
+ A: No! The client only needs `socket.io-client`. It's designed to be used in browsers or lightweight Node environments.
186
+
187
+ **Q: How does the server-side filtering work?**
188
+ A: The client SDK stringifies your filter function. The server then reconstructs it using `new Function()`. This is why the filter must be self-contained and not rely on variables outside its scope.
189
+
190
+ ---
191
+
192
+ ## Credits
193
+
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.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ MIT © 2026 VectoriaDB SDK Authors
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
- 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
- })
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
- server.listen().catch(err => {
17
- console.error(err)
18
- process.exit(1)
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.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",
@@ -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
- if (this._started) return
26
- // Initialize VectoriaDB (loads models / storage as configured)
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
- const nsp = this._io.of('/vectoriadb')
29
+ // if a start is already in progress, return the same promise
30
+ if (this._startPromise) return this._startPromise
43
31
 
44
- nsp.use((socket, next) => {
45
- // simple API key auth if configured
46
- if (this.apiKey) {
47
- const provided = socket.handshake.auth?.apiKey || socket.handshake.query?.apiKey
48
- if (!provided || provided !== this.apiKey) {
49
- return next(new Error('Unauthorized'))
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
- socket.on('request', async payload => {
60
- // payload: { id, method, params, collection, timestamp }
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._handleRequest(socket, payload)
63
- } catch (err) {
64
- socket.emit('response', { id: payload?.id ?? null, result: null, error: { message: err.message }, took: 0 })
65
- }
66
- })
67
-
68
- // allow ping from client
69
- socket.on('health', cb => cb && cb({ ok: true, ts: Date.now() }))
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
- this._started = true
77
- console.log(`VectoriaDB Server listening on ${this.host}:${this.port}`)
78
- return this
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) {