chromadb 3.2.0 → 3.2.2

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.
@@ -86,6 +86,12 @@ type HnswIndexConfig = {
86
86
  sync_threshold?: number | null;
87
87
  };
88
88
  type Include = 'distances' | 'documents' | 'embeddings' | 'metadatas' | 'uris';
89
+ type IndexStatusResponse = {
90
+ num_indexed_ops: number;
91
+ num_unindexed_ops: number;
92
+ op_indexing_progress: number;
93
+ total_ops: number;
94
+ };
89
95
  type IntInvertedIndexConfig$1 = {
90
96
  [key: string]: never;
91
97
  };
@@ -366,6 +372,19 @@ type VectorIndexType$1 = {
366
372
  * User identity information including tenant and database access.
367
373
  */
368
374
  type UserIdentity = GetUserIdentityResponse;
375
+ /**
376
+ * Read level controls whether queries read from the write-ahead log (WAL).
377
+ *
378
+ * - INDEX_AND_WAL: Read from both the compacted index and the WAL.
379
+ * All committed writes will be visible. This is the default.
380
+ * - INDEX_ONLY: Read only from the compacted index, skipping the WAL.
381
+ * Recent writes that haven't been compacted may not be visible, but queries are faster.
382
+ */
383
+ declare const ReadLevel: {
384
+ readonly INDEX_AND_WAL: "index_and_wal";
385
+ readonly INDEX_ONLY: "index_only";
386
+ };
387
+ type ReadLevel = (typeof ReadLevel)[keyof typeof ReadLevel];
369
388
 
370
389
  /**
371
390
  * Metadata that can be associated with a collection.
@@ -567,6 +586,10 @@ declare class QueryResult<TMeta extends Metadata = Metadata> {
567
586
  */
568
587
  rows(): QueryRowResult<TMeta>[][];
569
588
  }
589
+ /**
590
+ * Re-export IndexStatusResponse type for external use
591
+ */
592
+ type IndexingStatus = IndexStatusResponse;
570
593
 
571
594
  /**
572
595
  * Supported vector space types.
@@ -842,7 +865,7 @@ interface RrfOptions {
842
865
  weights?: number[];
843
866
  normalize?: boolean;
844
867
  }
845
- declare const Rrf: ({ ranks, k, weights, normalize }: RrfOptions) => RankExpression;
868
+ declare const Rrf: ({ ranks, k, weights, normalize, }: RrfOptions) => RankExpression;
846
869
  declare const Sum: (...inputs: RankInput[]) => RankExpression;
847
870
  declare const Sub: (left: RankInput, right: RankInput) => RankExpression;
848
871
  declare const Mul: (...inputs: RankInput[]) => RankExpression;
@@ -1642,7 +1665,19 @@ interface Collection {
1642
1665
  * @param searches - Single search payload or array of payloads
1643
1666
  * @returns Promise resolving to column-major search results
1644
1667
  */
1645
- search(searches: SearchLike | SearchLike[]): Promise<SearchResult>;
1668
+ search(searches: SearchLike | SearchLike[], options?: {
1669
+ /**
1670
+ * Controls whether to read from the write-ahead log.
1671
+ * - ReadLevel.INDEX_AND_WAL: Read from both index and WAL (default)
1672
+ * - ReadLevel.INDEX_ONLY: Read only from index, faster but recent writes may not be visible
1673
+ */
1674
+ readLevel?: ReadLevel;
1675
+ }): Promise<SearchResult>;
1676
+ /**
1677
+ * Gets the indexing status of the collection.
1678
+ * @returns Promise resolving to indexing status information
1679
+ */
1680
+ getIndexingStatus(): Promise<IndexingStatus>;
1646
1681
  }
1647
1682
 
1648
1683
  declare function withChroma(userNextConfig?: any): any;
@@ -1862,4 +1897,4 @@ declare class ChromaRateLimitError extends Error {
1862
1897
  }
1863
1898
  declare function createErrorByType(type: string, message: string): InvalidCollectionError | InvalidArgumentError | undefined;
1864
1899
 
