@duckedup/nidus 0.84.0 → 0.86.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
@@ -171,6 +171,16 @@ const hits = await db.textSearch({
171
171
  });
172
172
  ```
173
173
 
174
+ Set `prefix` to expand a clause's *final* term as a prefix match, for typeahead: `query:
175
+ "ru"` with `prefix: true` matches an indexed term like `"running"`; earlier terms in a
176
+ clause still require an exact stem match. On the `clauses` spelling, set `prefix` per
177
+ entry instead of at the top level.
178
+
179
+ ```ts
180
+ await db.textSearch({ field: "title", query: "ru", prefix: true });
181
+ await db.textSearch({ clauses: [{ field: "title", query: "ru", prefix: true }] });
182
+ ```
183
+
174
184
  ## Explaining and highlighting a hit
175
185
 
176
186
  `explain` reports what each leg and each matched clause contributed; `highlight` returns
package/dist/index.cjs CHANGED
@@ -423,7 +423,7 @@ var NidusClient = class {
423
423
  */
424
424
  textSearch(opts) {
425
425
  return this.searchRequest("/text-search", {
426
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, query: opts.query },
426
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, query: opts.query, prefix: opts.prefix },
427
427
  scope: opts.scope ?? [],
428
428
  top_k: opts.topK,
429
429
  offset: opts.offset,
@@ -447,7 +447,7 @@ var NidusClient = class {
447
447
  hybridSearch(opts) {
448
448
  return this.searchRequest("/hybrid-search", {
449
449
  vector: opts.vector,
450
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
450
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text, prefix: opts.prefix },
451
451
  scope: opts.scope ?? [],
452
452
  top_k: opts.topK,
453
453
  offset: opts.offset,
@@ -466,7 +466,7 @@ var NidusClient = class {
466
466
  hybridSearchWithPlan(opts) {
467
467
  return this.searchRequestWithPlan("/hybrid-search", {
468
468
  vector: opts.vector,
469
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
469
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text, prefix: opts.prefix },
470
470
  scope: opts.scope ?? [],
471
471
  top_k: opts.topK,
472
472
  offset: opts.offset,
@@ -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 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?: { field: string; score: number }[];\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 }),\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 }),\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 }),\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 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"]}
package/dist/index.d.cts CHANGED
@@ -120,6 +120,16 @@ interface LegScore {
120
120
  interface ClauseScore {
121
121
  field: string;
122
122
  score: number;
123
+ /** Set only for a prefix clause. `matched > scored` means the cap truncated it. */
124
+ expansion?: Expansion;
125
+ }
126
+ /**
127
+ * How far a prefix clause's final term expanded: how many indexed terms carried the
128
+ * prefix, and how many were scored after the expansion cap.
129
+ */
130
+ interface Expansion {
131
+ matched: number;
132
+ scored: number;
123
133
  }
124
134
  /**
125
135
  * An excerpt of a field's stored text plus the ranges a query term matched. The server
@@ -364,6 +374,8 @@ type FtsCombine = "Sum" | "Max";
364
374
  interface TextClause {
365
375
  field: string;
366
376
  query: string;
377
+ /** Expand the clause's final term as a prefix (typeahead). Omitted means `false`. */
378
+ prefix?: boolean;
367
379
  }
368
380
  /** How much text a highlight carries. `fragmentChars` is a character budget, not bytes. */
369
381
  interface HighlightOptions {
@@ -447,6 +459,8 @@ interface SimilarSearchOptions extends ProjectionOptions, RankingOptions {
447
459
  type TextQuerySpelling = {
448
460
  field: string;
449
461
  query: string;
462
+ /** Expand the shorthand's final term as a prefix (typeahead). Omitted means `false`. */
463
+ prefix?: boolean;
450
464
  clauses?: never;
451
465
  combine?: never;
452
466
  } | {
@@ -454,6 +468,7 @@ type TextQuerySpelling = {
454
468
  combine?: FtsCombine;
455
469
  field?: never;
456
470
  query?: never;
471
+ prefix?: never;
457
472
  };
458
473
  /** The knobs of {@link TextSearchOptions} that do not name what to search. */
459
474
  interface TextSearchBase extends ProjectionOptions, RankingOptions, AnnotationOptions {
@@ -509,6 +524,8 @@ interface FilterIndexField {
509
524
  type HybridQuerySpelling = {
510
525
  field: string;
511
526
  text: string;
527
+ /** Expand the shorthand's final term as a prefix (typeahead). Omitted means `false`. */
528
+ prefix?: boolean;
512
529
  clauses?: never;
513
530
  combine?: never;
514
531
  } | {
@@ -516,6 +533,7 @@ type HybridQuerySpelling = {
516
533
  combine?: FtsCombine;
517
534
  field?: never;
518
535
  text?: never;
536
+ prefix?: never;
519
537
  };
520
538
  /** The knobs of {@link HybridSearchOptions} that do not name what the text leg searches. */
521
539
  interface HybridSearchBase extends AnnotationOptions {
@@ -936,4 +954,4 @@ declare function decodeValue(value: Value): DecodedValue;
936
954
  /** Decode a whole wire `attrs` map back to plain JS values. */
937
955
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
938
956
 
939
- 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 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 };
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 };
package/dist/index.d.ts CHANGED
@@ -120,6 +120,16 @@ interface LegScore {
120
120
  interface ClauseScore {
121
121
  field: string;
122
122
  score: number;
123
+ /** Set only for a prefix clause. `matched > scored` means the cap truncated it. */
124
+ expansion?: Expansion;
125
+ }
126
+ /**
127
+ * How far a prefix clause's final term expanded: how many indexed terms carried the
128
+ * prefix, and how many were scored after the expansion cap.
129
+ */
130
+ interface Expansion {
131
+ matched: number;
132
+ scored: number;
123
133
  }
124
134
  /**
125
135
  * An excerpt of a field's stored text plus the ranges a query term matched. The server
@@ -364,6 +374,8 @@ type FtsCombine = "Sum" | "Max";
364
374
  interface TextClause {
365
375
  field: string;
366
376
  query: string;
377
+ /** Expand the clause's final term as a prefix (typeahead). Omitted means `false`. */
378
+ prefix?: boolean;
367
379
  }
368
380
  /** How much text a highlight carries. `fragmentChars` is a character budget, not bytes. */
369
381
  interface HighlightOptions {
@@ -447,6 +459,8 @@ interface SimilarSearchOptions extends ProjectionOptions, RankingOptions {
447
459
  type TextQuerySpelling = {
448
460
  field: string;
449
461
  query: string;
462
+ /** Expand the shorthand's final term as a prefix (typeahead). Omitted means `false`. */
463
+ prefix?: boolean;
450
464
  clauses?: never;
451
465
  combine?: never;
452
466
  } | {
@@ -454,6 +468,7 @@ type TextQuerySpelling = {
454
468
  combine?: FtsCombine;
455
469
  field?: never;
456
470
  query?: never;
471
+ prefix?: never;
457
472
  };
458
473
  /** The knobs of {@link TextSearchOptions} that do not name what to search. */
459
474
  interface TextSearchBase extends ProjectionOptions, RankingOptions, AnnotationOptions {
@@ -509,6 +524,8 @@ interface FilterIndexField {
509
524
  type HybridQuerySpelling = {
510
525
  field: string;
511
526
  text: string;
527
+ /** Expand the shorthand's final term as a prefix (typeahead). Omitted means `false`. */
528
+ prefix?: boolean;
512
529
  clauses?: never;
513
530
  combine?: never;
514
531
  } | {
@@ -516,6 +533,7 @@ type HybridQuerySpelling = {
516
533
  combine?: FtsCombine;
517
534
  field?: never;
518
535
  text?: never;
536
+ prefix?: never;
519
537
  };
520
538
  /** The knobs of {@link HybridSearchOptions} that do not name what the text leg searches. */
521
539
  interface HybridSearchBase extends AnnotationOptions {
@@ -936,4 +954,4 @@ declare function decodeValue(value: Value): DecodedValue;
936
954
  /** Decode a whole wire `attrs` map back to plain JS values. */
937
955
  declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
938
956
 
939
- 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 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 };
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 };
package/dist/index.js CHANGED
@@ -390,7 +390,7 @@ var NidusClient = class {
390
390
  */
391
391
  textSearch(opts) {
392
392
  return this.searchRequest("/text-search", {
393
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, query: opts.query },
393
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, query: opts.query, prefix: opts.prefix },
394
394
  scope: opts.scope ?? [],
395
395
  top_k: opts.topK,
396
396
  offset: opts.offset,
@@ -414,7 +414,7 @@ var NidusClient = class {
414
414
  hybridSearch(opts) {
415
415
  return this.searchRequest("/hybrid-search", {
416
416
  vector: opts.vector,
417
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
417
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text, prefix: opts.prefix },
418
418
  scope: opts.scope ?? [],
419
419
  top_k: opts.topK,
420
420
  offset: opts.offset,
@@ -433,7 +433,7 @@ var NidusClient = class {
433
433
  hybridSearchWithPlan(opts) {
434
434
  return this.searchRequestWithPlan("/hybrid-search", {
435
435
  vector: opts.vector,
436
- ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
436
+ ...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text, prefix: opts.prefix },
437
437
  scope: opts.scope ?? [],
438
438
  top_k: opts.topK,
439
439
  offset: opts.offset,
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?: { field: string; score: number }[];\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 }),\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 }),\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 }),\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 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"]}
@@ -14,15 +14,29 @@ export class NidusHandle {
14
14
  * trivial always-held guard on OPFS), and the JS wrapper is invalidated with it.
15
15
  */
16
16
  close(): void;
17
+ /**
18
+ * Drop a collection's rows. The terminal's `clear` — dropping rather than deleting
19
+ * OPFS files underneath the pool's open handles.
20
+ */
21
+ drop_collection(collection: string): void;
17
22
  /**
18
23
  * fsync both files.
19
24
  */
20
25
  flush(): void;
26
+ /**
27
+ * A RAM/disk footprint snapshot, shaped like `FootprintDto`. The terminal's `stats`.
28
+ */
29
+ footprint(): any;
21
30
  /**
22
31
  * Open (creating if absent) a store at `location` — `opfs://name` (needs
