@duckedup/nidus 0.1.0

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/dist/index.js ADDED
@@ -0,0 +1,379 @@
1
+ // src/errors.ts
2
+ var NidusError = class extends Error {
3
+ /** The HTTP status code, or `0` for a transport/timeout failure (no response). */
4
+ status;
5
+ constructor(message, status) {
6
+ super(message);
7
+ this.name = "NidusError";
8
+ this.status = status;
9
+ }
10
+ /** A malformed request the server rejected (HTTP 400). */
11
+ get isBadRequest() {
12
+ return this.status === 400;
13
+ }
14
+ /** The store is read-only (HTTP 403). */
15
+ get isReadOnly() {
16
+ return this.status === 403;
17
+ }
18
+ /** The writer lock is held by another process (HTTP 409). */
19
+ get isLocked() {
20
+ return this.status === 409;
21
+ }
22
+ /** Out of capacity: `max_vector_bytes` exceeded or OOM (HTTP 507). */
23
+ get isOutOfCapacity() {
24
+ return this.status === 507;
25
+ }
26
+ };
27
+
28
+ // src/values.ts
29
+ var v = {
30
+ str: (s) => ({ Str: s }),
31
+ int: (n) => {
32
+ if (!Number.isInteger(n)) {
33
+ throw new TypeError(`v.int expects an integer, got ${n}`);
34
+ }
35
+ return { Int: n };
36
+ },
37
+ bool: (b) => ({ Bool: b }),
38
+ list: (items) => ({ List: items }),
39
+ /** The explicit `Null` value — set-but-empty, distinct from an absent key. */
40
+ nil: () => "Null"
41
+ };
42
+ function isValue(x) {
43
+ if (x === "Null") return true;
44
+ if (typeof x !== "object" || x === null) return false;
45
+ return "Str" in x || "Int" in x || "Bool" in x || "List" in x;
46
+ }
47
+ function encodeValue(input) {
48
+ if (isValue(input)) return input;
49
+ if (input === null) return "Null";
50
+ switch (typeof input) {
51
+ case "string":
52
+ return { Str: input };
53
+ case "boolean":
54
+ return { Bool: input };
55
+ case "number":
56
+ return v.int(input);
57
+ case "object":
58
+ if (Array.isArray(input)) {
59
+ if (!input.every((e) => typeof e === "string")) {
60
+ throw new TypeError("a List attribute must contain only strings");
61
+ }
62
+ return { List: input };
63
+ }
64
+ // falls through
65
+ default:
66
+ throw new TypeError(`cannot encode attribute value: ${String(input)}`);
67
+ }
68
+ }
69
+ function encodeAttrs(attrs) {
70
+ const out = {};
71
+ for (const [k, val] of Object.entries(attrs)) {
72
+ out[k] = encodeValue(val);
73
+ }
74
+ return out;
75
+ }
76
+ function decodeValue(value) {
77
+ if (value === "Null") return null;
78
+ if ("Str" in value) return value.Str;
79
+ if ("Int" in value) return value.Int;
80
+ if ("Bool" in value) return value.Bool;
81
+ if ("List" in value) return value.List;
82
+ return value;
83
+ }
84
+ function decodeAttrs(attrs) {
85
+ const out = {};
86
+ for (const [k, val] of Object.entries(attrs)) {
87
+ out[k] = decodeValue(val);
88
+ }
89
+ return out;
90
+ }
91
+
92
+ // src/client.ts
93
+ var NidusClient = class {
94
+ baseUrl;
95
+ token;
96
+ doFetch;
97
+ timeoutMs;
98
+ extraHeaders;
99
+ constructor(options) {
100
+ if (!options.baseUrl) {
101
+ throw new TypeError("NidusClient requires a baseUrl");
102
+ }
103
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
104
+ this.token = options.token;
105
+ this.timeoutMs = options.timeoutMs ?? 0;
106
+ this.extraHeaders = options.headers ?? {};
107
+ const f2 = options.fetch ?? globalThis.fetch;
108
+ if (typeof f2 !== "function") {
109
+ throw new TypeError(
110
+ "no fetch available; pass options.fetch (Node < 18, or a custom runtime)"
111
+ );
112
+ }
113
+ this.doFetch = f2 === globalThis.fetch ? f2.bind(globalThis) : f2;
114
+ }
115
+ // ── Admin / introspection ─────────────────────────────────────────────────
116
+ /** Liveness check. Returns `true` when the server answers `/health`. */
117
+ async health() {
118
+ try {
119
+ const res = await this.raw("GET", "/health");
120
+ return res.ok;
121
+ } catch {
122
+ return false;
123
+ }
124
+ }
125
+ /** Store-wide introspection: dimension, distance, ANN config, collections, footprint. */
126
+ stats() {
127
+ return this.request("GET", "/stats");
128
+ }
129
+ /** List every collection name. */
130
+ collections() {
131
+ return this.request("GET", "/collections");
132
+ }
133
+ /** Create a collection. Idempotent on the server side. */
134
+ async createCollection(name) {
135
+ await this.request("POST", `/collections/${enc(name)}`, {});
136
+ }
137
+ /** Drop a collection and all its records. */
138
+ async dropCollection(name) {
139
+ await this.request("DELETE", `/collections/${enc(name)}`);
140
+ }
141
+ /** Read a collection's free-form string metadata. */
142
+ getMeta(name) {
143
+ return this.request(
144
+ "GET",
145
+ `/collections/${enc(name)}/meta`
146
+ );
147
+ }
148
+ /** Replace a collection's free-form string metadata. */
149
+ async setMeta(name, meta) {
150
+ await this.request("PUT", `/collections/${enc(name)}/meta`, meta);
151
+ }
152
+ // ── Data ──────────────────────────────────────────────────────────────────
153
+ /**
154
+ * Insert or replace records (idempotent on `id` within the collection).
155
+ * `attrs` accept plain JS values or `v.*` helpers; they are normalized for you.
156
+ * Returns the number of records upserted.
157
+ */
158
+ async upsert(name, records) {
159
+ const wire = records.map((r) => ({
160
+ id: r.id,
161
+ ...r.vector !== void 0 ? { vector: r.vector } : {},
162
+ attrs: encodeAttrs(r.attrs)
163
+ }));
164
+ const res = await this.request(
165
+ "POST",
166
+ `/collections/${enc(name)}/upsert`,
167
+ { records: wire }
168
+ );
169
+ return res.upserted;
170
+ }
171
+ /** Delete records by id. Returns the number deleted. */
172
+ async delete(name, opts) {
173
+ const res = await this.request(
174
+ "POST",
175
+ `/collections/${enc(name)}/delete`,
176
+ { ids: opts.ids }
177
+ );
178
+ return res.deleted;
179
+ }
180
+ /** Delete every record matching `filter`. Returns the number deleted. */
181
+ async deleteWhere(name, filter) {
182
+ const res = await this.request(
183
+ "POST",
184
+ `/collections/${enc(name)}/delete`,
185
+ { filter }
186
+ );
187
+ return res.deleted;
188
+ }
189
+ /** Fetch every record in a collection (attrs decoded to plain JS values). */
190
+ async records(name) {
191
+ const recs = await this.request(
192
+ "GET",
193
+ `/collections/${enc(name)}/records`
194
+ );
195
+ return recs.map((r) => ({
196
+ id: r.id,
197
+ ...r.vector !== void 0 ? { vector: r.vector } : {},
198
+ attrs: decodeAttrs(r.attrs)
199
+ }));
200
+ }
201
+ /** Declare the full-text-indexed attribute fields for a collection. */
202
+ async setFtsSchema(name, fields) {
203
+ await this.request("POST", `/collections/${enc(name)}/fts-schema`, {
204
+ fields
205
+ });
206
+ }
207
+ // ── Search ──────────────────────────────────────────────────────────────
208
+ /** Vector (cosine) nearest-neighbour search. Empty `scope` searches all collections. */
209
+ search(opts) {
210
+ return this.searchRequest("/search", {
211
+ query: opts.query,
212
+ scope: opts.scope ?? [],
213
+ top_k: opts.topK,
214
+ min_score: opts.minScore,
215
+ filter: opts.filter ?? []
216
+ });
217
+ }
218
+ /** BM25 full-text search over one indexed field. */
219
+ textSearch(opts) {
220
+ return this.searchRequest("/text-search", {
221
+ field: opts.field,
222
+ query: opts.query,
223
+ scope: opts.scope ?? [],
224
+ top_k: opts.topK,
225
+ min_score: opts.minScore,
226
+ filter: opts.filter ?? []
227
+ });
228
+ }
229
+ /** Hybrid search: fuse a vector query and a BM25 text query via RRF. */
230
+ hybridSearch(opts) {
231
+ return this.searchRequest("/hybrid-search", {
232
+ vector: opts.vector,
233
+ field: opts.field,
234
+ text: opts.text,
235
+ scope: opts.scope ?? [],
236
+ top_k: opts.topK,
237
+ filter: opts.filter ?? [],
238
+ rrf_k: opts.rrfK,
239
+ candidates: opts.candidates
240
+ });
241
+ }
242
+ /** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
243
+ list(opts = {}) {
244
+ return this.searchRequest("/list", {
245
+ scope: opts.scope ?? [],
246
+ offset: opts.offset,
247
+ limit: opts.limit,
248
+ filter: opts.filter ?? []
249
+ });
250
+ }
251
+ // ── Maintenance ───────────────────────────────────────────────────────────
252
+ /** Force a durability flush. */
253
+ async flush() {
254
+ await this.request("POST", "/flush", {});
255
+ }
256
+ /** Compact the store (reclaim space from deleted/overwritten rows). */
257
+ async compact() {
258
+ await this.request("POST", "/compact", {});
259
+ }
260
+ // ── Internals ─────────────────────────────────────────────────────────────
261
+ /** Run a search-family request and decode the resulting hits' attrs. */
262
+ async searchRequest(path, body) {
263
+ const hits = await this.request("POST", path, prune(body));
264
+ return hits.map((h) => ({
265
+ collection: h.collection,
266
+ id: h.id,
267
+ score: h.score,
268
+ attrs: decodeAttrs(h.attrs)
269
+ }));
270
+ }
271
+ /** Issue a request and parse a JSON body, mapping a non-2xx to {@link NidusError}. */
272
+ async request(method, path, body) {
273
+ const res = await this.raw(method, path, body);
274
+ const text = await res.text();
275
+ if (!res.ok) {
276
+ throw new NidusError(extractError(text, res.status), res.status);
277
+ }
278
+ return text ? JSON.parse(text) : void 0;
279
+ }
280
+ /** The bare transport: headers, auth, timeout, and transport-error mapping. */
281
+ async raw(method, path, body) {
282
+ const headers = { ...this.extraHeaders };
283
+ if (this.token) headers.authorization = `Bearer ${this.token}`;
284
+ let payload;
285
+ if (body !== void 0) {
286
+ headers["content-type"] = "application/json";
287
+ payload = JSON.stringify(body);
288
+ }
289
+ const controller = this.timeoutMs > 0 ? new AbortController() : void 0;
290
+ const timer = controller && this.timeoutMs > 0 ? setTimeout(() => controller.abort(), this.timeoutMs) : void 0;
291
+ try {
292
+ return await this.doFetch(`${this.baseUrl}${path}`, {
293
+ method,
294
+ headers,
295
+ body: payload,
296
+ signal: controller?.signal
297
+ });
298
+ } catch (err) {
299
+ const reason = controller?.signal.aborted ?? false ? `request to ${path} timed out after ${this.timeoutMs}ms` : `request to ${path} failed: ${err.message}`;
300
+ throw new NidusError(reason, 0);
301
+ } finally {
302
+ if (timer) clearTimeout(timer);
303
+ }
304
+ }
305
+ };
306
+ function enc(name) {
307
+ return encodeURIComponent(name);
308
+ }
309
+ function prune(body) {
310
+ const out = {};
311
+ for (const [k, val] of Object.entries(body)) {
312
+ if (val !== void 0) out[k] = val;
313
+ }
314
+ return out;
315
+ }
316
+ function extractError(text, status) {
317
+ try {
318
+ const parsed = JSON.parse(text);
319
+ if (parsed && typeof parsed.error === "string") return parsed.error;
320
+ } catch {
321
+ }
322
+ return text || `HTTP ${status}`;
323
+ }
324
+
325
+ // src/filter.ts
326
+ var f = {
327
+ /** `attrs[key] === value`. */
328
+ eq: (key, value) => ({
329
+ Eq: [key, encodeValue(value)]
330
+ }),
331
+ /** `attrs[key]` is present and `!== value`. */
332
+ ne: (key, value) => ({
333
+ Ne: [key, encodeValue(value)]
334
+ }),
335
+ /** `attrs[key]` is a `Str` matching the glob pattern (`*`, `?`, `[..]`). */
336
+ glob: (key, pattern) => ({ Glob: [key, pattern] }),
337
+ /** `attrs[key]` equals one of `values`. */
338
+ in: (key, values) => ({
339
+ In: [key, values.map(encodeValue)]
340
+ }),
341
+ /** `attrs[key]` is present and equals none of `values`. */
342
+ notIn: (key, values) => ({
343
+ NotIn: [key, values.map(encodeValue)]
344
+ }),
345
+ /** `attrs[key] < value` (same-type, orderable). */
346
+ lt: (key, value) => ({
347
+ Lt: [key, encodeValue(value)]
348
+ }),
349
+ /** `attrs[key] <= value` (same-type, orderable). */
350
+ le: (key, value) => ({
351
+ Le: [key, encodeValue(value)]
352
+ }),
353
+ /** `attrs[key] > value` (same-type, orderable). */
354
+ gt: (key, value) => ({
355
+ Gt: [key, encodeValue(value)]
356
+ }),
357
+ /** `attrs[key] >= value` (same-type, orderable). */
358
+ ge: (key, value) => ({
359
+ Ge: [key, encodeValue(value)]
360
+ }),
361
+ /** Collect predicates into a {@link Filter} (purely sugar — they already AND). */
362
+ and: (...preds) => preds
363
+ };
364
+ export {
365
+ NidusClient,
366
+ NidusError,
367
+ decodeAttrs,
368
+ decodeValue,
369
+ encodeAttrs,
370
+ encodeValue,
371
+ f,
372
+ v
373
+ };
374
+ //! Error type carrying the HTTP status the server reported.
375
+ //! Ergonomic constructors and decoders for the externally-tagged `Value` wire type.
376
+ //! `NidusClient` — a remote client over the `nidus serve` HTTP API.
377
+ //! Filter builder producing the bare predicate-array wire shape.
378
+ //! `@duckedup/nidus` — the JavaScript/TypeScript client for nidus.
379
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/values.ts","../src/client.ts","../src/filter.ts"],"sourcesContent":["//! Error type carrying the HTTP status the server reported.\n//\n// The server replies to a failed request with `{ \"error\": <message> }` and a\n// meaningful status (`src/server/mod.rs#classify`): 400 dimension mismatch,\n// 403 read-only store, 409 writer-lock conflict, 507 capacity/OOM, 500 otherwise.\n// Callers branch on `.status` to tell a client fault from a server fault.\n\n/** An error returned by a `nidus` server, or a transport failure reaching it. */\nexport class NidusError extends Error {\n /** The HTTP status code, or `0` for a transport/timeout failure (no response). */\n readonly status: number;\n\n constructor(message: string, status: number) {\n super(message);\n this.name = \"NidusError\";\n this.status = status;\n }\n\n /** A malformed request the server rejected (HTTP 400). */\n get isBadRequest(): boolean {\n return this.status === 400;\n }\n /** The store is read-only (HTTP 403). */\n get isReadOnly(): boolean {\n return this.status === 403;\n }\n /** The writer lock is held by another process (HTTP 409). */\n get isLocked(): boolean {\n return this.status === 409;\n }\n /** Out of capacity: `max_vector_bytes` exceeded or OOM (HTTP 507). */\n get isOutOfCapacity(): boolean {\n return this.status === 507;\n }\n}\n","//! Ergonomic constructors and decoders for the externally-tagged `Value` wire type.\n//\n// Callers should never hand-write `{ Str: \"x\" }`. Use `v.str(\"x\")`, `v.int(5)`,\n// etc., or just pass plain JS values into `attrs` — `encodeValue` normalizes them.\n\nimport type { AttrInput, DecodedValue, Value } from \"./types.js\";\n\n/**\n * Value constructors mirroring the `Value` variants. `v.int` requires a safe\n * integer (the store's attribute integer is an `i64`; a non-integer would be a\n * silent type error since there is no float attribute).\n */\nexport const v = {\n str: (s: string): Value => ({ Str: s }),\n int: (n: number): Value => {\n if (!Number.isInteger(n)) {\n throw new TypeError(`v.int expects an integer, got ${n}`);\n }\n return { Int: n };\n },\n bool: (b: boolean): Value => ({ Bool: b }),\n list: (items: string[]): Value => ({ List: items }),\n /** The explicit `Null` value — set-but-empty, distinct from an absent key. */\n nil: (): Value => \"Null\",\n} as const;\n\n/** True if `x` is already a wire-tagged {@link Value}. */\nfunction isValue(x: unknown): x is Value {\n if (x === \"Null\") return true;\n if (typeof x !== \"object\" || x === null) return false;\n return (\n \"Str\" in x || \"Int\" in x || \"Bool\" in x || \"List\" in x\n );\n}\n\n/**\n * Normalize a caller-supplied {@link AttrInput} into the wire {@link Value} shape.\n * Plain scalars map by type; an already-tagged `Value` passes through unchanged.\n * Throws on a non-integer number or a non-string list element.\n */\nexport function encodeValue(input: AttrInput): Value {\n if (isValue(input)) return input;\n if (input === null) return \"Null\";\n switch (typeof input) {\n case \"string\":\n return { Str: input };\n case \"boolean\":\n return { Bool: input };\n case \"number\":\n return v.int(input);\n case \"object\":\n if (Array.isArray(input)) {\n if (!input.every((e) => typeof e === \"string\")) {\n throw new TypeError(\"a List attribute must contain only strings\");\n }\n return { List: input };\n }\n // falls through\n default:\n throw new TypeError(`cannot encode attribute value: ${String(input)}`);\n }\n}\n\n/** Normalize a whole `attrs` map of {@link AttrInput} into wire {@link Value}s. */\nexport function encodeAttrs(\n attrs: Record<string, AttrInput>,\n): Record<string, Value> {\n const out: Record<string, Value> = {};\n for (const [k, val] of Object.entries(attrs)) {\n out[k] = encodeValue(val);\n }\n return out;\n}\n\n/** Decode a wire {@link Value} back to a plain JS value. */\nexport function decodeValue(value: Value): DecodedValue {\n if (value === \"Null\") return null;\n if (\"Str\" in value) return value.Str;\n if (\"Int\" in value) return value.Int;\n if (\"Bool\" in value) return value.Bool;\n if (\"List\" in value) return value.List;\n // Unknown tag (forward-compat): hand it back untouched.\n return value as unknown as DecodedValue;\n}\n\n/** Decode a whole wire `attrs` map back to plain JS values. */\nexport function decodeAttrs(\n attrs: Record<string, Value>,\n): Record<string, DecodedValue> {\n const out: Record<string, DecodedValue> = {};\n for (const [k, val] of Object.entries(attrs)) {\n out[k] = decodeValue(val);\n }\n return out;\n}\n","//! `NidusClient` — a remote client over the `nidus serve` HTTP API.\n//\n// One method per endpoint (`src/server/mod.rs`). \"Local vs remote\" is just the\n// base URL: point at a local `nidus serve` or any reachable host. Built on the\n// platform-global `fetch`, so it runs unchanged on Node 18+, Deno, Bun, Cloudflare\n// Workers, and browsers — with no runtime dependencies.\n\nimport { NidusError } from \"./errors.js\";\nimport type {\n DecodedRecord,\n Filter,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n RecordInput,\n SearchOptions,\n Stats,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\nimport { decodeAttrs, encodeAttrs } from \"./values.js\";\n\n/** Minimal `fetch` signature the client needs — satisfied by the platform global. */\nexport type FetchLike = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Construction options for {@link NidusClient}. */\nexport interface NidusClientOptions {\n /** Base URL of the server, e.g. `http://127.0.0.1:7700`. Trailing slash optional. */\n baseUrl: string;\n /** Bearer token, when the server was started with `--token`. */\n token?: string;\n /** Override the `fetch` implementation (defaults to `globalThis.fetch`). */\n fetch?: FetchLike;\n /** Per-request timeout in milliseconds. Omit (or `0`) to disable. */\n timeoutMs?: number;\n /** Extra headers sent on every request. */\n headers?: Record<string, string>;\n}\n\nexport class NidusClient {\n private readonly baseUrl: string;\n private readonly token?: string;\n private readonly doFetch: FetchLike;\n private readonly timeoutMs: number;\n private readonly extraHeaders: Record<string, string>;\n\n constructor(options: NidusClientOptions) {\n if (!options.baseUrl) {\n throw new TypeError(\"NidusClient requires a baseUrl\");\n }\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.token = options.token;\n this.timeoutMs = options.timeoutMs ?? 0;\n this.extraHeaders = options.headers ?? {};\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new TypeError(\n \"no fetch available; pass options.fetch (Node < 18, or a custom runtime)\",\n );\n }\n // Bind so a passed `globalThis.fetch` keeps its `this`.\n this.doFetch = f === globalThis.fetch ? f.bind(globalThis) : f;\n }\n\n // ── Admin / introspection ─────────────────────────────────────────────────\n\n /** Liveness check. Returns `true` when the server answers `/health`. */\n async health(): Promise<boolean> {\n try {\n const res = await this.raw(\"GET\", \"/health\");\n return res.ok;\n } catch {\n return false;\n }\n }\n\n /** Store-wide introspection: dimension, distance, ANN config, collections, footprint. */\n stats(): Promise<Stats> {\n return this.request<Stats>(\"GET\", \"/stats\");\n }\n\n /** List every collection name. */\n collections(): Promise<string[]> {\n return this.request<string[]>(\"GET\", \"/collections\");\n }\n\n /** Create a collection. Idempotent on the server side. */\n async createCollection(name: string): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}`, {});\n }\n\n /** Drop a collection and all its records. */\n async dropCollection(name: string): Promise<void> {\n await this.request(\"DELETE\", `/collections/${enc(name)}`);\n }\n\n /** Read a collection's free-form string metadata. */\n getMeta(name: string): Promise<Record<string, string>> {\n return this.request<Record<string, string>>(\n \"GET\",\n `/collections/${enc(name)}/meta`,\n );\n }\n\n /** Replace a collection's free-form string metadata. */\n async setMeta(name: string, meta: Record<string, string>): Promise<void> {\n await this.request(\"PUT\", `/collections/${enc(name)}/meta`, meta);\n }\n\n // ── Data ──────────────────────────────────────────────────────────────────\n\n /**\n * Insert or replace records (idempotent on `id` within the collection).\n * `attrs` accept plain JS values or `v.*` helpers; they are normalized for you.\n * Returns the number of records upserted.\n */\n async upsert(name: string, records: RecordInput[]): Promise<number> {\n const wire: NidusRecord[] = records.map((r) => ({\n id: r.id,\n ...(r.vector !== undefined ? { vector: r.vector } : {}),\n attrs: encodeAttrs(r.attrs),\n }));\n const res = await this.request<{ upserted: number }>(\n \"POST\",\n `/collections/${enc(name)}/upsert`,\n { records: wire },\n );\n return res.upserted;\n }\n\n /** Delete records by id. Returns the number deleted. */\n async delete(name: string, opts: { ids: string[] }): Promise<number> {\n const res = await this.request<{ deleted: number }>(\n \"POST\",\n `/collections/${enc(name)}/delete`,\n { ids: opts.ids },\n );\n return res.deleted;\n }\n\n /** Delete every record matching `filter`. Returns the number deleted. */\n async deleteWhere(name: string, filter: Filter): Promise<number> {\n const res = await this.request<{ deleted: number }>(\n \"POST\",\n `/collections/${enc(name)}/delete`,\n { filter },\n );\n return res.deleted;\n }\n\n /** Fetch every record in a collection (attrs decoded to plain JS values). */\n async records(name: string): Promise<DecodedRecord[]> {\n const recs = await this.request<NidusRecord[]>(\n \"GET\",\n `/collections/${enc(name)}/records`,\n );\n return recs.map((r) => ({\n id: r.id,\n ...(r.vector !== undefined ? { vector: r.vector } : {}),\n attrs: decodeAttrs(r.attrs),\n }));\n }\n\n /** Declare the full-text-indexed attribute fields for a collection. */\n async setFtsSchema(name: string, fields: string[]): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/fts-schema`, {\n fields,\n });\n }\n\n // ── Search ──────────────────────────────────────────────────────────────\n\n /** Vector (cosine) nearest-neighbour search. Empty `scope` searches all collections. */\n search(opts: SearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/search\", {\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n });\n }\n\n /** BM25 full-text search over one indexed field. */\n textSearch(opts: TextSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/text-search\", {\n field: opts.field,\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n });\n }\n\n /** Hybrid search: fuse a vector query and a BM25 text query via RRF. */\n hybridSearch(opts: HybridSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/hybrid-search\", {\n vector: opts.vector,\n field: opts.field,\n text: opts.text,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n });\n }\n\n /** Metadata-only listing (no vector), paginated by `offset`/`limit`. */\n list(opts: ListOptions = {}): Promise<Hit[]> {\n return this.searchRequest(\"/list\", {\n scope: opts.scope ?? [],\n offset: opts.offset,\n limit: opts.limit,\n filter: opts.filter ?? [],\n });\n }\n\n // ── Maintenance ───────────────────────────────────────────────────────────\n\n /** Force a durability flush. */\n async flush(): Promise<void> {\n await this.request(\"POST\", \"/flush\", {});\n }\n\n /** Compact the store (reclaim space from deleted/overwritten rows). */\n async compact(): Promise<void> {\n await this.request(\"POST\", \"/compact\", {});\n }\n\n // ── Internals ─────────────────────────────────────────────────────────────\n\n /** Run a search-family request and decode the resulting hits' attrs. */\n private async searchRequest(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Hit[]> {\n const hits = await this.request<RawHit[]>(\"POST\", path, prune(body));\n return hits.map((h) => ({\n collection: h.collection,\n id: h.id,\n score: h.score,\n attrs: decodeAttrs(h.attrs),\n }));\n }\n\n /** Issue a request and parse a JSON body, mapping a non-2xx to {@link NidusError}. */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const res = await this.raw(method, path, body);\n const text = await res.text();\n if (!res.ok) {\n throw new NidusError(extractError(text, res.status), res.status);\n }\n return (text ? JSON.parse(text) : undefined) as T;\n }\n\n /** The bare transport: headers, auth, timeout, and transport-error mapping. */\n private async raw(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<Response> {\n const headers: Record<string, string> = { ...this.extraHeaders };\n if (this.token) headers.authorization = `Bearer ${this.token}`;\n let payload: string | undefined;\n if (body !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n payload = JSON.stringify(body);\n }\n\n const controller =\n this.timeoutMs > 0 ? new AbortController() : undefined;\n const timer =\n controller && this.timeoutMs > 0\n ? setTimeout(() => controller.abort(), this.timeoutMs)\n : undefined;\n try {\n return await this.doFetch(`${this.baseUrl}${path}`, {\n method,\n headers,\n body: payload,\n signal: controller?.signal,\n });\n } catch (err) {\n const reason =\n controller?.signal.aborted ?? false\n ? `request to ${path} timed out after ${this.timeoutMs}ms`\n : `request to ${path} failed: ${(err as Error).message}`;\n throw new NidusError(reason, 0);\n } finally {\n if (timer) clearTimeout(timer);\n }\n }\n}\n\n/** A hit as it arrives on the wire, before attrs are decoded. */\ninterface RawHit {\n collection: string;\n id: string;\n score: number;\n attrs: Record<string, Value>;\n}\n\n/** Path-segment encode a collection name (allows slashes/spaces in names). */\nfunction enc(name: string): string {\n return encodeURIComponent(name);\n}\n\n/** Drop `undefined` fields so server `#[serde(default)]`s apply instead. */\nfunction prune(body: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(body)) {\n if (val !== undefined) out[k] = val;\n }\n return out;\n}\n\n/** Pull the `{ \"error\": … }` message out of a failed response, or fall back. */\nfunction extractError(text: string, status: number): string {\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed.error === \"string\") return parsed.error;\n } catch {\n // not JSON — fall through\n }\n return text || `HTTP ${status}`;\n}\n","//! Filter builder producing the bare predicate-array wire shape.\n//\n// A `Filter` is AND-combined predicates; on the wire it is a plain array. Each\n// predicate is a *positive assertion about a present attribute* — an absent key\n// matches nothing, including the negative predicates (`ne`/`notIn`) and ranges.\n// Comparisons are same-type only (Int↔Int numeric, Str↔Str lexical, Bool↔Bool).\n\nimport type { AttrInput, Filter, Predicate, Value } from \"./types.js\";\nimport { encodeValue } from \"./values.js\";\n\n/**\n * Predicate constructors. Each accepts a plain JS value (auto-normalized) or an\n * explicit `v.*` {@link Value}. Combine results into a {@link Filter} array, or\n * use {@link f.and} for readability.\n */\nexport const f = {\n /** `attrs[key] === value`. */\n eq: (key: string, value: AttrInput): Predicate => ({\n Eq: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is present and `!== value`. */\n ne: (key: string, value: AttrInput): Predicate => ({\n Ne: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a `Str` matching the glob pattern (`*`, `?`, `[..]`). */\n glob: (key: string, pattern: string): Predicate => ({ Glob: [key, pattern] }),\n /** `attrs[key]` equals one of `values`. */\n in: (key: string, values: AttrInput[]): Predicate => ({\n In: [key, values.map(encodeValue)],\n }),\n /** `attrs[key]` is present and equals none of `values`. */\n notIn: (key: string, values: AttrInput[]): Predicate => ({\n NotIn: [key, values.map(encodeValue)],\n }),\n /** `attrs[key] < value` (same-type, orderable). */\n lt: (key: string, value: AttrInput): Predicate => ({\n Lt: [key, encodeValue(value)],\n }),\n /** `attrs[key] <= value` (same-type, orderable). */\n le: (key: string, value: AttrInput): Predicate => ({\n Le: [key, encodeValue(value)],\n }),\n /** `attrs[key] > value` (same-type, orderable). */\n gt: (key: string, value: AttrInput): Predicate => ({\n Gt: [key, encodeValue(value)],\n }),\n /** `attrs[key] >= value` (same-type, orderable). */\n ge: (key: string, value: AttrInput): Predicate => ({\n Ge: [key, encodeValue(value)],\n }),\n /** Collect predicates into a {@link Filter} (purely sugar — they already AND). */\n and: (...preds: Predicate[]): Filter => preds,\n} as const;\n\n// Aliases for the comparison operators, for callers who prefer them.\nexport type { Filter, Predicate, Value };\n"],"mappings":"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","names":["f"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@duckedup/nidus",
3
+ "version": "0.1.0",
4
+ "description": "JavaScript/TypeScript client for nidus — a small, fast vector store. Connects to a local or remote `nidus serve` over HTTP.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "duckedup",
8
+ "homepage": "https://nidus.duckedup.org",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/duckedup/nidus.git",
12
+ "directory": "sdks/js"
13
+ },
14
+ "keywords": [
15
+ "nidus",
16
+ "vector",
17
+ "vector-store",
18
+ "vector-database",
19
+ "embeddings",
20
+ "semantic-search",
21
+ "similarity-search",
22
+ "client",
23
+ "sdk"
24
+ ],
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js",
37
+ "require": "./dist/index.cjs"
38
+ }
39
+ },
40
+ "sideEffects": false,
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "provenance": true
47
+ },
48
+ "scripts": {
49
+ "build": "tsup",
50
+ "typecheck": "tsc --noEmit",
51
+ "test": "vitest run",
52
+ "test:unit": "vitest run test/unit.test.ts",
53
+ "test:integration": "vitest run test/integration.test.ts",
54
+ "prepublishOnly": "npm run build"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^22.10.0",
58
+ "tsup": "^8.3.5",
59
+ "typescript": "^5.7.2",
60
+ "vitest": "^2.1.8"
61
+ }
62
+ }