@duckedup/nidus 0.1.0 → 0.2.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/README.md CHANGED
@@ -89,6 +89,32 @@ const hybrid = await db.hybridSearch({
89
89
  });
90
90
  ```
91
91
 
92
+ ## Remembering and recalling (text-native)
93
+
94
+ When the server is started with an embedder (`nidus serve --embed-provider …`), you
95
+ can send **text** and let the server embed it — no need to compute vectors client-side.
96
+ `remember` embeds and upserts; `recall` embeds the query and vector-searches.
97
+
98
+ ```ts
99
+ // Embed "the quick brown fox" and store it under id "a"
100
+ await db.remember("notes", "a", "the quick brown fox", { attrs: { tag: "x" } });
101
+
102
+ // Summarize first, then embed the summary (server also needs --summarize-provider).
103
+ // The stored record additionally carries `nidus.summary` and `nidus.source` attrs.
104
+ await db.remember("notes", "b", longArticle, { mode: "summarize" });
105
+
106
+ // Embed the query text and search, best-first (attrs decoded to plain JS values)
107
+ const hits = await db.recall("notes", "quick fox", {
108
+ topK: 5,
109
+ minScore: 0.2,
110
+ filter: f.and(f.eq("tag", "x")),
111
+ });
112
+ ```
113
+
114
+ Both throw a `NidusError` with status `400` if the server has no embedder configured
115
+ (the message names `--embed-provider`); `mode: "summarize"` without a summarizer is
116
+ likewise a `400`.
117
+
92
118
  ## Everything else
93
119
 
94
120
  ```ts
package/dist/index.cjs CHANGED
@@ -281,6 +281,43 @@ var NidusClient = class {
281
281
  filter: opts.filter ?? []
282
282
  });
283
283
  }
284
+ // ── Memory (text-native) ──────────────────────────────────────────────────
285
+ //
286
+ // Available only when `nidus serve` was started with an embedder
287
+ // (`--embed-provider …`); otherwise these answer `400`. The server embeds the
288
+ // text/query — the client only sends strings.
289
+ /**
290
+ * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).
291
+ * With `opts.mode === "summarize"` the server summarizes first, embeds the
292
+ * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the
293
+ * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`
294
+ * helpers; they are normalized for you.
295
+ */
296
+ async remember(collection, id, text, opts = {}) {
297
+ await this.request(
298
+ "POST",
299
+ `/collections/${enc(collection)}/remember`,
300
+ prune({
301
+ id,
302
+ text,
303
+ mode: opts.mode,
304
+ attrs: opts.attrs ? encodeAttrs(opts.attrs) : void 0
305
+ })
306
+ );
307
+ }
308
+ /**
309
+ * Embed `query` and vector-search `collection`, best-first (attrs decoded to
310
+ * plain JS values). Refused with a cross-model guard if the collection was
311
+ * written with a different embedder than the server's.
312
+ */
313
+ recall(collection, query, opts = {}) {
314
+ return this.searchRequest(`/collections/${enc(collection)}/recall`, {
315
+ query,
316
+ top_k: opts.topK,
317
+ min_score: opts.minScore,
318
+ filter: opts.filter ?? []
319
+ });
320
+ }
284
321
  // ── Maintenance ───────────────────────────────────────────────────────────
285
322
  /** Force a durability flush. */