1865
- export { Abs, AdminClient, type AdminClientArgs, AdminCloudClient, Aggregate, type AggregateInput, type AggregateJSON, type AnyEmbeddingFunction, type BaseRecordSet, BoolInvertedIndexConfig, BoolInvertedIndexType, BoolValueType, ChromaClient, type ChromaClientArgs, ChromaClientError, ChromaConnectionError, ChromaError, ChromaForbiddenError, ChromaNotFoundError, ChromaQuotaExceededError, ChromaRateLimitError, ChromaServerError, ChromaUnauthorizedError, ChromaUniqueError, ChromaValueError, CloudClient, Cmek, CmekProvider, type Collection, type CollectionConfiguration, type CollectionMetadata, type CreateCollectionConfiguration, DOCUMENT_KEY, Div, EMBEDDING_KEY, type EmbeddingFunction, type EmbeddingFunctionClass, type EmbeddingFunctionSpace, Exp, FloatInvertedIndexConfig, FloatInvertedIndexType, FloatListValueType, FloatValueType, FtsIndexConfig, FtsIndexType, GetResult, GroupBy, type GroupByInput, type GroupByJSON, type HNSWConfiguration, IncludeEnum, type IndexConfig, IntInvertedIndexConfig, IntInvertedIndexType, IntValueType, InvalidArgumentError, InvalidCollectionError, K, Key, type KeyFactory, Knn, type KnnOptions, Limit, type LimitInput, type LimitOptions, type ListDatabasesArgs, Log, Max, MaxK, type Metadata, Min, MinK, Mul, type PreparedInsertRecordSet, type PreparedRecordSet, type QueryRecordSet, QueryResult, type QueryRowResult, RankExpression, type RankInput, type RankLiteral, type RecordSet, Rrf, type RrfOptions, Schema, Search, type SearchInit, type SearchLike, SearchResult, type SearchResultRow, Select, type SelectInput, type SelectKeyInput, type SparseEmbeddingFunction, type SparseEmbeddingFunctionClass, type SparseVector, SparseVectorIndexConfig, type SparseVectorIndexConfigOptions, SparseVectorIndexType, SparseVectorValueType, StringInvertedIndexConfig, StringInvertedIndexType, StringValueType, Sub, Sum, type UpdateCollectionConfiguration, type UpdateHNSWConfiguration, type UpdateSPANNConfiguration, type UserIdentity, Val, ValueTypes, VectorIndexConfig, type VectorIndexConfigOptions, VectorIndexType, type Where, type WhereDocument, WhereExpression, type WhereInput, type WhereJSON, baseRecordSetFields, createErrorByType, getDefaultEFConfig, getEmbeddingFunction, getSparseEmbeddingFunction, knownEmbeddingFunctions, knownSparseEmbeddingFunctions, processCreateCollectionConfig, processUpdateCollectionConfig, recordSetFields, registerEmbeddingFunction, registerSparseEmbeddingFunction, serializeEmbeddingFunction, toSearch, withChroma };
1900
+ export { Abs, AdminClient, type AdminClientArgs, AdminCloudClient, Aggregate, type AggregateInput, type AggregateJSON, type AnyEmbeddingFunction, type BaseRecordSet, BoolInvertedIndexConfig, BoolInvertedIndexType, BoolValueType, ChromaClient, type ChromaClientArgs, ChromaClientError, ChromaConnectionError, ChromaError, ChromaForbiddenError, ChromaNotFoundError, ChromaQuotaExceededError, ChromaRateLimitError, ChromaServerError, ChromaUnauthorizedError, ChromaUniqueError, ChromaValueError, CloudClient, Cmek, CmekProvider, type Collection, type CollectionConfiguration, type CollectionMetadata, type CreateCollectionConfiguration, DOCUMENT_KEY, Div, EMBEDDING_KEY, type EmbeddingFunction, type EmbeddingFunctionClass, type EmbeddingFunctionSpace, Exp, FloatInvertedIndexConfig, FloatInvertedIndexType, FloatListValueType, FloatValueType, FtsIndexConfig, FtsIndexType, GetResult, GroupBy, type GroupByInput, type GroupByJSON, type HNSWConfiguration, IncludeEnum, type IndexConfig, type IndexingStatus, IntInvertedIndexConfig, IntInvertedIndexType, IntValueType, InvalidArgumentError, InvalidCollectionError, K, Key, type KeyFactory, Knn, type KnnOptions, Limit, type LimitInput, type LimitOptions, type ListDatabasesArgs, Log, Max, MaxK, type Metadata, Min, MinK, Mul, type PreparedInsertRecordSet, type PreparedRecordSet, type QueryRecordSet, QueryResult, type QueryRowResult, RankExpression, type RankInput, type RankLiteral, ReadLevel, type RecordSet, Rrf, type RrfOptions, Schema, Search, type SearchInit, type SearchLike, SearchResult, type SearchResultRow, Select, type SelectInput, type SelectKeyInput, type SparseEmbeddingFunction, type SparseEmbeddingFunctionClass, type SparseVector, SparseVectorIndexConfig, type SparseVectorIndexConfigOptions, SparseVectorIndexType, SparseVectorValueType, StringInvertedIndexConfig, StringInvertedIndexType, StringValueType, Sub, Sum, type UpdateCollectionConfiguration, type UpdateHNSWConfiguration, type UpdateSPANNConfiguration, type UserIdentity, Val, ValueTypes, VectorIndexConfig, type VectorIndexConfigOptions, VectorIndexType, type Where, type WhereDocument, WhereExpression, type WhereInput, type WhereJSON, baseRecordSetFields, createErrorByType, getDefaultEFConfig, getEmbeddingFunction, getSparseEmbeddingFunction, knownEmbeddingFunctions, knownSparseEmbeddingFunctions, processCreateCollectionConfig, processUpdateCollectionConfig, recordSetFields, registerEmbeddingFunction, registerSparseEmbeddingFunction, serializeEmbeddingFunction, toSearch, withChroma };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromadb",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "A JavaScript interface for chroma",
5
5
  "keywords": [
6
6
  "chroma",
@@ -60,11 +60,11 @@
60
60
  "@chroma-core/default-embed": "^0.1.9"
61
61
  },
