montycat 1.1.5 β 1.1.6
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 +125 -24
- package/dist/classes/generic.d.ts +74 -3
- package/dist/classes/generic.js +76 -6
- package/dist/core/engine.d.ts +119 -0
- package/dist/core/engine.js +174 -0
- package/dist/core/inmemory.d.ts +16 -5
- package/dist/core/inmemory.js +16 -10
- package/dist/core/persistent.d.ts +17 -5
- package/dist/core/persistent.js +17 -10
- package/dist/functions/storeGenericFunctions.js +17 -4
- package/package.json +45 -8
package/README.md
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
# π Montycat Node.js
|
|
1
|
+
# π Montycat for Node.js & TypeScript β The AI-Native NoSQL Database with Semantic Search for RAG & Agents
|
|
2
|
+
|
|
3
|
+
### Abolish the two-database stack.
|
|
4
|
+
|
|
5
|
+
The official Node.js & TypeScript SDK for [Montycat](https://montygovernance.com) β a self-hosted **NoSQL + vector database** with AI **semantic search** forged into the core, built for **RAG and AI-agent memory**. One Rust engine, not a sprawl of services. **Your hardware. Your data. Your meaning.**
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/montycat)
|
|
4
8
|
[](https://www.npmjs.com/package/montycat)
|
|
5
|
-
[](https://hub.docker.com/r/montygovernance/montycat)
|
|
6
10
|
[](https://nodejs.org/)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
12
|
+
[](https://github.com/MontyGovernance/montycat_node/blob/master/LICENSE)
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// Search your data by MEANING β no external APIs, no separate vector database.
|
|
16
|
+
// (already ON by default in the montycat-semantic server edition)
|
|
17
|
+
const hits = await Sales.semanticSearchGetValues({ query: 'something to listen to music without wires', limitOutput: { start: 0, stop: 5 } });
|
|
18
|
+
// β [{ key, score, value: { name: 'Wireless Headphones' } }, ...] (matched by meaning, not keywords)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
> ### π§© All-in-one. AI-native. **Zero external dependencies.**
|
|
22
|
+
> The vector-embedding engine runs **inside** the database β **no** separate vector DB, **no** embedding API, **no** API keys, **no** sidecar service. One engine, one binary, your hardware.
|
|
23
|
+
|
|
24
|
+
## What is Montycat?
|
|
25
|
+
|
|
26
|
+
For a generation we were told the price of intelligence was two systems: a database for your records, and a separate vector store β with its per-query bill β for their meaning. Montycat rejects that tax. It is a **self-hosted NoSQL + vector database**: one Rust-powered engine with semantic search built in, so **RAG, AI-agent memory, and vector search** live where your data already lives. No cloud lock-in. No ops headache. Decentralized by nature, ultra-fast, and natively async.
|
|
8
27
|
|
|
9
|
-
|
|
28
|
+
Think of it as an **open-source, self-hosted alternative to Pinecone, Weaviate, Chroma, Qdrant, and Redis** β a **vector database _and_ a NoSQL store in a single engine**, so your records and their embeddings live together instead of in two systems you have to keep in sync.
|
|
29
|
+
|
|
30
|
+
This client gives JavaScript and TypeScript developers structured, decentralized, secure data through a clean async API that feels native to the language β not another bloated driver. Montycat is not an incremental improvement on the databases you know. It is a break with them.
|
|
10
31
|
|
|
11
32
|
## π§ The Montycat Philosophy
|
|
12
33
|
|
|
@@ -27,6 +48,7 @@ Montycat Node.js Client is the official JavaScript and TypeScript SDK for Montyc
|
|
|
27
48
|
- π‘ `Real-Time Subscriptions` - Subscribe to keyspace or key changes with live updates.
|
|
28
49
|
- π `TLS Security` - Encrypted communication and authenticated connections.
|
|
29
50
|
- 𧬠`Schema Support` - Optional schema layer for validation, structure, and type safety.
|
|
51
|
+
- π§ `AI Semantic & Vector Search` - Rank stored items by meaning with on-device embeddings. kNN vector search for **RAG, AI agents & LLM apps** β no external API, no separate vector database.
|
|
30
52
|
- π§± `Zero Dependencies on ORMs` - No extra abstractions. Just pure, beautiful logic.
|
|
31
53
|
- π§ `Easy Integration` - Works with Express, Fastify, Next.js, Deno, and any Node.js runtime.
|
|
32
54
|
|
|
@@ -45,22 +67,37 @@ Montycat Node.js Client is the official JavaScript and TypeScript SDK for Montyc
|
|
|
45
67
|
|
|
46
68
|
## π The Future Is Structured
|
|
47
69
|
|
|
48
|
-
Other databases
|
|
49
|
-
`Montycat` was built
|
|
50
|
-
No adapters
|
|
70
|
+
Other databases were written in C, C++, or Java β for a world that no longer exists.
|
|
71
|
+
`Montycat` was built in Rust and made to speak JavaScript and TypeScript fluently.
|
|
72
|
+
No adapters. No legacy baggage. No permission asked. Just pure async data flow.
|
|
73
|
+
|
|
74
|
+
The old stack β a database here, a vector store there, an embedding API somewhere in the cloud, and a tangle of sync jobs holding it together β is not an architecture. It is a compromise. Montycat refuses the compromise: **one engine, your hardware, your data, your meaning.**
|
|
75
|
+
|
|
76
|
+
> **When you use Montycat, you are not querying a database. You are interacting with a living data mesh that speaks your language.**
|
|
77
|
+
|
|
78
|
+
## π Example Use Cases
|
|
51
79
|
|
|
52
|
-
|
|
80
|
+
- **RAG pipelines & semantic retrieval** for LLM-powered apps
|
|
81
|
+
- **AI agent / chatbot long-term memory** that survives restarts
|
|
82
|
+
- **Semantic product search & recommendations** β match intent, not keywords
|
|
83
|
+
- Real-time dashboards, analytics, and live collaborative apps
|
|
84
|
+
- Microservice data stores and event-driven systems
|
|
85
|
+
- Data products in a decentralized Mesh architecture
|
|
53
86
|
|
|
54
|
-
|
|
55
|
-
| ------------------------------ | ------------------------ |
|
|
56
|
-
| Insert (10k records) | 40k/sec |
|
|
57
|
-
| Lookup (single key) | 80k/sec |
|
|
58
|
-
| Lookup (filtered query) | 30k/sec |
|
|
59
|
-
| Real-Time subscription updates | < 2ms latency per update |
|
|
87
|
+
## π Get the Engine (30 seconds)
|
|
60
88
|
|
|
61
|
-
|
|
89
|
+
The client talks to a Montycat server. Fastest way β Docker, with AI semantic search built in:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
docker run -d --name montycat \
|
|
93
|
+
-p 21210:21210 -p 21211:21211 \
|
|
94
|
+
-e MONTYCAT_SUPEROWNER="admin" \
|
|
95
|
+
-e MONTYCAT_PASSWORD="change-me" \
|
|
96
|
+
-v montycat_data:/app/.montycat \
|
|
97
|
+
montygovernance/montycat:semantic
|
|
98
|
+
```
|
|
62
99
|
|
|
63
|
-
|
|
100
|
+
Prefer the lean edition without the embedding engine? Use the `latest` tag. Prebuilt packages (apt, macOS, Windows) at **https://montygovernance.com**.
|
|
64
101
|
|
|
65
102
|
## Installation
|
|
66
103
|
|
|
@@ -74,6 +111,10 @@ or with Yarn:
|
|
|
74
111
|
yarn add montycat
|
|
75
112
|
```
|
|
76
113
|
|
|
114
|
+
> **ESM-only, Node.js 18+.** This package ships native ES modules β use `import`, not
|
|
115
|
+
> `require()`. Works out of the box with TypeScript, Deno, Bun, and any modern Node.js
|
|
116
|
+
> project (`"type": "module"` or `.mjs`).
|
|
117
|
+
|
|
77
118
|
## Quick Start
|
|
78
119
|
|
|
79
120
|
### TypeScript Example
|
|
@@ -151,7 +192,7 @@ const newSale = new SalesSchema({
|
|
|
151
192
|
|
|
152
193
|
const newOrder = new ProductionSchema({
|
|
153
194
|
workOrder: 'WO 000012',
|
|
154
|
-
|
|
195
|
+
customer: 'ACME Corp',
|
|
155
196
|
}).serialize();
|
|
156
197
|
|
|
157
198
|
const res3 = await Sales.insertValue({ value: newSale });
|
|
@@ -167,12 +208,12 @@ const res5 = await Sales.lookupValuesWhere({
|
|
|
167
208
|
});
|
|
168
209
|
|
|
169
210
|
const res6 = await Production.lookupValuesWhere({
|
|
170
|
-
searchCriteria: {
|
|
211
|
+
searchCriteria: { customer: 'ACME Corp' },
|
|
171
212
|
schema: ProductionSchema,
|
|
172
213
|
keyIncluded: true
|
|
173
214
|
});
|
|
174
215
|
|
|
175
|
-
console.log('Lookup results:',
|
|
216
|
+
console.log('Lookup results:', res5, res6);
|
|
176
217
|
|
|
177
218
|
```
|
|
178
219
|
|
|
@@ -233,7 +274,7 @@ const newSale = new SalesSchema({
|
|
|
233
274
|
|
|
234
275
|
const newOrder = new ProductionSchema({
|
|
235
276
|
workOrder: 'WO 000012',
|
|
236
|
-
|
|
277
|
+
customer: 'ACME Corp',
|
|
237
278
|
}).serialize();
|
|
238
279
|
|
|
239
280
|
const res3 = await Sales.insertValue({ value: newSale });
|
|
@@ -249,11 +290,71 @@ const res5 = await Sales.lookupValuesWhere({
|
|
|
249
290
|
});
|
|
250
291
|
|
|
251
292
|
const res6 = await Production.lookupValuesWhere({
|
|
252
|
-
searchCriteria: {
|
|
253
|
-
schema: ProductionSchema
|
|
293
|
+
searchCriteria: { customer: 'ACME Corp' },
|
|
294
|
+
schema: ProductionSchema,
|
|
254
295
|
keyIncluded: true
|
|
255
296
|
});
|
|
256
297
|
|
|
257
|
-
console.log('Lookup results:',
|
|
298
|
+
console.log('Lookup results:', res5, res6);
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## π§ AI-Native Semantic Search β Vector Search Built Into Your Database
|
|
303
|
+
|
|
304
|
+
**Stop bolting a separate vector database onto your stack.** Montycat ranks your data by
|
|
305
|
+
*meaning*, not keywords β an embedded, on-device vector-embedding engine turns every write
|
|
306
|
+
into a searchable vector automatically. It's the retrieval layer for **RAG pipelines, AI
|
|
307
|
+
agents, semantic search, recommendation engines, and LLM-powered apps** β with **zero
|
|
308
|
+
external APIs, zero API keys, and zero extra infrastructure.**
|
|
309
|
+
|
|
310
|
+
- π **Semantic / vector search** β kNN similarity over on-device embeddings, not brittle keyword matches.
|
|
311
|
+
- π€ **Built for AI** β RAG, semantic retrieval, AI agents, recommendations, dedup, clustering.
|
|
312
|
+
- π **Private & free** β embeddings never leave your machine. No OpenAI/Cohere bill, no data egress.
|
|
313
|
+
- β‘ **One system, not two** β your data *and* its vectors live in the same database. No sync jobs, no drift, no second service to run.
|
|
314
|
+
- π **Zero setup** β no index tuning, no pipeline: `enableSemanticSearch()` and you're ranking by meaning.
|
|
315
|
+
|
|
316
|
+
> **β οΈ Requires the semantic edition of the server β nothing to compile.** Semantic
|
|
317
|
+
> search runs an embedded ONNX vector-embedding engine that ships only in the
|
|
318
|
+
> **`montycat-semantic`** edition; the default lean `montycat` server does not include it.
|
|
319
|
+
> Get it the way that suits you β pull the **Docker image**
|
|
320
|
+
> (`montygovernance/montycat:semantic`), download the prebuilt **package**, or install
|
|
321
|
+
> `montycat-semantic` from the **apt repository**. The Node.js client API is identical
|
|
322
|
+
> either way; just point it at a semantic-edition server (semantic search is enabled by
|
|
323
|
+
> default there, using the `bge-small` model).
|
|
324
|
+
|
|
325
|
+
The switch is DB-wide and already on in the semantic edition; every keyspace is embedded
|
|
326
|
+
in the background as data is written (the embedding model is downloaded on demand).
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Semantic search is ON by default in the montycat-semantic edition β just search.
|
|
330
|
+
// Rank stored items by meaning β two flavors:
|
|
331
|
+
// getValues β each hit is { key, score, value }
|
|
332
|
+
// getKeys β each hit is { key, score } (lighter; fetch a page later with getBulk)
|
|
333
|
+
const hits = await Sales.semanticSearchGetValues({ query: 'something to listen to music without wires', limitOutput: { start: 0, stop: 5 } });
|
|
334
|
+
const keys = await Sales.semanticSearchGetKeys({ query: 'something to listen to music without wires', limitOutput: { start: 0, stop: 5 } });
|
|
335
|
+
|
|
336
|
+
// Optionally drop weak matches by cosine similarity (range [-1, 1]).
|
|
337
|
+
const strong = await Sales.semanticSearchGetKeys({ query: 'something to listen to music without wires', limitOutput: { start: 0, stop: 5 }, minScore: 0.35 });
|
|
338
|
+
|
|
339
|
+
// Control the DB-wide switch (optional β it's already on):
|
|
340
|
+
// switch the embedding model: 'minilm' | 'bge-small' (default) | 'bge-base' | 'e5-small'
|
|
341
|
+
await engine.enableSemanticSearch({ model: 'bge-base' });
|
|
342
|
+
|
|
343
|
+
// turn it off (vectors are kept so re-enabling resumes instantly;
|
|
344
|
+
// pass { dropVectors: true } to also clear stored vectors)
|
|
345
|
+
await engine.disableSemanticSearch();
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## π Links
|
|
349
|
+
|
|
350
|
+
- π **Website & Docs** β https://montygovernance.com
|
|
351
|
+
- π¦ **npm** β https://www.npmjs.com/package/montycat
|
|
352
|
+
- π³ **Docker Hub** β https://hub.docker.com/r/montygovernance/montycat
|
|
353
|
+
- π» **Source** β https://github.com/MontyGovernance/montycat_node
|
|
354
|
+
|
|
355
|
+
## β FAQ
|
|
258
356
|
|
|
259
|
-
|
|
357
|
+
- **Is Montycat a vector database or a NoSQL database?** Both β one engine. Store records and query them by *meaning* (vector / semantic search) or by key/schema, without running two systems.
|
|
358
|
+
- **Do I need OpenAI or an embedding API?** No. Embeddings run on-device in the `montycat-semantic` server. No API keys, no per-query bill, no data egress.
|
|
359
|
+
- **Is it a Pinecone / Weaviate / Chroma / Qdrant alternative?** Yes β self-hosted and open-source, with a NoSQL store built in.
|
|
360
|
+
- **TypeScript support?** First-class β the package ships its own type definitions. Works with Node.js, Deno, Bun, Express, Fastify, and Next.js.
|
|
@@ -52,9 +52,10 @@ declare class GenericKV {
|
|
|
52
52
|
* @param customKey - The custom key to delete.
|
|
53
53
|
* @return A promise that resolves with the result of the deletion.
|
|
54
54
|
* */
|
|
55
|
-
static deleteKey({ key, customKey }?: {
|
|
55
|
+
static deleteKey({ key, customKey, waitForIndex }?: {
|
|
56
56
|
key?: string;
|
|
57
57
|
customKey?: string | null;
|
|
58
|
+
waitForIndex?: boolean | null;
|
|
58
59
|
}): Promise<any>;
|
|
59
60
|
/**
|
|
60
61
|
* Deletes a bulk of keys from the keyspace.
|
|
@@ -62,9 +63,10 @@ declare class GenericKV {
|
|
|
62
63
|
* @param bulkCustomKeys - An array of custom keys to delete.
|
|
63
64
|
* @return A promise that resolves with the result of the deletion.
|
|
64
65
|
* */
|
|
65
|
-
static deleteBulk({ bulkKeys, bulkCustomKeys }?: {
|
|
66
|
+
static deleteBulk({ bulkKeys, bulkCustomKeys, waitForIndex }?: {
|
|
66
67
|
bulkKeys?: string[];
|
|
67
68
|
bulkCustomKeys?: string[];
|
|
69
|
+
waitForIndex?: boolean | null;
|
|
68
70
|
}): Promise<any>;
|
|
69
71
|
/**
|
|
70
72
|
* Gets bulk values from the keyspace.
|
|
@@ -97,13 +99,14 @@ declare class GenericKV {
|
|
|
97
99
|
* @param bulkCustomKeysValues - An object where custom keys are the keys to update and values are the new values.
|
|
98
100
|
* @return A promise that resolves with the result of the update.
|
|
99
101
|
*/
|
|
100
|
-
static updateBulk({ bulkKeysValues, bulkCustomKeysValues }?: {
|
|
102
|
+
static updateBulk({ bulkKeysValues, bulkCustomKeysValues, waitForIndex }?: {
|
|
101
103
|
bulkKeysValues?: {
|
|
102
104
|
[key: string]: any;
|
|
103
105
|
};
|
|
104
106
|
bulkCustomKeysValues?: {
|
|
105
107
|
[key: string]: any;
|
|
106
108
|
};
|
|
109
|
+
waitForIndex?: boolean | null;
|
|
107
110
|
}): Promise<any>;
|
|
108
111
|
/**
|
|
109
112
|
* Looks up keys based on search criteria.
|
|
@@ -145,6 +148,74 @@ declare class GenericKV {
|
|
|
145
148
|
keyIncluded?: boolean;
|
|
146
149
|
pointersMetadata?: boolean;
|
|
147
150
|
}): Promise<any>;
|
|
151
|
+
/**
|
|
152
|
+
* Shared core for `semanticSearchGetKeys` / `semanticSearchGetValues`.
|
|
153
|
+
* The server command is the same either way (`semantic_search`); the two
|
|
154
|
+
* public methods differ only in which value-inclusion flags they pass,
|
|
155
|
+
* so the wire call lives here once.
|
|
156
|
+
*/
|
|
157
|
+
private static semanticSearchCore;
|
|
158
|
+
/**
|
|
159
|
+
* Semantic (vector similarity) search returning ranked keys only.
|
|
160
|
+
*
|
|
161
|
+
* Ranks stored items by how close their embeddings are to the embedding of
|
|
162
|
+
* `query` and returns just the matched key and score for each hit β the
|
|
163
|
+
* lightweight variant when you only need identity + ranking (e.g. to then
|
|
164
|
+
* `getBulk` a page, or to test membership). Use `semanticSearchGetValues`
|
|
165
|
+
* when you want the values inline.
|
|
166
|
+
*
|
|
167
|
+
* Semantic search must be enabled first (see `Engine.enableSemanticSearch`).
|
|
168
|
+
* The keyspace is embedded in the background as items are written, so
|
|
169
|
+
* results reflect whatever has been embedded so far.
|
|
170
|
+
*
|
|
171
|
+
* @param query - The natural-language query text to embed and search for.
|
|
172
|
+
* @param limitOutput - Start/stop over the ranked hits; `{start: 0, stop: 0}`
|
|
173
|
+
* (the default) lets the server apply its default top-k (10).
|
|
174
|
+
* @param minScore - Drop hits whose cosine similarity (in [-1, 1]) is below
|
|
175
|
+
* this value. Default null (no score filter).
|
|
176
|
+
* @return A promise resolving with ranked hits, each `{key, score}`.
|
|
177
|
+
*/
|
|
178
|
+
static semanticSearchGetKeys({ query, limitOutput, minScore }: {
|
|
179
|
+
query: string;
|
|
180
|
+
limitOutput?: {
|
|
181
|
+
start: number;
|
|
182
|
+
stop: number;
|
|
183
|
+
};
|
|
184
|
+
minScore?: number | null;
|
|
185
|
+
}): Promise<any>;
|
|
186
|
+
/**
|
|
187
|
+
* Semantic (vector similarity) search returning ranked hits with their values.
|
|
188
|
+
*
|
|
189
|
+
* Ranks stored items by how close their embeddings are to the embedding of
|
|
190
|
+
* `query` and returns the value inline with each hit β the key is always
|
|
191
|
+
* included so every value is tagged with its key. Use
|
|
192
|
+
* `semanticSearchGetKeys` when you only need keys + scores.
|
|
193
|
+
*
|
|
194
|
+
* Semantic search must be enabled first (see `Engine.enableSemanticSearch`).
|
|
195
|
+
* The keyspace is embedded in the background as items are written, so
|
|
196
|
+
* results reflect whatever has been embedded so far.
|
|
197
|
+
*
|
|
198
|
+
* @param query - The natural-language query text to embed and search for.
|
|
199
|
+
* @param limitOutput - Start/stop over the ranked hits; `{start: 0, stop: 0}`
|
|
200
|
+
* (the default) lets the server apply its default top-k (10).
|
|
201
|
+
* @param minScore - Drop hits whose cosine similarity (in [-1, 1]) is below
|
|
202
|
+
* this value. Default null (no score filter).
|
|
203
|
+
* @param withPointers - Whether to include pointers (foreign values) in each
|
|
204
|
+
* returned value.
|
|
205
|
+
* @param pointersMetadata - Whether to include pointer metadata in each
|
|
206
|
+
* returned value.
|
|
207
|
+
* @return A promise resolving with ranked hits, each `{key, score, value}`.
|
|
208
|
+
*/
|
|
209
|
+
static semanticSearchGetValues({ query, limitOutput, minScore, withPointers, pointersMetadata }: {
|
|
210
|
+
query: string;
|
|
211
|
+
limitOutput?: {
|
|
212
|
+
start: number;
|
|
213
|
+
stop: number;
|
|
214
|
+
};
|
|
215
|
+
minScore?: number | null;
|
|
216
|
+
withPointers?: boolean;
|
|
217
|
+
pointersMetadata?: boolean;
|
|
218
|
+
}): Promise<any>;
|
|
148
219
|
/**
|
|
149
220
|
* Gets the length of the keyspace.
|
|
150
221
|
* @returns A promise that resolves with the length of the keyspace.
|
package/dist/classes/generic.js
CHANGED
|
@@ -86,7 +86,7 @@ class GenericKV {
|
|
|
86
86
|
* @param customKey - The custom key to delete.
|
|
87
87
|
* @return A promise that resolves with the result of the deletion.
|
|
88
88
|
* */
|
|
89
|
-
static async deleteKey({ key = "", customKey = null } = {}) {
|
|
89
|
+
static async deleteKey({ key = "", customKey = null, waitForIndex = null } = {}) {
|
|
90
90
|
try {
|
|
91
91
|
if (key && customKey) {
|
|
92
92
|
throw new Error("Provide either 'key' or 'customKey', not both.");
|
|
@@ -97,7 +97,7 @@ class GenericKV {
|
|
|
97
97
|
throw new Error("No key provided");
|
|
98
98
|
}
|
|
99
99
|
this.command = "delete_key";
|
|
100
|
-
const query = convertToBinaryQuery(this, { key });
|
|
100
|
+
const query = convertToBinaryQuery(this, { key, waitForIndex });
|
|
101
101
|
return runQuery(this, query);
|
|
102
102
|
}
|
|
103
103
|
catch (err) {
|
|
@@ -110,7 +110,7 @@ class GenericKV {
|
|
|
110
110
|
* @param bulkCustomKeys - An array of custom keys to delete.
|
|
111
111
|
* @return A promise that resolves with the result of the deletion.
|
|
112
112
|
* */
|
|
113
|
-
static async deleteBulk({ bulkKeys = [], bulkCustomKeys = [] } = {}) {
|
|
113
|
+
static async deleteBulk({ bulkKeys = [], bulkCustomKeys = [], waitForIndex = null } = {}) {
|
|
114
114
|
try {
|
|
115
115
|
if (bulkCustomKeys.length)
|
|
116
116
|
bulkKeys = bulkKeys.concat(convertCustomKeys(bulkCustomKeys));
|
|
@@ -118,7 +118,7 @@ class GenericKV {
|
|
|
118
118
|
throw new Error("No keys provided");
|
|
119
119
|
}
|
|
120
120
|
this.command = "delete_bulk";
|
|
121
|
-
const query = convertToBinaryQuery(this, { bulkKeys });
|
|
121
|
+
const query = convertToBinaryQuery(this, { bulkKeys, waitForIndex });
|
|
122
122
|
return runQuery(this, query);
|
|
123
123
|
}
|
|
124
124
|
catch (err) {
|
|
@@ -162,7 +162,7 @@ class GenericKV {
|
|
|
162
162
|
* @param bulkCustomKeysValues - An object where custom keys are the keys to update and values are the new values.
|
|
163
163
|
* @return A promise that resolves with the result of the update.
|
|
164
164
|
*/
|
|
165
|
-
static async updateBulk({ bulkKeysValues = {}, bulkCustomKeysValues = {} } = {}) {
|
|
165
|
+
static async updateBulk({ bulkKeysValues = {}, bulkCustomKeysValues = {}, waitForIndex = null } = {}) {
|
|
166
166
|
try {
|
|
167
167
|
if (Object.keys(bulkCustomKeysValues).length) {
|
|
168
168
|
bulkKeysValues = { ...bulkKeysValues, ...convertCustomKeysValues(bulkCustomKeysValues) };
|
|
@@ -171,7 +171,7 @@ class GenericKV {
|
|
|
171
171
|
throw new Error("No keys provided");
|
|
172
172
|
}
|
|
173
173
|
this.command = "update_bulk";
|
|
174
|
-
const query = convertToBinaryQuery(this, { bulkKeysValues });
|
|
174
|
+
const query = convertToBinaryQuery(this, { bulkKeysValues, waitForIndex });
|
|
175
175
|
return runQuery(this, query);
|
|
176
176
|
}
|
|
177
177
|
catch (err) {
|
|
@@ -215,6 +215,76 @@ class GenericKV {
|
|
|
215
215
|
throw err;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Shared core for `semanticSearchGetKeys` / `semanticSearchGetValues`.
|
|
220
|
+
* The server command is the same either way (`semantic_search`); the two
|
|
221
|
+
* public methods differ only in which value-inclusion flags they pass,
|
|
222
|
+
* so the wire call lives here once.
|
|
223
|
+
*/
|
|
224
|
+
static async semanticSearchCore(query, limitOutput, minScore, withPointers, keyIncluded, pointersMetadata) {
|
|
225
|
+
if (!query || !query.trim()) {
|
|
226
|
+
throw new Error("No query text provided for semantic search.");
|
|
227
|
+
}
|
|
228
|
+
this.command = "semantic_search";
|
|
229
|
+
const binaryQuery = convertToBinaryQuery(this, {
|
|
230
|
+
semanticQuery: query,
|
|
231
|
+
limitOutput,
|
|
232
|
+
minScore,
|
|
233
|
+
withPointers,
|
|
234
|
+
keyIncluded,
|
|
235
|
+
pointersMetadata,
|
|
236
|
+
});
|
|
237
|
+
return runQuery(this, binaryQuery);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Semantic (vector similarity) search returning ranked keys only.
|
|
241
|
+
*
|
|
242
|
+
* Ranks stored items by how close their embeddings are to the embedding of
|
|
243
|
+
* `query` and returns just the matched key and score for each hit β the
|
|
244
|
+
* lightweight variant when you only need identity + ranking (e.g. to then
|
|
245
|
+
* `getBulk` a page, or to test membership). Use `semanticSearchGetValues`
|
|
246
|
+
* when you want the values inline.
|
|
247
|
+
*
|
|
248
|
+
* Semantic search must be enabled first (see `Engine.enableSemanticSearch`).
|
|
249
|
+
* The keyspace is embedded in the background as items are written, so
|
|
250
|
+
* results reflect whatever has been embedded so far.
|
|
251
|
+
*
|
|
252
|
+
* @param query - The natural-language query text to embed and search for.
|
|
253
|
+
* @param limitOutput - Start/stop over the ranked hits; `{start: 0, stop: 0}`
|
|
254
|
+
* (the default) lets the server apply its default top-k (10).
|
|
255
|
+
* @param minScore - Drop hits whose cosine similarity (in [-1, 1]) is below
|
|
256
|
+
* this value. Default null (no score filter).
|
|
257
|
+
* @return A promise resolving with ranked hits, each `{key, score}`.
|
|
258
|
+
*/
|
|
259
|
+
static async semanticSearchGetKeys({ query, limitOutput = { start: 0, stop: 0 }, minScore = null }) {
|
|
260
|
+
return this.semanticSearchCore(query, limitOutput, minScore, false, false, false);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Semantic (vector similarity) search returning ranked hits with their values.
|
|
264
|
+
*
|
|
265
|
+
* Ranks stored items by how close their embeddings are to the embedding of
|
|
266
|
+
* `query` and returns the value inline with each hit β the key is always
|
|
267
|
+
* included so every value is tagged with its key. Use
|
|
268
|
+
* `semanticSearchGetKeys` when you only need keys + scores.
|
|
269
|
+
*
|
|
270
|
+
* Semantic search must be enabled first (see `Engine.enableSemanticSearch`).
|
|
271
|
+
* The keyspace is embedded in the background as items are written, so
|
|
272
|
+
* results reflect whatever has been embedded so far.
|
|
273
|
+
*
|
|
274
|
+
* @param query - The natural-language query text to embed and search for.
|
|
275
|
+
* @param limitOutput - Start/stop over the ranked hits; `{start: 0, stop: 0}`
|
|
276
|
+
* (the default) lets the server apply its default top-k (10).
|
|
277
|
+
* @param minScore - Drop hits whose cosine similarity (in [-1, 1]) is below
|
|
278
|
+
* this value. Default null (no score filter).
|
|
279
|
+
* @param withPointers - Whether to include pointers (foreign values) in each
|
|
280
|
+
* returned value.
|
|
281
|
+
* @param pointersMetadata - Whether to include pointer metadata in each
|
|
282
|
+
* returned value.
|
|
283
|
+
* @return A promise resolving with ranked hits, each `{key, score, value}`.
|
|
284
|
+
*/
|
|
285
|
+
static async semanticSearchGetValues({ query, limitOutput = { start: 0, stop: 0 }, minScore = null, withPointers = false, pointersMetadata = false }) {
|
|
286
|
+
return this.semanticSearchCore(query, limitOutput, minScore, withPointers, true, pointersMetadata);
|
|
287
|
+
}
|
|
218
288
|
/**
|
|
219
289
|
* Gets the length of the keyspace.
|
|
220
290
|
* @returns A promise that resolves with the length of the keyspace.
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -109,11 +109,130 @@ declare class Engine {
|
|
|
109
109
|
keyspace: string;
|
|
110
110
|
};
|
|
111
111
|
}): Promise<unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* Enable semantic (vector similarity) search.
|
|
114
|
+
*
|
|
115
|
+
* Without `store`, this is DB-wide: it flips the whole database on, sets the
|
|
116
|
+
* default embedding model and field, and enrolls every existing keyspace that
|
|
117
|
+
* has no semantic config yet (each gets a background backfill so its existing
|
|
118
|
+
* items become searchable). The chosen model is downloaded on demand on first
|
|
119
|
+
* enable, so this call may take a while the first time.
|
|
120
|
+
*
|
|
121
|
+
* With `store`, it is scoped: only that store's un-enrolled keyspaces are
|
|
122
|
+
* enrolled and backfilled; the DB-wide switch and default model/field are left
|
|
123
|
+
* untouched. Use this to (re-)enable one store without re-embedding the entire
|
|
124
|
+
* database.
|
|
125
|
+
*
|
|
126
|
+
* @param {Object} options - Options for enabling semantic search.
|
|
127
|
+
* @param {string} [options.model] - The embedding model key to use by default.
|
|
128
|
+
* One of 'minilm', 'bge-small', 'bge-base',
|
|
129
|
+
* 'e5-small'. Defaults to the server default
|
|
130
|
+
* ('bge-small').
|
|
131
|
+
* @param {string} [options.field] - The JSON field of each value to embed.
|
|
132
|
+
* Defaults to embedding the whole value.
|
|
133
|
+
* @param {string} [options.store] - Restrict enrollment/backfill to this store
|
|
134
|
+
* only. If the DB-wide switch is off, a scoped
|
|
135
|
+
* enable enrolls but nothing embeds until a
|
|
136
|
+
* DB-wide enable.
|
|
137
|
+
* @returns {Promise<unknown>} The server's response describing the enabled
|
|
138
|
+
* model and enrolled keyspaces.
|
|
139
|
+
*/
|
|
140
|
+
enableSemanticSearch({ model, field, store }?: {
|
|
141
|
+
model?: string;
|
|
142
|
+
field?: string;
|
|
143
|
+
store?: string;
|
|
144
|
+
}): Promise<unknown>;
|
|
145
|
+
/**
|
|
146
|
+
* Disable semantic search.
|
|
147
|
+
*
|
|
148
|
+
* Without `store`, this is DB-wide: embedding and semantic queries stop across
|
|
149
|
+
* the whole database; stored vectors are kept by default so re-enabling
|
|
150
|
+
* resumes without a full re-embed.
|
|
151
|
+
*
|
|
152
|
+
* With `store`, it is scoped: only that store's keyspaces are unenrolled
|
|
153
|
+
* (their configs and resident graphs dropped); the DB-wide switch and all
|
|
154
|
+
* other stores are left untouched. This is the surgical way to reset one
|
|
155
|
+
* store's semantic state instead of nuking and re-backfilling the whole
|
|
156
|
+
* database.
|
|
157
|
+
*
|
|
158
|
+
* @param {Object} options - Options for disabling semantic search.
|
|
159
|
+
* @param {boolean} [options.dropVectors=false] - If true, also clear stored
|
|
160
|
+
* vectors β every keyspace's
|
|
161
|
+
* DB-wide, or the scoped store's
|
|
162
|
+
* when `store` is set. Required
|
|
163
|
+
* before switching to a different
|
|
164
|
+
* embedding model.
|
|
165
|
+
* @param {string} [options.store] - Restrict the disable to this store only.
|
|
166
|
+
* @returns {Promise<unknown>} The server's response confirming the disable.
|
|
167
|
+
*/
|
|
168
|
+
disableSemanticSearch({ dropVectors, store }?: {
|
|
169
|
+
dropVectors?: boolean;
|
|
170
|
+
store?: string;
|
|
171
|
+
}): Promise<unknown>;
|
|
112
172
|
/**
|
|
113
173
|
* Retrieves the structure of the store.
|
|
114
174
|
* @returns {Promise<unknown>} A promise that resolves with the structure of the store
|
|
115
175
|
* */
|
|
116
176
|
getStructureAvailable(): Promise<unknown>;
|
|
177
|
+
/**
|
|
178
|
+
* Enable the DB-wide "wait for index" default: writes block until their
|
|
179
|
+
* secondary indexes are updated before returning, so a write is immediately
|
|
180
|
+
* visible to index-backed reads (e.g. lookupValuesWhere) at the cost of
|
|
181
|
+
* higher write latency. Requires superowner credentials.
|
|
182
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
183
|
+
*/
|
|
184
|
+
enableWaitForIndex(): Promise<unknown>;
|
|
185
|
+
/**
|
|
186
|
+
* Disable the DB-wide "wait for index" default: writes return as soon as the
|
|
187
|
+
* data is committed and indexing happens asynchronously in the background
|
|
188
|
+
* (lower write latency; index-backed reads may briefly lag). This is the
|
|
189
|
+
* default behavior. Requires superowner credentials.
|
|
190
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
191
|
+
*/
|
|
192
|
+
disableWaitForIndex(): Promise<unknown>;
|
|
193
|
+
/** Internal helper for no-argument superowner raw commands. */
|
|
194
|
+
private _adminCommand;
|
|
195
|
+
/**
|
|
196
|
+
* Enable server-side operation reporting (logging). Requires superowner credentials.
|
|
197
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
198
|
+
*/
|
|
199
|
+
enableReports(): Promise<unknown>;
|
|
200
|
+
/**
|
|
201
|
+
* Disable server-side operation reporting (logging). Requires superowner credentials.
|
|
202
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
203
|
+
*/
|
|
204
|
+
disableReports(): Promise<unknown>;
|
|
205
|
+
/**
|
|
206
|
+
* Allow clients to open keyspace subscriptions DB-wide. Requires superowner credentials.
|
|
207
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
208
|
+
*/
|
|
209
|
+
allowSubscriptions(): Promise<unknown>;
|
|
210
|
+
/**
|
|
211
|
+
* Restrict (disallow) keyspace subscriptions DB-wide. Requires superowner credentials.
|
|
212
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
213
|
+
*/
|
|
214
|
+
restrictSubscriptions(): Promise<unknown>;
|
|
215
|
+
/**
|
|
216
|
+
* Sample the current depth of every background task queue (index, timer,
|
|
217
|
+
* counting) β an observability probe for whether the background runners are
|
|
218
|
+
* keeping up with the write rate. Requires superowner credentials.
|
|
219
|
+
* @returns {Promise<unknown>} The server's response whose payload maps
|
|
220
|
+
* "index" | "timer" | "counting" to per-queue depth maps.
|
|
221
|
+
*/
|
|
222
|
+
queueDepths(): Promise<unknown>;
|
|
223
|
+
/**
|
|
224
|
+
* Set the server-wide snapshot rate. Requires superowner credentials.
|
|
225
|
+
* @param {number} rate - The snapshot rate value (server-defined units).
|
|
226
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
227
|
+
*/
|
|
228
|
+
setSnapshotRate(rate: number): Promise<unknown>;
|
|
229
|
+
/**
|
|
230
|
+
* Set how often the server scans for expired keys. Requires superowner credentials.
|
|
231
|
+
* @param {number} rate - The check period in whole seconds (e.g. rate=10 β a scan
|
|
232
|
+
* every 10 seconds). Stored as-is, like the snapshot rate. Defaults to 1 second.
|
|
233
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
234
|
+
*/
|
|
235
|
+
setExpirationCheckRate(rate: number): Promise<unknown>;
|
|
117
236
|
}
|
|
118
237
|
/**
|
|
119
238
|
* Sends a string to the specified host and port, and returns the parsed response.
|
package/dist/core/engine.js
CHANGED
|
@@ -206,6 +206,81 @@ class Engine {
|
|
|
206
206
|
}
|
|
207
207
|
return sendData(this.host, this.port, JSONbig.stringify(query), undefined, this.useTls);
|
|
208
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Enable semantic (vector similarity) search.
|
|
211
|
+
*
|
|
212
|
+
* Without `store`, this is DB-wide: it flips the whole database on, sets the
|
|
213
|
+
* default embedding model and field, and enrolls every existing keyspace that
|
|
214
|
+
* has no semantic config yet (each gets a background backfill so its existing
|
|
215
|
+
* items become searchable). The chosen model is downloaded on demand on first
|
|
216
|
+
* enable, so this call may take a while the first time.
|
|
217
|
+
*
|
|
218
|
+
* With `store`, it is scoped: only that store's un-enrolled keyspaces are
|
|
219
|
+
* enrolled and backfilled; the DB-wide switch and default model/field are left
|
|
220
|
+
* untouched. Use this to (re-)enable one store without re-embedding the entire
|
|
221
|
+
* database.
|
|
222
|
+
*
|
|
223
|
+
* @param {Object} options - Options for enabling semantic search.
|
|
224
|
+
* @param {string} [options.model] - The embedding model key to use by default.
|
|
225
|
+
* One of 'minilm', 'bge-small', 'bge-base',
|
|
226
|
+
* 'e5-small'. Defaults to the server default
|
|
227
|
+
* ('bge-small').
|
|
228
|
+
* @param {string} [options.field] - The JSON field of each value to embed.
|
|
229
|
+
* Defaults to embedding the whole value.
|
|
230
|
+
* @param {string} [options.store] - Restrict enrollment/backfill to this store
|
|
231
|
+
* only. If the DB-wide switch is off, a scoped
|
|
232
|
+
* enable enrolls but nothing embeds until a
|
|
233
|
+
* DB-wide enable.
|
|
234
|
+
* @returns {Promise<unknown>} The server's response describing the enabled
|
|
235
|
+
* model and enrolled keyspaces.
|
|
236
|
+
*/
|
|
237
|
+
async enableSemanticSearch({ model, field, store } = {}) {
|
|
238
|
+
const rawQuery = {
|
|
239
|
+
raw: ['enable-semantic-search'],
|
|
240
|
+
credentials: [this.username, this.password],
|
|
241
|
+
};
|
|
242
|
+
if (model)
|
|
243
|
+
rawQuery.raw.push('model', model);
|
|
244
|
+
if (field)
|
|
245
|
+
rawQuery.raw.push('field', field);
|
|
246
|
+
if (store)
|
|
247
|
+
rawQuery.raw.push('store', store);
|
|
248
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Disable semantic search.
|
|
252
|
+
*
|
|
253
|
+
* Without `store`, this is DB-wide: embedding and semantic queries stop across
|
|
254
|
+
* the whole database; stored vectors are kept by default so re-enabling
|
|
255
|
+
* resumes without a full re-embed.
|
|
256
|
+
*
|
|
257
|
+
* With `store`, it is scoped: only that store's keyspaces are unenrolled
|
|
258
|
+
* (their configs and resident graphs dropped); the DB-wide switch and all
|
|
259
|
+
* other stores are left untouched. This is the surgical way to reset one
|
|
260
|
+
* store's semantic state instead of nuking and re-backfilling the whole
|
|
261
|
+
* database.
|
|
262
|
+
*
|
|
263
|
+
* @param {Object} options - Options for disabling semantic search.
|
|
264
|
+
* @param {boolean} [options.dropVectors=false] - If true, also clear stored
|
|
265
|
+
* vectors β every keyspace's
|
|
266
|
+
* DB-wide, or the scoped store's
|
|
267
|
+
* when `store` is set. Required
|
|
268
|
+
* before switching to a different
|
|
269
|
+
* embedding model.
|
|
270
|
+
* @param {string} [options.store] - Restrict the disable to this store only.
|
|
271
|
+
* @returns {Promise<unknown>} The server's response confirming the disable.
|
|
272
|
+
*/
|
|
273
|
+
async disableSemanticSearch({ dropVectors = false, store } = {}) {
|
|
274
|
+
const rawQuery = {
|
|
275
|
+
raw: ['disable-semantic-search'],
|
|
276
|
+
credentials: [this.username, this.password],
|
|
277
|
+
};
|
|
278
|
+
if (dropVectors)
|
|
279
|
+
rawQuery.raw.push('drop-vectors');
|
|
280
|
+
if (store)
|
|
281
|
+
rawQuery.raw.push('store', store);
|
|
282
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
283
|
+
}
|
|
209
284
|
/**
|
|
210
285
|
* Retrieves the structure of the store.
|
|
211
286
|
* @returns {Promise<unknown>} A promise that resolves with the structure of the store
|
|
@@ -218,6 +293,105 @@ class Engine {
|
|
|
218
293
|
};
|
|
219
294
|
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
220
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Enable the DB-wide "wait for index" default: writes block until their
|
|
298
|
+
* secondary indexes are updated before returning, so a write is immediately
|
|
299
|
+
* visible to index-backed reads (e.g. lookupValuesWhere) at the cost of
|
|
300
|
+
* higher write latency. Requires superowner credentials.
|
|
301
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
302
|
+
*/
|
|
303
|
+
async enableWaitForIndex() {
|
|
304
|
+
const rawQuery = {
|
|
305
|
+
raw: ['enable-wait-for-index'],
|
|
306
|
+
credentials: [this.username, this.password],
|
|
307
|
+
};
|
|
308
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Disable the DB-wide "wait for index" default: writes return as soon as the
|
|
312
|
+
* data is committed and indexing happens asynchronously in the background
|
|
313
|
+
* (lower write latency; index-backed reads may briefly lag). This is the
|
|
314
|
+
* default behavior. Requires superowner credentials.
|
|
315
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
316
|
+
*/
|
|
317
|
+
async disableWaitForIndex() {
|
|
318
|
+
const rawQuery = {
|
|
319
|
+
raw: ['disable-wait-for-index'],
|
|
320
|
+
credentials: [this.username, this.password],
|
|
321
|
+
};
|
|
322
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
323
|
+
}
|
|
324
|
+
/** Internal helper for no-argument superowner raw commands. */
|
|
325
|
+
async _adminCommand(command) {
|
|
326
|
+
const rawQuery = {
|
|
327
|
+
raw: [command],
|
|
328
|
+
credentials: [this.username, this.password],
|
|
329
|
+
};
|
|
330
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Enable server-side operation reporting (logging). Requires superowner credentials.
|
|
334
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
335
|
+
*/
|
|
336
|
+
async enableReports() {
|
|
337
|
+
return this._adminCommand('enable-reports');
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Disable server-side operation reporting (logging). Requires superowner credentials.
|
|
341
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
342
|
+
*/
|
|
343
|
+
async disableReports() {
|
|
344
|
+
return this._adminCommand('disable-reports');
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Allow clients to open keyspace subscriptions DB-wide. Requires superowner credentials.
|
|
348
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
349
|
+
*/
|
|
350
|
+
async allowSubscriptions() {
|
|
351
|
+
return this._adminCommand('allow-subscriptions');
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Restrict (disallow) keyspace subscriptions DB-wide. Requires superowner credentials.
|
|
355
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
356
|
+
*/
|
|
357
|
+
async restrictSubscriptions() {
|
|
358
|
+
return this._adminCommand('restrict-subscriptions');
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Sample the current depth of every background task queue (index, timer,
|
|
362
|
+
* counting) β an observability probe for whether the background runners are
|
|
363
|
+
* keeping up with the write rate. Requires superowner credentials.
|
|
364
|
+
* @returns {Promise<unknown>} The server's response whose payload maps
|
|
365
|
+
* "index" | "timer" | "counting" to per-queue depth maps.
|
|
366
|
+
*/
|
|
367
|
+
async queueDepths() {
|
|
368
|
+
return this._adminCommand('queue-depths');
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Set the server-wide snapshot rate. Requires superowner credentials.
|
|
372
|
+
* @param {number} rate - The snapshot rate value (server-defined units).
|
|
373
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
374
|
+
*/
|
|
375
|
+
async setSnapshotRate(rate) {
|
|
376
|
+
const rawQuery = {
|
|
377
|
+
raw: ['snapshot-rate', String(rate)],
|
|
378
|
+
credentials: [this.username, this.password],
|
|
379
|
+
};
|
|
380
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Set how often the server scans for expired keys. Requires superowner credentials.
|
|
384
|
+
* @param {number} rate - The check period in whole seconds (e.g. rate=10 β a scan
|
|
385
|
+
* every 10 seconds). Stored as-is, like the snapshot rate. Defaults to 1 second.
|
|
386
|
+
* @returns {Promise<unknown>} The server's response confirming the change.
|
|
387
|
+
*/
|
|
388
|
+
async setExpirationCheckRate(rate) {
|
|
389
|
+
const rawQuery = {
|
|
390
|
+
raw: ['expiration-check', String(rate)],
|
|
391
|
+
credentials: [this.username, this.password],
|
|
392
|
+
};
|
|
393
|
+
return sendData(this.host, this.port, JSONbig.stringify(rawQuery), undefined, this.useTls);
|
|
394
|
+
}
|
|
221
395
|
}
|
|
222
396
|
/**
|
|
223
397
|
* Sends data to a server. Supports one-time request/response or subscription.
|
package/dist/core/inmemory.d.ts
CHANGED
|
@@ -32,31 +32,38 @@ declare class InMemory extends GenericKV {
|
|
|
32
32
|
* @param expireSec - The expiration time in seconds for the value.
|
|
33
33
|
* @return A promise that resolves with the result of the insertion.
|
|
34
34
|
* */
|
|
35
|
-
static insertValue({ value, expireSec }?: {
|
|
35
|
+
static insertValue({ value, expireSec, waitForIndex }?: {
|
|
36
36
|
value?: any;
|
|
37
37
|
expireSec?: number;
|
|
38
|
+
waitForIndex?: boolean | null;
|
|
38
39
|
}): Promise<any>;
|
|
39
40
|
/**
|
|
40
41
|
* Inserts a custom key into the in-memory store.
|
|
41
42
|
* @param customKey - The custom key for the value.
|
|
42
43
|
* @param expireSec - The expiration time in seconds for the value.
|
|
44
|
+
* @param waitForIndex - Per-request synchronous-index override. No-op for in-memory
|
|
45
|
+
* keyspaces (snapshot-driven indexing); present for API symmetry with the persistent
|
|
46
|
+
* variant, where it takes effect.
|
|
43
47
|
* @return A promise that resolves with the result of the insertion.
|
|
44
48
|
*/
|
|
45
|
-
static insertCustomKey({ customKey, expireSec }: {
|
|
49
|
+
static insertCustomKey({ customKey, expireSec, waitForIndex }: {
|
|
46
50
|
customKey: string;
|
|
47
51
|
expireSec?: number;
|
|
52
|
+
waitForIndex?: boolean | null;
|
|
48
53
|
}): Promise<any>;
|
|
49
54
|
/**
|
|
50
55
|
* Inserts a custom key-value pair into the in-memory store.
|
|
51
56
|
* @param customKey - The custom key for the value.
|
|
52
57
|
* @param value - The value to insert.
|
|
53
58
|
* @param expireSec - The expiration time in seconds for the value.
|
|
59
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
54
60
|
* @return A promise that resolves with the result of the insertion.
|
|
55
61
|
*/
|
|
56
|
-
static insertCustomKeyValue({ customKey, value, expireSec }: {
|
|
62
|
+
static insertCustomKeyValue({ customKey, value, expireSec, waitForIndex }: {
|
|
57
63
|
customKey: string;
|
|
58
64
|
value?: any;
|
|
59
65
|
expireSec?: number;
|
|
66
|
+
waitForIndex?: boolean | null;
|
|
60
67
|
}): Promise<any>;
|
|
61
68
|
/**
|
|
62
69
|
* Updates a value in the in-memory store.
|
|
@@ -64,23 +71,27 @@ declare class InMemory extends GenericKV {
|
|
|
64
71
|
* @param customKey - The custom key for the value to update.
|
|
65
72
|
* @param value - The new value to set.
|
|
66
73
|
* @param expireSec - The expiration time in seconds for the value.
|
|
74
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
67
75
|
* @return A promise that resolves with the result of the update.
|
|
68
76
|
*/
|
|
69
|
-
static updateValue({ key, customKey, value, expireSec }?: {
|
|
77
|
+
static updateValue({ key, customKey, value, expireSec, waitForIndex }?: {
|
|
70
78
|
key?: string;
|
|
71
79
|
customKey?: string | null;
|
|
72
80
|
value?: any;
|
|
73
81
|
expireSec?: number;
|
|
82
|
+
waitForIndex?: boolean | null;
|
|
74
83
|
}): Promise<any>;
|
|
75
84
|
/**
|
|
76
85
|
* Inserts a bulk of values into the in-memory store.
|
|
77
86
|
* @param bulk - An array of values to insert.
|
|
78
87
|
* @param expireSec - The expiration time in seconds for the values.
|
|
88
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
79
89
|
* @return A promise that resolves with the result of the insertion.
|
|
80
90
|
*/
|
|
81
|
-
static insertBulk({ bulk, expireSec }?: {
|
|
91
|
+
static insertBulk({ bulk, expireSec, waitForIndex }?: {
|
|
82
92
|
bulk?: any[];
|
|
83
93
|
expireSec?: number;
|
|
94
|
+
waitForIndex?: boolean | null;
|
|
84
95
|
}): Promise<any>;
|
|
85
96
|
/**
|
|
86
97
|
* Gets keys from the in-memory store.
|
package/dist/core/inmemory.js
CHANGED
|
@@ -84,23 +84,26 @@ class InMemory extends GenericKV {
|
|
|
84
84
|
* @param expireSec - The expiration time in seconds for the value.
|
|
85
85
|
* @return A promise that resolves with the result of the insertion.
|
|
86
86
|
* */
|
|
87
|
-
static async insertValue({ value = {}, expireSec = 0 } = {}) {
|
|
87
|
+
static async insertValue({ value = {}, expireSec = 0, waitForIndex = null } = {}) {
|
|
88
88
|
this.command = "insert_value";
|
|
89
|
-
const query = convertToBinaryQuery(this, { value, expireSec });
|
|
89
|
+
const query = convertToBinaryQuery(this, { value, expireSec, waitForIndex });
|
|
90
90
|
return runQuery(this, query);
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Inserts a custom key into the in-memory store.
|
|
94
94
|
* @param customKey - The custom key for the value.
|
|
95
95
|
* @param expireSec - The expiration time in seconds for the value.
|
|
96
|
+
* @param waitForIndex - Per-request synchronous-index override. No-op for in-memory
|
|
97
|
+
* keyspaces (snapshot-driven indexing); present for API symmetry with the persistent
|
|
98
|
+
* variant, where it takes effect.
|
|
96
99
|
* @return A promise that resolves with the result of the insertion.
|
|
97
100
|
*/
|
|
98
|
-
static async insertCustomKey({ customKey, expireSec = 0 }) {
|
|
101
|
+
static async insertCustomKey({ customKey, expireSec = 0, waitForIndex = null }) {
|
|
99
102
|
if (!customKey) {
|
|
100
103
|
throw new Error("No key provided");
|
|
101
104
|
}
|
|
102
105
|
this.command = "insert_custom_key";
|
|
103
|
-
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), expireSec });
|
|
106
|
+
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), expireSec, waitForIndex });
|
|
104
107
|
return runQuery(this, query);
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
@@ -108,11 +111,12 @@ class InMemory extends GenericKV {
|
|
|
108
111
|
* @param customKey - The custom key for the value.
|
|
109
112
|
* @param value - The value to insert.
|
|
110
113
|
* @param expireSec - The expiration time in seconds for the value.
|
|
114
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
111
115
|
* @return A promise that resolves with the result of the insertion.
|
|
112
116
|
*/
|
|
113
|
-
static async insertCustomKeyValue({ customKey, value = {}, expireSec = 0 }) {
|
|
117
|
+
static async insertCustomKeyValue({ customKey, value = {}, expireSec = 0, waitForIndex = null }) {
|
|
114
118
|
this.command = "insert_custom_key_value";
|
|
115
|
-
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), value, expireSec });
|
|
119
|
+
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), value, expireSec, waitForIndex });
|
|
116
120
|
return runQuery(this, query);
|
|
117
121
|
}
|
|
118
122
|
/**
|
|
@@ -121,29 +125,31 @@ class InMemory extends GenericKV {
|
|
|
121
125
|
* @param customKey - The custom key for the value to update.
|
|
122
126
|
* @param value - The new value to set.
|
|
123
127
|
* @param expireSec - The expiration time in seconds for the value.
|
|
128
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
124
129
|
* @return A promise that resolves with the result of the update.
|
|
125
130
|
*/
|
|
126
|
-
static async updateValue({ key = "", customKey = null, value = {}, expireSec = 0 } = {}) {
|
|
131
|
+
static async updateValue({ key = "", customKey = null, value = {}, expireSec = 0, waitForIndex = null } = {}) {
|
|
127
132
|
const effectiveKey = customKey ? convertCustomKey(customKey) : key;
|
|
128
133
|
if (!effectiveKey) {
|
|
129
134
|
throw new Error("No key provided");
|
|
130
135
|
}
|
|
131
136
|
this.command = "update_value";
|
|
132
|
-
const query = convertToBinaryQuery(this, { key: effectiveKey, value, expireSec });
|
|
137
|
+
const query = convertToBinaryQuery(this, { key: effectiveKey, value, expireSec, waitForIndex });
|
|
133
138
|
return runQuery(this, query);
|
|
134
139
|
}
|
|
135
140
|
/**
|
|
136
141
|
* Inserts a bulk of values into the in-memory store.
|
|
137
142
|
* @param bulk - An array of values to insert.
|
|
138
143
|
* @param expireSec - The expiration time in seconds for the values.
|
|
144
|
+
* @param waitForIndex - Per-request synchronous-index override; no-op for in-memory.
|
|
139
145
|
* @return A promise that resolves with the result of the insertion.
|
|
140
146
|
*/
|
|
141
|
-
static async insertBulk({ bulk = [], expireSec = 0 } = {}) {
|
|
147
|
+
static async insertBulk({ bulk = [], expireSec = 0, waitForIndex = null } = {}) {
|
|
142
148
|
if (!bulk || bulk.length === 0) {
|
|
143
149
|
throw new Error("No values provided");
|
|
144
150
|
}
|
|
145
151
|
this.command = "insert_bulk";
|
|
146
|
-
const query = convertToBinaryQuery(this, { bulkValues: bulk, expireSec });
|
|
152
|
+
const query = convertToBinaryQuery(this, { bulkValues: bulk, expireSec, waitForIndex });
|
|
147
153
|
return runQuery(this, query);
|
|
148
154
|
}
|
|
149
155
|
/**
|
|
@@ -18,46 +18,58 @@ declare class Persistent extends GenericKV {
|
|
|
18
18
|
* @param value - The value to insert.
|
|
19
19
|
* @return A promise that resolves with the result of the insertion.
|
|
20
20
|
*/
|
|
21
|
-
static insertValue({ value }?: {
|
|
21
|
+
static insertValue({ value, waitForIndex }?: {
|
|
22
22
|
value?: any;
|
|
23
|
+
waitForIndex?: boolean | null;
|
|
23
24
|
}): Promise<any>;
|
|
24
25
|
/**
|
|
25
26
|
* Inserts a custom key into the persistent store.
|
|
26
27
|
* @param customKey - The custom key to insert.
|
|
28
|
+
* @param waitForIndex - Per-request synchronous-index override. `true` β the write
|
|
29
|
+
* returns only after its secondary indexes are updated (read-your-writes); `false`
|
|
30
|
+
* β fire-and-forget indexing; `null` (default) β use the DB-wide default (see
|
|
31
|
+
* `Engine.enable/disableWaitForIndex`). Applies to persistent writes.
|
|
27
32
|
* @return A promise that resolves with the result of the insertion.
|
|
28
33
|
*/
|
|
29
|
-
static insertCustomKey({ customKey }: {
|
|
34
|
+
static insertCustomKey({ customKey, waitForIndex }: {
|
|
30
35
|
customKey: string;
|
|
36
|
+
waitForIndex?: boolean | null;
|
|
31
37
|
}): Promise<any>;
|
|
32
38
|
/**
|
|
33
39
|
* Inserts a custom key-value pair into the persistent store.
|
|
34
40
|
* @param customKey - The custom key for the value.
|
|
35
41
|
* @param value - The value to insert.
|
|
42
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
36
43
|
* @return A promise that resolves with the result of the insertion.
|
|
37
44
|
*/
|
|
38
|
-
static insertCustomKeyValue({ customKey, value }: {
|
|
45
|
+
static insertCustomKeyValue({ customKey, value, waitForIndex }: {
|
|
39
46
|
customKey: string;
|
|
40
47
|
value?: any;
|
|
48
|
+
waitForIndex?: boolean | null;
|
|
41
49
|
}): Promise<any>;
|
|
42
50
|
/**
|
|
43
51
|
* Updates a value in the persistent store.
|
|
44
52
|
* @param key - The key for the value to update.
|
|
45
53
|
* @param customKey - The custom key for the value to update.
|
|
46
54
|
* @param value - The new value to set.
|
|
55
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
47
56
|
* @return A promise that resolves with the result of the update.
|
|
48
57
|
*/
|
|
49
|
-
static updateValue({ key, customKey, value }?: {
|
|
58
|
+
static updateValue({ key, customKey, value, waitForIndex }?: {
|
|
50
59
|
key?: string;
|
|
51
60
|
customKey?: string | null;
|
|
52
61
|
value?: any;
|
|
62
|
+
waitForIndex?: boolean | null;
|
|
53
63
|
}): Promise<any>;
|
|
54
64
|
/**
|
|
55
65
|
* Inserts multiple key-value pairs into the persistent store in bulk.
|
|
56
66
|
* @param bulk - An array of key-value pairs to insert.
|
|
67
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
57
68
|
* @return A promise that resolves with the result of the bulk insertion.
|
|
58
69
|
*/
|
|
59
|
-
static insertBulk({ bulk }?: {
|
|
70
|
+
static insertBulk({ bulk, waitForIndex }?: {
|
|
60
71
|
bulk?: any[];
|
|
72
|
+
waitForIndex?: boolean | null;
|
|
61
73
|
}): Promise<any>;
|
|
62
74
|
/**
|
|
63
75
|
* Retrieves keys from the persistent store based on provided options.
|
package/dist/core/persistent.js
CHANGED
|
@@ -17,36 +17,41 @@ class Persistent extends GenericKV {
|
|
|
17
17
|
* @param value - The value to insert.
|
|
18
18
|
* @return A promise that resolves with the result of the insertion.
|
|
19
19
|
*/
|
|
20
|
-
static async insertValue({ value = {} } = {}) {
|
|
20
|
+
static async insertValue({ value = {}, waitForIndex = null } = {}) {
|
|
21
21
|
this.command = "insert_value";
|
|
22
|
-
const query = convertToBinaryQuery(this, { value });
|
|
22
|
+
const query = convertToBinaryQuery(this, { value, waitForIndex });
|
|
23
23
|
return runQuery(this, query);
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Inserts a custom key into the persistent store.
|
|
27
27
|
* @param customKey - The custom key to insert.
|
|
28
|
+
* @param waitForIndex - Per-request synchronous-index override. `true` β the write
|
|
29
|
+
* returns only after its secondary indexes are updated (read-your-writes); `false`
|
|
30
|
+
* β fire-and-forget indexing; `null` (default) β use the DB-wide default (see
|
|
31
|
+
* `Engine.enable/disableWaitForIndex`). Applies to persistent writes.
|
|
28
32
|
* @return A promise that resolves with the result of the insertion.
|
|
29
33
|
*/
|
|
30
|
-
static async insertCustomKey({ customKey }) {
|
|
34
|
+
static async insertCustomKey({ customKey, waitForIndex = null }) {
|
|
31
35
|
if (!customKey) {
|
|
32
36
|
throw new Error("No key provided");
|
|
33
37
|
}
|
|
34
38
|
this.command = "insert_custom_key";
|
|
35
|
-
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey) });
|
|
39
|
+
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), waitForIndex });
|
|
36
40
|
return runQuery(this, query);
|
|
37
41
|
}
|
|
38
42
|
/**
|
|
39
43
|
* Inserts a custom key-value pair into the persistent store.
|
|
40
44
|
* @param customKey - The custom key for the value.
|
|
41
45
|
* @param value - The value to insert.
|
|
46
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
42
47
|
* @return A promise that resolves with the result of the insertion.
|
|
43
48
|
*/
|
|
44
|
-
static async insertCustomKeyValue({ customKey, value = {} }) {
|
|
49
|
+
static async insertCustomKeyValue({ customKey, value = {}, waitForIndex = null }) {
|
|
45
50
|
if (!customKey) {
|
|
46
51
|
throw new Error("No key provided");
|
|
47
52
|
}
|
|
48
53
|
this.command = "insert_custom_key_value";
|
|
49
|
-
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), value });
|
|
54
|
+
const query = convertToBinaryQuery(this, { key: convertCustomKey(customKey), value, waitForIndex });
|
|
50
55
|
return runQuery(this, query);
|
|
51
56
|
}
|
|
52
57
|
/**
|
|
@@ -54,28 +59,30 @@ class Persistent extends GenericKV {
|
|
|
54
59
|
* @param key - The key for the value to update.
|
|
55
60
|
* @param customKey - The custom key for the value to update.
|
|
56
61
|
* @param value - The new value to set.
|
|
62
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
57
63
|
* @return A promise that resolves with the result of the update.
|
|
58
64
|
*/
|
|
59
|
-
static async updateValue({ key = "", customKey = null, value = {} } = {}) {
|
|
65
|
+
static async updateValue({ key = "", customKey = null, value = {}, waitForIndex = null } = {}) {
|
|
60
66
|
const effectiveKey = customKey ? convertCustomKey(customKey) : key;
|
|
61
67
|
if (!effectiveKey) {
|
|
62
68
|
throw new Error("No key provided");
|
|
63
69
|
}
|
|
64
70
|
this.command = "update_value";
|
|
65
|
-
const query = convertToBinaryQuery(this, { key: effectiveKey, value });
|
|
71
|
+
const query = convertToBinaryQuery(this, { key: effectiveKey, value, waitForIndex });
|
|
66
72
|
return runQuery(this, query);
|
|
67
73
|
}
|
|
68
74
|
/**
|
|
69
75
|
* Inserts multiple key-value pairs into the persistent store in bulk.
|
|
70
76
|
* @param bulk - An array of key-value pairs to insert.
|
|
77
|
+
* @param waitForIndex - Per-request synchronous-index override; null (default) uses the DB-wide default.
|
|
71
78
|
* @return A promise that resolves with the result of the bulk insertion.
|
|
72
79
|
*/
|
|
73
|
-
static async insertBulk({ bulk = [] } = {}) {
|
|
80
|
+
static async insertBulk({ bulk = [], waitForIndex = null } = {}) {
|
|
74
81
|
if (!bulk || bulk.length === 0) {
|
|
75
82
|
throw new Error("No values provided");
|
|
76
83
|
}
|
|
77
84
|
this.command = "insert_bulk";
|
|
78
|
-
const query = convertToBinaryQuery(this, { bulkValues: bulk });
|
|
85
|
+
const query = convertToBinaryQuery(this, { bulkValues: bulk, waitForIndex });
|
|
79
86
|
return runQuery(this, query);
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
@@ -58,12 +58,12 @@ function processBulkKeysValues(bulkKeysValues) {
|
|
|
58
58
|
* @returns A JSON string representing the binary query.
|
|
59
59
|
* */
|
|
60
60
|
function convertToBinaryQuery(cls, options = {}) {
|
|
61
|
-
const { key = null, value = {}, expireSec = 0, bulkValues = [], bulkKeys = [], bulkKeysValues = {}, searchCriteria = {}, limitOutput = { start: 0, stop: 0 }, withPointers = false, schema = null, keyIncluded = false, pointersMetadata = false, volumes = [], latestVolume = false, } = options;
|
|
61
|
+
const { key = null, value = {}, expireSec = 0, bulkValues = [], bulkKeys = [], bulkKeysValues = {}, searchCriteria = {}, limitOutput = { start: 0, stop: 0 }, withPointers = false, schema = null, keyIncluded = false, pointersMetadata = false, volumes = [], latestVolume = false, semanticQuery = null, minScore = null, waitForIndex = null, } = options;
|
|
62
62
|
const { processedValue, foundSchema } = processValue(value);
|
|
63
63
|
const { processedBulkValues, uniqueSchema } = processBulkValues(bulkValues);
|
|
64
64
|
const bulkKeysValuesProcessed = processBulkKeysValues(bulkKeysValues);
|
|
65
65
|
const processedSearchCriteria = processSearchCriteria(searchCriteria);
|
|
66
|
-
|
|
66
|
+
const queryDict = {
|
|
67
67
|
username: cls.username,
|
|
68
68
|
password: cls.password,
|
|
69
69
|
namespace: cls.namespace,
|
|
@@ -79,14 +79,27 @@ function convertToBinaryQuery(cls, options = {}) {
|
|
|
79
79
|
bulk_values: processedBulkValues.map(v => JSON.stringify(v)),
|
|
80
80
|
bulk_keys: bulkKeys,
|
|
81
81
|
bulk_keys_values: bulkKeysValuesProcessed,
|
|
82
|
-
|
|
82
|
+
// `semantic_search` sends the raw query text (the engine trims it as a
|
|
83
|
+
// plain string); every other command sends a JSON-encoded filter map.
|
|
84
|
+
search_criteria: semanticQuery !== null ? semanticQuery : JSON.stringify(processedSearchCriteria),
|
|
83
85
|
with_pointers: withPointers,
|
|
84
86
|
schema: foundSchema ? foundSchema : uniqueSchema ? uniqueSchema : schema,
|
|
85
87
|
key_included: keyIncluded,
|
|
86
88
|
pointers_metadata: pointersMetadata,
|
|
87
89
|
volumes,
|
|
88
90
|
latest_volume: latestVolume,
|
|
89
|
-
}
|
|
91
|
+
};
|
|
92
|
+
// Only `semantic_search` honors min_score; omit it otherwise so the wire is
|
|
93
|
+
// unchanged for existing commands (the engine defaults the field to None).
|
|
94
|
+
if (minScore !== null) {
|
|
95
|
+
queryDict.min_score = minScore;
|
|
96
|
+
}
|
|
97
|
+
// Per-request wait_for_index override for persistent writes; omit when null
|
|
98
|
+
// so the server falls back to its DB-wide default (existing wire unchanged).
|
|
99
|
+
if (waitForIndex !== null) {
|
|
100
|
+
queryDict.wait_for_index = waitForIndex;
|
|
101
|
+
}
|
|
102
|
+
return JSON.stringify(queryDict);
|
|
90
103
|
}
|
|
91
104
|
function processSearchCriteria(searchCriteria) {
|
|
92
105
|
const processedCriteria = {};
|
package/package.json
CHANGED
|
@@ -1,20 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "montycat",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.6",
|
|
4
|
+
"description": "Self-hosted vector database + NoSQL with built-in AI semantic search β the Node.js & TypeScript client for Montycat. A Rust-powered, AI-native Pinecone / Weaviate / Chroma alternative for RAG, AI agents & LLM memory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"homepage": "https://montygovernance.com",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/MontyGovernance/montycat_node.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/MontyGovernance/montycat_node/issues"
|
|
16
|
+
},
|
|
9
17
|
"keywords": [
|
|
18
|
+
"vector-database",
|
|
19
|
+
"vector-search",
|
|
20
|
+
"semantic-search",
|
|
21
|
+
"embeddings",
|
|
22
|
+
"similarity-search",
|
|
23
|
+
"knn",
|
|
24
|
+
"hnsw",
|
|
10
25
|
"database",
|
|
11
26
|
"nosql",
|
|
12
|
-
"
|
|
27
|
+
"database-client",
|
|
28
|
+
"rag",
|
|
29
|
+
"retrieval-augmented-generation",
|
|
30
|
+
"ai",
|
|
31
|
+
"ai-agents",
|
|
32
|
+
"agent-memory",
|
|
33
|
+
"ai-memory",
|
|
34
|
+
"llm",
|
|
35
|
+
"mcp",
|
|
36
|
+
"self-hosted",
|
|
37
|
+
"embedded-database",
|
|
38
|
+
"pinecone-alternative",
|
|
39
|
+
"weaviate-alternative",
|
|
40
|
+
"chroma-alternative",
|
|
41
|
+
"qdrant-alternative",
|
|
42
|
+
"redis-alternative",
|
|
13
43
|
"data-mesh",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
44
|
+
"async",
|
|
45
|
+
"typescript",
|
|
46
|
+
"rust",
|
|
17
47
|
"realtime",
|
|
48
|
+
"key-value",
|
|
49
|
+
"cache",
|
|
18
50
|
"montycat"
|
|
19
51
|
],
|
|
20
52
|
"exports": {
|
|
@@ -23,8 +55,14 @@
|
|
|
23
55
|
"types": "./dist/index.d.ts"
|
|
24
56
|
}
|
|
25
57
|
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist"
|
|
63
|
+
],
|
|
26
64
|
"scripts": {
|
|
27
|
-
"test": "
|
|
65
|
+
"test": "tsc --noEmit",
|
|
28
66
|
"build": "tsc",
|
|
29
67
|
"start": "node dist/index.js",
|
|
30
68
|
"dev": "tsc --watch"
|
|
@@ -39,7 +77,6 @@
|
|
|
39
77
|
"license": "MIT",
|
|
40
78
|
"dependencies": {
|
|
41
79
|
"json-bigint": "^1.0.0",
|
|
42
|
-
"xxhash-wasm": "^1.0.2",
|
|
43
80
|
"xxhashjs": "^0.2.2"
|
|
44
81
|
}
|
|
45
82
|
}
|