23
32
  * `init_opfs_pool` first, same thread) or `file://…`/a bare path.
24
33
  */
25
34
  static open(location: string, dimension: number): NidusHandle;
35
+ /**
36
+ * Open a RAM-only store, no persistence config. The terminal's fallback when the
37
+ * worker/OPFS handshake fails.
38
+ */
39
+ static open_in_memory(dimension: number): NidusHandle;
26
40
  /**
27
41
  * Nearest-neighbour search in `collection`, returning a JS array of hits shaped like
28
42
  * `server::dto::HitDto`: `{collection, id, score, attrs}`.
@@ -56,8 +70,11 @@ export interface InitOutput {
56
70
  readonly grow_opfs_pool: (a: number, b: number) => void;
57
71
  readonly init_opfs_pool: (a: number, b: number) => void;
58
72
  readonly nidushandle_close: (a: number) => void;
73
+ readonly nidushandle_drop_collection: (a: number, b: number, c: number, d: number) => void;
59
74
  readonly nidushandle_flush: (a: number, b: number) => void;
75
+ readonly nidushandle_footprint: (a: number, b: number) => void;
60
76
  readonly nidushandle_open: (a: number, b: number, c: number, d: number) => void;
77
+ readonly nidushandle_open_in_memory: (a: number, b: number) => void;
61
78
  readonly nidushandle_search: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
62
79
  readonly nidushandle_upsert: (a: number, b: number, c: number, d: number, e: number) => void;
63
80
  readonly __wbindgen_export: (a: number, b: number) => number;
@@ -29,6 +29,26 @@ export class NidusHandle {
29
29
  const ptr = this.__destroy_into_raw();
30
30
  wasm.nidushandle_close(ptr);
31
31
  }
32
+ /**
33
+ * Drop a collection's rows. The terminal's `clear` — dropping rather than deleting
34
+ * OPFS files underneath the pool's open handles.
35
+ * @param {string} collection
36
+ */
37
+ drop_collection(collection) {
38
+ try {
39
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
40
+ const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_export, wasm.__wbindgen_export2);
41
+ const len0 = WASM_VECTOR_LEN;
42
+ wasm.nidushandle_drop_collection(retptr, this.__wbg_ptr, ptr0, len0);
43
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
44
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
45
+ if (r1) {
46
+ throw takeObject(r0);
47
+ }
48
+ } finally {
49
+ wasm.__wbindgen_add_to_stack_pointer(16);
50
+ }
51
+ }
32
52
  /**
33
53
  * fsync both files.
34
54
  */