62
62
  "optionalDependencies": {
63
- "chromadb-js-bindings-darwin-arm64": "^1.2.0",
64
- "chromadb-js-bindings-darwin-x64": "^1.2.0",
65
- "chromadb-js-bindings-linux-arm64-gnu": "^1.2.0",
66
- "chromadb-js-bindings-linux-x64-gnu": "^1.2.0",
67
- "chromadb-js-bindings-win32-x64-msvc": "^1.2.0"
63
+ "chromadb-js-bindings-darwin-arm64": "^1.2.1",
64
+ "chromadb-js-bindings-darwin-x64": "^1.2.1",
65
+ "chromadb-js-bindings-linux-arm64-gnu": "^1.2.1",
66
+ "chromadb-js-bindings-linux-x64-gnu": "^1.2.1",
67
+ "chromadb-js-bindings-win32-x64-msvc": "^1.2.1"
68
68
  },
69
69
  "engines": {
70
70
  "node": ">=20"
@@ -1,7 +1,7 @@
1
1
  // This file is auto-generated by @hey-api/openapi-ts
2
2
 
3
3
  import type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';
4
- import type { GetUserIdentityData, GetUserIdentityResponse2, GetUserIdentityError, GetCollectionByCrnData, GetCollectionByCrnResponse, GetCollectionByCrnError, HealthcheckData, HealthcheckResponse, HealthcheckError, HeartbeatData, HeartbeatResponse2, HeartbeatError, PreFlightChecksData, PreFlightChecksResponse, PreFlightChecksError, ResetData, ResetResponse, ResetError, CreateTenantData, CreateTenantResponse2, CreateTenantError, GetTenantData, GetTenantResponse2, GetTenantError, UpdateTenantData, UpdateTenantResponse2, UpdateTenantError, ListDatabasesData, ListDatabasesResponse, ListDatabasesError, CreateDatabaseData, CreateDatabaseResponse2, CreateDatabaseError, DeleteDatabaseData, DeleteDatabaseResponse2, DeleteDatabaseError, GetDatabaseData, GetDatabaseResponse, GetDatabaseError, ListCollectionsData, ListCollectionsResponse, ListCollectionsError, CreateCollectionData, CreateCollectionResponse, CreateCollectionError, DeleteCollectionData, DeleteCollectionResponse, DeleteCollectionError, GetCollectionData, GetCollectionResponse, GetCollectionError, UpdateCollectionData, UpdateCollectionResponse2, UpdateCollectionError, CollectionAddData, CollectionAddResponse, DetachFunctionData, DetachFunctionResponse2, DetachFunctionError, CollectionCountData, CollectionCountResponse, CollectionCountError, CollectionDeleteData, CollectionDeleteResponse, CollectionDeleteError, ForkCollectionData, ForkCollectionResponse, ForkCollectionError, AttachFunctionData, AttachFunctionResponse2, AttachFunctionError, GetAttachedFunctionData, GetAttachedFunctionResponse2, GetAttachedFunctionError, CollectionGetData, CollectionGetResponse, CollectionGetError, CollectionQueryData, CollectionQueryResponse, CollectionQueryError, CollectionSearchData, CollectionSearchResponse, CollectionSearchError, CollectionUpdateData, CollectionUpdateResponse, CollectionUpsertData, CollectionUpsertResponse, CollectionUpsertError, CountCollectionsData, CountCollectionsResponse, CountCollectionsError, VersionData, VersionResponse } from './types.gen';
4
+ import type { GetUserIdentityData, GetUserIdentityResponse2, GetUserIdentityError, GetCollectionByCrnData, GetCollectionByCrnResponse, GetCollectionByCrnError, HealthcheckData, HealthcheckResponse, HealthcheckError, HeartbeatData, HeartbeatResponse2, HeartbeatError, PreFlightChecksData, PreFlightChecksResponse, PreFlightChecksError, ResetData, ResetResponse, ResetError, CreateTenantData, CreateTenantResponse2, CreateTenantError, GetTenantData, GetTenantResponse2, GetTenantError, UpdateTenantData, UpdateTenantResponse2, UpdateTenantError, ListDatabasesData, ListDatabasesResponse, ListDatabasesError, CreateDatabaseData, CreateDatabaseResponse2, CreateDatabaseError, DeleteDatabaseData, DeleteDatabaseResponse2, DeleteDatabaseError, GetDatabaseData, GetDatabaseResponse, GetDatabaseError, ListCollectionsData, ListCollectionsResponse, ListCollectionsError, CreateCollectionData, CreateCollectionResponse, CreateCollectionError, DeleteCollectionData, DeleteCollectionResponse, DeleteCollectionError, GetCollectionData, GetCollectionResponse, GetCollectionError, UpdateCollectionData, UpdateCollectionResponse2, UpdateCollectionError, CollectionAddData, CollectionAddResponse, DetachFunctionData, DetachFunctionResponse2, DetachFunctionError, CollectionCountData, CollectionCountResponse, CollectionCountError, CollectionDeleteData, CollectionDeleteResponse, CollectionDeleteError, ForkCollectionData, ForkCollectionResponse, ForkCollectionError, AttachFunctionData, AttachFunctionResponse2, AttachFunctionError, GetAttachedFunctionData, GetAttachedFunctionResponse2, GetAttachedFunctionError, CollectionGetData, CollectionGetResponse, CollectionGetError, IndexingStatusData, IndexingStatusResponse, IndexingStatusError, CollectionQueryData, CollectionQueryResponse, CollectionQueryError, CollectionSearchData, CollectionSearchResponse, CollectionSearchError, CollectionUpdateData, CollectionUpdateResponse, CollectionUpsertData, CollectionUpsertResponse, CollectionUpsertError, CountCollectionsData, CountCollectionsResponse, CountCollectionsError, VersionData, VersionResponse } from './types.gen';
5
5
  import { client as _heyApiClient } from './client.gen';
6
6
 
7
7
  export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
@@ -323,6 +323,16 @@ export class DefaultService {
323
323
  });