286
323
  async flush() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/values.ts","../src/client.ts","../src/filter.ts"],"sourcesContent":["//! `@duckedup/nidus` — the JavaScript/TypeScript client for nidus.\n//\n// A zero-dependency, cross-runtime remote client over the `nidus serve` HTTP API.\n// Point a {@link NidusClient} at a local or remote server, then upsert and search.\n\nexport { NidusClient } from \"./client.js\";\nexport type { FetchLike, NidusClientOptions } from \"./client.js\";\nexport { NidusError } from \"./errors.js\";\nexport { f } from \"./filter.js\";\nexport { decodeAttrs, decodeValue, encodeAttrs, encodeValue, v } from \"./values.js\";\nexport type {\n AnnInfo,\n AttrInput,\n DecodedRecord,\n DecodedValue,\n Filter,\n Footprint,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n Predicate,\n RecordInput,\n SearchOptions,\n Stats,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\n","//! 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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/values.ts","../src/client.ts","../src/filter.ts"],"sourcesContent":["//! `@duckedup/nidus` — the JavaScript/TypeScript client for nidus.\n//\n// A zero-dependency, cross-runtime remote client over the `nidus serve` HTTP API.\n// Point a {@link NidusClient} at a local or remote server, then upsert and search.\n\nexport { NidusClient } from \"./client.js\";\nexport type { FetchLike, NidusClientOptions } from \"./client.js\";\nexport { NidusError } from \"./errors.js\";\nexport { f } from \"./filter.js\";\nexport { decodeAttrs, decodeValue, encodeAttrs, encodeValue, v } from \"./values.js\";\nexport type {\n AnnInfo,\n AttrInput,\n DecodedRecord,\n DecodedValue,\n Filter,\n Footprint,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n Predicate,\n RecallOptions,\n RecordInput,\n RememberOptions,\n SearchOptions,\n Stats,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\n","//! 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 RecallOptions,\n RecordInput,\n RememberOptions,\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 // ── Memory (text-native) ──────────────────────────────────────────────────\n //\n // Available only when `nidus serve` was started with an embedder\n // (`--embed-provider …`); otherwise these answer `400`. The server embeds the\n // text/query — the client only sends strings.\n\n /**\n * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).\n * With `opts.mode === \"summarize\"` the server summarizes first, embeds the\n * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the\n * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<void> {\n await this.request(\n \"POST\",\n `/collections/${enc(collection)}/remember`,\n prune({\n id,\n text,\n mode: opts.mode,\n attrs: opts.attrs ? encodeAttrs(opts.attrs) : undefined,\n }),\n );\n }\n\n /**\n * Embed `query` and vector-search `collection`, best-first (attrs decoded to\n * plain JS values). Refused with a cross-model guard if the collection was\n * written with a different embedder than the server's.\n */\n recall(\n collection: string,\n query: string,\n opts: RecallOptions = {},\n ): Promise<Hit[]> {\n return this.searchRequest(`/collections/${enc(collection)}/recall`, {\n query,\n top_k: opts.topK,\n min_score: opts.minScore,\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/dist/index.d.cts CHANGED
@@ -140,6 +140,27 @@ interface ListOptions {
140
140
  limit?: number;
141
141
  filter?: Filter;
142
142
  }
143
+ /**
144
+ * Options for {@link NidusClient.remember} (text-native ingest). The server
145
+ * embeds the text and upserts; `mode: "summarize"` summarizes it first (and
146
+ * requires the server to have been started with a summarizer).
147
+ */
148
+ interface RememberOptions {
149
+ /**
150
+ * `"raw"` (embed the text as given, the default) or `"summarize"` (summarize
151
+ * first, then embed the summary — stamps `nidus.summary`/`nidus.source` attrs).
152
+ */
153
+ mode?: "raw" | "summarize";
154
+ /** Typed metadata to stamp on the stored record (plain JS values auto-normalized). */
155
+ attrs?: Record<string, AttrInput>;
156
+ }
157
+ /** Options for {@link NidusClient.recall} (embed the query text, then vector-search). */
158
+ interface RecallOptions {
159
+ topK?: number;
160
+ /** Cosine-similarity floor; hits below it are dropped. */
161
+ minScore?: number;
162
+ filter?: Filter;
163
+ }
143
164
 
144
165
  /** Minimal `fetch` signature the client needs — satisfied by the platform global. */
145
166
  type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