@@ -45,6 +65,25 @@ export class NidusHandle {
45
65
  wasm.__wbindgen_add_to_stack_pointer(16);
46
66
  }
47
67
  }
68
+ /**
69
+ * A RAM/disk footprint snapshot, shaped like `FootprintDto`. The terminal's `stats`.
70
+ * @returns {any}
71
+ */
72
+ footprint() {
73
+ try {
74
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
75
+ wasm.nidushandle_footprint(retptr, this.__wbg_ptr);
76
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
77
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
78
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
79
+ if (r2) {
80
+ throw takeObject(r1);
81
+ }
82
+ return takeObject(r0);
83
+ } finally {
84
+ wasm.__wbindgen_add_to_stack_pointer(16);
85
+ }
86
+ }
48
87
  /**
49
88
  * Open (creating if absent) a store at `location` — `opfs://name` (needs
50
89
  * `init_opfs_pool` first, same thread) or `file://…`/a bare path.
@@ -69,6 +108,27 @@ export class NidusHandle {
69
108
  wasm.__wbindgen_add_to_stack_pointer(16);
70
109
  }
71
110
  }
111
+ /**
112
+ * Open a RAM-only store, no persistence config. The terminal's fallback when the
113
+ * worker/OPFS handshake fails.
114
+ * @param {number} dimension
115
+ * @returns {NidusHandle}
116
+ */
117
+ static open_in_memory(dimension) {
118
+ try {
119
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
120
+ wasm.nidushandle_open_in_memory(retptr, dimension);
121
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
122
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
123
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
124
+ if (r2) {
125
+ throw takeObject(r1);
126
+ }
127
+ return NidusHandle.__wrap(r0);
128
+ } finally {
129
+ wasm.__wbindgen_add_to_stack_pointer(16);
130
+ }
131
+ }
72
132
  /**
73
133
  * Nearest-neighbour search in `collection`, returning a JS array of hits shaped like
74
134
  * `server::dto::HitDto`: `{collection, id, score, attrs}`.
@@ -414,6 +474,11 @@ function __wbg_get_imports() {
414
474
  const ret = getStringFromWasm0(arg0, arg1);
415
475
  return addHeapObject(ret);
416
476
  },
477
+ __wbindgen_cast_0000000000000004: function(arg0) {
478
+ // Cast intrinsic for `U64 -> Externref`.
479
+ const ret = BigInt.asUintN(64, arg0);
480
+ return addHeapObject(ret);
481
+ },
417
482
  __wbindgen_object_clone_ref: function(arg0) {
418
483
  const ret = getObject(arg0);
419
484
  return addHeapObject(ret);
Binary file
@@ -5,8 +5,11 @@ export const __wbg_nidushandle_free: (a: number, b: number) => void;
5
5
  export const grow_opfs_pool: (a: number, b: number) => void;
6
6
  export const init_opfs_pool: (a: number, b: number) => void;
7
7
  export const nidushandle_close: (a: number) => void;
8
+ export const nidushandle_drop_collection: (a: number, b: number, c: number, d: number) => void;
8
9
  export const nidushandle_flush: (a: number, b: number) => void;
10
+ export const nidushandle_footprint: (a: number, b: number) => void;
9
11
  export const nidushandle_open: (a: number, b: number, c: number, d: number) => void;
12
+ export const nidushandle_open_in_memory: (a: number, b: number) => void;
10
13
  export const nidushandle_search: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
11
14
  export const nidushandle_upsert: (a: number, b: number, c: number, d: number, e: number) => void;
12
15
  export const __wbindgen_export: (a: number, b: number) => number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckedup/nidus",
3
- "version": "0.84.0",
3
+ "version": "0.86.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",