324
324
  }
325
325
 
326
+ /**
327
+ * Retrieves the indexing status of a collection.
328
+ */
329
+ public static indexingStatus<ThrowOnError extends boolean = true>(options: Options<IndexingStatusData, ThrowOnError>) {
330
+ return (options.client ?? _heyApiClient).get<IndexingStatusResponse, IndexingStatusError, ThrowOnError>({
331
+ url: '/api/v2/tenants/{tenant}/databases/{database}/collections/{collection_id}/indexing_status',
332
+ ...options
333
+ });
334
+ }
335
+
326
336
  /**
327
337
  * Query a collection in a variety of ways, including vector search, metadata filtering, and full-text search
328
338
  */
@@ -304,6 +304,13 @@ export type Include = 'distances' | 'documents' | 'embeddings' | 'metadatas' | '
304
304
 
305
305
  export type IncludeList = Array<Include>;
306
306
 
307
+ export type IndexStatusResponse = {
308
+ num_indexed_ops: number;
309
+ num_unindexed_ops: number;
310
+ op_indexing_progress: number;
311
+ total_ops: number;
312
+ };
313
+
307
314
  export type IntInvertedIndexConfig = {
308
315
  [key: string]: never;
309
316
  };
@@ -412,6 +419,8 @@ export type RawWhereFields = {
412
419
  where_document?: unknown;
413
420
  };
414
421
 
422
+ export type ReadLevel = 'index_and_wal' | 'index_only';
423
+
415
424
  /**
416
425
  * Schema representation for collection index configurations
417
426
  *
@@ -467,6 +476,11 @@ export type SearchPayload = {
467
476
  };
468
477
 
469
478
  export type SearchRequestPayload = {
479
+ /**
480
+ * Specifies the read level for consistency vs performance tradeoffs.
481
+ * Defaults to IndexAndWal (full consistency).
482
+ */
483
+ read_level?: ReadLevel;
470
484
  searches: Array<SearchPayload>;
471
485
  };
472
486
 