@@ -201,6 +222,20 @@ declare class NidusClient {
201
222
  hybridSearch(opts: HybridSearchOptions): Promise<Hit[]>;
202
223
  /** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
203
224
  list(opts?: ListOptions): Promise<Hit[]>;
225
+ /**
226
+ * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).
227
+ * With `opts.mode === "summarize"` the server summarizes first, embeds the
228
+ * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the
229
+ * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`
230
+ * helpers; they are normalized for you.
231
+ */
232
+ remember(collection: string, id: string, text: string, opts?: RememberOptions): Promise<void>;
233
+ /**
234
+ * Embed `query` and vector-search `collection`, best-first (attrs decoded to
235
+ * plain JS values). Refused with a cross-model guard if the collection was
236
+ * written with a different embedder than the server's.
237
+ */
238
+ recall(collection: string, query: string, opts?: RecallOptions): Promise<Hit[]>;
204
239
  /** Force a durability flush. */
205
240
  flush(): Promise<void>;
206
241
  /** Compact the store (reclaim space from deleted/overwritten rows). */
@@ -282,4 +317,4 @@ declare function decodeValue(value: Value): DecodedValue;
282
317
  /** Decode a whole wire `attrs` map back to plain JS values. */
283
318
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
284
319
 
285
- export { type AnnInfo, type AttrInput, type DecodedRecord, type DecodedValue, type FetchLike, type Filter, type Footprint, type Hit, type HybridSearchOptions, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type Predicate, type RecordInput, type SearchOptions, type Stats, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
320
+ export { type AnnInfo, type AttrInput, type DecodedRecord, type DecodedValue, type FetchLike, type Filter, type Footprint, type Hit, type HybridSearchOptions, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type Predicate, type RecallOptions, type RecordInput, type RememberOptions, type SearchOptions, type Stats, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
package/dist/index.d.ts CHANGED
@@ -140,6 +140,27 @@ interface ListOptions {
140
140
  limit?: number;
141
141
  filter?: Filter;
142
142
  }
143
+ /**
144
+ * Options for {@link NidusClient.remember} (text-native ingest). The server
145
+ * embeds the text and upserts; `mode: "summarize"` summarizes it first (and
146
+ * requires the server to have been started with a summarizer).
147
+ */
148
+ interface RememberOptions {
149
+ /**
150
+ * `"raw"` (embed the text as given, the default) or `"summarize"` (summarize
151
+ * first, then embed the summary — stamps `nidus.summary`/`nidus.source` attrs).
152
+ */
153
+ mode?: "raw" | "summarize";
154
+ /** Typed metadata to stamp on the stored record (plain JS values auto-normalized). */
155
+ attrs?: Record<string, AttrInput>;
156
+ }
157
+ /** Options for {@link NidusClient.recall} (embed the query text, then vector-search). */
158
+ interface RecallOptions {
159
+ topK?: number;
160
+ /** Cosine-similarity floor; hits below it are dropped. */
161
+ minScore?: number;
162
+ filter?: Filter;
163
+ }
143
164
 
144
165
  /** Minimal `fetch` signature the client needs — satisfied by the platform global. */
145
166
  type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
@@ -201,6 +222,20 @@ declare class NidusClient {
201
222
  hybridSearch(opts: HybridSearchOptions): Promise<Hit[]>;
202
223
  /** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
203
224
  list(opts?: ListOptions): Promise<Hit[]>;
225
+ /**
226
+ * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).
227
+ * With `opts.mode === "summarize"` the server summarizes first, embeds the
228
+ * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the
229
+ * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`
230
+ * helpers; they are normalized for you.
231
+ */
232
+ remember(collection: string, id: string, text: string, opts?: RememberOptions): Promise<void>;
233
+ /**
234
+ * Embed `query` and vector-search `collection`, best-first (attrs decoded to
235
+ * plain JS values). Refused with a cross-model guard if the collection was
236
+ * written with a different embedder than the server's.
237
+ */
238
+ recall(collection: string, query: string, opts?: RecallOptions): Promise<Hit[]>;
204
239
  /** Force a durability flush. */
205
240
  flush(): Promise<void>;
206
241
  /** Compact the store (reclaim space from deleted/overwritten rows). */
@@ -282,4 +317,4 @@ declare function decodeValue(value: Value): DecodedValue;
282
317
  /** Decode a whole wire `attrs` map back to plain JS values. */
283
318
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
284
319
 
285
- export { type AnnInfo, type AttrInput, type DecodedRecord, type DecodedValue, type FetchLike, type Filter, type Footprint, type Hit, type HybridSearchOptions, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type Predicate, type RecordInput, type SearchOptions, type Stats, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
320
+ export { type AnnInfo, type AttrInput, type DecodedRecord, type DecodedValue, type FetchLike, type Filter, type Footprint, type Hit, type HybridSearchOptions, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type Predicate, type RecallOptions, type RecordInput, type RememberOptions, type SearchOptions, type Stats, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
package/dist/index.js CHANGED
@@ -248,6 +248,43 @@ var NidusClient = class {
248
248
  filter: opts.filter ?? []
249
249
  });
250
250
  }
251
+ // ── Memory (text-native) ──────────────────────────────────────────────────
252
+ //
253
+ // Available only when `nidus serve` was started with an embedder
254
+ // (`--embed-provider …`); otherwise these answer `400`. The server embeds the
255
+ // text/query — the client only sends strings.
256
+ /**
257
+ * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).
258
+ * With `opts.mode === "summarize"` the server summarizes first, embeds the
259
+ * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the
260
+ * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`
261
+ * helpers; they are normalized for you.
262
+ */
263
+ async remember(collection, id, text, opts = {}) {
264
+ await this.request(
265
+ "POST",
266
+ `/collections/${enc(collection)}/remember`,
267
+ prune({
268
+ id,
269
+ text,
270
+ mode: opts.mode,
271
+ attrs: opts.attrs ? encodeAttrs(opts.attrs) : void 0
272
+ })
273
+ );
274
+ }
275
+ /**
276
+ * Embed `query` and vector-search `collection`, best-first (attrs decoded to
277
+ * plain JS values). Refused with a cross-model guard if the collection was
278
+ * written with a different embedder than the server's.
279
+ */
280
+ recall(collection, query, opts = {}) {
281
+ return this.searchRequest(`/collections/${enc(collection)}/recall`, {
282
+ query,
283
+ top_k: opts.topK,
284
+ min_score: opts.minScore,
285
+ filter: opts.filter ?? []
286
+ });
287
+ }
251
288
  // ── Maintenance ───────────────────────────────────────────────────────────
252
289
  /** Force a durability flush. */
253
290
  async flush() {
package/dist/index.js.map CHANGED
@@ -1 +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"]}
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 RecallOptions,\n RecordInput,\n RememberOptions,\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 // ── Memory (text-native) ──────────────────────────────────────────────────\n //\n // Available only when `nidus serve` was started with an embedder\n // (`--embed-provider …`); otherwise these answer `400`. The server embeds the\n // text/query — the client only sends strings.\n\n /**\n * Embed `text` and upsert it under `id` in `collection` (idempotent on `id`).\n * With `opts.mode === \"summarize\"` the server summarizes first, embeds the\n * summary, and stamps `nidus.summary`/`nidus.source` attrs (requires the\n * server to have a summarizer). `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<void> {\n await this.request(\n \"POST\",\n `/collections/${enc(collection)}/remember`,\n prune({\n id,\n text,\n mode: opts.mode,\n attrs: opts.attrs ? encodeAttrs(opts.attrs) : undefined,\n }),\n );\n }\n\n /**\n * Embed `query` and vector-search `collection`, best-first (attrs decoded to\n * plain JS values). Refused with a cross-model guard if the collection was\n * written with a different embedder than the server's.\n */\n recall(\n collection: string,\n query: string,\n opts: RecallOptions = {},\n ): Promise<Hit[]> {\n return this.searchRequest(`/collections/${enc(collection)}/recall`, {\n query,\n top_k: opts.topK,\n min_score: opts.minScore,\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckedup/nidus",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "JavaScript/TypeScript client for nidus — a small, fast vector store. Connects to a local or remote `nidus serve` over HTTP.",
5
5
  "type": "module",
6
6
  "license": "MIT",