@duckedup/nidus 0.81.0 → 0.82.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 +15 -0
- package/dist/index.cjs +100 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +100 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -201,6 +201,21 @@ converts them for you: `fragment.spans` are JS string indices, and `fragment.tex
|
|
|
201
201
|
is the matched term. If you compare them against the raw HTTP response, expect the
|
|
202
202
|
numbers to differ wherever the excerpt is not ASCII.
|
|
203
203
|
|
|
204
|
+
## Inspecting how a query was answered
|
|
205
|
+
|
|
206
|
+
`searchWithPlan`, `searchSimilarWithPlan`, and `hybridSearchWithPlan` are siblings of
|
|
207
|
+
`search`/`searchSimilar`/`hybridSearch` that return `{ hits, plan }` instead of a bare
|
|
208
|
+
`Hit[]` — the plan reports which scan strategy the server took (`ann`, `exact`, …), how
|
|
209
|
+
many rows it scanned, and per-stage timings in microseconds. `textSearch` has no plan.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const { hits, plan } = await db.searchWithPlan({ query: [0.1, 0.2, 0.3], topK: 10 });
|
|
213
|
+
console.log(plan.path, plan.timings.totalUs);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`plan.path` is a plain string, not a closed union: treat an unrecognized value as
|
|
217
|
+
"some scan strategy newer than this SDK" rather than an error.
|
|
218
|
+
|
|
204
219
|
## Ranking, grouping, ordering, and aggregating
|
|
205
220
|
|
|
206
221
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -360,6 +360,25 @@ var NidusClient = class {
|
|
|
360
360
|
rerank: encodeRerank(opts.rerank)
|
|
361
361
|
});
|
|
362
362
|
}
|
|
363
|
+
/** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */
|
|
364
|
+
searchWithPlan(opts) {
|
|
365
|
+
return this.searchRequestWithPlan("/search", {
|
|
366
|
+
query: opts.query,
|
|
367
|
+
scope: opts.scope ?? [],
|
|
368
|
+
top_k: opts.topK,
|
|
369
|
+
offset: opts.offset,
|
|
370
|
+
min_score: opts.minScore,
|
|
371
|
+
filter: opts.filter ?? [],
|
|
372
|
+
exact: opts.exact,
|
|
373
|
+
include_attributes: opts.includeAttributes,
|
|
374
|
+
exclude_attributes: opts.excludeAttributes,
|
|
375
|
+
rank_by: encodeRankBy(opts.rankBy),
|
|
376
|
+
limit_per: opts.limitPer,
|
|
377
|
+
diversity: opts.diversity,
|
|
378
|
+
expand: encodeExpand(opts.expand),
|
|
379
|
+
rerank: encodeRerank(opts.rerank)
|
|
380
|
+
});
|
|
381
|
+
}
|
|
363
382
|
/** Records most like an existing one. The source record itself is never returned. */
|
|
364
383
|
searchSimilar(opts) {
|
|
365
384
|
return this.searchRequest("/search/similar", {
|
|
@@ -379,6 +398,25 @@ var NidusClient = class {
|
|
|
379
398
|
expand: encodeExpand(opts.expand)
|
|
380
399
|
});
|
|
381
400
|
}
|
|
401
|
+
/** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */
|
|
402
|
+
searchSimilarWithPlan(opts) {
|
|
403
|
+
return this.searchRequestWithPlan("/search/similar", {
|
|
404
|
+
collection: opts.collection,
|
|
405
|
+
id: opts.id,
|
|
406
|
+
scope: opts.scope ?? [],
|
|
407
|
+
top_k: opts.topK,
|
|
408
|
+
offset: opts.offset,
|
|
409
|
+
min_score: opts.minScore,
|
|
410
|
+
filter: opts.filter ?? [],
|
|
411
|
+
exact: opts.exact,
|
|
412
|
+
include_attributes: opts.includeAttributes,
|
|
413
|
+
exclude_attributes: opts.excludeAttributes,
|
|
414
|
+
rank_by: encodeRankBy(opts.rankBy),
|
|
415
|
+
limit_per: opts.limitPer,
|
|
416
|
+
diversity: opts.diversity,
|
|
417
|
+
expand: encodeExpand(opts.expand)
|
|
418
|
+
});
|
|
419
|
+
}
|
|
382
420
|
/**
|
|
383
421
|
* BM25 full-text search over one indexed field, or over a `clauses` list folded by
|
|
384
422
|
* `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
|
|
@@ -424,6 +462,25 @@ var NidusClient = class {
|
|
|
424
462
|
rerank: encodeRerank(opts.rerank)
|
|
425
463
|
});
|
|
426
464
|
}
|
|
465
|
+
/** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */
|
|
466
|
+
hybridSearchWithPlan(opts) {
|
|
467
|
+
return this.searchRequestWithPlan("/hybrid-search", {
|
|
468
|
+
vector: opts.vector,
|
|
469
|
+
...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
|
|
470
|
+
scope: opts.scope ?? [],
|
|
471
|
+
top_k: opts.topK,
|
|
472
|
+
offset: opts.offset,
|
|
473
|
+
filter: opts.filter ?? [],
|
|
474
|
+
rrf_k: opts.rrfK,
|
|
475
|
+
candidates: opts.candidates,
|
|
476
|
+
explain: opts.explain,
|
|
477
|
+
highlight: encodeHighlight(opts.highlight),
|
|
478
|
+
vector_weight: opts.vectorWeight,
|
|
479
|
+
text_weight: opts.textWeight,
|
|
480
|
+
expand: encodeExpand(opts.expand),
|
|
481
|
+
rerank: encodeRerank(opts.rerank)
|
|
482
|
+
});
|
|
483
|
+
}
|
|
427
484
|
/** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
|
|
428
485
|
list(opts = {}) {
|
|
429
486
|
return this.searchRequest("/list", {
|
|
@@ -578,6 +635,18 @@ var NidusClient = class {
|
|
|
578
635
|
const hits = await this.request("POST", path, prune(body));
|
|
579
636
|
return hits.map((h) => this.decodeHit(h));
|
|
580
637
|
}
|
|
638
|
+
/** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */
|
|
639
|
+
async searchRequestWithPlan(path, body) {
|
|
640
|
+
const res = await this.request(
|
|
641
|
+
"POST",
|
|
642
|
+
path,
|
|
643
|
+
prune({ ...body, plan: true })
|
|
644
|
+
);
|
|
645
|
+
return {
|
|
646
|
+
hits: res.hits.map((h) => this.decodeHit(h)),
|
|
647
|
+
plan: decodeQueryPlan(res.plan)
|
|
648
|
+
};
|
|
649
|
+
}
|
|
581
650
|
/** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */
|
|
582
651
|
decodeHit(h) {
|
|
583
652
|
return {
|
|
@@ -625,6 +694,37 @@ var NidusClient = class {
|
|
|
625
694
|
}
|
|
626
695
|
}
|
|
627
696
|
};
|
|
697
|
+
function decodeQueryPlan(p) {
|
|
698
|
+
const candidates = p.candidates ? {
|
|
699
|
+
surfaced: p.candidates.surfaced,
|
|
700
|
+
survived: p.candidates.survived,
|
|
701
|
+
droppedOutOfScope: p.candidates.dropped_out_of_scope,
|
|
702
|
+
droppedStale: p.candidates.dropped_stale,
|
|
703
|
+
droppedFiltered: p.candidates.dropped_filtered,
|
|
704
|
+
droppedMinScore: p.candidates.dropped_min_score
|
|
705
|
+
} : void 0;
|
|
706
|
+
const t = p.timings;
|
|
707
|
+
const timings = {
|
|
708
|
+
...t.narrow_us !== void 0 ? { narrowUs: t.narrow_us } : {},
|
|
709
|
+
...t.gather_us !== void 0 ? { gatherUs: t.gather_us } : {},
|
|
710
|
+
...t.walk_us !== void 0 ? { walkUs: t.walk_us } : {},
|
|
711
|
+
...t.resolve_us !== void 0 ? { resolveUs: t.resolve_us } : {},
|
|
712
|
+
...t.first_pass_us !== void 0 ? { firstPassUs: t.first_pass_us } : {},
|
|
713
|
+
...t.rescore_us !== void 0 ? { rescoreUs: t.rescore_us } : {},
|
|
714
|
+
...t.score_us !== void 0 ? { scoreUs: t.score_us } : {},
|
|
715
|
+
totalUs: t.total_us
|
|
716
|
+
};
|
|
717
|
+
return {
|
|
718
|
+
path: p.path,
|
|
719
|
+
...p.rows_scanned !== void 0 ? { rowsScanned: p.rows_scanned } : {},
|
|
720
|
+
...candidates ? { candidates } : {},
|
|
721
|
+
narrowing: {
|
|
722
|
+
state: p.narrowing.state,
|
|
723
|
+
...p.narrowing.candidates !== void 0 ? { candidates: p.narrowing.candidates } : {}
|
|
724
|
+
},
|
|
725
|
+
timings
|
|
726
|
+
};
|
|
727
|
+
}
|
|
628
728
|
function encodeExpand(e) {
|
|
629
729
|
if (!e) return void 0;
|
|
630
730
|
return prune({
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 Predicate,\n ProjectionOptions,\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 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 /** 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 /**\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 /** 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 /** 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/** 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 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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -149,6 +149,52 @@ interface Annotations {
|
|
|
149
149
|
/** Highlighted fragments, one entry per clause field that had a match. */
|
|
150
150
|
highlights?: Highlight[];
|
|
151
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* The scan strategy a `*WithPlan` query actually took. An open string, not a closed
|
|
154
|
+
* union: known values today are `"ann"`, `"ann_prefilter_fallback"`, `"segmented"`,
|
|
155
|
+
* `"quantized"`, `"exact"`, but a newer server may report one this SDK predates.
|
|
156
|
+
*/
|
|
157
|
+
type QueryPath = string;
|
|
158
|
+
/** How many candidates survived each stage of a `*WithPlan` query, per {@link QueryPlan}. */
|
|
159
|
+
interface PlanCandidates {
|
|
160
|
+
surfaced: number;
|
|
161
|
+
survived: number;
|
|
162
|
+
droppedOutOfScope: number;
|
|
163
|
+
droppedStale: number;
|
|
164
|
+
droppedFiltered: number;
|
|
165
|
+
droppedMinScore: number;
|
|
166
|
+
}
|
|
167
|
+
/** Whether a `*WithPlan` query's filter index narrowed the scan, per {@link QueryPlan}. */
|
|
168
|
+
interface PlanNarrowing {
|
|
169
|
+
state: "inactive" | "declined" | "narrowed";
|
|
170
|
+
/** Present only when `state` is `"narrowed"`. */
|
|
171
|
+
candidates?: number;
|
|
172
|
+
}
|
|
173
|
+
/** Per-stage timings of a `*WithPlan` query, in integer microseconds. */
|
|
174
|
+
interface PlanTimings {
|
|
175
|
+
narrowUs?: number;
|
|
176
|
+
gatherUs?: number;
|
|
177
|
+
walkUs?: number;
|
|
178
|
+
resolveUs?: number;
|
|
179
|
+
firstPassUs?: number;
|
|
180
|
+
rescoreUs?: number;
|
|
181
|
+
scoreUs?: number;
|
|
182
|
+
totalUs: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* How the server answered a `*WithPlan` query, returned alongside its hits by
|
|
186
|
+
* {@link NidusClient.searchWithPlan}, {@link NidusClient.searchSimilarWithPlan}, and
|
|
187
|
+
* {@link NidusClient.hybridSearchWithPlan}.
|
|
188
|
+
*/
|
|
189
|
+
interface QueryPlan {
|
|
190
|
+
path: QueryPath;
|
|
191
|
+
/** Absent on the `ann`/`segmented` paths, where it does not apply. */
|
|
192
|
+
rowsScanned?: number;
|
|
193
|
+
/** Absent when no filter-index walk ran. */
|
|
194
|
+
candidates?: PlanCandidates;
|
|
195
|
+
narrowing: PlanNarrowing;
|
|
196
|
+
timings: PlanTimings;
|
|
197
|
+
}
|
|
152
198
|
/**
|
|
153
199
|
* A {@link Value} decoded back to a plain JS value. A `DateTime` comes back as a
|
|
154
200
|
* `Date`, not a number, so a decoded `attrs` map re-encodes to what it came from.
|
|
@@ -696,8 +742,18 @@ declare class NidusClient {
|
|
|
696
742
|
setFilterIndex(name: string, fields: (string | FilterIndexField)[]): Promise<void>;
|
|
697
743
|
/** Vector (cosine) nearest-neighbour search. Empty `scope` searches all collections. */
|
|
698
744
|
search(opts: SearchOptions): Promise<Hit[]>;
|
|
745
|
+
/** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */
|
|
746
|
+
searchWithPlan(opts: SearchOptions): Promise<{
|
|
747
|
+
hits: Hit[];
|
|
748
|
+
plan: QueryPlan;
|
|
749
|
+
}>;
|
|
699
750
|
/** Records most like an existing one. The source record itself is never returned. */
|
|
700
751
|
searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]>;
|
|
752
|
+
/** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */
|
|
753
|
+
searchSimilarWithPlan(opts: SimilarSearchOptions): Promise<{
|
|
754
|
+
hits: Hit[];
|
|
755
|
+
plan: QueryPlan;
|
|
756
|
+
}>;
|
|
701
757
|
/**
|
|
702
758
|
* BM25 full-text search over one indexed field, or over a `clauses` list folded by
|
|
703
759
|
* `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
|
|
@@ -708,6 +764,11 @@ declare class NidusClient {
|
|
|
708
764
|
* the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
|
|
709
765
|
*/
|
|
710
766
|
hybridSearch(opts: HybridSearchOptions): Promise<Hit[]>;
|
|
767
|
+
/** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */
|
|
768
|
+
hybridSearchWithPlan(opts: HybridSearchOptions): Promise<{
|
|
769
|
+
hits: Hit[];
|
|
770
|
+
plan: QueryPlan;
|
|
771
|
+
}>;
|
|
711
772
|
/** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
|
|
712
773
|
list(opts?: ListOptions): Promise<Hit[]>;
|
|
713
774
|
/**
|
|
@@ -749,6 +810,8 @@ declare class NidusClient {
|
|
|
749
810
|
refresh(): Promise<boolean>;
|
|
750
811
|
/** Run a search-family request and decode the resulting hits' attrs. */
|
|
751
812
|
private searchRequest;
|
|
813
|
+
/** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */
|
|
814
|
+
private searchRequestWithPlan;
|
|
752
815
|
/** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */
|
|
753
816
|
private decodeHit;
|
|
754
817
|
/** Issue a request and parse a JSON body, mapping a non-2xx to {@link NidusError}. */
|
|
@@ -873,4 +936,4 @@ declare function decodeValue(value: Value): DecodedValue;
|
|
|
873
936
|
/** Decode a whole wire `attrs` map back to plain JS values. */
|
|
874
937
|
declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
|
|
875
938
|
|
|
876
|
-
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 Predicate, type ProjectionOptions, 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 };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -149,6 +149,52 @@ interface Annotations {
|
|
|
149
149
|
/** Highlighted fragments, one entry per clause field that had a match. */
|
|
150
150
|
highlights?: Highlight[];
|
|
151
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* The scan strategy a `*WithPlan` query actually took. An open string, not a closed
|
|
154
|
+
* union: known values today are `"ann"`, `"ann_prefilter_fallback"`, `"segmented"`,
|
|
155
|
+
* `"quantized"`, `"exact"`, but a newer server may report one this SDK predates.
|
|
156
|
+
*/
|
|
157
|
+
type QueryPath = string;
|
|
158
|
+
/** How many candidates survived each stage of a `*WithPlan` query, per {@link QueryPlan}. */
|
|
159
|
+
interface PlanCandidates {
|
|
160
|
+
surfaced: number;
|
|
161
|
+
survived: number;
|
|
162
|
+
droppedOutOfScope: number;
|
|
163
|
+
droppedStale: number;
|
|
164
|
+
droppedFiltered: number;
|
|
165
|
+
droppedMinScore: number;
|
|
166
|
+
}
|
|
167
|
+
/** Whether a `*WithPlan` query's filter index narrowed the scan, per {@link QueryPlan}. */
|
|
168
|
+
interface PlanNarrowing {
|
|
169
|
+
state: "inactive" | "declined" | "narrowed";
|
|
170
|
+
/** Present only when `state` is `"narrowed"`. */
|
|
171
|
+
candidates?: number;
|
|
172
|
+
}
|
|
173
|
+
/** Per-stage timings of a `*WithPlan` query, in integer microseconds. */
|
|
174
|
+
interface PlanTimings {
|
|
175
|
+
narrowUs?: number;
|
|
176
|
+
gatherUs?: number;
|
|
177
|
+
walkUs?: number;
|
|
178
|
+
resolveUs?: number;
|
|
179
|
+
firstPassUs?: number;
|
|
180
|
+
rescoreUs?: number;
|
|
181
|
+
scoreUs?: number;
|
|
182
|
+
totalUs: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* How the server answered a `*WithPlan` query, returned alongside its hits by
|
|
186
|
+
* {@link NidusClient.searchWithPlan}, {@link NidusClient.searchSimilarWithPlan}, and
|
|
187
|
+
* {@link NidusClient.hybridSearchWithPlan}.
|
|
188
|
+
*/
|
|
189
|
+
interface QueryPlan {
|
|
190
|
+
path: QueryPath;
|
|
191
|
+
/** Absent on the `ann`/`segmented` paths, where it does not apply. */
|
|
192
|
+
rowsScanned?: number;
|
|
193
|
+
/** Absent when no filter-index walk ran. */
|
|
194
|
+
candidates?: PlanCandidates;
|
|
195
|
+
narrowing: PlanNarrowing;
|
|
196
|
+
timings: PlanTimings;
|
|
197
|
+
}
|
|
152
198
|
/**
|
|
153
199
|
* A {@link Value} decoded back to a plain JS value. A `DateTime` comes back as a
|
|
154
200
|
* `Date`, not a number, so a decoded `attrs` map re-encodes to what it came from.
|
|
@@ -696,8 +742,18 @@ declare class NidusClient {
|
|
|
696
742
|
setFilterIndex(name: string, fields: (string | FilterIndexField)[]): Promise<void>;
|
|
697
743
|
/** Vector (cosine) nearest-neighbour search. Empty `scope` searches all collections. */
|
|
698
744
|
search(opts: SearchOptions): Promise<Hit[]>;
|
|
745
|
+
/** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */
|
|
746
|
+
searchWithPlan(opts: SearchOptions): Promise<{
|
|
747
|
+
hits: Hit[];
|
|
748
|
+
plan: QueryPlan;
|
|
749
|
+
}>;
|
|
699
750
|
/** Records most like an existing one. The source record itself is never returned. */
|
|
700
751
|
searchSimilar(opts: SimilarSearchOptions): Promise<Hit[]>;
|
|
752
|
+
/** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */
|
|
753
|
+
searchSimilarWithPlan(opts: SimilarSearchOptions): Promise<{
|
|
754
|
+
hits: Hit[];
|
|
755
|
+
plan: QueryPlan;
|
|
756
|
+
}>;
|
|
701
757
|
/**
|
|
702
758
|
* BM25 full-text search over one indexed field, or over a `clauses` list folded by
|
|
703
759
|
* `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
|
|
@@ -708,6 +764,11 @@ declare class NidusClient {
|
|
|
708
764
|
* the same single-field / `clauses` choice as {@link NidusClient.textSearch}.
|
|
709
765
|
*/
|
|
710
766
|
hybridSearch(opts: HybridSearchOptions): Promise<Hit[]>;
|
|
767
|
+
/** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */
|
|
768
|
+
hybridSearchWithPlan(opts: HybridSearchOptions): Promise<{
|
|
769
|
+
hits: Hit[];
|
|
770
|
+
plan: QueryPlan;
|
|
771
|
+
}>;
|
|
711
772
|
/** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
|
|
712
773
|
list(opts?: ListOptions): Promise<Hit[]>;
|
|
713
774
|
/**
|
|
@@ -749,6 +810,8 @@ declare class NidusClient {
|
|
|
749
810
|
refresh(): Promise<boolean>;
|
|
750
811
|
/** Run a search-family request and decode the resulting hits' attrs. */
|
|
751
812
|
private searchRequest;
|
|
813
|
+
/** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */
|
|
814
|
+
private searchRequestWithPlan;
|
|
752
815
|
/** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */
|
|
753
816
|
private decodeHit;
|
|
754
817
|
/** Issue a request and parse a JSON body, mapping a non-2xx to {@link NidusError}. */
|
|
@@ -873,4 +936,4 @@ declare function decodeValue(value: Value): DecodedValue;
|
|
|
873
936
|
/** Decode a whole wire `attrs` map back to plain JS values. */
|
|
874
937
|
declare function decodeAttrs(attrs: Record<string, Value>): Record<string, DecodedValue>;
|
|
875
938
|
|
|
876
|
-
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 Predicate, type ProjectionOptions, 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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -327,6 +327,25 @@ var NidusClient = class {
|
|
|
327
327
|
rerank: encodeRerank(opts.rerank)
|
|
328
328
|
});
|
|
329
329
|
}
|
|
330
|
+
/** Like {@link NidusClient.search}, but also reports the scan strategy the server took. */
|
|
331
|
+
searchWithPlan(opts) {
|
|
332
|
+
return this.searchRequestWithPlan("/search", {
|
|
333
|
+
query: opts.query,
|
|
334
|
+
scope: opts.scope ?? [],
|
|
335
|
+
top_k: opts.topK,
|
|
336
|
+
offset: opts.offset,
|
|
337
|
+
min_score: opts.minScore,
|
|
338
|
+
filter: opts.filter ?? [],
|
|
339
|
+
exact: opts.exact,
|
|
340
|
+
include_attributes: opts.includeAttributes,
|
|
341
|
+
exclude_attributes: opts.excludeAttributes,
|
|
342
|
+
rank_by: encodeRankBy(opts.rankBy),
|
|
343
|
+
limit_per: opts.limitPer,
|
|
344
|
+
diversity: opts.diversity,
|
|
345
|
+
expand: encodeExpand(opts.expand),
|
|
346
|
+
rerank: encodeRerank(opts.rerank)
|
|
347
|
+
});
|
|
348
|
+
}
|
|
330
349
|
/** Records most like an existing one. The source record itself is never returned. */
|
|
331
350
|
searchSimilar(opts) {
|
|
332
351
|
return this.searchRequest("/search/similar", {
|
|
@@ -346,6 +365,25 @@ var NidusClient = class {
|
|
|
346
365
|
expand: encodeExpand(opts.expand)
|
|
347
366
|
});
|
|
348
367
|
}
|
|
368
|
+
/** Like {@link NidusClient.searchSimilar}, but also reports the scan strategy taken. */
|
|
369
|
+
searchSimilarWithPlan(opts) {
|
|
370
|
+
return this.searchRequestWithPlan("/search/similar", {
|
|
371
|
+
collection: opts.collection,
|
|
372
|
+
id: opts.id,
|
|
373
|
+
scope: opts.scope ?? [],
|
|
374
|
+
top_k: opts.topK,
|
|
375
|
+
offset: opts.offset,
|
|
376
|
+
min_score: opts.minScore,
|
|
377
|
+
filter: opts.filter ?? [],
|
|
378
|
+
exact: opts.exact,
|
|
379
|
+
include_attributes: opts.includeAttributes,
|
|
380
|
+
exclude_attributes: opts.excludeAttributes,
|
|
381
|
+
rank_by: encodeRankBy(opts.rankBy),
|
|
382
|
+
limit_per: opts.limitPer,
|
|
383
|
+
diversity: opts.diversity,
|
|
384
|
+
expand: encodeExpand(opts.expand)
|
|
385
|
+
});
|
|
386
|
+
}
|
|
349
387
|
/**
|
|
350
388
|
* BM25 full-text search over one indexed field, or over a `clauses` list folded by
|
|
351
389
|
* `combine` (`"Sum"` unless said otherwise). Naming the fields both ways is a `400`.
|
|
@@ -391,6 +429,25 @@ var NidusClient = class {
|
|
|
391
429
|
rerank: encodeRerank(opts.rerank)
|
|
392
430
|
});
|
|
393
431
|
}
|
|
432
|
+
/** Like {@link NidusClient.hybridSearch}, but also reports the scan strategy taken. */
|
|
433
|
+
hybridSearchWithPlan(opts) {
|
|
434
|
+
return this.searchRequestWithPlan("/hybrid-search", {
|
|
435
|
+
vector: opts.vector,
|
|
436
|
+
...opts.clauses ? { clauses: opts.clauses, combine: opts.combine } : { field: opts.field, text: opts.text },
|
|
437
|
+
scope: opts.scope ?? [],
|
|
438
|
+
top_k: opts.topK,
|
|
439
|
+
offset: opts.offset,
|
|
440
|
+
filter: opts.filter ?? [],
|
|
441
|
+
rrf_k: opts.rrfK,
|
|
442
|
+
candidates: opts.candidates,
|
|
443
|
+
explain: opts.explain,
|
|
444
|
+
highlight: encodeHighlight(opts.highlight),
|
|
445
|
+
vector_weight: opts.vectorWeight,
|
|
446
|
+
text_weight: opts.textWeight,
|
|
447
|
+
expand: encodeExpand(opts.expand),
|
|
448
|
+
rerank: encodeRerank(opts.rerank)
|
|
449
|
+
});
|
|
450
|
+
}
|
|
394
451
|
/** Metadata-only listing (no vector), paginated by `offset`/`limit`. */
|
|
395
452
|
list(opts = {}) {
|
|
396
453
|
return this.searchRequest("/list", {
|
|
@@ -545,6 +602,18 @@ var NidusClient = class {
|
|
|
545
602
|
const hits = await this.request("POST", path, prune(body));
|
|
546
603
|
return hits.map((h) => this.decodeHit(h));
|
|
547
604
|
}
|
|
605
|
+
/** Like {@link NidusClient.searchRequest}, asking for `plan: true` and decoding it too. */
|
|
606
|
+
async searchRequestWithPlan(path, body) {
|
|
607
|
+
const res = await this.request(
|
|
608
|
+
"POST",
|
|
609
|
+
path,
|
|
610
|
+
prune({ ...body, plan: true })
|
|
611
|
+
);
|
|
612
|
+
return {
|
|
613
|
+
hits: res.hits.map((h) => this.decodeHit(h)),
|
|
614
|
+
plan: decodeQueryPlan(res.plan)
|
|
615
|
+
};
|
|
616
|
+
}
|
|
548
617
|
/** One wire hit into a {@link Hit}. Shared so every search surface decodes identically. */
|
|
549
618
|
decodeHit(h) {
|
|
550
619
|
return {
|
|
@@ -592,6 +661,37 @@ var NidusClient = class {
|
|
|
592
661
|
}
|
|
593
662
|
}
|
|
594
663
|
};
|
|
664
|
+
function decodeQueryPlan(p) {
|
|
665
|
+
const candidates = p.candidates ? {
|
|
666
|
+
surfaced: p.candidates.surfaced,
|
|
667
|
+
survived: p.candidates.survived,
|
|
668
|
+
droppedOutOfScope: p.candidates.dropped_out_of_scope,
|
|
669
|
+
droppedStale: p.candidates.dropped_stale,
|
|
670
|
+
droppedFiltered: p.candidates.dropped_filtered,
|
|
671
|
+
droppedMinScore: p.candidates.dropped_min_score
|
|
672
|
+
} : void 0;
|
|
673
|
+
const t = p.timings;
|
|
674
|
+
const timings = {
|
|
675
|
+
...t.narrow_us !== void 0 ? { narrowUs: t.narrow_us } : {},
|
|
676
|
+
...t.gather_us !== void 0 ? { gatherUs: t.gather_us } : {},
|
|
677
|
+
...t.walk_us !== void 0 ? { walkUs: t.walk_us } : {},
|
|
678
|
+
...t.resolve_us !== void 0 ? { resolveUs: t.resolve_us } : {},
|
|
679
|
+
...t.first_pass_us !== void 0 ? { firstPassUs: t.first_pass_us } : {},
|
|
680
|
+
...t.rescore_us !== void 0 ? { rescoreUs: t.rescore_us } : {},
|
|
681
|
+
...t.score_us !== void 0 ? { scoreUs: t.score_us } : {},
|
|
682
|
+
totalUs: t.total_us
|
|
683
|
+
};
|
|
684
|
+
return {
|
|
685
|
+
path: p.path,
|
|
686
|
+
...p.rows_scanned !== void 0 ? { rowsScanned: p.rows_scanned } : {},
|
|
687
|
+
...candidates ? { candidates } : {},
|
|
688
|
+
narrowing: {
|
|
689
|
+
state: p.narrowing.state,
|
|
690
|
+
...p.narrowing.candidates !== void 0 ? { candidates: p.narrowing.candidates } : {}
|
|
691
|
+
},
|
|
692
|
+
timings
|
|
693
|
+
};
|
|
694
|
+
}
|
|
595
695
|
function encodeExpand(e) {
|
|
596
696
|
if (!e) return void 0;
|
|
597
697
|
return prune({
|
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 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 /** 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 /**\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 /** 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 /** 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/** 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?: { 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":";AAgCO,SAAS,kBAAkB,GAAiC;AACjE,QAAM,MAAmB,CAAC;AAC1B,MAAI,EAAE,OAAQ,KAAI,SAAS,EAAE;AAC7B,MAAI,EAAE,KAAM,KAAI,OAAO,EAAE;AACzB,MAAI,EAAE,QAAS,KAAI,UAAU,EAAE;AAC/B,MAAI,EAAE,WAAY,KAAI,aAAa,EAAE,WAAW,IAAI,eAAe;AACnE,SAAO;AACT;AAEA,SAAS,gBAAgB,GAA6B;AACpD,SAAO,EAAE,OAAO,EAAE,OAAO,WAAW,EAAE,UAAU,IAAI,cAAc,EAAE;AACtE;AAEA,SAAS,eAAe,IAA4B;AAClD,SAAO,EAAE,MAAM,GAAG,MAAM,OAAO,gBAAgB,GAAG,MAAM,GAAG,KAAK,EAAE;AACpE;AAOO,SAAS,gBACd,MACA,OACoB;AACpB,MAAI,MAAM,WAAW,KAAK,QAAQ,IAAI,EAAG,QAAO;AAChD,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,KAAK,CAAC,MACV,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC;AAClD,SAAO,MAAM,IAAI,CAAC,CAAC,OAAO,GAAG,MAAwB,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;AAC3E;AAGA,SAAS,WAAW,MAAwB;AAC1C,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO;AAGX,aAAW,MAAM,MAAM;AACrB,aAAS,IAAI,QAAQ,GAAG,YAAY,CAAC,CAAE,GAAG,IAAI,GAAG,IAAK,OAAM,KAAK,IAAI;AACrE,YAAQ,GAAG;AAAA,EACb;AACA,QAAM,KAAK,IAAI;AACf,SAAO;AACT;AAEA,SAAS,QAAQ,WAA2B;AAC1C,MAAI,YAAY,IAAM,QAAO;AAC7B,MAAI,YAAY,KAAO,QAAO;AAC9B,SAAO,YAAY,QAAU,IAAI;AACnC;AAGA,SAAS,QAAQ,MAAuB;AACtC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,WAAW,CAAC,IAAI,IAAM,QAAO;AAAA,EACxC;AACA,SAAO;AACT;;;ACnFO,IAAM,aAAN,cAAyB,MAAM;AAAA;AAAA,EAE3B;AAAA,EAET,YAAY,SAAiB,QAAgB;AAC3C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,eAAwB;AAC1B,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAEA,IAAI,aAAsB;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAEA,IAAI,WAAoB;AACtB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAEA,IAAI,kBAA2B;AAC7B,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;ACpBA,IAAM,OAAO,CAAC,OAAO,OAAO,QAAQ,QAAQ,SAAS,UAAU;AAOxD,IAAM,IAAI;AAAA,EACf,KAAK,CAAC,OAAsB,EAAE,KAAK,EAAE;AAAA,EACrC,KAAK,CAAC,MAAqB;AACzB,QAAI,CAAC,OAAO,UAAU,CAAC,GAAG;AACxB,YAAM,IAAI,UAAU,iCAAiC,CAAC,EAAE;AAAA,IAC1D;AACA,WAAO,EAAE,KAAK,EAAE;AAAA,EAClB;AAAA,EACA,OAAO,CAAC,MAAqB;AAC3B,QAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;AAChD,YAAM,IAAI,UAAU,wCAAwC,CAAC,EAAE;AAAA,IACjE;AACA,WAAO,EAAE,OAAO,EAAE;AAAA,EACpB;AAAA,EACA,MAAM,CAAC,OAAuB,EAAE,MAAM,EAAE;AAAA,EACxC,MAAM,CAAC,WAA4B,EAAE,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAKjD,UAAU,CAAC,SAA+B;AACxC,UAAM,KAAK,gBAAgB,OAAO,KAAK,QAAQ,IAAI;AACnD,QAAI,CAAC,OAAO,cAAc,EAAE,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR,oDAAoD,IAAI;AAAA,MAC1D;AAAA,IACF;AACA,WAAO,EAAE,UAAU,GAAG;AAAA,EACxB;AAAA;AAAA,EAEA,KAAK,MAAa;AACpB;AAGA,SAAS,QAAQ,GAAwB;AACvC,MAAI,MAAM,OAAQ,QAAO;AACzB,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,SAAO,KAAK,KAAK,CAAC,QAAQ,OAAO,CAAC;AACpC;AAOO,SAAS,YAAY,OAAyB;AACnD,MAAI,QAAQ,KAAK,EAAG,QAAO;AAC3B,MAAI,UAAU,KAAM,QAAO;AAC3B,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AACH,aAAO,EAAE,KAAK,MAAM;AAAA,IACtB,KAAK;AACH,aAAO,EAAE,MAAM,MAAM;AAAA,IACvB,KAAK;AACH,aAAO,OAAO,UAAU,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,MAAM,KAAK;AAAA,IAC/D,KAAK;AAEH,UAAI,iBAAiB,KAAM,QAAO,EAAE,SAAS,KAAK;AAClD,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAI,CAAC,MAAM,MAAM,CAAC,MAAM,OAAO,MAAM,QAAQ,GAAG;AAC9C,gBAAM,IAAI,UAAU,4CAA4C;AAAA,QAClE;AACA,eAAO,EAAE,MAAM,MAAM;AAAA,MACvB;AAAA;AAAA,IAEF;AACE,YAAM,IAAI,UAAU,kCAAkC,OAAO,KAAK,CAAC,EAAE;AAAA,EACzE;AACF;AAGO,SAAS,YACd,OACuB;AACvB,QAAM,MAA6B,CAAC;AACpC,aAAW,CAAC,GAAG,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC5C,QAAI,CAAC,IAAI,YAAY,GAAG;AAAA,EAC1B;AACA,SAAO;AACT;AAGO,SAAS,YAAY,OAA4B;AACtD,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,SAAS,MAAO,QAAO,MAAM;AACjC,MAAI,SAAS,MAAO,QAAO,MAAM;AACjC,MAAI,UAAU,MAAO,QAAO,MAAM;AAClC,MAAI,UAAU,MAAO,QAAO,MAAM;AAClC,MAAI,WAAW,MAAO,QAAO,MAAM;AAGnC,MAAI,cAAc,MAAO,QAAO,IAAI,KAAK,MAAM,QAAQ;AAEvD,SAAO;AACT;AAGO,SAAS,YACd,OAC8B;AAC9B,QAAM,MAAoC,CAAC;AAC3C,aAAW,CAAC,GAAG,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC5C,QAAI,CAAC,IAAI,YAAY,GAAG;AAAA,EAC1B;AACA,SAAO;AACT;;;AC7DO,IAAM,cAAN,MAAkB;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAA6B;AACvC,QAAI,CAAC,QAAQ,SAAS;AACpB,YAAM,IAAI,UAAU,gCAAgC;AAAA,IACtD;AACA,SAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACjD,SAAK,QAAQ,QAAQ;AACrB,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,eAAe,QAAQ,WAAW,CAAC;AACxC,UAAMA,KAAI,QAAQ,SAAS,WAAW;AACtC,QAAI,OAAOA,OAAM,YAAY;AAC3B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,SAAK,UAAUA,OAAM,WAAW,QAAQA,GAAE,KAAK,UAAU,IAAIA;AAAA,EAC/D;AAAA;AAAA;AAAA,EAKA,MAAM,SAA2B;AAC/B,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,IAAI,OAAO,SAAS;AAC3C,aAAO,IAAI;AAAA,IACb,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,QAAwB;AACtB,WAAO,KAAK,QAAe,OAAO,QAAQ;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAA4B;AAChC,UAAM,MAAM,MAAM,KAAK,IAAI,OAAO,QAAQ;AAC1C,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,IAAI,WAAW,IAAK,QAAO,EAAE,OAAO,OAAO,QAAQ,aAAa,MAAM,GAAG,EAAE;AAC/E,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,WAAW,aAAa,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM;AAC5E,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AAAA;AAAA,EAGA,UAAkC;AAChC,WAAO,KAAK,QAAuB,OAAO,UAAU;AAAA,EACtD;AAAA;AAAA,EAGA,WAAmC;AACjC,WAAO,KAAK,QAAuB,OAAO,WAAW;AAAA,EACvD;AAAA;AAAA,EAGA,cAAiC;AAC/B,WAAO,KAAK,QAAkB,OAAO,cAAc;AAAA,EACrD;AAAA;AAAA,EAGA,MAAM,iBAAiB,MAA6B;AAClD,UAAM,KAAK,QAAQ,QAAQ,gBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,EAC5D;AAAA;AAAA,EAGA,MAAM,eAAe,MAA6B;AAChD,UAAM,KAAK,QAAQ,UAAU,gBAAgB,IAAI,IAAI,CAAC,EAAE;AAAA,EAC1D;AAAA;AAAA,EAGA,QAAQ,MAA+C;AACrD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,gBAAgB,IAAI,IAAI,CAAC;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QAAQ,MAAc,MAA6C;AACvE,UAAM,KAAK,QAAQ,OAAO,gBAAgB,IAAI,IAAI,CAAC,SAAS,IAAI;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,MAAc,SAAyC;AAClE,UAAM,OAAsB,QAAQ,IAAI,CAAC,OAAO;AAAA,MAC9C,IAAI,EAAE;AAAA,MACN,GAAI,EAAE,WAAW,SAAY,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC;AAAA,MACrD,OAAO,YAAY,EAAE,KAAK;AAAA,IAC5B,EAAE;AACF,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA,gBAAgB,IAAI,IAAI,CAAC;AAAA,MACzB,EAAE,SAAS,KAAK;AAAA,IAClB;AACA,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,OAAO,MAAc,MAA0C;AACnE,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA,gBAAgB,IAAI,IAAI,CAAC;AAAA,MACzB,EAAE,KAAK,KAAK,IAAI;AAAA,IAClB;AACA,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,YAAY,MAAc,QAAiC;AAC/D,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA,gBAAgB,IAAI,IAAI,CAAC;AAAA,MACzB,EAAE,OAAO;AAAA,IACX;AACA,WAAO,IAAI;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,QAAQ,MAAwC;AACpD,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB;AAAA,MACA,gBAAgB,IAAI,IAAI,CAAC;AAAA,IAC3B;AACA,WAAO,KAAK,IAAI,CAAC,OAAO;AAAA,MACtB,IAAI,EAAE;AAAA,MACN,GAAI,EAAE,WAAW,SAAY,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC;AAAA,MACrD,OAAO,YAAY,EAAE,KAAK;AAAA,IAC5B,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aACJ,MACA,QACe;AACf,UAAM,KAAK,QAAQ,QAAQ,gBAAgB,IAAI,IAAI,CAAC,eAAe;AAAA,MACjE,QAAQ,OAAO,IAAI,cAAc;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,eACJ,MACA,QACe;AACf,UAAM,KAAK,QAAQ,QAAQ,gBAAgB,IAAI,IAAI,CAAC,iBAAiB;AAAA,MACnE,QAAQ,OAAO,IAAI,sBAAsB;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAKA,OAAO,MAAqC;AAC1C,WAAO,KAAK,cAAc,WAAW;AAAA,MACnC,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,eACE,MAC2C;AAC3C,WAAO,KAAK,sBAAsB,WAAW;AAAA,MAC3C,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,cAAc,MAA4C;AACxD,WAAO,KAAK,cAAc,mBAAmB;AAAA,MAC3C,YAAY,KAAK;AAAA,MACjB,IAAI,KAAK;AAAA,MACT,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,sBACE,MAC2C;AAC3C,WAAO,KAAK,sBAAsB,mBAAmB;AAAA,MACnD,YAAY,KAAK;AAAA,MACjB,IAAI,KAAK;AAAA,MACT,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,MAAyC;AAClD,WAAO,KAAK,cAAc,gBAAgB;AAAA,MACxC,GAAI,KAAK,UACL,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ,IAC/C,EAAE,OAAO,KAAK,OAAO,OAAO,KAAK,MAAM;AAAA,MAC3C,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,SAAS,KAAK;AAAA,MACd,WAAW,gBAAgB,KAAK,SAAS;AAAA,MACzC,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAA2C;AACtD,WAAO,KAAK,cAAc,kBAAkB;AAAA,MAC1C,QAAQ,KAAK;AAAA,MACb,GAAI,KAAK,UACL,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ,IAC/C,EAAE,OAAO,KAAK,OAAO,MAAM,KAAK,KAAK;AAAA,MACzC,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,MACd,WAAW,gBAAgB,KAAK,SAAS;AAAA,MACzC,eAAe,KAAK;AAAA,MACpB,aAAa,KAAK;AAAA,MAClB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,qBACE,MAC2C;AAC3C,WAAO,KAAK,sBAAsB,kBAAkB;AAAA,MAClD,QAAQ,KAAK;AAAA,MACb,GAAI,KAAK,UACL,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,QAAQ,IAC/C,EAAE,OAAO,KAAK,OAAO,MAAM,KAAK,KAAK;AAAA,MACzC,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,MACd,WAAW,gBAAgB,KAAK,SAAS;AAAA,MACzC,eAAe,KAAK;AAAA,MACpB,aAAa,KAAK;AAAA,MAClB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,KAAK,OAAoB,CAAC,GAAmB;AAC3C,WAAO,KAAK,cAAc,SAAS;AAAA,MACjC,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,UAAU,KAAK;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAU,OAAyB,CAAC,GAAyB;AACjE,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA,MAAM;AAAA,QACJ,OAAO,KAAK,SAAS,CAAC;AAAA,QACtB,QAAQ,KAAK,UAAU,CAAC;AAAA,QACxB,KAAK,KAAK,OAAO,CAAC;AAAA,QAClB,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,OAAO,IAAI;AAAA,MACX,MAAM,YAAY,IAAI,IAAI;AAAA;AAAA,MAE1B,GAAI,IAAI,SACJ;AAAA,QACE,QAAQ,IAAI,OAAO,IAAI,CAAC,OAAO;AAAA,UAC7B,OAAO,EAAE,UAAU,OAAO,OAAO,YAAY,EAAE,KAAK;AAAA,UACpD,OAAO,EAAE;AAAA,UACT,MAAM,YAAY,EAAE,IAAI;AAAA,QAC1B,EAAE;AAAA,MACJ,IACA,CAAC;AAAA,MACL,GAAI,IAAI,mBAAmB,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,YAAY,MAA4C;AAC5D,UAAM,OAAO,MAAM;AAAA,MACjB,SAAS,KAAK,QAAQ,IAAI,CAAC,OAAO;AAAA,QAChC,OAAO,EAAE;AAAA,QACT,OAAO,EAAE,SAAS,CAAC;AAAA,QACnB,OAAO,EAAE;AAAA,QACT,QAAQ,EAAE;AAAA,QACV,WAAW,EAAE;AAAA,QACb,QAAQ,EAAE,UAAU,CAAC;AAAA,QACrB,OAAO,EAAE;AAAA,QACT,oBAAoB,EAAE;AAAA,QACtB,oBAAoB,EAAE;AAAA,QACtB,SAAS,aAAa,EAAE,MAAM;AAAA,QAC9B,WAAW,EAAE;AAAA,QACb,WAAW,EAAE;AAAA,QACb,QAAQ,aAAa,EAAE,MAAM;AAAA,MAC/B,EAAE;AAAA,MACF,MAAM,KAAK,OACP,MAAM;AAAA,QACJ,OAAO,KAAK,KAAK;AAAA,QACjB,SAAS,KAAK,KAAK;AAAA,QACnB,OAAO,KAAK,KAAK;AAAA,MACnB,CAAC,IACD;AAAA,IACN,CAAC;AACD,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,YAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAK,IAAI,WAAW,CAAC,GAAI;AAAA,MAAI,CAAC,SAC1D,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,SACJ,YACA,IACA,MACA,OAAwB,CAAC,GACA;AACzB,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA,gBAAgB,IAAI,UAAU,CAAC;AAAA,MAC/B,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,MAAM,KAAK;AAAA,QACX,OAAO,KAAK,QAAQ,YAAY,KAAK,KAAK,IAAI;AAAA,QAC9C,aAAa,KAAK;AAAA,QAClB,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAAA,IACH;AAGA,WAAO;AAAA,MACL,IAAI,KAAK,MAAM;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OACE,YACA,OACA,OAAsB,CAAC,GACP;AAChB,WAAO,KAAK,cAAc,gBAAgB,IAAI,UAAU,CAAC,WAAW;AAAA,MAClE;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,WAAW,KAAK;AAAA,MAChB,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,QAAQ,aAAa,KAAK,MAAM;AAAA,MAChC,WAAW,KAAK;AAAA,MAChB,oBAAoB,KAAK;AAAA,MACzB,SAAS,aAAa,KAAK,MAAM;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,UAAM,KAAK,QAAQ,QAAQ,UAAU,CAAC,CAAC;AAAA,EACzC;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,KAAK,QAAQ,QAAQ,YAAY,CAAC,CAAC;AAAA,EAC3C;AAAA;AAAA,EAGA,MAAM,UAA4B;AAChC,UAAM,MAAM,MAAM,KAAK,QAA8B,QAAQ,YAAY,CAAC,CAAC;AAC3E,WAAO,IAAI;AAAA,EACb;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,MACA,MACgB;AAChB,UAAM,OAAO,MAAM,KAAK,QAAkB,QAAQ,MAAM,MAAM,IAAI,CAAC;AACnE,WAAO,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;AAAA,EAC1C;AAAA;AAAA,EAGA,MAAc,sBACZ,MACA,MAC2C;AAC3C,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA,MAAM,EAAE,GAAG,MAAM,MAAM,KAAK,CAAC;AAAA,IAC/B;AACA,WAAO;AAAA,MACL,MAAM,IAAI,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;AAAA,MAC3C,MAAM,gBAAgB,IAAI,IAAI;AAAA,IAChC;AAAA,EACF;AAAA;AAAA,EAGQ,UAAU,GAAgB;AAChC,WAAO;AAAA,MACL,YAAY,EAAE;AAAA,MACd,IAAI,EAAE;AAAA,MACN,OAAO,EAAE;AAAA,MACT,OAAO,YAAY,EAAE,KAAK;AAAA;AAAA,MAE1B,GAAI,EAAE,cACF,EAAE,aAAa,kBAAkB,EAAE,WAAW,EAAE,IAChD,CAAC;AAAA,MACL,GAAI,EAAE,YAAY,SAAY,EAAE,SAAS,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,MAAM,KAAK,IAAI,QAAQ,MAAM,IAAI;AAC7C,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,WAAW,aAAa,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM;AAAA,IACjE;AACA,WAAQ,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EACpC;AAAA;AAAA,EAGA,MAAc,IACZ,QACA,MACA,MACmB;AACnB,UAAM,UAAkC,EAAE,GAAG,KAAK,aAAa;AAC/D,QAAI,KAAK,MAAO,SAAQ,gBAAgB,UAAU,KAAK,KAAK;AAC5D,QAAI;AACJ,QAAI,SAAS,QAAW;AACtB,cAAQ,cAAc,IAAI;AAC1B,gBAAU,KAAK,UAAU,IAAI;AAAA,IAC/B;AAEA,UAAM,aAAa,KAAK,YAAY,IAAI,IAAI,gBAAgB,IAAI;AAChE,UAAM,QACJ,cAAc,KAAK,YAAY,IAC3B,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,SAAS,IACnD;AACN,QAAI;AACF,aAAO,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AAAA,QAClD;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,QAAQ,YAAY;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,SACH,YAAY,OAAO,WAAW,QAC3B,cAAc,IAAI,oBAAoB,KAAK,SAAS,OACpD,cAAc,IAAI,YAAa,IAAc,OAAO;AAC1D,YAAM,IAAI,WAAW,QAAQ,CAAC;AAAA,IAChC,UAAE;AACA,UAAI,MAAO,cAAa,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;AAsCA,SAAS,gBAAgB,GAA4B;AACnD,QAAM,aAAyC,EAAE,aAC7C;AAAA,IACE,UAAU,EAAE,WAAW;AAAA,IACvB,UAAU,EAAE,WAAW;AAAA,IACvB,mBAAmB,EAAE,WAAW;AAAA,IAChC,cAAc,EAAE,WAAW;AAAA,IAC3B,iBAAiB,EAAE,WAAW;AAAA,IAC9B,iBAAiB,EAAE,WAAW;AAAA,EAChC,IACA;AACJ,QAAM,IAAI,EAAE;AACZ,QAAM,UAAuB;AAAA,IAC3B,GAAI,EAAE,cAAc,SAAY,EAAE,UAAU,EAAE,UAAU,IAAI,CAAC;AAAA,IAC7D,GAAI,EAAE,cAAc,SAAY,EAAE,UAAU,EAAE,UAAU,IAAI,CAAC;AAAA,IAC7D,GAAI,EAAE,YAAY,SAAY,EAAE,QAAQ,EAAE,QAAQ,IAAI,CAAC;AAAA,IACvD,GAAI,EAAE,eAAe,SAAY,EAAE,WAAW,EAAE,WAAW,IAAI,CAAC;AAAA,IAChE,GAAI,EAAE,kBAAkB,SAAY,EAAE,aAAa,EAAE,cAAc,IAAI,CAAC;AAAA,IACxE,GAAI,EAAE,eAAe,SAAY,EAAE,WAAW,EAAE,WAAW,IAAI,CAAC;AAAA,IAChE,GAAI,EAAE,aAAa,SAAY,EAAE,SAAS,EAAE,SAAS,IAAI,CAAC;AAAA,IAC1D,SAAS,EAAE;AAAA,EACb;AACA,SAAO;AAAA,IACL,MAAM,EAAE;AAAA,IACR,GAAI,EAAE,iBAAiB,SAAY,EAAE,aAAa,EAAE,aAAa,IAAI,CAAC;AAAA,IACtE,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACnC,WAAW;AAAA,MACT,OAAO,EAAE,UAAU;AAAA,MACnB,GAAI,EAAE,UAAU,eAAe,SAC3B,EAAE,YAAY,EAAE,UAAU,WAAW,IACrC,CAAC;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;AAsBA,SAAS,aAAa,GAAgC;AACpD,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,MAAM;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,cAAc,EAAE;AAAA,IAChB,aAAa,EAAE;AAAA,IACf,YAAY,EAAE;AAAA,EAChB,CAAC;AACH;AAEA,SAAS,aAAa,GAAgC;AACpD,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,MAAM,EAAE,YAAY,EAAE,WAAW,YAAY,EAAE,WAAW,CAAC;AACpE;AAEA,SAAS,aAAa,MAAmC;AACvD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,KAAK;AACf,SAAO;AAAA,IACL,OAAO,MAAM;AAAA,MACX,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE,kBAAkB,OAAO,EAAE,OAAO,QAAQ,IAAI,EAAE;AAAA,MAC1D,OAAO,EAAE;AAAA,MACT,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE;AAAA,MACV,SAAS,EAAE;AAAA,MACX,aAAa,EAAE;AAAA,MACf,aAAa,EAAE;AAAA,MACf,cAAc,EAAE;AAAA,IAClB,CAAC;AAAA,EACH;AACF;AAGA,SAAS,gBAAgB,GAAoD;AAC3E,MAAI,MAAM,UAAa,MAAM,MAAO,QAAO;AAC3C,MAAI,MAAM,KAAM,QAAO,CAAC;AACxB,SAAO,MAAM;AAAA,IACX,eAAe,EAAE;AAAA,IACjB,gBAAgB,EAAE;AAAA,EACpB,CAAC;AACH;AAGA,SAAS,aAAa,GAAuC;AAC3D,MAAI,MAAM,OAAW,QAAO;AAC5B,SAAO,EAAE,OAAO,EAAE,OAAO,UAAU,EAAE,UAAU,WAAW,EAAE,SAAS;AACvE;AAGA,SAAS,IAAI,MAAsB;AACjC,SAAO,mBAAmB,IAAI;AAChC;AAOA,SAAS,eAAeA,IAA+B;AACrD,MAAI,OAAOA,OAAM,SAAU,QAAOA;AAClC,SAAO,MAAM;AAAA,IACX,OAAOA,GAAE;AAAA,IACT,IAAIA,GAAE;AAAA,IACN,GAAGA,GAAE;AAAA,IACL,UAAUA,GAAE;AAAA,IACZ,eAAeA,GAAE;AAAA,IACjB,eAAeA,GAAE;AAAA,EACnB,CAAC;AACH;AAOA,SAAS,uBAAuBA,IAAuC;AACrE,MAAI,OAAOA,OAAM,SAAU,QAAOA;AAClC,SAAO,MAAM;AAAA,IACX,OAAOA,GAAE;AAAA,IACT,QAAQA,GAAE;AAAA,IACV,UAAUA,GAAE;AAAA,EACd,CAAC;AACH;AAGA,SAAS,MAAM,MAAwD;AACrE,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC3C,QAAI,QAAQ,OAAW,KAAI,CAAC,IAAI;AAAA,EAClC;AACA,SAAO;AACT;AAGA,SAAS,aAAa,MAAc,QAAwB;AAC1D,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,UAAU,OAAO,OAAO,UAAU,SAAU,QAAO,OAAO;AAAA,EAChE,QAAQ;AAAA,EAER;AACA,SAAO,QAAQ,QAAQ,MAAM;AAC/B;;;ACl1BO,IAAM,IAAI;AAAA;AAAA,EAEf,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,MAAM,CAAC,KAAa,aAAgC,EAAE,MAAM,CAAC,KAAK,OAAO,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,EAK3E,OAAO,CAAC,KAAa,aAAgC;AAAA,IACnD,OAAO,CAAC,KAAK,OAAO;AAAA,EACtB;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,YAAoC;AAAA,IACpD,IAAI,CAAC,KAAK,OAAO,IAAI,WAAW,CAAC;AAAA,EACnC;AAAA;AAAA,EAEA,OAAO,CAAC,KAAa,YAAoC;AAAA,IACvD,OAAO,CAAC,KAAK,OAAO,IAAI,WAAW,CAAC;AAAA,EACtC;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,IAAI,CAAC,KAAa,WAAiC;AAAA,IACjD,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA,EAEA,UAAU,CAAC,KAAa,WAAiC;AAAA,IACvD,UAAU,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EACpC;AAAA;AAAA,EAEA,aAAa,CAAC,KAAa,WAAiC;AAAA,IAC1D,aAAa,CAAC,KAAK,YAAY,KAAK,CAAC;AAAA,EACvC;AAAA;AAAA,EAEA,aAAa,CAAC,KAAa,YAAoC;AAAA,IAC7D,aAAa,CAAC,KAAK,OAAO,IAAI,WAAW,CAAC;AAAA,EAC5C;AAAA;AAAA,EAEA,KAAK,IAAI,WAAmC,EAAE,KAAK,MAAM;AAAA;AAAA,EAEzD,KAAK,IAAI,WAAmC,EAAE,KAAK,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAKzD,KAAK,CAAC,UAAgC,EAAE,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,OAAO,CAAC,KAAa,MAAc,cAAiC;AAAA,IAClE,OAAO,CAAC,KAAK,MAAM,QAAQ;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,CAAC,KAAa,UAA6B;AAAA,IAC5D,mBAAmB,CAAC,KAAK,IAAI;AAAA,EAC/B;AAAA;AAAA,EAEA,kBAAkB,CAAC,KAAa,UAA6B;AAAA,IAC3D,kBAAkB,CAAC,KAAK,IAAI;AAAA,EAC9B;AAAA;AAAA,EAEA,uBAAuB,CAAC,KAAa,UAA6B;AAAA,IAChE,uBAAuB,CAAC,KAAK,IAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,CAAC,KAAa,aAAgC,EAAE,OAAO,CAAC,KAAK,OAAO,EAAE;AAAA;AAAA,EAE7E,KAAK,IAAI,UAA+B;AAC1C;","names":["f"]}
|
package/package.json
CHANGED