@@ -1696,6 +1710,52 @@ export type CollectionGetResponses = {
1696
1710
 
1697
1711
  export type CollectionGetResponse = CollectionGetResponses[keyof CollectionGetResponses];
1698
1712
 
1713
+ export type IndexingStatusData = {
1714
+ body?: never;
1715
+ path: {
1716
+ /**
1717
+ * Tenant ID
1718
+ */
1719
+ tenant: string;
1720
+ /**
1721
+ * Database name for the collection
1722
+ */
1723
+ database: string;
1724
+ /**
1725
+ * Collection ID to get index status for
1726
+ */
1727
+ collection_id: string;
1728
+ };
1729
+ query?: never;
1730
+ url: '/api/v2/tenants/{tenant}/databases/{database}/collections/{collection_id}/indexing_status';
1731
+ };
1732
+
1733
+ export type IndexingStatusErrors = {
1734
+ /**
1735
+ * Unauthorized
1736
+ */
1737
+ 401: ErrorResponse;
1738
+ /**
1739
+ * Collection not found
1740
+ */
1741
+ 404: ErrorResponse;
1742
+ /**
1743
+ * Server error
1744
+ */
1745
+ 500: ErrorResponse;
1746
+ };
1747
+
1748
+ export type IndexingStatusError = IndexingStatusErrors[keyof IndexingStatusErrors];
1749
+
1750
+ export type IndexingStatusResponses = {
1751
+ /**
1752
+ * Index status retrieved successfully
1753
+ */
1754
+ 200: IndexStatusResponse;
1755
+ };
1756
+
1757
+ export type IndexingStatusResponse = IndexingStatusResponses[keyof IndexingStatusResponses];
1758
+
1699
1759
  export type CollectionQueryData = {
1700
1760
  body: QueryRequestPayload;
1701
1761
  path: {
@@ -14,16 +14,18 @@ import {
14
14
  const offlineError = (error: any): boolean => {
15
15
  return Boolean(
16
16
  (error?.name === "TypeError" || error?.name === "FetchError") &&
17
- (error.message?.includes("fetch failed") ||
18
- error.message?.includes("Failed to fetch") ||
19
- error.message?.includes("ENOTFOUND")),
17
+ (error.message?.includes("fetch failed") ||
18
+ error.message?.includes("Failed to fetch") ||
19
+ error.message?.includes("ENOTFOUND")),
20
20
  );
21
21
  };
22
22
 
23
23
  const getErrorMessage = async (response: Response): Promise<string> => {
24
24
  try {
25
25
  const body = await response.clone().json();
26
- return body.message || body.error || `${response.status}: ${response.statusText}`;
26
+ return (
27
+ body.message || body.error || `${response.status}: ${response.statusText}`
28
+ );
27
29
  } catch {
28
30
  return `${response.status}: ${response.statusText}`;
29
31
  }
@@ -52,9 +54,10 @@ export const chromaFetch: typeof fetch = async (input, init) => {
52
54
  try {
53
55
  const responseBody = await response.json();
54
56
  status = responseBody.message || status;
55
- } catch { }
57
+ } catch {}
56
58
  throw new ChromaClientError(
57
- `Bad request to ${(input as Request).url || "Chroma"
59
+ `Bad request to ${
60
+ (input as Request).url || "Chroma"
58
61
  } with status: ${status}`,
59
62
  );
60
63
  case 401:
@@ -82,10 +85,15 @@ export const chromaFetch: typeof fetch = async (input, init) => {
82
85
  }
83
86
  throw new ChromaClientError(body?.message || "Unprocessable Entity");
84
87
  } catch (error) {
85
- if (error instanceof ChromaQuotaExceededError || error instanceof ChromaClientError) {
88
+ if (
89
+ error instanceof ChromaQuotaExceededError ||
90
+ error instanceof ChromaClientError
91
+ ) {
86
92
  throw error;
87
93
  }
88
- throw new ChromaClientError(`Unprocessable Entity: ${response.statusText}`);
94
+ throw new ChromaClientError(
95
+ `Unprocessable Entity: ${response.statusText}`,
96
+ );
89
97
  }
90
98
  case 429:
91
99
  throw new ChromaRateLimitError("Rate limit exceeded");
@@ -126,8 +126,11 @@ export const processCreateCollectionConfig = async ({
126
126
  !supportedSpaces.includes(configuration.hnsw.space)
127
127
  ) {
128
128
  console.warn(
129
- `Space '${configuration.hnsw.space}' is not supported by embedding function '${overallEf.name || "unknown"}'. ` +
130
- `Supported spaces: ${supportedSpaces.join(", ")}`,
129
+ `Space '${
130
+ configuration.hnsw.space
131
+ }' is not supported by embedding function '${
132
+ overallEf.name || "unknown"
133
+ }'. ` + `Supported spaces: ${supportedSpaces.join(", ")}`,
131
134
  );
132
135
  }
133
136
 
@@ -136,8 +139,11 @@ export const processCreateCollectionConfig = async ({
136
139
  !supportedSpaces.includes(configuration.spann.space)
137
140
  ) {
138
141
  console.warn(
139
- `Space '${configuration.spann.space}' is not supported by embedding function '${overallEf.name || "unknown"}'. ` +
140
- `Supported spaces: ${supportedSpaces.join(", ")}`,
142
+ `Space '${
143
+ configuration.spann.space
144
+ }' is not supported by embedding function '${
145
+ overallEf.name || "unknown"
146
+ }'. ` + `Supported spaces: ${supportedSpaces.join(", ")}`,
141
147
  );
142
148
  }
143
149
 
@@ -151,8 +157,11 @@ export const processCreateCollectionConfig = async ({
151
157
  )
152
158
  ) {
153
159
  console.warn(
154
- `Space '${metadata["hnsw:space"]}' from metadata is not supported by embedding function '${overallEf.name || "unknown"}'. ` +
155
- `Supported spaces: ${supportedSpaces.join(", ")}`,
160
+ `Space '${
161
+ metadata["hnsw:space"]
162
+ }' from metadata is not supported by embedding function '${
163
+ overallEf.name || "unknown"
164
+ }'. ` + `Supported spaces: ${supportedSpaces.join(", ")}`,
156
165
  );
157
166
  }
158
167
  }
package/src/collection.ts CHANGED
@@ -7,11 +7,13 @@ import {
7
7
  BaseRecordSet,
8
8
  CollectionMetadata,
9
9
  GetResult,
10
+ IndexingStatus,
10
11
  Metadata,
11
12
  PreparedRecordSet,
12
13
  PreparedInsertRecordSet,
13
14
  QueryRecordSet,
14
15
  QueryResult,
16
+ ReadLevel,
15
17
  RecordSet,
16
18
  Where,
17
19
  WhereDocument,
@@ -203,7 +205,22 @@ export interface Collection {
203
205
  * @param searches - Single search payload or array of payloads
204
206
  * @returns Promise resolving to column-major search results
205
207
  */
206
- search(searches: SearchLike | SearchLike[]): Promise<SearchResult>;
208
+ search(
209
+ searches: SearchLike | SearchLike[],
210
+ options?: {
211
+ /**
212
+ * Controls whether to read from the write-ahead log.
213
+ * - ReadLevel.INDEX_AND_WAL: Read from both index and WAL (default)
214
+ * - ReadLevel.INDEX_ONLY: Read only from index, faster but recent writes may not be visible
215
+ */
216
+ readLevel?: ReadLevel;
217
+ },
218
+ ): Promise<SearchResult>;
219
+ /**
220
+ * Gets the indexing status of the collection.
221
+ * @returns Promise resolving to indexing status information
222
+ */
223
+ getIndexingStatus(): Promise<IndexingStatus>;
207
224
  }
208
225
 
209
226
  /**
@@ -887,6 +904,9 @@ export class CollectionImpl implements Collection {
887
904
 
888
905
  public async search(
889
906
  searches: SearchLike | SearchLike[],
907
+ options?: {
908
+ readLevel?: ReadLevel;
909
+ },
890
910
  ): Promise<SearchResult> {
891
911
  const items = Array.isArray(searches) ? searches : [searches];
892
912
 
@@ -906,7 +926,10 @@ export class CollectionImpl implements Collection {
906
926
  const { data } = await Api.collectionSearch({
907
927
  client: this.apiClient,
908
928
  path: await this.path(),
909
- body: { searches: payloads },
929
+ body: {
930
+ searches: payloads,
931
+ read_level: options?.readLevel,
932
+ },
910
933
  });
911
934
 
912
935
  return new SearchResult(data);
@@ -1079,4 +1102,13 @@ export class CollectionImpl implements Collection {
1079
1102
  },
1080
1103
  });
1081
1104
  }
1105
+
1106
+ public async getIndexingStatus(): Promise<IndexingStatus> {
1107
+ const { data } = await Api.indexingStatus({
1108
+ client: this.apiClient,
1109
+ path: await this.path(),
1110
+ });
1111
+
1112
+ return data;
1113
+ }
1082
1114
  }
@@ -1,6 +1,8 @@
1
1
  export type IterableInput<T> = Iterable<T> | ArrayLike<T>;
2
2
 
3
- export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
3
+ export const isPlainObject = (
4
+ value: unknown,
5
+ ): value is Record<string, unknown> => {
4
6
  if (typeof value !== "object" || value === null) {
5
7
  return false;
6
8
  }
@@ -59,10 +59,7 @@ export abstract class Aggregate {
59
59
  }
60
60
 
61
61
  export class MinK extends Aggregate {
62
- constructor(
63
- public readonly keys: Key[],
64
- public readonly k: number,
65
- ) {
62
+ constructor(public readonly keys: Key[], public readonly k: number) {
66
63
  super();
67
64
  if (keys.length === 0) {
68
65
  throw new Error("MinK keys cannot be empty");
@@ -83,10 +80,7 @@ export class MinK extends Aggregate {
83
80
  }
84
81
 
85
82
  export class MaxK extends Aggregate {
86
- constructor(
87
- public readonly keys: Key[],
88
- public readonly k: number,
89
- ) {
83
+ constructor(public readonly keys: Key[], public readonly k: number) {
90
84
  super();
91
85
  if (keys.length === 0) {
92
86
  throw new Error("MaxK keys cannot be empty");
@@ -143,7 +137,9 @@ export class GroupBy {
143
137
  Aggregate.from(data.aggregate),
144
138
  );
145
139
  }
146
- throw new TypeError("GroupBy input must be a GroupBy instance or plain object");
140
+ throw new TypeError(
141
+ "GroupBy input must be a GroupBy instance or plain object",
142
+ );
147
143
  }
148
144
 
149
145
  public toJSON(): GroupByJSON {
@@ -3,10 +3,19 @@ import { deepClone, isPlainObject, IterableInput } from "./common";
3
3
  import { Key } from "./key";
4
4
 
5
5
  export type RankLiteral = Record<string, unknown>;
6
- export type RankInput = RankExpression | RankLiteral | number | null | undefined;
6
+ export type RankInput =
7
+ | RankExpression
8
+ | RankLiteral
9
+ | number
10
+ | null
11
+ | undefined;
7
12
 
8
13
  const requireNumber = (value: unknown, message: string): number => {
9
- if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
14
+ if (
15
+ typeof value !== "number" ||
16
+ Number.isNaN(value) ||
17
+ !Number.isFinite(value)
18
+ ) {
10
19
  throw new TypeError(message);
11
20
  }
12
21
  return value;
@@ -39,7 +48,9 @@ abstract class RankExpressionBase {
39
48
  }
40
49
  const expressions = [
41
50
  this as unknown as RankExpression,
42
- ...others.map((item, index) => requireRank(item, `multiply operand ${index}`)),
51
+ ...others.map((item, index) =>
52
+ requireRank(item, `multiply operand ${index}`),
53
+ ),
43
54
  ];
44
55
  return MulRankExpression.create(expressions);
45
56
  }
@@ -104,7 +115,9 @@ export abstract class RankExpression extends RankExpressionBase {
104
115
  if (isPlainObject(input)) {
105
116
  return new RawRankExpression(input);
106
117
  }
107
- throw new TypeError("Rank input must be a RankExpression, number, or plain object");
118
+ throw new TypeError(
119
+ "Rank input must be a RankExpression, number, or plain object",
120
+ );
108
121
  }
109
122
  }
110
123
 
@@ -355,7 +368,11 @@ const normalizeDenseVector = (vector: IterableInput<number>): number[] => {
355
368
  return vector.slice();
356
369
  }
357
370
  return Array.from(vector as Iterable<number>, (value) => {
358
- if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
371
+ if (
372
+ typeof value !== "number" ||
373
+ Number.isNaN(value) ||
374
+ !Number.isFinite(value)
375
+ ) {
359
376
  throw new TypeError("Dense query vector values must be finite numbers");
360
377
  }
361
378
  return value;
@@ -387,7 +404,8 @@ const normalizeKnnOptions = (options: KnnOptions): KnnOptionsNormalized => {
387
404
  query = normalizeDenseVector(queryInput as IterableInput<number>);
388
405
  }
389
406
 
390
- const key = options.key instanceof Key ? options.key.name : options.key ?? "#embedding";
407
+ const key =
408
+ options.key instanceof Key ? options.key.name : options.key ?? "#embedding";
391
409
  if (typeof key !== "string") {
392
410
  throw new TypeError("Knn key must be a string or Key instance");
393
411
  }
@@ -402,7 +420,10 @@ const normalizeKnnOptions = (options: KnnOptions): KnnOptionsNormalized => {
402
420
  }
403
421
 
404
422
  return {
405
- query: Array.isArray(query) || typeof query === "string" ? query : deepClone(query),
423
+ query:
424
+ Array.isArray(query) || typeof query === "string"
425
+ ? query
426
+ : deepClone(query),
406
427
  key,
407
428
  limit,
408
429
  defaultValue,
@@ -431,7 +452,12 @@ export interface RrfOptions {
431
452
  normalize?: boolean;
432
453
  }
433
454
 
434
- export const Rrf = ({ ranks, k = 60, weights, normalize = false }: RrfOptions): RankExpression => {
455
+ export const Rrf = ({
456
+ ranks,
457
+ k = 60,
458
+ weights,
459
+ normalize = false,
460
+ }: RrfOptions): RankExpression => {
435
461
  if (!Number.isInteger(k) || k <= 0) {
436
462
  throw new TypeError("Rrf k must be a positive integer");
437
463
  }
@@ -439,9 +465,13 @@ export const Rrf = ({ ranks, k = 60, weights, normalize = false }: RrfOptions):
439
465
  throw new TypeError("Rrf requires at least one rank expression");
440
466
  }
441
467
 
442
- const expressions = ranks.map((rank, index) => requireRank(rank, `ranks[${index}]`));
468
+ const expressions = ranks.map((rank, index) =>
469
+ requireRank(rank, `ranks[${index}]`),
470
+ );
443
471
 
444
- let weightValues = weights ? weights.slice() : new Array(expressions.length).fill(1);
472
+ let weightValues = weights
473
+ ? weights.slice()
474
+ : new Array(expressions.length).fill(1);
445
475
  if (weightValues.length !== expressions.length) {
446
476
  throw new Error("Number of weights must match number of ranks");
447
477
  }
@@ -452,7 +482,9 @@ export const Rrf = ({ ranks, k = 60, weights, normalize = false }: RrfOptions):
452
482
  if (normalize) {
453
483
  const total = weightValues.reduce((sum, value) => sum + value, 0);
454
484
  if (total <= 0) {
455
- throw new Error("Weights must sum to a positive value when normalize=true");
485
+ throw new Error(
486
+ "Weights must sum to a positive value when normalize=true",
487
+ );
456
488
  }
457
489
  weightValues = weightValues.map((value) => value / total);
458
490
  }
@@ -472,35 +504,50 @@ export const Sum = (...inputs: RankInput[]): RankExpression => {
472
504
  if (inputs.length === 0) {
473
505
  throw new Error("Sum requires at least one rank expression");
474
506
  }
475
- const expressions = inputs.map((rank, index) => requireRank(rank, `Sum operand ${index}`));
507
+ const expressions = inputs.map((rank, index) =>
508
+ requireRank(rank, `Sum operand ${index}`),
509
+ );
476
510
  return SumRankExpression.create(expressions);
477
511
  };
478
512
 
479
513
  export const Sub = (left: RankInput, right: RankInput): RankExpression =>
480
- new SubRankExpression(requireRank(left, "Sub left"), requireRank(right, "Sub right"));
514
+ new SubRankExpression(
515
+ requireRank(left, "Sub left"),
516
+ requireRank(right, "Sub right"),
517
+ );
481
518
 
482
519
  export const Mul = (...inputs: RankInput[]): RankExpression => {
483
520
  if (inputs.length === 0) {
484
521
  throw new Error("Mul requires at least one rank expression");
485
522
  }
486
- const expressions = inputs.map((rank, index) => requireRank(rank, `Mul operand ${index}`));
523
+ const expressions = inputs.map((rank, index) =>
524
+ requireRank(rank, `Mul operand ${index}`),
525
+ );
487
526
  return MulRankExpression.create(expressions);
488
527
  };
489
528
 
490
529
  export const Div = (left: RankInput, right: RankInput): RankExpression =>
491
- new DivRankExpression(requireRank(left, "Div left"), requireRank(right, "Div right"));
530
+ new DivRankExpression(
531
+ requireRank(left, "Div left"),
532
+ requireRank(right, "Div right"),
533
+ );
492
534
 
493
- export const Abs = (input: RankInput): RankExpression => requireRank(input, "Abs").abs();
535
+ export const Abs = (input: RankInput): RankExpression =>
536
+ requireRank(input, "Abs").abs();
494
537
 
495
- export const Exp = (input: RankInput): RankExpression => requireRank(input, "Exp").exp();
538
+ export const Exp = (input: RankInput): RankExpression =>
539
+ requireRank(input, "Exp").exp();
496
540
 
497
- export const Log = (input: RankInput): RankExpression => requireRank(input, "Log").log();
541
+ export const Log = (input: RankInput): RankExpression =>
542
+ requireRank(input, "Log").log();
498
543
 
499
544
  export const Max = (...inputs: RankInput[]): RankExpression => {
500
545
  if (inputs.length === 0) {
501
546
  throw new Error("Max requires at least one rank expression");
502
547
  }
503
- const expressions = inputs.map((rank, index) => requireRank(rank, `Max operand ${index}`));
548
+ const expressions = inputs.map((rank, index) =>
549
+ requireRank(rank, `Max operand ${index}`),
550
+ );
504
551
  return MaxRankExpression.create(expressions);
505
552
  };
506
553
 
@@ -508,6 +555,8 @@ export const Min = (...inputs: RankInput[]): RankExpression => {
508
555
  if (inputs.length === 0) {
509
556
  throw new Error("Min requires at least one rank expression");
510
557
  }
511
- const expressions = inputs.map((rank, index) => requireRank(rank, `Min operand ${index}`));
558
+ const expressions = inputs.map((rank, index) =>
559
+ requireRank(rank, `Min operand ${index}`),
560
+ );
512
561
  return MinRankExpression.create(expressions);
513
562
  };
@@ -20,7 +20,9 @@ const normalizePayloadArray = <T>(
20
20
  if (payload.length === count) {
21
21
  return payload.map((item) => (item ? item.slice() : null));
22
22
  }
23
- const result: Array<T[] | null> = payload.map((item) => (item ? item.slice() : null));
23
+ const result: Array<T[] | null> = payload.map((item) =>
24
+ item ? item.slice() : null,
25
+ );
24
26
  while (result.length < count) {
25
27
  result.push(null);
26
28
  }
@@ -40,7 +42,10 @@ export class SearchResult {
40
42
  const payloadCount = this.ids.length;
41
43
  this.documents = normalizePayloadArray(response.documents, payloadCount);
42
44
  this.embeddings = normalizePayloadArray(response.embeddings, payloadCount);
43
- const rawMetadatas = normalizePayloadArray(response.metadatas, payloadCount);
45
+ const rawMetadatas = normalizePayloadArray(
46
+ response.metadatas,
47
+ payloadCount,
48
+ );
44
49
  this.metadatas = rawMetadatas.map((payload) => {
45
50
  if (!payload) {
46
51
  return null;
@@ -54,7 +59,11 @@ export class SearchResult {
54
59
  public rows(): SearchResultRow[][] {
55
60
  const results: SearchResultRow[][] = [];
56
61
 
57
- for (let payloadIndex = 0; payloadIndex < this.ids.length; payloadIndex += 1) {
62
+ for (
63
+ let payloadIndex = 0;
64
+ payloadIndex < this.ids.length;
65
+ payloadIndex += 1
66
+ ) {
58
67
  const ids = this.ids[payloadIndex];
59
68
  const docPayload = this.documents[payloadIndex] ?? [];
60
69
  const embedPayload = this.embeddings[payloadIndex] ?? [];