@duckedup/nidus 0.86.0 → 0.87.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
@@ -181,6 +181,26 @@ await db.textSearch({ field: "title", query: "ru", prefix: true });
181
181
  await db.textSearch({ clauses: [{ field: "title", query: "ru", prefix: true }] });
182
182
  ```
183
183
 
184
+ ## Suggesting completions
185
+
186
+ `suggest` completes a partial word from an indexed field's vocabulary, ranked by
187
+ document frequency (the commonest term first), for an autocomplete dropdown. That is
188
+ the opposite of how a prefix clause ranks documents, so it is its own method rather
189
+ than a `textSearch` option. Completions are real words: surface forms are indexed
190
+ alongside stems, so every keystroke of `"running"` completes to `"running"` rather
191
+ than to the stem `"run"`.
192
+
193
+ ```ts
194
+ const { suggestions, matched } = await db.suggest({
195
+ collection: "docs",
196
+ field: "body",
197
+ prefix: "vec",
198
+ limit: 10,
199
+ });
200
+ for (const { term, df } of suggestions) console.log(term, df);
201
+ // matched > suggestions.length means the server's 256-term cap truncated the list.
202
+ ```
203
+
184
204
  ## Explaining and highlighting a hit
185
205
 
186
206
  `explain` reports what each leg and each matched clause contributed; `highlight` returns
package/dist/index.cjs CHANGED
@@ -440,6 +440,18 @@ var NidusClient = class {
440
440
  rerank: encodeRerank(opts.rerank)
441
441
  });
442
442
  }
443
+ /**
444
+ * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by
445
+ * document frequency (commonest first), which is the opposite of how a prefix clause
446
+ * ranks documents. Completions are stems: the prefix is folded, not stemmed.
447
+ */
448
+ suggest(opts) {
449
+ return this.request(
450
+ "POST",
451
+ `/collections/${enc(opts.collection)}/suggest`,
452
+ prune({ field: opts.field, prefix: opts.prefix, limit: opts.limit })
453
+ );
454
+ }
443
455
  /**
444
456
  * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes
445
457
  * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/annotations.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 AggregateOptions,\n Aggregation,\n AnnInfo,\n AnnotationOptions,\n Annotations,\n AttrInput,\n ClauseScore,\n Expansion,\n ClusterStatus,\n Decay,\n DecodedRecord,\n DecodedValue,\n Expand,\n Filter,\n FilterIndexField,\n Footprint,\n Fragment,\n FtsCombine,\n FtsField,\n Highlight,\n HighlightOptions,\n Hit,\n HybridQuerySpelling,\n HybridSearchBase,\n HybridSearchOptions,\n LegScore,\n LimitPer,\n ListOptions,\n NidusRecord,\n OrderBy,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n Predicate,\n ProjectionOptions,\n QueryPath,\n QueryPlan,\n RankBy,\n RankingOptions,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n TextClause,\n TextQuerySpelling,\n TextSearchBase,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\n","//! Decoding a hit's optional annotations — the opt-in \"why did this match\".\n//\n// One rule here is JS's alone. The server reports a highlight span as a **UTF-8 byte**\n// range into the fragment text, but a JS string is indexed in UTF-16 code units, so\n// `text.slice(...span)` on a raw span is wrong for any non-ASCII excerpt. Converted here,\n// once, so a caller's obvious slice is the right one.\n\nimport type { Annotations, Fragment, Highlight } from \"./types.js\";\n\n/** A fragment as it arrives: `spans` are UTF-8 byte offsets into `text`. */\ninterface WireFragment {\n text: string;\n spans: [number, number][];\n}\n\ninterface WireHighlight {\n field: string;\n fragments: WireFragment[];\n}\n\n/** A hit's annotations as they arrive, before the span offsets are converted. */\nexport interface WireAnnotations {\n vector?: { rank: number; score: number };\n text?: { rank: number; score: number };\n clauses?: {\n field: string;\n score: number;\n expansion?: { matched: number; scored: number };\n }[];\n highlights?: WireHighlight[];\n}\n\n/**\n * Decode a hit's annotations, converting every highlight span to JS string indices. The\n * parts the server omitted stay omitted rather than becoming empty arrays.\n */\nexport function decodeAnnotations(a: WireAnnotations): Annotations {\n const out: Annotations = {};\n if (a.vector) out.vector = a.vector;\n if (a.text) out.text = a.text;\n if (a.clauses) out.clauses = a.clauses;\n if (a.highlights) out.highlights = a.highlights.map(decodeHighlight);\n return out;\n}\n\nfunction decodeHighlight(h: WireHighlight): Highlight {\n return { field: h.field, fragments: h.fragments.map(decodeFragment) };\n}\n\nfunction decodeFragment(fr: WireFragment): Fragment {\n return { text: fr.text, spans: toStringIndices(fr.text, fr.spans) };\n}\n\n/**\n * Convert UTF-8 byte ranges into `text` to JS string indices (UTF-16 code units), so\n * `text.slice(...span)` yields the matched term. An all-ASCII excerpt needs no conversion\n * and is the common case, so it is detected before any table is built.\n */\nexport function toStringIndices(\n text: string,\n spans: [number, number][],\n): [number, number][] {\n if (spans.length === 0 || isAscii(text)) return spans;\n const index = byteToUnit(text);\n const at = (b: number): number =>\n index[Math.min(Math.max(b, 0), index.length - 1)]!;\n return spans.map(([start, end]): [number, number] => [at(start), at(end)]);\n}\n\n/** One entry per byte of `text` (plus its end), holding that byte's UTF-16 index. */\nfunction byteToUnit(text: string): number[] {\n const index: number[] = [];\n let unit = 0;\n // A byte *inside* a codepoint maps to that codepoint's start. Spans land on token\n // boundaries, so this only keeps a malformed offset from landing mid-surrogate.\n for (const ch of text) {\n for (let n = utf8Len(ch.codePointAt(0)!); n > 0; n--) index.push(unit);\n unit += ch.length;\n }\n index.push(unit);\n return index;\n}\n\nfunction utf8Len(codePoint: number): number {\n if (codePoint < 0x80) return 1;\n if (codePoint < 0x800) return 2;\n return codePoint < 0x10000 ? 3 : 4;\n}\n\n/** True when every code unit is ASCII, i.e. byte offsets already *are* string indices. */\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 0x7f) return false;\n }\n return true;\n}\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//\n// One rule is JS's alone. The store's `Int` and `Float` are separate types compared\n// same-type only, but JS has one `number` and `1.0 === 1`, so `Number.isInteger` has to\n// decide. A whole-numbered measurement therefore lands as an `Int` in whichever records\n// it came out round, and a `Float` range filter then skips exactly those: write such a\n// field with `v.float`. Go and Python have the types JS lacks and decide from them.\n\nimport type { AttrInput, DecodedValue, Value } from \"./types.js\";\n\n/** Every tag this SDK version knows, in the order `decodeValue` tries them. */\nconst TAGS = [\"Str\", \"Int\", \"Bool\", \"List\", \"Float\", \"DateTime\"] as const;\n\n/**\n * Value constructors mirroring the `Value` variants. `v.int` requires a safe\n * integer and `v.float` a finite number — `NaN`/`Infinity` have no JSON spelling,\n * and `JSON.stringify` would quietly write `null`.\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 float: (n: number): Value => {\n if (typeof n !== \"number\" || !Number.isFinite(n)) {\n throw new TypeError(`v.float expects a finite number, got ${n}`);\n }\n return { Float: n };\n },\n bool: (b: boolean): Value => ({ Bool: b }),\n list: (items: string[]): Value => ({ List: items }),\n /**\n * A UTC instant, from a `Date` or a raw epoch-millisecond count. Milliseconds is\n * the wire type, so there is no sub-millisecond precision and no timezone.\n */\n datetime: (when: Date | number): Value => {\n const ms = when instanceof Date ? when.getTime() : when;\n if (!Number.isSafeInteger(ms)) {\n throw new TypeError(\n `v.datetime expects a valid Date or epoch ms, got ${when}`,\n );\n }\n return { DateTime: ms };\n },\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 TAGS.some((tag) => tag in x);\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-finite number, an invalid `Date`, 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 Number.isInteger(input) ? v.int(input) : v.float(input);\n case \"object\":\n // Date before the array check: both are objects, only one is a list.\n if (input instanceof Date) return v.datetime(input);\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 if (\"Float\" in value) return value.Float;\n // A Date, not the raw number: a number would demote every instant to an Int\n // when a decoded attrs map is written back.\n if (\"DateTime\" in value) return new Date(value.DateTime);\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 { decodeAnnotations, type WireAnnotations } from \"./annotations.js\";\nimport { NidusError } from \"./errors.js\";\nimport type {\n AggregateOptions,\n Aggregation,\n BatchSearchOptions,\n ClusterStatus,\n DecodedRecord,\n Expand,\n Filter,\n FilterIndexField,\n FtsField,\n HighlightOptions,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n QueryPlan,\n RankBy,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\nimport { decodeAttrs, decodeValue, 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 /**\n * Readiness: whether this instance can serve. A `503` is the negative answer, not an\n * error, so a poll loop branches on `ready` instead of catching. Other failures throw.\n */\n async ready(): Promise<Readiness> {\n const res = await this.raw(\"GET\", \"/ready\");\n const text = await res.text();\n if (res.status === 503) return { ready: false, reason: extractError(text, 503) };\n if (!res.ok) throw new NidusError(extractError(text, res.status), res.status);\n return JSON.parse(text) as Readiness;\n }\n\n /** Cluster role, writer-handle state, fencing token, commit counter, staleness. */\n cluster(): Promise<ClusterStatus> {\n return this.request<ClusterStatus>(\"GET\", \"/cluster\");\n }\n\n /** The readable commit points and this instance's pin, if any. */\n versions(): Promise<StoreVersions> {\n return this.request<StoreVersions>(\"GET\", \"/versions\");\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 /**\n * Declare the full-text-indexed attribute fields for a collection. A bare string\n * takes the server's BM25/analyzer defaults; an {@link FtsField} object tunes `k1`,\n * `b`, and the analyzer for that field alone.\n */\n async setFtsSchema(\n name: string,\n fields: (string | FtsField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/fts-schema`, {\n fields: fields.map(encodeFtsField),\n });\n }\n\n /**\n * Declare which attribute fields are indexed for the text predicates (`Fuzzy`,\n * `ContainsAllTokens`, `ContainsAnyToken`, `ContainsTokenSequence`, `Regex`). Fields\n * already written are indexed as part of applying the declaration.\n *\n * This changes how fast those predicates run, never what they return: the index\n * proposes candidate documents and the predicate itself still decides. The cost is\n * paid at write time and in memory. Pass an empty array to drop the declaration.\n */\n async setFilterIndex(\n name: string,\n fields: (string | FilterIndexField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/filter-index`, {\n fields: fields.map(encodeFilterIndexField),\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 offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */\n searchWithPlan(\n opts: SearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search\", {\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Records most like an existing one. The source record itself is never returned. */\n searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */\n searchSimilarWithPlan(\n opts: SimilarSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /**\n * BM25 full-text search over one indexed field, or over a `clauses` list folded by\n * `combine` (`\"Sum\"` unless said otherwise). Naming the fields both ways is a `400`.\n */\n textSearch(opts: TextSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/text-search\", {\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, query: opts.query, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /**\n * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes\n * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.\n */\n hybridSearch(opts: HybridSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */\n hybridSearchWithPlan(\n opts: HybridSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\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 include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n order_by: opts.orderBy,\n });\n }\n\n /**\n * Count the records matching a filter and sum the named attributes. Answered from the\n * in-RAM index alone — no record is built and no vector is read.\n */\n async aggregate(opts: AggregateOptions = {}): Promise<Aggregation> {\n const res = await this.request<RawAggregation>(\n \"POST\",\n \"/aggregate\",\n prune({\n scope: opts.scope ?? [],\n filter: opts.filter ?? [],\n sum: opts.sum ?? [],\n group_by: opts.groupBy,\n }),\n );\n // Every sum is an `Int` or a `Float`, both of which decode to a JS number.\n return {\n count: res.count,\n sums: decodeAttrs(res.sums) as Record<string, number>,\n // Kept absent, not `undefined`, so an ungrouped answer is the shape it always was.\n ...(res.groups\n ? {\n groups: res.groups.map((g) => ({\n value: g.value === null ? null : decodeValue(g.value),\n count: g.count,\n sums: decodeAttrs(g.sums) as Record<string, number>,\n })),\n }\n : {}),\n ...(res.groups_truncated ? { groupsTruncated: true } : {}),\n };\n }\n\n /**\n * Answer several vector queries in one round-trip (16 max). Returns one ranking per\n * query in request order, or — with `opts.fuse` — a single array holding the one fused\n * ranking, so the return shape is uniform either way.\n *\n * The server validates the whole batch before running any leg, so a malformed query\n * fails the call rather than returning a partial answer that cannot be told apart.\n */\n async batchSearch(opts: BatchSearchOptions): Promise<Hit[][]> {\n const body = prune({\n queries: opts.queries.map((q) => ({\n query: q.query,\n scope: q.scope ?? [],\n top_k: q.topK,\n offset: q.offset,\n min_score: q.minScore,\n filter: q.filter ?? [],\n exact: q.exact,\n include_attributes: q.includeAttributes,\n exclude_attributes: q.excludeAttributes,\n rank_by: encodeRankBy(q.rankBy),\n limit_per: q.limitPer,\n diversity: q.diversity,\n expand: encodeExpand(q.expand),\n })),\n fuse: opts.fuse\n ? prune({\n rrf_k: opts.fuse.rrfK,\n weights: opts.fuse.weights,\n top_k: opts.fuse.topK,\n })\n : undefined,\n });\n const res = await this.request<RawBatchSearch>(\n \"POST\",\n \"/search/batch\",\n body,\n );\n return (res.fused ? [res.fused] : (res.results ?? [])).map((hits) =>\n hits.map((h) => this.decodeHit(h)),\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 a `nidus.summary` attr (requires the server to have a\n * summarizer). The raw text is always stored under `nidus.text`. `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n *\n * Read `id` off the result rather than assuming the one you passed:\n * `opts.dedupeThreshold` can redirect the write onto a near-duplicate.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<RememberResult> {\n const res = await this.request<Partial<RememberResult> | undefined>(\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 ttl_seconds: opts.ttlSeconds,\n dedupe_threshold: opts.dedupeThreshold,\n }),\n );\n // A server predating the echoed fields answers `{ok, upserted}`; falling back to the\n // requested id keeps that case honest instead of reporting `undefined` as the target.\n return {\n id: res?.id ?? id,\n upserted: res?.upserted ?? 0,\n deduped: res?.deduped ?? false,\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 diversity: opts.diversity,\n rollup: encodeRollup(opts.rollup),\n rerank: encodeRerank(opts.rerank),\n reinforce: opts.reinforce,\n extend_ttl_seconds: opts.extendTtlSeconds,\n rank_by: encodeRankBy(opts.rankBy),\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 /** Adopt a writer's newer committed state. Returns whether anything was adopted. */\n async refresh(): Promise<boolean> {\n const res = await this.request<{ adopted: boolean }>(\"POST\", \"/refresh\", {});\n return res.adopted;\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) => this.decodeHit(h));\n }\n\n /** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */\n private async searchRequestWithPlan(\n path: string,\n body: Record<string, unknown>,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n const res = await this.request<{ hits: RawHit[]; plan: RawQueryPlan }>(\n \"POST\",\n path,\n prune({ ...body, plan: true }),\n );\n return {\n hits: res.hits.map((h) => this.decodeHit(h)),\n plan: decodeQueryPlan(res.plan),\n };\n }\n\n /** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */\n private decodeHit(h: RawHit): Hit {\n return {\n collection: h.collection,\n id: h.id,\n score: h.score,\n attrs: decodeAttrs(h.attrs),\n // Kept absent, not `undefined`, so an unannotated hit is the shape it always was.\n ...(h.annotations\n ? { annotations: decodeAnnotations(h.annotations) }\n : {}),\n ...(h.context !== undefined ? { context: h.context } : {}),\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 = 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 annotations?: WireAnnotations;\n context?: string;\n}\n\n/** A `QueryPlan` as it arrives on the wire (snake_case), before camelCasing. */\ninterface RawQueryPlan {\n path: string;\n rows_scanned?: number;\n candidates?: {\n surfaced: number;\n survived: number;\n dropped_out_of_scope: number;\n dropped_stale: number;\n dropped_filtered: number;\n dropped_min_score: number;\n };\n narrowing: { state: PlanNarrowing[\"state\"]; candidates?: number };\n timings: {\n narrow_us?: number;\n gather_us?: number;\n walk_us?: number;\n resolve_us?: number;\n first_pass_us?: number;\n rescore_us?: number;\n score_us?: number;\n total_us: number;\n };\n}\n\n/** Wire `QueryPlan` into its camelCase {@link QueryPlan} shape. */\nfunction decodeQueryPlan(p: RawQueryPlan): QueryPlan {\n const candidates: PlanCandidates | undefined = p.candidates\n ? {\n surfaced: p.candidates.surfaced,\n survived: p.candidates.survived,\n droppedOutOfScope: p.candidates.dropped_out_of_scope,\n droppedStale: p.candidates.dropped_stale,\n droppedFiltered: p.candidates.dropped_filtered,\n droppedMinScore: p.candidates.dropped_min_score,\n }\n : undefined;\n const t = p.timings;\n const timings: PlanTimings = {\n ...(t.narrow_us !== undefined ? { narrowUs: t.narrow_us } : {}),\n ...(t.gather_us !== undefined ? { gatherUs: t.gather_us } : {}),\n ...(t.walk_us !== undefined ? { walkUs: t.walk_us } : {}),\n ...(t.resolve_us !== undefined ? { resolveUs: t.resolve_us } : {}),\n ...(t.first_pass_us !== undefined ? { firstPassUs: t.first_pass_us } : {}),\n ...(t.rescore_us !== undefined ? { rescoreUs: t.rescore_us } : {}),\n ...(t.score_us !== undefined ? { scoreUs: t.score_us } : {}),\n totalUs: t.total_us,\n };\n return {\n path: p.path,\n ...(p.rows_scanned !== undefined ? { rowsScanned: p.rows_scanned } : {}),\n ...(candidates ? { candidates } : {}),\n narrowing: {\n state: p.narrowing.state,\n ...(p.narrowing.candidates !== undefined\n ? { candidates: p.narrowing.candidates }\n : {}),\n },\n timings,\n };\n}\n\n/** An `/aggregate` response, whose sums arrive as tagged {@link Value}s. */\ninterface RawAggregation {\n count: number;\n sums: Record<string, Value>;\n groups?: {\n value: Value | null;\n count: number;\n sums: Record<string, Value>;\n }[];\n groups_truncated?: boolean;\n}\n\n/** A `/search/batch` response: exactly one of the two fields is present. */\ninterface RawBatchSearch {\n results?: RawHit[][];\n fused?: RawHit[];\n}\n\n/** Encode `rankBy` to its externally-tagged wire form, dropping the knobs left unset. */\n/** camelCase → the wire's snake_case, omitting the object entirely when unset. */\nfunction encodeExpand(e: Expand | undefined): unknown {\n if (!e) return undefined;\n return prune({\n radius: e.radius,\n parent_field: e.parentField,\n index_field: e.indexField,\n text_field: e.textField,\n });\n}\n\nfunction encodeRollup(r: Rollup | undefined): unknown {\n if (!r) return undefined;\n return prune({ per_parent: r.perParent, neighbours: r.neighbours });\n}\n\nfunction encodeRankBy(rank: RankBy | undefined): unknown {\n if (!rank) return undefined;\n const d = rank.decay;\n return {\n Decay: prune({\n field: d.field,\n origin: d.origin instanceof Date ? d.origin.getTime() : d.origin,\n scale: d.scale,\n decay: d.decay,\n lambda: d.lambda,\n missing: d.missing,\n count_field: d.countField,\n count_scale: d.countScale,\n count_lambda: d.countLambda,\n }),\n };\n}\n\n/** Encode `highlight`: `true` is the empty object the server reads as \"all defaults\". */\nfunction encodeHighlight(h: boolean | HighlightOptions | undefined): unknown {\n if (h === undefined || h === false) return undefined;\n if (h === true) return {};\n return prune({\n max_fragments: h.maxFragments,\n fragment_chars: h.fragmentChars,\n });\n}\n\n/** Encode `rerank`. Undefined sub-fields drop out at `JSON.stringify`, not here. */\nfunction encodeRerank(r: RerankOptions | undefined): unknown {\n if (r === undefined) return undefined;\n return { query: r.query, overscan: r.overscan, text_attr: r.textAttr };\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/**\n * Encode one `setFtsSchema` field. A string passes through as the server's bare-name\n * form; an object becomes the snake_case body, pruned so an unset knob keeps the\n * server's default rather than being sent as `undefined`.\n */\nfunction encodeFtsField(f: string | FtsField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n k1: f.k1,\n b: f.b,\n language: f.language,\n ascii_folding: f.asciiFolding,\n max_token_len: f.maxTokenLen,\n });\n}\n\n/**\n * Encode one `setFilterIndex` field, on the same bare-name-or-object rule as\n * {@link encodeFtsField}. Pruning matters here: the server defaults both structures to\n * `true`, so sending an explicit `undefined` would be indistinguishable from `false`.\n */\nfunction encodeFilterIndexField(f: string | FilterIndexField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n tokens: f.tokens,\n trigrams: f.trigrams,\n });\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, Float↔Float by IEEE, Str↔Str\n// lexical, Bool↔Bool, DateTime↔DateTime as instants), so an operand's encoded type\n// has to match the attribute's: `ge(\"score\", v.float(2))`, not `ge(\"score\", 2)`.\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 /**\n * {@link f.glob}, ignoring **ASCII** case on both sides — `\"Src/*\"` matches\n * `\"src/main.rs\"`. Non-ASCII is not folded (`É` does not match `é`).\n */\n iglob: (key: string, pattern: string): Predicate => ({\n IGlob: [key, pattern],\n }),\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 /** `attrs[key]` is a `List` containing `value` (whole-element, not substring). */\n contains: (key: string, value: AttrInput): Predicate => ({\n Contains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a present `List` not containing `value`. */\n notContains: (key: string, value: AttrInput): Predicate => ({\n NotContains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a `List` sharing at least one element with `values`. */\n containsAny: (key: string, values: AttrInput[]): Predicate => ({\n ContainsAny: [key, values.map(encodeValue)],\n }),\n /** Every sub-predicate holds. `all()` is `true`. */\n all: (...preds: Predicate[]): Predicate => ({ All: preds }),\n /** At least one sub-predicate holds. `any()` is `false`. */\n any: (...preds: Predicate[]): Predicate => ({ Any: preds }),\n /**\n * The sub-predicate does not hold. Differs from {@link f.ne} on an absent key:\n * `not(eq(k, v))` matches a record with no `k`, `ne(k, v)` does not.\n */\n not: (pred: Predicate): Predicate => ({ Not: pred }),\n /**\n * `attrs[key]` is within `maxEdits` Levenshtein edits of `text`, ASCII-case-folded on\n * both sides; a `List` matches if any element does. The only three-element predicate.\n * A `maxEdits` above 8 is refused by the server, not clamped.\n */\n fuzzy: (key: string, text: string, maxEdits: number): Predicate => ({\n Fuzzy: [key, text, maxEdits],\n }),\n /**\n * Every token of `text` appears among `attrs[key]`'s tokens, in any order. Tokens are\n * ASCII-case-folded runs of alphanumerics; a `List` matches if any single element does.\n */\n containsAllTokens: (key: string, text: string): Predicate => ({\n ContainsAllTokens: [key, text],\n }),\n /** At least one token of `text` appears among `attrs[key]`'s tokens. Empty never matches. */\n containsAnyToken: (key: string, text: string): Predicate => ({\n ContainsAnyToken: [key, text],\n }),\n /** `text`'s tokens appear consecutively and in order — a phrase match. */\n containsTokenSequence: (key: string, text: string): Predicate => ({\n ContainsTokenSequence: [key, text],\n }),\n /**\n * `attrs[key]` matches the regular expression, **anchored at both ends** like\n * {@link f.glob} — `.*` opts back into a substring search, and `(?i)` into case folding.\n * The syntax is Rust's `regex`, not JS's: no backreferences and no lookaround.\n */\n regex: (key: string, pattern: string): Predicate => ({ Regex: [key, pattern] }),\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/annotations.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 AggregateOptions,\n Aggregation,\n AnnInfo,\n AnnotationOptions,\n Annotations,\n AttrInput,\n ClauseScore,\n Expansion,\n ClusterStatus,\n Decay,\n DecodedRecord,\n DecodedValue,\n Expand,\n Filter,\n FilterIndexField,\n Footprint,\n Fragment,\n FtsCombine,\n FtsField,\n Highlight,\n HighlightOptions,\n Hit,\n HybridQuerySpelling,\n HybridSearchBase,\n HybridSearchOptions,\n LegScore,\n LimitPer,\n ListOptions,\n NidusRecord,\n OrderBy,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n Predicate,\n ProjectionOptions,\n QueryPath,\n QueryPlan,\n RankBy,\n RankingOptions,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n Suggestion,\n Suggestions,\n SuggestOptions,\n TextClause,\n TextQuerySpelling,\n TextSearchBase,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\n","//! Decoding a hit's optional annotations — the opt-in \"why did this match\".\n//\n// One rule here is JS's alone. The server reports a highlight span as a **UTF-8 byte**\n// range into the fragment text, but a JS string is indexed in UTF-16 code units, so\n// `text.slice(...span)` on a raw span is wrong for any non-ASCII excerpt. Converted here,\n// once, so a caller's obvious slice is the right one.\n\nimport type { Annotations, Fragment, Highlight } from \"./types.js\";\n\n/** A fragment as it arrives: `spans` are UTF-8 byte offsets into `text`. */\ninterface WireFragment {\n text: string;\n spans: [number, number][];\n}\n\ninterface WireHighlight {\n field: string;\n fragments: WireFragment[];\n}\n\n/** A hit's annotations as they arrive, before the span offsets are converted. */\nexport interface WireAnnotations {\n vector?: { rank: number; score: number };\n text?: { rank: number; score: number };\n clauses?: {\n field: string;\n score: number;\n expansion?: { matched: number; scored: number };\n }[];\n highlights?: WireHighlight[];\n}\n\n/**\n * Decode a hit's annotations, converting every highlight span to JS string indices. The\n * parts the server omitted stay omitted rather than becoming empty arrays.\n */\nexport function decodeAnnotations(a: WireAnnotations): Annotations {\n const out: Annotations = {};\n if (a.vector) out.vector = a.vector;\n if (a.text) out.text = a.text;\n if (a.clauses) out.clauses = a.clauses;\n if (a.highlights) out.highlights = a.highlights.map(decodeHighlight);\n return out;\n}\n\nfunction decodeHighlight(h: WireHighlight): Highlight {\n return { field: h.field, fragments: h.fragments.map(decodeFragment) };\n}\n\nfunction decodeFragment(fr: WireFragment): Fragment {\n return { text: fr.text, spans: toStringIndices(fr.text, fr.spans) };\n}\n\n/**\n * Convert UTF-8 byte ranges into `text` to JS string indices (UTF-16 code units), so\n * `text.slice(...span)` yields the matched term. An all-ASCII excerpt needs no conversion\n * and is the common case, so it is detected before any table is built.\n */\nexport function toStringIndices(\n text: string,\n spans: [number, number][],\n): [number, number][] {\n if (spans.length === 0 || isAscii(text)) return spans;\n const index = byteToUnit(text);\n const at = (b: number): number =>\n index[Math.min(Math.max(b, 0), index.length - 1)]!;\n return spans.map(([start, end]): [number, number] => [at(start), at(end)]);\n}\n\n/** One entry per byte of `text` (plus its end), holding that byte's UTF-16 index. */\nfunction byteToUnit(text: string): number[] {\n const index: number[] = [];\n let unit = 0;\n // A byte *inside* a codepoint maps to that codepoint's start. Spans land on token\n // boundaries, so this only keeps a malformed offset from landing mid-surrogate.\n for (const ch of text) {\n for (let n = utf8Len(ch.codePointAt(0)!); n > 0; n--) index.push(unit);\n unit += ch.length;\n }\n index.push(unit);\n return index;\n}\n\nfunction utf8Len(codePoint: number): number {\n if (codePoint < 0x80) return 1;\n if (codePoint < 0x800) return 2;\n return codePoint < 0x10000 ? 3 : 4;\n}\n\n/** True when every code unit is ASCII, i.e. byte offsets already *are* string indices. */\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 0x7f) return false;\n }\n return true;\n}\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//\n// One rule is JS's alone. The store's `Int` and `Float` are separate types compared\n// same-type only, but JS has one `number` and `1.0 === 1`, so `Number.isInteger` has to\n// decide. A whole-numbered measurement therefore lands as an `Int` in whichever records\n// it came out round, and a `Float` range filter then skips exactly those: write such a\n// field with `v.float`. Go and Python have the types JS lacks and decide from them.\n\nimport type { AttrInput, DecodedValue, Value } from \"./types.js\";\n\n/** Every tag this SDK version knows, in the order `decodeValue` tries them. */\nconst TAGS = [\"Str\", \"Int\", \"Bool\", \"List\", \"Float\", \"DateTime\"] as const;\n\n/**\n * Value constructors mirroring the `Value` variants. `v.int` requires a safe\n * integer and `v.float` a finite number — `NaN`/`Infinity` have no JSON spelling,\n * and `JSON.stringify` would quietly write `null`.\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 float: (n: number): Value => {\n if (typeof n !== \"number\" || !Number.isFinite(n)) {\n throw new TypeError(`v.float expects a finite number, got ${n}`);\n }\n return { Float: n };\n },\n bool: (b: boolean): Value => ({ Bool: b }),\n list: (items: string[]): Value => ({ List: items }),\n /**\n * A UTC instant, from a `Date` or a raw epoch-millisecond count. Milliseconds is\n * the wire type, so there is no sub-millisecond precision and no timezone.\n */\n datetime: (when: Date | number): Value => {\n const ms = when instanceof Date ? when.getTime() : when;\n if (!Number.isSafeInteger(ms)) {\n throw new TypeError(\n `v.datetime expects a valid Date or epoch ms, got ${when}`,\n );\n }\n return { DateTime: ms };\n },\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 TAGS.some((tag) => tag in x);\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-finite number, an invalid `Date`, 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 Number.isInteger(input) ? v.int(input) : v.float(input);\n case \"object\":\n // Date before the array check: both are objects, only one is a list.\n if (input instanceof Date) return v.datetime(input);\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 if (\"Float\" in value) return value.Float;\n // A Date, not the raw number: a number would demote every instant to an Int\n // when a decoded attrs map is written back.\n if (\"DateTime\" in value) return new Date(value.DateTime);\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 { decodeAnnotations, type WireAnnotations } from \"./annotations.js\";\nimport { NidusError } from \"./errors.js\";\nimport type {\n AggregateOptions,\n Aggregation,\n BatchSearchOptions,\n ClusterStatus,\n DecodedRecord,\n Expand,\n Filter,\n FilterIndexField,\n FtsField,\n HighlightOptions,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n QueryPlan,\n RankBy,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n Suggestions,\n SuggestOptions,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\nimport { decodeAttrs, decodeValue, 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 /**\n * Readiness: whether this instance can serve. A `503` is the negative answer, not an\n * error, so a poll loop branches on `ready` instead of catching. Other failures throw.\n */\n async ready(): Promise<Readiness> {\n const res = await this.raw(\"GET\", \"/ready\");\n const text = await res.text();\n if (res.status === 503) return { ready: false, reason: extractError(text, 503) };\n if (!res.ok) throw new NidusError(extractError(text, res.status), res.status);\n return JSON.parse(text) as Readiness;\n }\n\n /** Cluster role, writer-handle state, fencing token, commit counter, staleness. */\n cluster(): Promise<ClusterStatus> {\n return this.request<ClusterStatus>(\"GET\", \"/cluster\");\n }\n\n /** The readable commit points and this instance's pin, if any. */\n versions(): Promise<StoreVersions> {\n return this.request<StoreVersions>(\"GET\", \"/versions\");\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 /**\n * Declare the full-text-indexed attribute fields for a collection. A bare string\n * takes the server's BM25/analyzer defaults; an {@link FtsField} object tunes `k1`,\n * `b`, and the analyzer for that field alone.\n */\n async setFtsSchema(\n name: string,\n fields: (string | FtsField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/fts-schema`, {\n fields: fields.map(encodeFtsField),\n });\n }\n\n /**\n * Declare which attribute fields are indexed for the text predicates (`Fuzzy`,\n * `ContainsAllTokens`, `ContainsAnyToken`, `ContainsTokenSequence`, `Regex`). Fields\n * already written are indexed as part of applying the declaration.\n *\n * This changes how fast those predicates run, never what they return: the index\n * proposes candidate documents and the predicate itself still decides. The cost is\n * paid at write time and in memory. Pass an empty array to drop the declaration.\n */\n async setFilterIndex(\n name: string,\n fields: (string | FilterIndexField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/filter-index`, {\n fields: fields.map(encodeFilterIndexField),\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 offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */\n searchWithPlan(\n opts: SearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search\", {\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Records most like an existing one. The source record itself is never returned. */\n searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */\n searchSimilarWithPlan(\n opts: SimilarSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /**\n * BM25 full-text search over one indexed field, or over a `clauses` list folded by\n * `combine` (`\"Sum\"` unless said otherwise). Naming the fields both ways is a `400`.\n */\n textSearch(opts: TextSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/text-search\", {\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, query: opts.query, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /**\n * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by\n * document frequency (commonest first), which is the opposite of how a prefix clause\n * ranks documents. Completions are stems: the prefix is folded, not stemmed.\n */\n suggest(opts: SuggestOptions): Promise<Suggestions> {\n return this.request<Suggestions>(\n \"POST\",\n `/collections/${enc(opts.collection)}/suggest`,\n prune({ field: opts.field, prefix: opts.prefix, limit: opts.limit }),\n );\n }\n\n /**\n * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes\n * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.\n */\n hybridSearch(opts: HybridSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */\n hybridSearchWithPlan(\n opts: HybridSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\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 include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n order_by: opts.orderBy,\n });\n }\n\n /**\n * Count the records matching a filter and sum the named attributes. Answered from the\n * in-RAM index alone — no record is built and no vector is read.\n */\n async aggregate(opts: AggregateOptions = {}): Promise<Aggregation> {\n const res = await this.request<RawAggregation>(\n \"POST\",\n \"/aggregate\",\n prune({\n scope: opts.scope ?? [],\n filter: opts.filter ?? [],\n sum: opts.sum ?? [],\n group_by: opts.groupBy,\n }),\n );\n // Every sum is an `Int` or a `Float`, both of which decode to a JS number.\n return {\n count: res.count,\n sums: decodeAttrs(res.sums) as Record<string, number>,\n // Kept absent, not `undefined`, so an ungrouped answer is the shape it always was.\n ...(res.groups\n ? {\n groups: res.groups.map((g) => ({\n value: g.value === null ? null : decodeValue(g.value),\n count: g.count,\n sums: decodeAttrs(g.sums) as Record<string, number>,\n })),\n }\n : {}),\n ...(res.groups_truncated ? { groupsTruncated: true } : {}),\n };\n }\n\n /**\n * Answer several vector queries in one round-trip (16 max). Returns one ranking per\n * query in request order, or — with `opts.fuse` — a single array holding the one fused\n * ranking, so the return shape is uniform either way.\n *\n * The server validates the whole batch before running any leg, so a malformed query\n * fails the call rather than returning a partial answer that cannot be told apart.\n */\n async batchSearch(opts: BatchSearchOptions): Promise<Hit[][]> {\n const body = prune({\n queries: opts.queries.map((q) => ({\n query: q.query,\n scope: q.scope ?? [],\n top_k: q.topK,\n offset: q.offset,\n min_score: q.minScore,\n filter: q.filter ?? [],\n exact: q.exact,\n include_attributes: q.includeAttributes,\n exclude_attributes: q.excludeAttributes,\n rank_by: encodeRankBy(q.rankBy),\n limit_per: q.limitPer,\n diversity: q.diversity,\n expand: encodeExpand(q.expand),\n })),\n fuse: opts.fuse\n ? prune({\n rrf_k: opts.fuse.rrfK,\n weights: opts.fuse.weights,\n top_k: opts.fuse.topK,\n })\n : undefined,\n });\n const res = await this.request<RawBatchSearch>(\n \"POST\",\n \"/search/batch\",\n body,\n );\n return (res.fused ? [res.fused] : (res.results ?? [])).map((hits) =>\n hits.map((h) => this.decodeHit(h)),\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 a `nidus.summary` attr (requires the server to have a\n * summarizer). The raw text is always stored under `nidus.text`. `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n *\n * Read `id` off the result rather than assuming the one you passed:\n * `opts.dedupeThreshold` can redirect the write onto a near-duplicate.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<RememberResult> {\n const res = await this.request<Partial<RememberResult> | undefined>(\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 ttl_seconds: opts.ttlSeconds,\n dedupe_threshold: opts.dedupeThreshold,\n }),\n );\n // A server predating the echoed fields answers `{ok, upserted}`; falling back to the\n // requested id keeps that case honest instead of reporting `undefined` as the target.\n return {\n id: res?.id ?? id,\n upserted: res?.upserted ?? 0,\n deduped: res?.deduped ?? false,\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 diversity: opts.diversity,\n rollup: encodeRollup(opts.rollup),\n rerank: encodeRerank(opts.rerank),\n reinforce: opts.reinforce,\n extend_ttl_seconds: opts.extendTtlSeconds,\n rank_by: encodeRankBy(opts.rankBy),\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 /** Adopt a writer's newer committed state. Returns whether anything was adopted. */\n async refresh(): Promise<boolean> {\n const res = await this.request<{ adopted: boolean }>(\"POST\", \"/refresh\", {});\n return res.adopted;\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) => this.decodeHit(h));\n }\n\n /** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */\n private async searchRequestWithPlan(\n path: string,\n body: Record<string, unknown>,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n const res = await this.request<{ hits: RawHit[]; plan: RawQueryPlan }>(\n \"POST\",\n path,\n prune({ ...body, plan: true }),\n );\n return {\n hits: res.hits.map((h) => this.decodeHit(h)),\n plan: decodeQueryPlan(res.plan),\n };\n }\n\n /** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */\n private decodeHit(h: RawHit): Hit {\n return {\n collection: h.collection,\n id: h.id,\n score: h.score,\n attrs: decodeAttrs(h.attrs),\n // Kept absent, not `undefined`, so an unannotated hit is the shape it always was.\n ...(h.annotations\n ? { annotations: decodeAnnotations(h.annotations) }\n : {}),\n ...(h.context !== undefined ? { context: h.context } : {}),\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 = 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 annotations?: WireAnnotations;\n context?: string;\n}\n\n/** A `QueryPlan` as it arrives on the wire (snake_case), before camelCasing. */\ninterface RawQueryPlan {\n path: string;\n rows_scanned?: number;\n candidates?: {\n surfaced: number;\n survived: number;\n dropped_out_of_scope: number;\n dropped_stale: number;\n dropped_filtered: number;\n dropped_min_score: number;\n };\n narrowing: { state: PlanNarrowing[\"state\"]; candidates?: number };\n timings: {\n narrow_us?: number;\n gather_us?: number;\n walk_us?: number;\n resolve_us?: number;\n first_pass_us?: number;\n rescore_us?: number;\n score_us?: number;\n total_us: number;\n };\n}\n\n/** Wire `QueryPlan` into its camelCase {@link QueryPlan} shape. */\nfunction decodeQueryPlan(p: RawQueryPlan): QueryPlan {\n const candidates: PlanCandidates | undefined = p.candidates\n ? {\n surfaced: p.candidates.surfaced,\n survived: p.candidates.survived,\n droppedOutOfScope: p.candidates.dropped_out_of_scope,\n droppedStale: p.candidates.dropped_stale,\n droppedFiltered: p.candidates.dropped_filtered,\n droppedMinScore: p.candidates.dropped_min_score,\n }\n : undefined;\n const t = p.timings;\n const timings: PlanTimings = {\n ...(t.narrow_us !== undefined ? { narrowUs: t.narrow_us } : {}),\n ...(t.gather_us !== undefined ? { gatherUs: t.gather_us } : {}),\n ...(t.walk_us !== undefined ? { walkUs: t.walk_us } : {}),\n ...(t.resolve_us !== undefined ? { resolveUs: t.resolve_us } : {}),\n ...(t.first_pass_us !== undefined ? { firstPassUs: t.first_pass_us } : {}),\n ...(t.rescore_us !== undefined ? { rescoreUs: t.rescore_us } : {}),\n ...(t.score_us !== undefined ? { scoreUs: t.score_us } : {}),\n totalUs: t.total_us,\n };\n return {\n path: p.path,\n ...(p.rows_scanned !== undefined ? { rowsScanned: p.rows_scanned } : {}),\n ...(candidates ? { candidates } : {}),\n narrowing: {\n state: p.narrowing.state,\n ...(p.narrowing.candidates !== undefined\n ? { candidates: p.narrowing.candidates }\n : {}),\n },\n timings,\n };\n}\n\n/** An `/aggregate` response, whose sums arrive as tagged {@link Value}s. */\ninterface RawAggregation {\n count: number;\n sums: Record<string, Value>;\n groups?: {\n value: Value | null;\n count: number;\n sums: Record<string, Value>;\n }[];\n groups_truncated?: boolean;\n}\n\n/** A `/search/batch` response: exactly one of the two fields is present. */\ninterface RawBatchSearch {\n results?: RawHit[][];\n fused?: RawHit[];\n}\n\n/** Encode `rankBy` to its externally-tagged wire form, dropping the knobs left unset. */\n/** camelCase → the wire's snake_case, omitting the object entirely when unset. */\nfunction encodeExpand(e: Expand | undefined): unknown {\n if (!e) return undefined;\n return prune({\n radius: e.radius,\n parent_field: e.parentField,\n index_field: e.indexField,\n text_field: e.textField,\n });\n}\n\nfunction encodeRollup(r: Rollup | undefined): unknown {\n if (!r) return undefined;\n return prune({ per_parent: r.perParent, neighbours: r.neighbours });\n}\n\nfunction encodeRankBy(rank: RankBy | undefined): unknown {\n if (!rank) return undefined;\n const d = rank.decay;\n return {\n Decay: prune({\n field: d.field,\n origin: d.origin instanceof Date ? d.origin.getTime() : d.origin,\n scale: d.scale,\n decay: d.decay,\n lambda: d.lambda,\n missing: d.missing,\n count_field: d.countField,\n count_scale: d.countScale,\n count_lambda: d.countLambda,\n }),\n };\n}\n\n/** Encode `highlight`: `true` is the empty object the server reads as \"all defaults\". */\nfunction encodeHighlight(h: boolean | HighlightOptions | undefined): unknown {\n if (h === undefined || h === false) return undefined;\n if (h === true) return {};\n return prune({\n max_fragments: h.maxFragments,\n fragment_chars: h.fragmentChars,\n });\n}\n\n/** Encode `rerank`. Undefined sub-fields drop out at `JSON.stringify`, not here. */\nfunction encodeRerank(r: RerankOptions | undefined): unknown {\n if (r === undefined) return undefined;\n return { query: r.query, overscan: r.overscan, text_attr: r.textAttr };\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/**\n * Encode one `setFtsSchema` field. A string passes through as the server's bare-name\n * form; an object becomes the snake_case body, pruned so an unset knob keeps the\n * server's default rather than being sent as `undefined`.\n */\nfunction encodeFtsField(f: string | FtsField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n k1: f.k1,\n b: f.b,\n language: f.language,\n ascii_folding: f.asciiFolding,\n max_token_len: f.maxTokenLen,\n });\n}\n\n/**\n * Encode one `setFilterIndex` field, on the same bare-name-or-object rule as\n * {@link encodeFtsField}. Pruning matters here: the server defaults both structures to\n * `true`, so sending an explicit `undefined` would be indistinguishable from `false`.\n */\nfunction encodeFilterIndexField(f: string | FilterIndexField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n tokens: f.tokens,\n trigrams: f.trigrams,\n });\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, Float↔Float by IEEE, Str↔Str\n// lexical, Bool↔Bool, DateTime↔DateTime as instants), so an operand's encoded type\n// has to match the attribute's: `ge(\"score\", v.float(2))`, not `ge(\"score\", 2)`.\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 /**\n * {@link f.glob}, ignoring **ASCII** case on both sides — `\"Src/*\"` matches\n * `\"src/main.rs\"`. Non-ASCII is not folded (`É` does not match `é`).\n */\n iglob: (key: string, pattern: string): Predicate => ({\n IGlob: [key, pattern],\n }),\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 /** `attrs[key]` is a `List` containing `value` (whole-element, not substring). */\n contains: (key: string, value: AttrInput): Predicate => ({\n Contains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a present `List` not containing `value`. */\n notContains: (key: string, value: AttrInput): Predicate => ({\n NotContains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a `List` sharing at least one element with `values`. */\n containsAny: (key: string, values: AttrInput[]): Predicate => ({\n ContainsAny: [key, values.map(encodeValue)],\n }),\n /** Every sub-predicate holds. `all()` is `true`. */\n all: (...preds: Predicate[]): Predicate => ({ All: preds }),\n /** At least one sub-predicate holds. `any()` is `false`. */\n any: (...preds: Predicate[]): Predicate => ({ Any: preds }),\n /**\n * The sub-predicate does not hold. Differs from {@link f.ne} on an absent key:\n * `not(eq(k, v))` matches a record with no `k`, `ne(k, v)` does not.\n */\n not: (pred: Predicate): Predicate => ({ Not: pred }),\n /**\n * `attrs[key]` is within `maxEdits` Levenshtein edits of `text`, ASCII-case-folded on\n * both sides; a `List` matches if any element does. The only three-element predicate.\n * A `maxEdits` above 8 is refused by the server, not clamped.\n */\n fuzzy: (key: string, text: string, maxEdits: number): Predicate => ({\n Fuzzy: [key, text, maxEdits],\n }),\n /**\n * Every token of `text` appears among `attrs[key]`'s tokens, in any order. Tokens are\n * ASCII-case-folded runs of alphanumerics; a `List` matches if any single element does.\n */\n containsAllTokens: (key: string, text: string): Predicate => ({\n ContainsAllTokens: [key, text],\n }),\n /** At least one token of `text` appears among `attrs[key]`'s tokens. Empty never matches. */\n containsAnyToken: (key: string, text: string): Predicate => ({\n ContainsAnyToken: [key, text],\n }),\n /** `text`'s tokens appear consecutively and in order — a phrase match. */\n containsTokenSequence: (key: string, text: string): Predicate => ({\n ContainsTokenSequence: [key, text],\n }),\n /**\n * `attrs[key]` matches the regular expression, **anchored at both ends** like\n * {@link f.glob} — `.*` opts back into a substring search, and `(?i)` into case folding.\n * The syntax is Rust's `regex`, not JS's: no backreferences and no lookaround.\n */\n regex: (key: string, pattern: string): Predicate => ({ Regex: [key, pattern] }),\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
@@ -484,6 +484,29 @@ interface TextSearchBase extends ProjectionOptions, RankingOptions, AnnotationOp
484
484
  }
485
485
  /** Options for {@link NidusClient.textSearch} (BM25). */
486
486
  type TextSearchOptions = TextSearchBase & TextQuerySpelling;
487
+ /** Options for {@link NidusClient.suggest}. */
488
+ interface SuggestOptions {
489
+ collection: string;
490
+ /** The full-text-indexed field whose vocabulary to complete from. */
491
+ field: string;
492
+ /** The partial word being typed. Only its final token is completed. */
493
+ prefix: string;
494
+ /** How many completions to return. The server defaults to 10. */
495
+ limit?: number;
496
+ }
497
+ /** One completion: an indexed term and how many live documents contain it. */
498
+ interface Suggestion {
499
+ term: string;
500
+ df: number;
501
+ }
502
+ /**
503
+ * {@link NidusClient.suggest}'s result. `matched` counts every term the prefix matched
504
+ * before the server's 256-term cap, so `matched > suggestions.length` means it truncated.
505
+ */
506
+ interface Suggestions {
507
+ suggestions: Suggestion[];
508
+ matched: number;
509
+ }
487
510
  /**
488
511
  * One entry of {@link NidusClient.setFtsSchema}'s `fields`: the attribute to index
489
512
  * plus any BM25/analyzer knobs to override. Every knob is optional — omit them all
@@ -777,6 +800,12 @@ declare class NidusClient {
777
800
  * `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
778
801
  */
779
802
  textSearch(opts: TextSearchOptions): Promise<Hit[]>;
803
+ /**
804
+ * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by
805
+ * document frequency (commonest first), which is the opposite of how a prefix clause
806
+ * ranks documents. Completions are stems: the prefix is folded, not stemmed.
807
+ */
808
+ suggest(opts: SuggestOptions): Promise<Suggestions>;
780
809
  /**
781
810
  * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes
782
811
  * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
@@ -954,4 +983,4 @@ declare function decodeValue(value: Value): DecodedValue;
954
983
  /** Decode a whole wire `attrs` map back to plain JS values. */
955
984
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
956
985
 
957
- export { type AggregateOptions, type Aggregation, type AnnInfo, type AnnotationOptions, type Annotations, type AttrInput, type ClauseScore, type ClusterStatus, type Decay, type DecodedRecord, type DecodedValue, type Expand, type Expansion, type FetchLike, type Filter, type FilterIndexField, type Footprint, type Fragment, type FtsCombine, type FtsField, type Highlight, type HighlightOptions, type Hit, type HybridQuerySpelling, type HybridSearchBase, type HybridSearchOptions, type LegScore, type LimitPer, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type OrderBy, type PlanCandidates, type PlanNarrowing, type PlanTimings, type Predicate, type ProjectionOptions, type QueryPath, type QueryPlan, type RankBy, type RankingOptions, type Readiness, type RecallOptions, type RecordInput, type RememberOptions, type RememberResult, type RerankOptions, type Rollup, type SearchOptions, type SimilarSearchOptions, type Stats, type StoreVersions, type TextClause, type TextQuerySpelling, type TextSearchBase, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
986
+ export { type AggregateOptions, type Aggregation, type AnnInfo, type AnnotationOptions, type Annotations, type AttrInput, type ClauseScore, type ClusterStatus, type Decay, type DecodedRecord, type DecodedValue, type Expand, type Expansion, type FetchLike, type Filter, type FilterIndexField, type Footprint, type Fragment, type FtsCombine, type FtsField, type Highlight, type HighlightOptions, type Hit, type HybridQuerySpelling, type HybridSearchBase, type HybridSearchOptions, type LegScore, type LimitPer, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type OrderBy, type PlanCandidates, type PlanNarrowing, type PlanTimings, type Predicate, type ProjectionOptions, type QueryPath, type QueryPlan, type RankBy, type RankingOptions, type Readiness, type RecallOptions, type RecordInput, type RememberOptions, type RememberResult, type RerankOptions, type Rollup, type SearchOptions, type SimilarSearchOptions, type Stats, type StoreVersions, type SuggestOptions, type Suggestion, type Suggestions, type TextClause, type TextQuerySpelling, type TextSearchBase, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
package/dist/index.d.ts CHANGED
@@ -484,6 +484,29 @@ interface TextSearchBase extends ProjectionOptions, RankingOptions, AnnotationOp
484
484
  }
485
485
  /** Options for {@link NidusClient.textSearch} (BM25). */
486
486
  type TextSearchOptions = TextSearchBase & TextQuerySpelling;
487
+ /** Options for {@link NidusClient.suggest}. */
488
+ interface SuggestOptions {
489
+ collection: string;
490
+ /** The full-text-indexed field whose vocabulary to complete from. */
491
+ field: string;
492
+ /** The partial word being typed. Only its final token is completed. */
493
+ prefix: string;
494
+ /** How many completions to return. The server defaults to 10. */
495
+ limit?: number;
496
+ }
497
+ /** One completion: an indexed term and how many live documents contain it. */
498
+ interface Suggestion {
499
+ term: string;
500
+ df: number;
501
+ }
502
+ /**
503
+ * {@link NidusClient.suggest}'s result. `matched` counts every term the prefix matched
504
+ * before the server's 256-term cap, so `matched > suggestions.length` means it truncated.
505
+ */
506
+ interface Suggestions {
507
+ suggestions: Suggestion[];
508
+ matched: number;
509
+ }
487
510
  /**
488
511
  * One entry of {@link NidusClient.setFtsSchema}'s `fields`: the attribute to index
489
512
  * plus any BM25/analyzer knobs to override. Every knob is optional — omit them all
@@ -777,6 +800,12 @@ declare class NidusClient {
777
800
  * `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
778
801
  */
779
802
  textSearch(opts: TextSearchOptions): Promise<Hit[]>;
803
+ /**
804
+ * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by
805
+ * document frequency (commonest first), which is the opposite of how a prefix clause
806
+ * ranks documents. Completions are stems: the prefix is folded, not stemmed.
807
+ */
808
+ suggest(opts: SuggestOptions): Promise<Suggestions>;
780
809
  /**
781
810
  * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes
782
811
  * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
@@ -954,4 +983,4 @@ declare function decodeValue(value: Value): DecodedValue;
954
983
  /** Decode a whole wire `attrs` map back to plain JS values. */
955
984
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
956
985
 
957
- export { type AggregateOptions, type Aggregation, type AnnInfo, type AnnotationOptions, type Annotations, type AttrInput, type ClauseScore, type ClusterStatus, type Decay, type DecodedRecord, type DecodedValue, type Expand, type Expansion, type FetchLike, type Filter, type FilterIndexField, type Footprint, type Fragment, type FtsCombine, type FtsField, type Highlight, type HighlightOptions, type Hit, type HybridQuerySpelling, type HybridSearchBase, type HybridSearchOptions, type LegScore, type LimitPer, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type OrderBy, type PlanCandidates, type PlanNarrowing, type PlanTimings, type Predicate, type ProjectionOptions, type QueryPath, type QueryPlan, type RankBy, type RankingOptions, type Readiness, type RecallOptions, type RecordInput, type RememberOptions, type RememberResult, type RerankOptions, type Rollup, type SearchOptions, type SimilarSearchOptions, type Stats, type StoreVersions, type TextClause, type TextQuerySpelling, type TextSearchBase, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
986
+ export { type AggregateOptions, type Aggregation, type AnnInfo, type AnnotationOptions, type Annotations, type AttrInput, type ClauseScore, type ClusterStatus, type Decay, type DecodedRecord, type DecodedValue, type Expand, type Expansion, type FetchLike, type Filter, type FilterIndexField, type Footprint, type Fragment, type FtsCombine, type FtsField, type Highlight, type HighlightOptions, type Hit, type HybridQuerySpelling, type HybridSearchBase, type HybridSearchOptions, type LegScore, type LimitPer, type ListOptions, NidusClient, type NidusClientOptions, NidusError, type NidusRecord, type OrderBy, type PlanCandidates, type PlanNarrowing, type PlanTimings, type Predicate, type ProjectionOptions, type QueryPath, type QueryPlan, type RankBy, type RankingOptions, type Readiness, type RecallOptions, type RecordInput, type RememberOptions, type RememberResult, type RerankOptions, type Rollup, type SearchOptions, type SimilarSearchOptions, type Stats, type StoreVersions, type SuggestOptions, type Suggestion, type Suggestions, type TextClause, type TextQuerySpelling, type TextSearchBase, type TextSearchOptions, type Value, decodeAttrs, decodeValue, encodeAttrs, encodeValue, f, v };
package/dist/index.js CHANGED
@@ -407,6 +407,18 @@ var NidusClient = class {
407
407
  rerank: encodeRerank(opts.rerank)
408
408
  });
409
409
  }
410
+ /**
411
+ * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by
412
+ * document frequency (commonest first), which is the opposite of how a prefix clause
413
+ * ranks documents. Completions are stems: the prefix is folded, not stemmed.
414
+ */
415
+ suggest(opts) {
416
+ return this.request(
417
+ "POST",
418
+ `/collections/${enc(opts.collection)}/suggest`,
419
+ prune({ field: opts.field, prefix: opts.prefix, limit: opts.limit })
420
+ );
421
+ }
410
422
  /**
411
423
  * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes
412
424
  * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/annotations.ts","../src/errors.ts","../src/values.ts","../src/client.ts","../src/filter.ts"],"sourcesContent":["//! Decoding a hit's optional annotations — the opt-in \"why did this match\".\n//\n// One rule here is JS's alone. The server reports a highlight span as a **UTF-8 byte**\n// range into the fragment text, but a JS string is indexed in UTF-16 code units, so\n// `text.slice(...span)` on a raw span is wrong for any non-ASCII excerpt. Converted here,\n// once, so a caller's obvious slice is the right one.\n\nimport type { Annotations, Fragment, Highlight } from \"./types.js\";\n\n/** A fragment as it arrives: `spans` are UTF-8 byte offsets into `text`. */\ninterface WireFragment {\n text: string;\n spans: [number, number][];\n}\n\ninterface WireHighlight {\n field: string;\n fragments: WireFragment[];\n}\n\n/** A hit's annotations as they arrive, before the span offsets are converted. */\nexport interface WireAnnotations {\n vector?: { rank: number; score: number };\n text?: { rank: number; score: number };\n clauses?: {\n field: string;\n score: number;\n expansion?: { matched: number; scored: number };\n }[];\n highlights?: WireHighlight[];\n}\n\n/**\n * Decode a hit's annotations, converting every highlight span to JS string indices. The\n * parts the server omitted stay omitted rather than becoming empty arrays.\n */\nexport function decodeAnnotations(a: WireAnnotations): Annotations {\n const out: Annotations = {};\n if (a.vector) out.vector = a.vector;\n if (a.text) out.text = a.text;\n if (a.clauses) out.clauses = a.clauses;\n if (a.highlights) out.highlights = a.highlights.map(decodeHighlight);\n return out;\n}\n\nfunction decodeHighlight(h: WireHighlight): Highlight {\n return { field: h.field, fragments: h.fragments.map(decodeFragment) };\n}\n\nfunction decodeFragment(fr: WireFragment): Fragment {\n return { text: fr.text, spans: toStringIndices(fr.text, fr.spans) };\n}\n\n/**\n * Convert UTF-8 byte ranges into `text` to JS string indices (UTF-16 code units), so\n * `text.slice(...span)` yields the matched term. An all-ASCII excerpt needs no conversion\n * and is the common case, so it is detected before any table is built.\n */\nexport function toStringIndices(\n text: string,\n spans: [number, number][],\n): [number, number][] {\n if (spans.length === 0 || isAscii(text)) return spans;\n const index = byteToUnit(text);\n const at = (b: number): number =>\n index[Math.min(Math.max(b, 0), index.length - 1)]!;\n return spans.map(([start, end]): [number, number] => [at(start), at(end)]);\n}\n\n/** One entry per byte of `text` (plus its end), holding that byte's UTF-16 index. */\nfunction byteToUnit(text: string): number[] {\n const index: number[] = [];\n let unit = 0;\n // A byte *inside* a codepoint maps to that codepoint's start. Spans land on token\n // boundaries, so this only keeps a malformed offset from landing mid-surrogate.\n for (const ch of text) {\n for (let n = utf8Len(ch.codePointAt(0)!); n > 0; n--) index.push(unit);\n unit += ch.length;\n }\n index.push(unit);\n return index;\n}\n\nfunction utf8Len(codePoint: number): number {\n if (codePoint < 0x80) return 1;\n if (codePoint < 0x800) return 2;\n return codePoint < 0x10000 ? 3 : 4;\n}\n\n/** True when every code unit is ASCII, i.e. byte offsets already *are* string indices. */\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 0x7f) return false;\n }\n return true;\n}\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//\n// One rule is JS's alone. The store's `Int` and `Float` are separate types compared\n// same-type only, but JS has one `number` and `1.0 === 1`, so `Number.isInteger` has to\n// decide. A whole-numbered measurement therefore lands as an `Int` in whichever records\n// it came out round, and a `Float` range filter then skips exactly those: write such a\n// field with `v.float`. Go and Python have the types JS lacks and decide from them.\n\nimport type { AttrInput, DecodedValue, Value } from \"./types.js\";\n\n/** Every tag this SDK version knows, in the order `decodeValue` tries them. */\nconst TAGS = [\"Str\", \"Int\", \"Bool\", \"List\", \"Float\", \"DateTime\"] as const;\n\n/**\n * Value constructors mirroring the `Value` variants. `v.int` requires a safe\n * integer and `v.float` a finite number — `NaN`/`Infinity` have no JSON spelling,\n * and `JSON.stringify` would quietly write `null`.\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 float: (n: number): Value => {\n if (typeof n !== \"number\" || !Number.isFinite(n)) {\n throw new TypeError(`v.float expects a finite number, got ${n}`);\n }\n return { Float: n };\n },\n bool: (b: boolean): Value => ({ Bool: b }),\n list: (items: string[]): Value => ({ List: items }),\n /**\n * A UTC instant, from a `Date` or a raw epoch-millisecond count. Milliseconds is\n * the wire type, so there is no sub-millisecond precision and no timezone.\n */\n datetime: (when: Date | number): Value => {\n const ms = when instanceof Date ? when.getTime() : when;\n if (!Number.isSafeInteger(ms)) {\n throw new TypeError(\n `v.datetime expects a valid Date or epoch ms, got ${when}`,\n );\n }\n return { DateTime: ms };\n },\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 TAGS.some((tag) => tag in x);\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-finite number, an invalid `Date`, 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 Number.isInteger(input) ? v.int(input) : v.float(input);\n case \"object\":\n // Date before the array check: both are objects, only one is a list.\n if (input instanceof Date) return v.datetime(input);\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 if (\"Float\" in value) return value.Float;\n // A Date, not the raw number: a number would demote every instant to an Int\n // when a decoded attrs map is written back.\n if (\"DateTime\" in value) return new Date(value.DateTime);\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 { decodeAnnotations, type WireAnnotations } from \"./annotations.js\";\nimport { NidusError } from \"./errors.js\";\nimport type {\n AggregateOptions,\n Aggregation,\n BatchSearchOptions,\n ClusterStatus,\n DecodedRecord,\n Expand,\n Filter,\n FilterIndexField,\n FtsField,\n HighlightOptions,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n QueryPlan,\n RankBy,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\nimport { decodeAttrs, decodeValue, 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 /**\n * Readiness: whether this instance can serve. A `503` is the negative answer, not an\n * error, so a poll loop branches on `ready` instead of catching. Other failures throw.\n */\n async ready(): Promise<Readiness> {\n const res = await this.raw(\"GET\", \"/ready\");\n const text = await res.text();\n if (res.status === 503) return { ready: false, reason: extractError(text, 503) };\n if (!res.ok) throw new NidusError(extractError(text, res.status), res.status);\n return JSON.parse(text) as Readiness;\n }\n\n /** Cluster role, writer-handle state, fencing token, commit counter, staleness. */\n cluster(): Promise<ClusterStatus> {\n return this.request<ClusterStatus>(\"GET\", \"/cluster\");\n }\n\n /** The readable commit points and this instance's pin, if any. */\n versions(): Promise<StoreVersions> {\n return this.request<StoreVersions>(\"GET\", \"/versions\");\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 /**\n * Declare the full-text-indexed attribute fields for a collection. A bare string\n * takes the server's BM25/analyzer defaults; an {@link FtsField} object tunes `k1`,\n * `b`, and the analyzer for that field alone.\n */\n async setFtsSchema(\n name: string,\n fields: (string | FtsField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/fts-schema`, {\n fields: fields.map(encodeFtsField),\n });\n }\n\n /**\n * Declare which attribute fields are indexed for the text predicates (`Fuzzy`,\n * `ContainsAllTokens`, `ContainsAnyToken`, `ContainsTokenSequence`, `Regex`). Fields\n * already written are indexed as part of applying the declaration.\n *\n * This changes how fast those predicates run, never what they return: the index\n * proposes candidate documents and the predicate itself still decides. The cost is\n * paid at write time and in memory. Pass an empty array to drop the declaration.\n */\n async setFilterIndex(\n name: string,\n fields: (string | FilterIndexField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/filter-index`, {\n fields: fields.map(encodeFilterIndexField),\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 offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */\n searchWithPlan(\n opts: SearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search\", {\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Records most like an existing one. The source record itself is never returned. */\n searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */\n searchSimilarWithPlan(\n opts: SimilarSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /**\n * BM25 full-text search over one indexed field, or over a `clauses` list folded by\n * `combine` (`\"Sum\"` unless said otherwise). Naming the fields both ways is a `400`.\n */\n textSearch(opts: TextSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/text-search\", {\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, query: opts.query, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /**\n * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes\n * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.\n */\n hybridSearch(opts: HybridSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */\n hybridSearchWithPlan(\n opts: HybridSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\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 include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n order_by: opts.orderBy,\n });\n }\n\n /**\n * Count the records matching a filter and sum the named attributes. Answered from the\n * in-RAM index alone — no record is built and no vector is read.\n */\n async aggregate(opts: AggregateOptions = {}): Promise<Aggregation> {\n const res = await this.request<RawAggregation>(\n \"POST\",\n \"/aggregate\",\n prune({\n scope: opts.scope ?? [],\n filter: opts.filter ?? [],\n sum: opts.sum ?? [],\n group_by: opts.groupBy,\n }),\n );\n // Every sum is an `Int` or a `Float`, both of which decode to a JS number.\n return {\n count: res.count,\n sums: decodeAttrs(res.sums) as Record<string, number>,\n // Kept absent, not `undefined`, so an ungrouped answer is the shape it always was.\n ...(res.groups\n ? {\n groups: res.groups.map((g) => ({\n value: g.value === null ? null : decodeValue(g.value),\n count: g.count,\n sums: decodeAttrs(g.sums) as Record<string, number>,\n })),\n }\n : {}),\n ...(res.groups_truncated ? { groupsTruncated: true } : {}),\n };\n }\n\n /**\n * Answer several vector queries in one round-trip (16 max). Returns one ranking per\n * query in request order, or — with `opts.fuse` — a single array holding the one fused\n * ranking, so the return shape is uniform either way.\n *\n * The server validates the whole batch before running any leg, so a malformed query\n * fails the call rather than returning a partial answer that cannot be told apart.\n */\n async batchSearch(opts: BatchSearchOptions): Promise<Hit[][]> {\n const body = prune({\n queries: opts.queries.map((q) => ({\n query: q.query,\n scope: q.scope ?? [],\n top_k: q.topK,\n offset: q.offset,\n min_score: q.minScore,\n filter: q.filter ?? [],\n exact: q.exact,\n include_attributes: q.includeAttributes,\n exclude_attributes: q.excludeAttributes,\n rank_by: encodeRankBy(q.rankBy),\n limit_per: q.limitPer,\n diversity: q.diversity,\n expand: encodeExpand(q.expand),\n })),\n fuse: opts.fuse\n ? prune({\n rrf_k: opts.fuse.rrfK,\n weights: opts.fuse.weights,\n top_k: opts.fuse.topK,\n })\n : undefined,\n });\n const res = await this.request<RawBatchSearch>(\n \"POST\",\n \"/search/batch\",\n body,\n );\n return (res.fused ? [res.fused] : (res.results ?? [])).map((hits) =>\n hits.map((h) => this.decodeHit(h)),\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 a `nidus.summary` attr (requires the server to have a\n * summarizer). The raw text is always stored under `nidus.text`. `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n *\n * Read `id` off the result rather than assuming the one you passed:\n * `opts.dedupeThreshold` can redirect the write onto a near-duplicate.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<RememberResult> {\n const res = await this.request<Partial<RememberResult> | undefined>(\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 ttl_seconds: opts.ttlSeconds,\n dedupe_threshold: opts.dedupeThreshold,\n }),\n );\n // A server predating the echoed fields answers `{ok, upserted}`; falling back to the\n // requested id keeps that case honest instead of reporting `undefined` as the target.\n return {\n id: res?.id ?? id,\n upserted: res?.upserted ?? 0,\n deduped: res?.deduped ?? false,\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 diversity: opts.diversity,\n rollup: encodeRollup(opts.rollup),\n rerank: encodeRerank(opts.rerank),\n reinforce: opts.reinforce,\n extend_ttl_seconds: opts.extendTtlSeconds,\n rank_by: encodeRankBy(opts.rankBy),\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 /** Adopt a writer's newer committed state. Returns whether anything was adopted. */\n async refresh(): Promise<boolean> {\n const res = await this.request<{ adopted: boolean }>(\"POST\", \"/refresh\", {});\n return res.adopted;\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) => this.decodeHit(h));\n }\n\n /** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */\n private async searchRequestWithPlan(\n path: string,\n body: Record<string, unknown>,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n const res = await this.request<{ hits: RawHit[]; plan: RawQueryPlan }>(\n \"POST\",\n path,\n prune({ ...body, plan: true }),\n );\n return {\n hits: res.hits.map((h) => this.decodeHit(h)),\n plan: decodeQueryPlan(res.plan),\n };\n }\n\n /** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */\n private decodeHit(h: RawHit): Hit {\n return {\n collection: h.collection,\n id: h.id,\n score: h.score,\n attrs: decodeAttrs(h.attrs),\n // Kept absent, not `undefined`, so an unannotated hit is the shape it always was.\n ...(h.annotations\n ? { annotations: decodeAnnotations(h.annotations) }\n : {}),\n ...(h.context !== undefined ? { context: h.context } : {}),\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 = 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 annotations?: WireAnnotations;\n context?: string;\n}\n\n/** A `QueryPlan` as it arrives on the wire (snake_case), before camelCasing. */\ninterface RawQueryPlan {\n path: string;\n rows_scanned?: number;\n candidates?: {\n surfaced: number;\n survived: number;\n dropped_out_of_scope: number;\n dropped_stale: number;\n dropped_filtered: number;\n dropped_min_score: number;\n };\n narrowing: { state: PlanNarrowing[\"state\"]; candidates?: number };\n timings: {\n narrow_us?: number;\n gather_us?: number;\n walk_us?: number;\n resolve_us?: number;\n first_pass_us?: number;\n rescore_us?: number;\n score_us?: number;\n total_us: number;\n };\n}\n\n/** Wire `QueryPlan` into its camelCase {@link QueryPlan} shape. */\nfunction decodeQueryPlan(p: RawQueryPlan): QueryPlan {\n const candidates: PlanCandidates | undefined = p.candidates\n ? {\n surfaced: p.candidates.surfaced,\n survived: p.candidates.survived,\n droppedOutOfScope: p.candidates.dropped_out_of_scope,\n droppedStale: p.candidates.dropped_stale,\n droppedFiltered: p.candidates.dropped_filtered,\n droppedMinScore: p.candidates.dropped_min_score,\n }\n : undefined;\n const t = p.timings;\n const timings: PlanTimings = {\n ...(t.narrow_us !== undefined ? { narrowUs: t.narrow_us } : {}),\n ...(t.gather_us !== undefined ? { gatherUs: t.gather_us } : {}),\n ...(t.walk_us !== undefined ? { walkUs: t.walk_us } : {}),\n ...(t.resolve_us !== undefined ? { resolveUs: t.resolve_us } : {}),\n ...(t.first_pass_us !== undefined ? { firstPassUs: t.first_pass_us } : {}),\n ...(t.rescore_us !== undefined ? { rescoreUs: t.rescore_us } : {}),\n ...(t.score_us !== undefined ? { scoreUs: t.score_us } : {}),\n totalUs: t.total_us,\n };\n return {\n path: p.path,\n ...(p.rows_scanned !== undefined ? { rowsScanned: p.rows_scanned } : {}),\n ...(candidates ? { candidates } : {}),\n narrowing: {\n state: p.narrowing.state,\n ...(p.narrowing.candidates !== undefined\n ? { candidates: p.narrowing.candidates }\n : {}),\n },\n timings,\n };\n}\n\n/** An `/aggregate` response, whose sums arrive as tagged {@link Value}s. */\ninterface RawAggregation {\n count: number;\n sums: Record<string, Value>;\n groups?: {\n value: Value | null;\n count: number;\n sums: Record<string, Value>;\n }[];\n groups_truncated?: boolean;\n}\n\n/** A `/search/batch` response: exactly one of the two fields is present. */\ninterface RawBatchSearch {\n results?: RawHit[][];\n fused?: RawHit[];\n}\n\n/** Encode `rankBy` to its externally-tagged wire form, dropping the knobs left unset. */\n/** camelCase → the wire's snake_case, omitting the object entirely when unset. */\nfunction encodeExpand(e: Expand | undefined): unknown {\n if (!e) return undefined;\n return prune({\n radius: e.radius,\n parent_field: e.parentField,\n index_field: e.indexField,\n text_field: e.textField,\n });\n}\n\nfunction encodeRollup(r: Rollup | undefined): unknown {\n if (!r) return undefined;\n return prune({ per_parent: r.perParent, neighbours: r.neighbours });\n}\n\nfunction encodeRankBy(rank: RankBy | undefined): unknown {\n if (!rank) return undefined;\n const d = rank.decay;\n return {\n Decay: prune({\n field: d.field,\n origin: d.origin instanceof Date ? d.origin.getTime() : d.origin,\n scale: d.scale,\n decay: d.decay,\n lambda: d.lambda,\n missing: d.missing,\n count_field: d.countField,\n count_scale: d.countScale,\n count_lambda: d.countLambda,\n }),\n };\n}\n\n/** Encode `highlight`: `true` is the empty object the server reads as \"all defaults\". */\nfunction encodeHighlight(h: boolean | HighlightOptions | undefined): unknown {\n if (h === undefined || h === false) return undefined;\n if (h === true) return {};\n return prune({\n max_fragments: h.maxFragments,\n fragment_chars: h.fragmentChars,\n });\n}\n\n/** Encode `rerank`. Undefined sub-fields drop out at `JSON.stringify`, not here. */\nfunction encodeRerank(r: RerankOptions | undefined): unknown {\n if (r === undefined) return undefined;\n return { query: r.query, overscan: r.overscan, text_attr: r.textAttr };\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/**\n * Encode one `setFtsSchema` field. A string passes through as the server's bare-name\n * form; an object becomes the snake_case body, pruned so an unset knob keeps the\n * server's default rather than being sent as `undefined`.\n */\nfunction encodeFtsField(f: string | FtsField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n k1: f.k1,\n b: f.b,\n language: f.language,\n ascii_folding: f.asciiFolding,\n max_token_len: f.maxTokenLen,\n });\n}\n\n/**\n * Encode one `setFilterIndex` field, on the same bare-name-or-object rule as\n * {@link encodeFtsField}. Pruning matters here: the server defaults both structures to\n * `true`, so sending an explicit `undefined` would be indistinguishable from `false`.\n */\nfunction encodeFilterIndexField(f: string | FilterIndexField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n tokens: f.tokens,\n trigrams: f.trigrams,\n });\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, Float↔Float by IEEE, Str↔Str\n// lexical, Bool↔Bool, DateTime↔DateTime as instants), so an operand's encoded type\n// has to match the attribute's: `ge(\"score\", v.float(2))`, not `ge(\"score\", 2)`.\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 /**\n * {@link f.glob}, ignoring **ASCII** case on both sides — `\"Src/*\"` matches\n * `\"src/main.rs\"`. Non-ASCII is not folded (`É` does not match `é`).\n */\n iglob: (key: string, pattern: string): Predicate => ({\n IGlob: [key, pattern],\n }),\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 /** `attrs[key]` is a `List` containing `value` (whole-element, not substring). */\n contains: (key: string, value: AttrInput): Predicate => ({\n Contains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a present `List` not containing `value`. */\n notContains: (key: string, value: AttrInput): Predicate => ({\n NotContains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a `List` sharing at least one element with `values`. */\n containsAny: (key: string, values: AttrInput[]): Predicate => ({\n ContainsAny: [key, values.map(encodeValue)],\n }),\n /** Every sub-predicate holds. `all()` is `true`. */\n all: (...preds: Predicate[]): Predicate => ({ All: preds }),\n /** At least one sub-predicate holds. `any()` is `false`. */\n any: (...preds: Predicate[]): Predicate => ({ Any: preds }),\n /**\n * The sub-predicate does not hold. Differs from {@link f.ne} on an absent key:\n * `not(eq(k, v))` matches a record with no `k`, `ne(k, v)` does not.\n */\n not: (pred: Predicate): Predicate => ({ Not: pred }),\n /**\n * `attrs[key]` is within `maxEdits` Levenshtein edits of `text`, ASCII-case-folded on\n * both sides; a `List` matches if any element does. The only three-element predicate.\n * A `maxEdits` above 8 is refused by the server, not clamped.\n */\n fuzzy: (key: string, text: string, maxEdits: number): Predicate => ({\n Fuzzy: [key, text, maxEdits],\n }),\n /**\n * Every token of `text` appears among `attrs[key]`'s tokens, in any order. Tokens are\n * ASCII-case-folded runs of alphanumerics; a `List` matches if any single element does.\n */\n containsAllTokens: (key: string, text: string): Predicate => ({\n ContainsAllTokens: [key, text],\n }),\n /** At least one token of `text` appears among `attrs[key]`'s tokens. Empty never matches. */\n containsAnyToken: (key: string, text: string): Predicate => ({\n ContainsAnyToken: [key, text],\n }),\n /** `text`'s tokens appear consecutively and in order — a phrase match. */\n containsTokenSequence: (key: string, text: string): Predicate => ({\n ContainsTokenSequence: [key, text],\n }),\n /**\n * `attrs[key]` matches the regular expression, **anchored at both ends** like\n * {@link f.glob} — `.*` opts back into a substring search, and `(?i)` into case folding.\n * The syntax is Rust's `regex`, not JS's: no backreferences and no lookaround.\n */\n regex: (key: string, pattern: string): Predicate => ({ Regex: [key, pattern] }),\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/annotations.ts","../src/errors.ts","../src/values.ts","../src/client.ts","../src/filter.ts"],"sourcesContent":["//! Decoding a hit's optional annotations — the opt-in \"why did this match\".\n//\n// One rule here is JS's alone. The server reports a highlight span as a **UTF-8 byte**\n// range into the fragment text, but a JS string is indexed in UTF-16 code units, so\n// `text.slice(...span)` on a raw span is wrong for any non-ASCII excerpt. Converted here,\n// once, so a caller's obvious slice is the right one.\n\nimport type { Annotations, Fragment, Highlight } from \"./types.js\";\n\n/** A fragment as it arrives: `spans` are UTF-8 byte offsets into `text`. */\ninterface WireFragment {\n text: string;\n spans: [number, number][];\n}\n\ninterface WireHighlight {\n field: string;\n fragments: WireFragment[];\n}\n\n/** A hit's annotations as they arrive, before the span offsets are converted. */\nexport interface WireAnnotations {\n vector?: { rank: number; score: number };\n text?: { rank: number; score: number };\n clauses?: {\n field: string;\n score: number;\n expansion?: { matched: number; scored: number };\n }[];\n highlights?: WireHighlight[];\n}\n\n/**\n * Decode a hit's annotations, converting every highlight span to JS string indices. The\n * parts the server omitted stay omitted rather than becoming empty arrays.\n */\nexport function decodeAnnotations(a: WireAnnotations): Annotations {\n const out: Annotations = {};\n if (a.vector) out.vector = a.vector;\n if (a.text) out.text = a.text;\n if (a.clauses) out.clauses = a.clauses;\n if (a.highlights) out.highlights = a.highlights.map(decodeHighlight);\n return out;\n}\n\nfunction decodeHighlight(h: WireHighlight): Highlight {\n return { field: h.field, fragments: h.fragments.map(decodeFragment) };\n}\n\nfunction decodeFragment(fr: WireFragment): Fragment {\n return { text: fr.text, spans: toStringIndices(fr.text, fr.spans) };\n}\n\n/**\n * Convert UTF-8 byte ranges into `text` to JS string indices (UTF-16 code units), so\n * `text.slice(...span)` yields the matched term. An all-ASCII excerpt needs no conversion\n * and is the common case, so it is detected before any table is built.\n */\nexport function toStringIndices(\n text: string,\n spans: [number, number][],\n): [number, number][] {\n if (spans.length === 0 || isAscii(text)) return spans;\n const index = byteToUnit(text);\n const at = (b: number): number =>\n index[Math.min(Math.max(b, 0), index.length - 1)]!;\n return spans.map(([start, end]): [number, number] => [at(start), at(end)]);\n}\n\n/** One entry per byte of `text` (plus its end), holding that byte's UTF-16 index. */\nfunction byteToUnit(text: string): number[] {\n const index: number[] = [];\n let unit = 0;\n // A byte *inside* a codepoint maps to that codepoint's start. Spans land on token\n // boundaries, so this only keeps a malformed offset from landing mid-surrogate.\n for (const ch of text) {\n for (let n = utf8Len(ch.codePointAt(0)!); n > 0; n--) index.push(unit);\n unit += ch.length;\n }\n index.push(unit);\n return index;\n}\n\nfunction utf8Len(codePoint: number): number {\n if (codePoint < 0x80) return 1;\n if (codePoint < 0x800) return 2;\n return codePoint < 0x10000 ? 3 : 4;\n}\n\n/** True when every code unit is ASCII, i.e. byte offsets already *are* string indices. */\nfunction isAscii(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 0x7f) return false;\n }\n return true;\n}\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//\n// One rule is JS's alone. The store's `Int` and `Float` are separate types compared\n// same-type only, but JS has one `number` and `1.0 === 1`, so `Number.isInteger` has to\n// decide. A whole-numbered measurement therefore lands as an `Int` in whichever records\n// it came out round, and a `Float` range filter then skips exactly those: write such a\n// field with `v.float`. Go and Python have the types JS lacks and decide from them.\n\nimport type { AttrInput, DecodedValue, Value } from \"./types.js\";\n\n/** Every tag this SDK version knows, in the order `decodeValue` tries them. */\nconst TAGS = [\"Str\", \"Int\", \"Bool\", \"List\", \"Float\", \"DateTime\"] as const;\n\n/**\n * Value constructors mirroring the `Value` variants. `v.int` requires a safe\n * integer and `v.float` a finite number — `NaN`/`Infinity` have no JSON spelling,\n * and `JSON.stringify` would quietly write `null`.\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 float: (n: number): Value => {\n if (typeof n !== \"number\" || !Number.isFinite(n)) {\n throw new TypeError(`v.float expects a finite number, got ${n}`);\n }\n return { Float: n };\n },\n bool: (b: boolean): Value => ({ Bool: b }),\n list: (items: string[]): Value => ({ List: items }),\n /**\n * A UTC instant, from a `Date` or a raw epoch-millisecond count. Milliseconds is\n * the wire type, so there is no sub-millisecond precision and no timezone.\n */\n datetime: (when: Date | number): Value => {\n const ms = when instanceof Date ? when.getTime() : when;\n if (!Number.isSafeInteger(ms)) {\n throw new TypeError(\n `v.datetime expects a valid Date or epoch ms, got ${when}`,\n );\n }\n return { DateTime: ms };\n },\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 TAGS.some((tag) => tag in x);\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-finite number, an invalid `Date`, 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 Number.isInteger(input) ? v.int(input) : v.float(input);\n case \"object\":\n // Date before the array check: both are objects, only one is a list.\n if (input instanceof Date) return v.datetime(input);\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 if (\"Float\" in value) return value.Float;\n // A Date, not the raw number: a number would demote every instant to an Int\n // when a decoded attrs map is written back.\n if (\"DateTime\" in value) return new Date(value.DateTime);\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 { decodeAnnotations, type WireAnnotations } from \"./annotations.js\";\nimport { NidusError } from \"./errors.js\";\nimport type {\n AggregateOptions,\n Aggregation,\n BatchSearchOptions,\n ClusterStatus,\n DecodedRecord,\n Expand,\n Filter,\n FilterIndexField,\n FtsField,\n HighlightOptions,\n Hit,\n HybridSearchOptions,\n ListOptions,\n NidusRecord,\n PlanCandidates,\n PlanNarrowing,\n PlanTimings,\n QueryPlan,\n RankBy,\n Readiness,\n RecallOptions,\n RecordInput,\n RememberOptions,\n RememberResult,\n RerankOptions,\n Rollup,\n SearchOptions,\n SimilarSearchOptions,\n Stats,\n StoreVersions,\n Suggestions,\n SuggestOptions,\n TextSearchOptions,\n Value,\n} from \"./types.js\";\nimport { decodeAttrs, decodeValue, 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 /**\n * Readiness: whether this instance can serve. A `503` is the negative answer, not an\n * error, so a poll loop branches on `ready` instead of catching. Other failures throw.\n */\n async ready(): Promise<Readiness> {\n const res = await this.raw(\"GET\", \"/ready\");\n const text = await res.text();\n if (res.status === 503) return { ready: false, reason: extractError(text, 503) };\n if (!res.ok) throw new NidusError(extractError(text, res.status), res.status);\n return JSON.parse(text) as Readiness;\n }\n\n /** Cluster role, writer-handle state, fencing token, commit counter, staleness. */\n cluster(): Promise<ClusterStatus> {\n return this.request<ClusterStatus>(\"GET\", \"/cluster\");\n }\n\n /** The readable commit points and this instance's pin, if any. */\n versions(): Promise<StoreVersions> {\n return this.request<StoreVersions>(\"GET\", \"/versions\");\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 /**\n * Declare the full-text-indexed attribute fields for a collection. A bare string\n * takes the server's BM25/analyzer defaults; an {@link FtsField} object tunes `k1`,\n * `b`, and the analyzer for that field alone.\n */\n async setFtsSchema(\n name: string,\n fields: (string | FtsField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/fts-schema`, {\n fields: fields.map(encodeFtsField),\n });\n }\n\n /**\n * Declare which attribute fields are indexed for the text predicates (`Fuzzy`,\n * `ContainsAllTokens`, `ContainsAnyToken`, `ContainsTokenSequence`, `Regex`). Fields\n * already written are indexed as part of applying the declaration.\n *\n * This changes how fast those predicates run, never what they return: the index\n * proposes candidate documents and the predicate itself still decides. The cost is\n * paid at write time and in memory. Pass an empty array to drop the declaration.\n */\n async setFilterIndex(\n name: string,\n fields: (string | FilterIndexField)[],\n ): Promise<void> {\n await this.request(\"POST\", `/collections/${enc(name)}/filter-index`, {\n fields: fields.map(encodeFilterIndexField),\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 offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */\n searchWithPlan(\n opts: SearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search\", {\n query: opts.query,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Records most like an existing one. The source record itself is never returned. */\n searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */\n searchSimilarWithPlan(\n opts: SimilarSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/search/similar\", {\n collection: opts.collection,\n id: opts.id,\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n exact: opts.exact,\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n });\n }\n\n /**\n * BM25 full-text search over one indexed field, or over a `clauses` list folded by\n * `combine` (`\"Sum\"` unless said otherwise). Naming the fields both ways is a `400`.\n */\n textSearch(opts: TextSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/text-search\", {\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, query: opts.query, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n min_score: opts.minScore,\n filter: opts.filter ?? [],\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n rank_by: encodeRankBy(opts.rankBy),\n limit_per: opts.limitPer,\n diversity: opts.diversity,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /**\n * Ranked term completions for a partial word, for an autocomplete dropdown. Ranked by\n * document frequency (commonest first), which is the opposite of how a prefix clause\n * ranks documents. Completions are stems: the prefix is folded, not stemmed.\n */\n suggest(opts: SuggestOptions): Promise<Suggestions> {\n return this.request<Suggestions>(\n \"POST\",\n `/collections/${enc(opts.collection)}/suggest`,\n prune({ field: opts.field, prefix: opts.prefix, limit: opts.limit }),\n );\n }\n\n /**\n * Hybrid search: fuse a vector query and a BM25 text query via RRF. The text leg takes\n * the same single-field / `clauses` choice as {@link NidusClient.textSearch}.\n */\n hybridSearch(opts: HybridSearchOptions): Promise<Hit[]> {\n return this.searchRequest(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\n });\n }\n\n /** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */\n hybridSearchWithPlan(\n opts: HybridSearchOptions,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n return this.searchRequestWithPlan(\"/hybrid-search\", {\n vector: opts.vector,\n ...(opts.clauses\n ? { clauses: opts.clauses, combine: opts.combine }\n : { field: opts.field, text: opts.text, prefix: opts.prefix }),\n scope: opts.scope ?? [],\n top_k: opts.topK,\n offset: opts.offset,\n filter: opts.filter ?? [],\n rrf_k: opts.rrfK,\n candidates: opts.candidates,\n explain: opts.explain,\n highlight: encodeHighlight(opts.highlight),\n vector_weight: opts.vectorWeight,\n text_weight: opts.textWeight,\n expand: encodeExpand(opts.expand),\n rerank: encodeRerank(opts.rerank),\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 include_attributes: opts.includeAttributes,\n exclude_attributes: opts.excludeAttributes,\n order_by: opts.orderBy,\n });\n }\n\n /**\n * Count the records matching a filter and sum the named attributes. Answered from the\n * in-RAM index alone — no record is built and no vector is read.\n */\n async aggregate(opts: AggregateOptions = {}): Promise<Aggregation> {\n const res = await this.request<RawAggregation>(\n \"POST\",\n \"/aggregate\",\n prune({\n scope: opts.scope ?? [],\n filter: opts.filter ?? [],\n sum: opts.sum ?? [],\n group_by: opts.groupBy,\n }),\n );\n // Every sum is an `Int` or a `Float`, both of which decode to a JS number.\n return {\n count: res.count,\n sums: decodeAttrs(res.sums) as Record<string, number>,\n // Kept absent, not `undefined`, so an ungrouped answer is the shape it always was.\n ...(res.groups\n ? {\n groups: res.groups.map((g) => ({\n value: g.value === null ? null : decodeValue(g.value),\n count: g.count,\n sums: decodeAttrs(g.sums) as Record<string, number>,\n })),\n }\n : {}),\n ...(res.groups_truncated ? { groupsTruncated: true } : {}),\n };\n }\n\n /**\n * Answer several vector queries in one round-trip (16 max). Returns one ranking per\n * query in request order, or — with `opts.fuse` — a single array holding the one fused\n * ranking, so the return shape is uniform either way.\n *\n * The server validates the whole batch before running any leg, so a malformed query\n * fails the call rather than returning a partial answer that cannot be told apart.\n */\n async batchSearch(opts: BatchSearchOptions): Promise<Hit[][]> {\n const body = prune({\n queries: opts.queries.map((q) => ({\n query: q.query,\n scope: q.scope ?? [],\n top_k: q.topK,\n offset: q.offset,\n min_score: q.minScore,\n filter: q.filter ?? [],\n exact: q.exact,\n include_attributes: q.includeAttributes,\n exclude_attributes: q.excludeAttributes,\n rank_by: encodeRankBy(q.rankBy),\n limit_per: q.limitPer,\n diversity: q.diversity,\n expand: encodeExpand(q.expand),\n })),\n fuse: opts.fuse\n ? prune({\n rrf_k: opts.fuse.rrfK,\n weights: opts.fuse.weights,\n top_k: opts.fuse.topK,\n })\n : undefined,\n });\n const res = await this.request<RawBatchSearch>(\n \"POST\",\n \"/search/batch\",\n body,\n );\n return (res.fused ? [res.fused] : (res.results ?? [])).map((hits) =>\n hits.map((h) => this.decodeHit(h)),\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 a `nidus.summary` attr (requires the server to have a\n * summarizer). The raw text is always stored under `nidus.text`. `opts.attrs` accept plain JS values or `v.*`\n * helpers; they are normalized for you.\n *\n * Read `id` off the result rather than assuming the one you passed:\n * `opts.dedupeThreshold` can redirect the write onto a near-duplicate.\n */\n async remember(\n collection: string,\n id: string,\n text: string,\n opts: RememberOptions = {},\n ): Promise<RememberResult> {\n const res = await this.request<Partial<RememberResult> | undefined>(\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 ttl_seconds: opts.ttlSeconds,\n dedupe_threshold: opts.dedupeThreshold,\n }),\n );\n // A server predating the echoed fields answers `{ok, upserted}`; falling back to the\n // requested id keeps that case honest instead of reporting `undefined` as the target.\n return {\n id: res?.id ?? id,\n upserted: res?.upserted ?? 0,\n deduped: res?.deduped ?? false,\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 diversity: opts.diversity,\n rollup: encodeRollup(opts.rollup),\n rerank: encodeRerank(opts.rerank),\n reinforce: opts.reinforce,\n extend_ttl_seconds: opts.extendTtlSeconds,\n rank_by: encodeRankBy(opts.rankBy),\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 /** Adopt a writer's newer committed state. Returns whether anything was adopted. */\n async refresh(): Promise<boolean> {\n const res = await this.request<{ adopted: boolean }>(\"POST\", \"/refresh\", {});\n return res.adopted;\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) => this.decodeHit(h));\n }\n\n /** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */\n private async searchRequestWithPlan(\n path: string,\n body: Record<string, unknown>,\n ): Promise<{ hits: Hit[]; plan: QueryPlan }> {\n const res = await this.request<{ hits: RawHit[]; plan: RawQueryPlan }>(\n \"POST\",\n path,\n prune({ ...body, plan: true }),\n );\n return {\n hits: res.hits.map((h) => this.decodeHit(h)),\n plan: decodeQueryPlan(res.plan),\n };\n }\n\n /** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */\n private decodeHit(h: RawHit): Hit {\n return {\n collection: h.collection,\n id: h.id,\n score: h.score,\n attrs: decodeAttrs(h.attrs),\n // Kept absent, not `undefined`, so an unannotated hit is the shape it always was.\n ...(h.annotations\n ? { annotations: decodeAnnotations(h.annotations) }\n : {}),\n ...(h.context !== undefined ? { context: h.context } : {}),\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 = 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 annotations?: WireAnnotations;\n context?: string;\n}\n\n/** A `QueryPlan` as it arrives on the wire (snake_case), before camelCasing. */\ninterface RawQueryPlan {\n path: string;\n rows_scanned?: number;\n candidates?: {\n surfaced: number;\n survived: number;\n dropped_out_of_scope: number;\n dropped_stale: number;\n dropped_filtered: number;\n dropped_min_score: number;\n };\n narrowing: { state: PlanNarrowing[\"state\"]; candidates?: number };\n timings: {\n narrow_us?: number;\n gather_us?: number;\n walk_us?: number;\n resolve_us?: number;\n first_pass_us?: number;\n rescore_us?: number;\n score_us?: number;\n total_us: number;\n };\n}\n\n/** Wire `QueryPlan` into its camelCase {@link QueryPlan} shape. */\nfunction decodeQueryPlan(p: RawQueryPlan): QueryPlan {\n const candidates: PlanCandidates | undefined = p.candidates\n ? {\n surfaced: p.candidates.surfaced,\n survived: p.candidates.survived,\n droppedOutOfScope: p.candidates.dropped_out_of_scope,\n droppedStale: p.candidates.dropped_stale,\n droppedFiltered: p.candidates.dropped_filtered,\n droppedMinScore: p.candidates.dropped_min_score,\n }\n : undefined;\n const t = p.timings;\n const timings: PlanTimings = {\n ...(t.narrow_us !== undefined ? { narrowUs: t.narrow_us } : {}),\n ...(t.gather_us !== undefined ? { gatherUs: t.gather_us } : {}),\n ...(t.walk_us !== undefined ? { walkUs: t.walk_us } : {}),\n ...(t.resolve_us !== undefined ? { resolveUs: t.resolve_us } : {}),\n ...(t.first_pass_us !== undefined ? { firstPassUs: t.first_pass_us } : {}),\n ...(t.rescore_us !== undefined ? { rescoreUs: t.rescore_us } : {}),\n ...(t.score_us !== undefined ? { scoreUs: t.score_us } : {}),\n totalUs: t.total_us,\n };\n return {\n path: p.path,\n ...(p.rows_scanned !== undefined ? { rowsScanned: p.rows_scanned } : {}),\n ...(candidates ? { candidates } : {}),\n narrowing: {\n state: p.narrowing.state,\n ...(p.narrowing.candidates !== undefined\n ? { candidates: p.narrowing.candidates }\n : {}),\n },\n timings,\n };\n}\n\n/** An `/aggregate` response, whose sums arrive as tagged {@link Value}s. */\ninterface RawAggregation {\n count: number;\n sums: Record<string, Value>;\n groups?: {\n value: Value | null;\n count: number;\n sums: Record<string, Value>;\n }[];\n groups_truncated?: boolean;\n}\n\n/** A `/search/batch` response: exactly one of the two fields is present. */\ninterface RawBatchSearch {\n results?: RawHit[][];\n fused?: RawHit[];\n}\n\n/** Encode `rankBy` to its externally-tagged wire form, dropping the knobs left unset. */\n/** camelCase → the wire's snake_case, omitting the object entirely when unset. */\nfunction encodeExpand(e: Expand | undefined): unknown {\n if (!e) return undefined;\n return prune({\n radius: e.radius,\n parent_field: e.parentField,\n index_field: e.indexField,\n text_field: e.textField,\n });\n}\n\nfunction encodeRollup(r: Rollup | undefined): unknown {\n if (!r) return undefined;\n return prune({ per_parent: r.perParent, neighbours: r.neighbours });\n}\n\nfunction encodeRankBy(rank: RankBy | undefined): unknown {\n if (!rank) return undefined;\n const d = rank.decay;\n return {\n Decay: prune({\n field: d.field,\n origin: d.origin instanceof Date ? d.origin.getTime() : d.origin,\n scale: d.scale,\n decay: d.decay,\n lambda: d.lambda,\n missing: d.missing,\n count_field: d.countField,\n count_scale: d.countScale,\n count_lambda: d.countLambda,\n }),\n };\n}\n\n/** Encode `highlight`: `true` is the empty object the server reads as \"all defaults\". */\nfunction encodeHighlight(h: boolean | HighlightOptions | undefined): unknown {\n if (h === undefined || h === false) return undefined;\n if (h === true) return {};\n return prune({\n max_fragments: h.maxFragments,\n fragment_chars: h.fragmentChars,\n });\n}\n\n/** Encode `rerank`. Undefined sub-fields drop out at `JSON.stringify`, not here. */\nfunction encodeRerank(r: RerankOptions | undefined): unknown {\n if (r === undefined) return undefined;\n return { query: r.query, overscan: r.overscan, text_attr: r.textAttr };\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/**\n * Encode one `setFtsSchema` field. A string passes through as the server's bare-name\n * form; an object becomes the snake_case body, pruned so an unset knob keeps the\n * server's default rather than being sent as `undefined`.\n */\nfunction encodeFtsField(f: string | FtsField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n k1: f.k1,\n b: f.b,\n language: f.language,\n ascii_folding: f.asciiFolding,\n max_token_len: f.maxTokenLen,\n });\n}\n\n/**\n * Encode one `setFilterIndex` field, on the same bare-name-or-object rule as\n * {@link encodeFtsField}. Pruning matters here: the server defaults both structures to\n * `true`, so sending an explicit `undefined` would be indistinguishable from `false`.\n */\nfunction encodeFilterIndexField(f: string | FilterIndexField): unknown {\n if (typeof f === \"string\") return f;\n return prune({\n field: f.field,\n tokens: f.tokens,\n trigrams: f.trigrams,\n });\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, Float↔Float by IEEE, Str↔Str\n// lexical, Bool↔Bool, DateTime↔DateTime as instants), so an operand's encoded type\n// has to match the attribute's: `ge(\"score\", v.float(2))`, not `ge(\"score\", 2)`.\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 /**\n * {@link f.glob}, ignoring **ASCII** case on both sides — `\"Src/*\"` matches\n * `\"src/main.rs\"`. Non-ASCII is not folded (`É` does not match `é`).\n */\n iglob: (key: string, pattern: string): Predicate => ({\n IGlob: [key, pattern],\n }),\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 /** `attrs[key]` is a `List` containing `value` (whole-element, not substring). */\n contains: (key: string, value: AttrInput): Predicate => ({\n Contains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a present `List` not containing `value`. */\n notContains: (key: string, value: AttrInput): Predicate => ({\n NotContains: [key, encodeValue(value)],\n }),\n /** `attrs[key]` is a `List` sharing at least one element with `values`. */\n containsAny: (key: string, values: AttrInput[]): Predicate => ({\n ContainsAny: [key, values.map(encodeValue)],\n }),\n /** Every sub-predicate holds. `all()` is `true`. */\n all: (...preds: Predicate[]): Predicate => ({ All: preds }),\n /** At least one sub-predicate holds. `any()` is `false`. */\n any: (...preds: Predicate[]): Predicate => ({ Any: preds }),\n /**\n * The sub-predicate does not hold. Differs from {@link f.ne} on an absent key:\n * `not(eq(k, v))` matches a record with no `k`, `ne(k, v)` does not.\n */\n not: (pred: Predicate): Predicate => ({ Not: pred }),\n /**\n * `attrs[key]` is within `maxEdits` Levenshtein edits of `text`, ASCII-case-folded on\n * both sides; a `List` matches if any element does. The only three-element predicate.\n * A `maxEdits` above 8 is refused by the server, not clamped.\n */\n fuzzy: (key: string, text: string, maxEdits: number): Predicate => ({\n Fuzzy: [key, text, maxEdits],\n }),\n /**\n * Every token of `text` appears among `attrs[key]`'s tokens, in any order. Tokens are\n * ASCII-case-folded runs of alphanumerics; a `List` matches if any single element does.\n */\n containsAllTokens: (key: string, text: string): Predicate => ({\n ContainsAllTokens: [key, text],\n }),\n /** At least one token of `text` appears among `attrs[key]`'s tokens. Empty never matches. */\n containsAnyToken: (key: string, text: string): Predicate => ({\n ContainsAnyToken: [key, text],\n }),\n /** `text`'s tokens appear consecutively and in order — a phrase match. */\n containsTokenSequence: (key: string, text: string): Predicate => ({\n ContainsTokenSequence: [key, text],\n }),\n /**\n * `attrs[key]` matches the regular expression, **anchored at both ends** like\n * {@link f.glob} — `.*` opts back into a substring search, and `(?i)` into case folding.\n * The syntax is Rust's `regex`, not JS's: no backreferences and no lookaround.\n */\n regex: (key: string, pattern: string): Predicate => ({ Regex: [key, pattern] }),\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"]}
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckedup/nidus",
3
- "version": "0.86.0",
3
+ "version": "0.87.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",