@anvailabs/proximadb-client 0.3.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.
Files changed (65) hide show
  1. package/README.md +160 -0
  2. package/dist/client.d.ts +319 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +681 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/collection.d.ts +227 -0
  7. package/dist/collection.d.ts.map +1 -0
  8. package/dist/collection.js +436 -0
  9. package/dist/collection.js.map +1 -0
  10. package/dist/esm/client.js +674 -0
  11. package/dist/esm/client.js.map +1 -0
  12. package/dist/esm/collection.js +428 -0
  13. package/dist/esm/collection.js.map +1 -0
  14. package/dist/esm/filter.js +228 -0
  15. package/dist/esm/filter.js.map +1 -0
  16. package/dist/esm/generated/schema.js +6 -0
  17. package/dist/esm/generated/schema.js.map +1 -0
  18. package/dist/esm/graph.js +678 -0
  19. package/dist/esm/graph.js.map +1 -0
  20. package/dist/esm/index.js +86 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/search.js +317 -0
  23. package/dist/esm/search.js.map +1 -0
  24. package/dist/esm/transport.js +33 -0
  25. package/dist/esm/transport.js.map +1 -0
  26. package/dist/esm/types.js +181 -0
  27. package/dist/esm/types.js.map +1 -0
  28. package/dist/filter.d.ts +51 -0
  29. package/dist/filter.d.ts.map +1 -0
  30. package/dist/filter.js +241 -0
  31. package/dist/filter.js.map +1 -0
  32. package/dist/generated/schema.d.ts +4271 -0
  33. package/dist/generated/schema.d.ts.map +1 -0
  34. package/dist/generated/schema.js +7 -0
  35. package/dist/generated/schema.js.map +1 -0
  36. package/dist/graph.d.ts +350 -0
  37. package/dist/graph.d.ts.map +1 -0
  38. package/dist/graph.js +690 -0
  39. package/dist/graph.js.map +1 -0
  40. package/dist/index.d.ts +58 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +126 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/search.d.ts +160 -0
  45. package/dist/search.d.ts.map +1 -0
  46. package/dist/search.js +322 -0
  47. package/dist/search.js.map +1 -0
  48. package/dist/transport.d.ts +40 -0
  49. package/dist/transport.d.ts.map +1 -0
  50. package/dist/transport.js +39 -0
  51. package/dist/transport.js.map +1 -0
  52. package/dist/types.d.ts +632 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +185 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +72 -0
  57. package/src/client.ts +856 -0
  58. package/src/collection.ts +578 -0
  59. package/src/filter.ts +280 -0
  60. package/src/generated/schema.ts +4271 -0
  61. package/src/graph.ts +811 -0
  62. package/src/index.ts +184 -0
  63. package/src/search.ts +401 -0
  64. package/src/transport.ts +52 -0
  65. package/src/types.ts +726 -0
package/src/index.ts ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * ProximaDB TypeScript SDK
3
+ *
4
+ * A modern, async-first TypeScript client for ProximaDB vector database.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { connect, FilterBuilder } from "@proximadb/client";
9
+ *
10
+ * // Connect to ProximaDB
11
+ * const client = connect("http://localhost:5678");
12
+ *
13
+ * // Create a collection
14
+ * await client.createCollection("embeddings")
15
+ * .dimension(768)
16
+ * .engine(StorageEngine.Sst)
17
+ * .execute();
18
+ *
19
+ * // Insert vectors
20
+ * await client.collection("embeddings")
21
+ * .insert()
22
+ * .id("vec_1")
23
+ * .vector([0.1, 0.2, ...])
24
+ * .meta("category", "tech")
25
+ * .execute();
26
+ *
27
+ * // Search with filters
28
+ * const results = await client.collection("embeddings")
29
+ * .search()
30
+ * .vector(queryVector)
31
+ * .topK(10)
32
+ * .filterEq("category", "tech")
33
+ * .execute();
34
+ *
35
+ * // Graph operations
36
+ * await client.createGraph("knowledge").execute();
37
+ * await client.graph("knowledge")
38
+ * .addNode()
39
+ * .id("person_1")
40
+ * .label("Person")
41
+ * .property("name", "Alice")
42
+ * .execute();
43
+ * ```
44
+ *
45
+ * Copyright 2025 ProximaDB Contributors
46
+ * Licensed under the Apache License, Version 2.0
47
+ */
48
+
49
+ // ============================================================================
50
+ // VERSION
51
+ // ============================================================================
52
+
53
+ export const VERSION = "1.0.0";
54
+
55
+ // ============================================================================
56
+ // TYPES
57
+ // ============================================================================
58
+
59
+ // Enums (runtime values)
60
+ export {
61
+ DistanceMetric,
62
+ StorageEngine,
63
+ IndexType,
64
+ FilterOp,
65
+ LogicalOp,
66
+ SearchMode,
67
+ TraversalDirection,
68
+ ErrorCode,
69
+ ProximaDBError,
70
+ } from "./types";
71
+
72
+ // Type-only exports (interfaces and types)
73
+ export type {
74
+ ProximaRecord,
75
+ VectorRecord,
76
+ SearchResult,
77
+ CollectionConfig,
78
+ CollectionStats,
79
+ CollectionInfo,
80
+ HealthStatus,
81
+ Metadata,
82
+ MetadataValue,
83
+ JsonValue,
84
+ Filter,
85
+ FilterCondition,
86
+ FilterGroup,
87
+ FilterNode,
88
+ GraphNode,
89
+ GraphEdge,
90
+ TraversalResult,
91
+ GraphInfo,
92
+ ClientConfig,
93
+ SearchOptions,
94
+ InsertOptions,
95
+ UpdateOptions,
96
+ DeleteResult,
97
+ OperationMetrics,
98
+ SearchResultBatch,
99
+ SearchResultIterator,
100
+ ProbeResponse,
101
+ ColumnDefinition,
102
+ SchemaDefinition,
103
+ SchemaResponse,
104
+ UpdateSchemaRequest,
105
+ UpdateSchemaResponse,
106
+ QueryLanguage,
107
+ QueryRequest,
108
+ ExplainQueryRequest,
109
+ QueryResponse,
110
+ } from "./types";
111
+
112
+ // ============================================================================
113
+ // CLIENT
114
+ // ============================================================================
115
+
116
+ export {
117
+ ProximaDBClient,
118
+ ClientBuilder,
119
+ connect,
120
+ connectRest,
121
+ } from "./client";
122
+
123
+ // ============================================================================
124
+ // COLLECTION
125
+ // ============================================================================
126
+
127
+ export {
128
+ CollectionHandle,
129
+ CollectionBuilder,
130
+ InsertBuilder,
131
+ BatchInsertBuilder,
132
+ UpdateBuilder,
133
+ } from "./collection";
134
+
135
+ // ============================================================================
136
+ // SEARCH
137
+ // ============================================================================
138
+
139
+ export {
140
+ SearchBuilder,
141
+ createSearchBuilder,
142
+ } from "./search";
143
+
144
+ // ============================================================================
145
+ // FILTER
146
+ // ============================================================================
147
+
148
+ export {
149
+ FilterBuilder,
150
+ // Convenience functions
151
+ eq,
152
+ ne,
153
+ gt,
154
+ lt,
155
+ inList,
156
+ range,
157
+ andFilters,
158
+ orFilters,
159
+ filterToExpression,
160
+ } from "./filter";
161
+
162
+ // ============================================================================
163
+ // GRAPH
164
+ // ============================================================================
165
+
166
+ export {
167
+ GraphHandle,
168
+ GraphBuilder,
169
+ NodeBuilder,
170
+ EdgeBuilder,
171
+ TraversalBuilder,
172
+ // Convenience functions
173
+ createNode,
174
+ node,
175
+ createEdge,
176
+ edge,
177
+ } from "./graph";
178
+
179
+ // ============================================================================
180
+ // DEFAULT EXPORT
181
+ // ============================================================================
182
+
183
+ import { ProximaDBClient } from "./client";
184
+ export default ProximaDBClient;
package/src/search.ts ADDED
@@ -0,0 +1,401 @@
1
+ /**
2
+ * ProximaDB TypeScript SDK - Search Builder
3
+ *
4
+ * Provides a fluent API for building and executing vector similarity searches.
5
+ *
6
+ * Copyright 2025 ProximaDB Contributors
7
+ * Licensed under the Apache License, Version 2.0
8
+ */
9
+
10
+ import type {
11
+ Filter,
12
+ SearchResult,
13
+ JsonValue,
14
+ SearchResultIterator,
15
+ } from "./types";
16
+ import { SearchMode } from "./types";
17
+ import { FilterBuilder, filterToExpression } from "./filter";
18
+
19
+ /**
20
+ * Internal search request structure
21
+ */
22
+ interface SearchRequest {
23
+ vector: number[];
24
+ top_k: number;
25
+ filter?: string;
26
+ searchMode?: string;
27
+ include_vector: boolean;
28
+ include_text: boolean;
29
+ timeoutMs?: number;
30
+ }
31
+
32
+ /**
33
+ * HTTP client interface for search operations
34
+ */
35
+ export interface SearchHttpClient {
36
+ post<T>(url: string, body: unknown): Promise<T>;
37
+ url(): string;
38
+ /**
39
+ * Typed transport for vector search (TD-126 Phase 4). Routes through the
40
+ * generated REST client (POST /api/v2/collections/{collection_id}/search).
41
+ */
42
+ searchRecordsRequest(
43
+ collectionId: string,
44
+ body: Record<string, unknown>,
45
+ ): Promise<unknown>;
46
+ }
47
+
48
+ /**
49
+ * Builder for search queries with fluent API
50
+ */
51
+ export class SearchBuilder {
52
+ private client: SearchHttpClient;
53
+ private collectionName: string;
54
+ private queryVector: number[] | null = null;
55
+ private k: number = 10;
56
+ private filterExpr: string | null = null;
57
+ private filterBuilder: FilterBuilder | null = null;
58
+ private searchMode: SearchMode = SearchMode.Exact;
59
+ private nprobeValue: number | null = null;
60
+ private adaptiveThreshold: number | null = null;
61
+ private includeVectorsFlag: boolean = false;
62
+ private minScoreValue: number | null = null;
63
+ private timeoutMsValue: number | null = null;
64
+
65
+ constructor(client: SearchHttpClient, collection: string) {
66
+ this.client = client;
67
+ this.collectionName = collection;
68
+ }
69
+
70
+ /**
71
+ * Set the query vector
72
+ */
73
+ vector(vec: number[]): SearchBuilder {
74
+ this.queryVector = vec;
75
+ return this;
76
+ }
77
+
78
+ /**
79
+ * Set the number of results to return
80
+ */
81
+ topK(k: number): SearchBuilder {
82
+ this.k = k;
83
+ return this;
84
+ }
85
+
86
+ /**
87
+ * Alias for topK
88
+ */
89
+ limit(k: number): SearchBuilder {
90
+ return this.topK(k);
91
+ }
92
+
93
+ /**
94
+ * Set a filter expression string
95
+ */
96
+ filter(filterStr: string): SearchBuilder {
97
+ this.filterExpr = filterStr;
98
+ return this;
99
+ }
100
+
101
+ /**
102
+ * Apply a pre-built filter
103
+ */
104
+ withFilter(filterObj: Filter): SearchBuilder {
105
+ this.filterExpr = filterToExpression(filterObj);
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Set the search mode
111
+ */
112
+ mode(searchMode: SearchMode): SearchBuilder {
113
+ this.searchMode = searchMode;
114
+ return this;
115
+ }
116
+
117
+ /**
118
+ * Use exact search (100% recall)
119
+ */
120
+ exact(): SearchBuilder {
121
+ this.searchMode = SearchMode.Exact;
122
+ return this;
123
+ }
124
+
125
+ /**
126
+ * Use approximate search for faster results
127
+ */
128
+ approximate(): SearchBuilder {
129
+ this.searchMode = SearchMode.Approximate;
130
+ return this;
131
+ }
132
+
133
+ /**
134
+ * Use approximate search with specific nprobe value
135
+ */
136
+ approximateWithNprobe(nprobe: number): SearchBuilder {
137
+ this.searchMode = SearchMode.Approximate;
138
+ this.nprobeValue = nprobe;
139
+ return this;
140
+ }
141
+
142
+ /**
143
+ * Use adaptive search mode
144
+ */
145
+ adaptive(threshold: number): SearchBuilder {
146
+ this.searchMode = SearchMode.Adaptive;
147
+ this.adaptiveThreshold = threshold;
148
+ return this;
149
+ }
150
+
151
+ /**
152
+ * Include vectors in results
153
+ */
154
+ includeVectors(include: boolean = true): SearchBuilder {
155
+ this.includeVectorsFlag = include;
156
+ return this;
157
+ }
158
+
159
+ /**
160
+ * Include metadata in results
161
+ */
162
+ includeMetadata(_include: boolean = true): SearchBuilder {
163
+ return this;
164
+ }
165
+
166
+ /**
167
+ * Set minimum score threshold
168
+ */
169
+ minScore(score: number): SearchBuilder {
170
+ this.minScoreValue = score;
171
+ return this;
172
+ }
173
+
174
+ /**
175
+ * Set request timeout in milliseconds
176
+ */
177
+ timeoutMs(timeout: number): SearchBuilder {
178
+ this.timeoutMsValue = timeout;
179
+ return this;
180
+ }
181
+
182
+ /**
183
+ * Set timeout in seconds (convenience method)
184
+ */
185
+ timeoutSecs(secs: number): SearchBuilder {
186
+ this.timeoutMsValue = secs * 1000;
187
+ return this;
188
+ }
189
+
190
+ // =========================================================================
191
+ // Inline filter methods for convenience
192
+ // =========================================================================
193
+
194
+ /**
195
+ * Add an equality filter condition
196
+ */
197
+ filterEq(field: string, value: JsonValue): SearchBuilder {
198
+ this.ensureFilterBuilder();
199
+ this.filterBuilder = this.filterBuilder!.eq(field, value);
200
+ return this;
201
+ }
202
+
203
+ /**
204
+ * Add a not-equal filter condition
205
+ */
206
+ filterNe(field: string, value: JsonValue): SearchBuilder {
207
+ this.ensureFilterBuilder();
208
+ this.filterBuilder = this.filterBuilder!.ne(field, value);
209
+ return this;
210
+ }
211
+
212
+ /**
213
+ * Add a greater-than filter condition
214
+ */
215
+ filterGt(field: string, value: JsonValue): SearchBuilder {
216
+ this.ensureFilterBuilder();
217
+ this.filterBuilder = this.filterBuilder!.gt(field, value);
218
+ return this;
219
+ }
220
+
221
+ /**
222
+ * Add a greater-than-or-equal filter condition
223
+ */
224
+ filterGte(field: string, value: JsonValue): SearchBuilder {
225
+ this.ensureFilterBuilder();
226
+ this.filterBuilder = this.filterBuilder!.gte(field, value);
227
+ return this;
228
+ }
229
+
230
+ /**
231
+ * Add a less-than filter condition
232
+ */
233
+ filterLt(field: string, value: JsonValue): SearchBuilder {
234
+ this.ensureFilterBuilder();
235
+ this.filterBuilder = this.filterBuilder!.lt(field, value);
236
+ return this;
237
+ }
238
+
239
+ /**
240
+ * Add a less-than-or-equal filter condition
241
+ */
242
+ filterLte(field: string, value: JsonValue): SearchBuilder {
243
+ this.ensureFilterBuilder();
244
+ this.filterBuilder = this.filterBuilder!.lte(field, value);
245
+ return this;
246
+ }
247
+
248
+ /**
249
+ * Add a range filter condition (inclusive)
250
+ */
251
+ filterRange(field: string, min: JsonValue, max: JsonValue): SearchBuilder {
252
+ this.ensureFilterBuilder();
253
+ this.filterBuilder = this.filterBuilder!.range(field, min, max);
254
+ return this;
255
+ }
256
+
257
+ /**
258
+ * Add an IN filter condition
259
+ */
260
+ filterIn(field: string, values: JsonValue[]): SearchBuilder {
261
+ this.ensureFilterBuilder();
262
+ this.filterBuilder = this.filterBuilder!.inList(field, values);
263
+ return this;
264
+ }
265
+
266
+ /**
267
+ * Add a contains filter condition
268
+ */
269
+ filterContains(field: string, value: JsonValue): SearchBuilder {
270
+ this.ensureFilterBuilder();
271
+ this.filterBuilder = this.filterBuilder!.contains(field, value);
272
+ return this;
273
+ }
274
+
275
+ /**
276
+ * Add an exists filter condition
277
+ */
278
+ filterExists(field: string): SearchBuilder {
279
+ this.ensureFilterBuilder();
280
+ this.filterBuilder = this.filterBuilder!.exists(field);
281
+ return this;
282
+ }
283
+
284
+ private ensureFilterBuilder(): void {
285
+ if (this.filterBuilder === null) {
286
+ this.filterBuilder = FilterBuilder.new();
287
+ }
288
+ }
289
+
290
+ private buildFilter(): string | undefined {
291
+ if (this.filterBuilder !== null) {
292
+ return this.filterBuilder.toExpression();
293
+ }
294
+ return this.filterExpr ?? undefined;
295
+ }
296
+
297
+ private buildSearchModeString(): string {
298
+ switch (this.searchMode) {
299
+ case SearchMode.Exact:
300
+ return "exact";
301
+ case SearchMode.Approximate:
302
+ if (this.nprobeValue !== null) {
303
+ return "approximate:" + this.nprobeValue;
304
+ }
305
+ return "approximate";
306
+ case SearchMode.Adaptive:
307
+ if (this.adaptiveThreshold !== null) {
308
+ return "adaptive:" + this.adaptiveThreshold;
309
+ }
310
+ return "adaptive:10000";
311
+ default:
312
+ return "exact";
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Execute the search query
318
+ */
319
+ async execute(): Promise<SearchResult[]> {
320
+ if (this.queryVector === null) {
321
+ throw new Error("Query vector is required");
322
+ }
323
+
324
+ if (this.k <= 0 || this.k > 10000) {
325
+ throw new Error("topK must be between 1 and 10000");
326
+ }
327
+
328
+ const request: SearchRequest = {
329
+ vector: this.queryVector,
330
+ top_k: this.k,
331
+ filter: this.buildFilter(),
332
+ searchMode: this.buildSearchModeString(),
333
+ include_vector: this.includeVectorsFlag,
334
+ include_text: false,
335
+ timeoutMs: this.timeoutMsValue ?? undefined,
336
+ };
337
+
338
+ const response = (await this.client.searchRecordsRequest(
339
+ this.collectionName,
340
+ request as unknown as Record<string, unknown>,
341
+ )) as { results: SearchResult[] };
342
+
343
+ let results = response.results;
344
+
345
+ // Apply min_score filter if set
346
+ if (this.minScoreValue !== null) {
347
+ results = results.filter((r) => r.score >= this.minScoreValue!);
348
+ }
349
+
350
+ return results;
351
+ }
352
+
353
+ /**
354
+ * Execute the search and return a streaming iterator
355
+ */
356
+ async *stream(): AsyncGenerator<SearchResult, void, unknown> {
357
+ const results = await this.execute();
358
+ for (const result of results) {
359
+ yield result;
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Create an async iterator for streaming results
365
+ */
366
+ async iterate(): Promise<SearchResultIterator> {
367
+ const results = await this.execute();
368
+ let index = 0;
369
+ const total = results.length;
370
+
371
+ const iterator: SearchResultIterator = {
372
+ [Symbol.asyncIterator](): AsyncIterableIterator<SearchResult> {
373
+ return iterator;
374
+ },
375
+ async next(): Promise<IteratorResult<SearchResult>> {
376
+ if (index < results.length) {
377
+ return { value: results[index++]!, done: false };
378
+ }
379
+ return { value: undefined as unknown as SearchResult, done: true };
380
+ },
381
+ getTotal(): number {
382
+ return total;
383
+ },
384
+ isComplete(): boolean {
385
+ return index >= results.length;
386
+ },
387
+ };
388
+
389
+ return iterator;
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Create a new search builder
395
+ */
396
+ export function createSearchBuilder(
397
+ client: SearchHttpClient,
398
+ collection: string
399
+ ): SearchBuilder {
400
+ return new SearchBuilder(client, collection);
401
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ProximaDB TypeScript SDK - Generated REST transport seam (TD-126 Phase 4)
3
+ *
4
+ * This is the thin, hand-written ergonomic facade over the GENERATED REST
5
+ * transport. The wire contract — path templates, path/query parameter
6
+ * encoding, request/response JSON shapes — is generated from
7
+ * `docs/openapi/proximadb-openapi.yaml` into `src/generated/schema.ts`
8
+ * (openapi-typescript, pinned in package.json; regenerate with
9
+ * `npm run gen-sdk`). `openapi-fetch` turns those generated `paths` types into
10
+ * a typed runtime client.
11
+ *
12
+ * Generators don't do ergonomics; this layer is the value-add: it injects the
13
+ * facade's own `fetch` (which owns bearer auth, retries, and error mapping —
14
+ * see `client.ts`) into the typed client, so the generated wire plumbing and
15
+ * the hand-written transport policy compose without either reimplementing the
16
+ * other. This mirrors the merged Go pilot (TD-126 Phase 2), where the generated
17
+ * `genrest.Client` is driven through `RequestEditorFn`s + a custom `http.Client`.
18
+ *
19
+ * Copyright 2025 ProximaDB Contributors
20
+ * Licensed under the Apache License, Version 2.0
21
+ */
22
+
23
+ import createClient from "openapi-fetch";
24
+ import type { Client } from "openapi-fetch";
25
+ import type { paths } from "./generated/schema";
26
+
27
+ /**
28
+ * The typed REST client over the generated OpenAPI `paths`.
29
+ */
30
+ export type GeneratedClient = Client<paths>;
31
+
32
+ /**
33
+ * A fetch implementation matching the facade's transport policy. It is given a
34
+ * resolved `Request` (URL + method + body assembled by the generated client)
35
+ * and must return a native `Response`. The facade implements auth/retry/error
36
+ * mapping inside this function (see `ProximaDBClient`).
37
+ */
38
+ export type TransportFetch = (input: Request) => Promise<Response>;
39
+
40
+ /**
41
+ * Construct the generated typed REST client, routing every request the
42
+ * generated client issues through the facade's transport `fetch`.
43
+ */
44
+ export function createTransport(
45
+ baseUrl: string,
46
+ fetchImpl: TransportFetch,
47
+ ): GeneratedClient {
48
+ return createClient<paths>({
49
+ baseUrl,
50
+ fetch: fetchImpl,
51
+ });
52
+ }