@mastra/turbopuffer 0.10.3 → 0.11.0-alpha.1

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.
@@ -1,12 +1,15 @@
1
1
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
+ import type { BlacklistedRootOperators } from '@mastra/core/vector/filter';
2
3
  import type { CreateIndexParams } from '@mastra/core/vector';
3
4
  import type { DeleteIndexParams } from '@mastra/core/vector';
4
5
  import type { DeleteVectorParams } from '@mastra/core/vector';
5
6
  import type { DescribeIndexParams } from '@mastra/core/vector';
6
7
  import type { Filters } from '@turbopuffer/turbopuffer';
7
8
  import type { IndexStats } from '@mastra/core/vector';
9
+ import type { LogicalOperatorValueMap } from '@mastra/core/vector/filter';
8
10
  import { MastraVector } from '@mastra/core/vector';
9
11
  import type { OperatorSupport } from '@mastra/core/vector/filter';
12
+ import type { OperatorValueMap } from '@mastra/core/vector/filter';
10
13
  import type { QueryResult } from '@mastra/core/vector';
11
14
  import type { QueryVectorParams } from '@mastra/core/vector';
12
15
  import type { Schema } from '@turbopuffer/turbopuffer';
@@ -14,13 +17,15 @@ import type { UpdateVectorParams } from '@mastra/core/vector';
14
17
  import type { UpsertVectorParams } from '@mastra/core/vector';
15
18
  import type { VectorFilter } from '@mastra/core/vector/filter';
16
19
 
20
+ declare type TurbopufferBlacklistedRootOperators = BlacklistedRootOperators | '$nor' | '$not';
21
+
17
22
  /**
18
23
  * Translator for converting Mastra filters to Turbopuffer format
19
24
  *
20
25
  * Mastra filters: { field: { $gt: 10 } }
21
26
  * Turbopuffer filters: ["And", [["field", "Gt", 10]]]
22
27
  */
23
- export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
28
+ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator<TurbopufferVectorFilter, Filters | undefined> {
24
29
  protected getSupportedOperators(): OperatorSupport;
25
30
  /**
26
31
  * Map Mastra operators to Turbopuffer operators
@@ -29,7 +34,7 @@ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
29
34
  /**
30
35
  * Convert the Mastra filter to Turbopuffer format
31
36
  */
32
- translate(filter?: VectorFilter): Filters | undefined;
37
+ translate(filter?: TurbopufferVectorFilter): Filters | undefined;
33
38
  /**
34
39
  * Recursively translate a filter node
35
40
  */
@@ -56,7 +61,13 @@ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
56
61
  protected normalizeArrayValues(values: any[]): any[];
57
62
  }
58
63
 
59
- declare class TurbopufferVector extends MastraVector {
64
+ declare type TurbopufferLogicalOperatorValueMap = Omit<LogicalOperatorValueMap, '$nor' | '$not'>;
65
+
66
+ declare type TurbopufferOperatorValueMap = Omit<OperatorValueMap, '$regex' | '$options' | '$elemMatch'>;
67
+
68
+ declare type TurbopufferQueryVectorParams = QueryVectorParams<TurbopufferVectorFilter>;
69
+
70
+ declare class TurbopufferVector extends MastraVector<TurbopufferVectorFilter> {
60
71
  private client;
61
72
  private filterTranslator;
62
73
  private createIndexCache;
@@ -64,7 +75,7 @@ declare class TurbopufferVector extends MastraVector {
64
75
  constructor(opts: TurbopufferVectorOptions);
65
76
  createIndex({ indexName, dimension, metric }: CreateIndexParams): Promise<void>;
66
77
  upsert({ indexName, vectors, metadata, ids }: UpsertVectorParams): Promise<string[]>;
67
- query({ indexName, queryVector, topK, filter, includeVector }: QueryVectorParams): Promise<QueryResult[]>;
78
+ query({ indexName, queryVector, topK, filter, includeVector, }: TurbopufferQueryVectorParams): Promise<QueryResult[]>;
68
79
  listIndexes(): Promise<string[]>;
69
80
  /**
70
81
  * Retrieves statistics about a vector index.
@@ -97,6 +108,8 @@ declare class TurbopufferVector extends MastraVector {
97
108
  export { TurbopufferVector }
98
109
  export { TurbopufferVector as TurbopufferVector_alias_1 }
99
110
 
111
+ export declare type TurbopufferVectorFilter = VectorFilter<keyof TurbopufferOperatorValueMap, TurbopufferOperatorValueMap, TurbopufferLogicalOperatorValueMap, TurbopufferBlacklistedRootOperators>;
112
+
100
113
  declare interface TurbopufferVectorOptions {
101
114
  /** The API key to authenticate with. */
102
115
  apiKey: string;
@@ -1,12 +1,15 @@
1
1
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
2
+ import type { BlacklistedRootOperators } from '@mastra/core/vector/filter';
2
3
  import type { CreateIndexParams } from '@mastra/core/vector';
3
4
  import type { DeleteIndexParams } from '@mastra/core/vector';
4
5
  import type { DeleteVectorParams } from '@mastra/core/vector';
5
6
  import type { DescribeIndexParams } from '@mastra/core/vector';
6
7
  import type { Filters } from '@turbopuffer/turbopuffer';
7
8
  import type { IndexStats } from '@mastra/core/vector';
9
+ import type { LogicalOperatorValueMap } from '@mastra/core/vector/filter';
8
10
  import { MastraVector } from '@mastra/core/vector';
9
11
  import type { OperatorSupport } from '@mastra/core/vector/filter';
12
+ import type { OperatorValueMap } from '@mastra/core/vector/filter';
10
13
  import type { QueryResult } from '@mastra/core/vector';
11
14
  import type { QueryVectorParams } from '@mastra/core/vector';
12
15
  import type { Schema } from '@turbopuffer/turbopuffer';
@@ -14,13 +17,15 @@ import type { UpdateVectorParams } from '@mastra/core/vector';
14
17
  import type { UpsertVectorParams } from '@mastra/core/vector';
15
18
  import type { VectorFilter } from '@mastra/core/vector/filter';
16
19
 
20
+ declare type TurbopufferBlacklistedRootOperators = BlacklistedRootOperators | '$nor' | '$not';
21
+
17
22
  /**
18
23
  * Translator for converting Mastra filters to Turbopuffer format
19
24
  *
20
25
  * Mastra filters: { field: { $gt: 10 } }
21
26
  * Turbopuffer filters: ["And", [["field", "Gt", 10]]]
22
27
  */
23
- export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
28
+ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator<TurbopufferVectorFilter, Filters | undefined> {
24
29
  protected getSupportedOperators(): OperatorSupport;
25
30
  /**
26
31
  * Map Mastra operators to Turbopuffer operators
@@ -29,7 +34,7 @@ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
29
34
  /**
30
35
  * Convert the Mastra filter to Turbopuffer format
31
36
  */
32
- translate(filter?: VectorFilter): Filters | undefined;
37
+ translate(filter?: TurbopufferVectorFilter): Filters | undefined;
33
38
  /**
34
39
  * Recursively translate a filter node
35
40
  */
@@ -56,7 +61,13 @@ export declare class TurbopufferFilterTranslator extends BaseFilterTranslator {
56
61
  protected normalizeArrayValues(values: any[]): any[];
57
62
  }
58
63
 
59
- declare class TurbopufferVector extends MastraVector {
64
+ declare type TurbopufferLogicalOperatorValueMap = Omit<LogicalOperatorValueMap, '$nor' | '$not'>;
65
+
66
+ declare type TurbopufferOperatorValueMap = Omit<OperatorValueMap, '$regex' | '$options' | '$elemMatch'>;
67
+
68
+ declare type TurbopufferQueryVectorParams = QueryVectorParams<TurbopufferVectorFilter>;
69
+
70
+ declare class TurbopufferVector extends MastraVector<TurbopufferVectorFilter> {
60
71
  private client;
61
72
  private filterTranslator;
62
73
  private createIndexCache;
@@ -64,7 +75,7 @@ declare class TurbopufferVector extends MastraVector {
64
75
  constructor(opts: TurbopufferVectorOptions);
65
76
  createIndex({ indexName, dimension, metric }: CreateIndexParams): Promise<void>;
66
77
  upsert({ indexName, vectors, metadata, ids }: UpsertVectorParams): Promise<string[]>;
67
- query({ indexName, queryVector, topK, filter, includeVector }: QueryVectorParams): Promise<QueryResult[]>;
78
+ query({ indexName, queryVector, topK, filter, includeVector, }: TurbopufferQueryVectorParams): Promise<QueryResult[]>;
68
79
  listIndexes(): Promise<string[]>;
69
80
  /**
70
81
  * Retrieves statistics about a vector index.
@@ -97,6 +108,8 @@ declare class TurbopufferVector extends MastraVector {
97
108
  export { TurbopufferVector }
98
109
  export { TurbopufferVector as TurbopufferVector_alias_1 }
99
110
 
111
+ export declare type TurbopufferVectorFilter = VectorFilter<keyof TurbopufferOperatorValueMap, TurbopufferOperatorValueMap, TurbopufferLogicalOperatorValueMap, TurbopufferBlacklistedRootOperators>;
112
+
100
113
  declare interface TurbopufferVectorOptions {
101
114
  /** The API key to authenticate with. */
102
115
  apiKey: string;
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var error = require('@mastra/core/error');
3
4
  var vector = require('@mastra/core/vector');
4
5
  var turbopuffer = require('@turbopuffer/turbopuffer');
5
6
  var filter = require('@mastra/core/vector/filter');
@@ -188,28 +189,40 @@ var TurbopufferVector = class extends vector.MastraVector {
188
189
  }
189
190
  async createIndex({ indexName, dimension, metric }) {
190
191
  metric = metric ?? "cosine";
191
- if (this.createIndexCache.has(indexName)) {
192
- const expected = this.createIndexCache.get(indexName);
193
- if (dimension !== expected.dimension || metric !== expected.metric) {
194
- throw new Error(
195
- `createIndex() called more than once with inconsistent inputs. Index ${indexName} expected dimensions=${expected.dimension} and metric=${expected.metric} but got dimensions=${dimension} and metric=${metric}`
196
- );
197
- }
198
- return;
199
- }
200
- if (dimension <= 0) {
201
- throw new Error("Dimension must be a positive integer");
202
- }
203
192
  let distanceMetric = "cosine_distance";
204
- switch (metric) {
205
- case "cosine":
206
- distanceMetric = "cosine_distance";
207
- break;
208
- case "euclidean":
209
- distanceMetric = "euclidean_squared";
210
- break;
211
- case "dotproduct":
212
- throw new Error("dotproduct is not supported in Turbopuffer");
193
+ try {
194
+ if (this.createIndexCache.has(indexName)) {
195
+ const expected = this.createIndexCache.get(indexName);
196
+ if (dimension !== expected.dimension || metric !== expected.metric) {
197
+ throw new Error(
198
+ `createIndex() called more than once with inconsistent inputs. Index ${indexName} expected dimensions=${expected.dimension} and metric=${expected.metric} but got dimensions=${dimension} and metric=${metric}`
199
+ );
200
+ }
201
+ return;
202
+ }
203
+ if (dimension <= 0) {
204
+ throw new Error("Dimension must be a positive integer");
205
+ }
206
+ switch (metric) {
207
+ case "cosine":
208
+ distanceMetric = "cosine_distance";
209
+ break;
210
+ case "euclidean":
211
+ distanceMetric = "euclidean_squared";
212
+ break;
213
+ case "dotproduct":
214
+ throw new Error("dotproduct is not supported in Turbopuffer");
215
+ }
216
+ } catch (error$1) {
217
+ throw new error.MastraError(
218
+ {
219
+ id: "STORAGE_TURBOBUFFER_VECTOR_CREATE_INDEX_INVALID_ARGS",
220
+ domain: error.ErrorDomain.STORAGE,
221
+ category: error.ErrorCategory.USER,
222
+ details: { indexName, dimension, metric }
223
+ },
224
+ error$1
225
+ );
213
226
  }
214
227
  this.createIndexCache.set(indexName, {
215
228
  indexName,
@@ -219,15 +232,29 @@ var TurbopufferVector = class extends vector.MastraVector {
219
232
  });
220
233
  }
221
234
  async upsert({ indexName, vectors, metadata, ids }) {
235
+ let index;
236
+ let createIndex;
222
237
  try {
223
238
  if (vectors.length === 0) {
224
239
  throw new Error("upsert() called with empty vectors");
225
240
  }
226
- const index = this.client.namespace(indexName);
227
- const createIndex = this.createIndexCache.get(indexName);
241
+ index = this.client.namespace(indexName);
242
+ createIndex = this.createIndexCache.get(indexName);
228
243
  if (!createIndex) {
229
244
  throw new Error(`createIndex() not called for this index`);
230
245
  }
246
+ } catch (error$1) {
247
+ throw new error.MastraError(
248
+ {
249
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPSERT_INVALID_ARGS",
250
+ domain: error.ErrorDomain.STORAGE,
251
+ category: error.ErrorCategory.USER,
252
+ details: { indexName }
253
+ },
254
+ error$1
255
+ );
256
+ }
257
+ try {
231
258
  const distanceMetric = createIndex.tpufDistanceMetric;
232
259
  const vectorIds = ids || vectors.map(() => crypto.randomUUID());
233
260
  const records = vectors.map((vector, i) => ({
@@ -254,22 +281,49 @@ var TurbopufferVector = class extends vector.MastraVector {
254
281
  await index.upsert(upsertOptions);
255
282
  }
256
283
  return vectorIds;
257
- } catch (error) {
258
- throw new Error(`Failed to upsert vectors into Turbopuffer namespace ${indexName}: ${error}`);
284
+ } catch (error$1) {
285
+ throw new error.MastraError(
286
+ {
287
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPSERT_FAILED",
288
+ domain: error.ErrorDomain.STORAGE,
289
+ category: error.ErrorCategory.THIRD_PARTY,
290
+ details: { indexName }
291
+ },
292
+ error$1
293
+ );
259
294
  }
260
295
  }
261
- async query({ indexName, queryVector, topK, filter, includeVector }) {
262
- const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
263
- if (schemaConfig) {
264
- if (queryVector.length !== schemaConfig.dimensions) {
265
- throw new Error(
266
- `Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to query with queryVector.length=${queryVector.length}`
267
- );
296
+ async query({
297
+ indexName,
298
+ queryVector,
299
+ topK,
300
+ filter,
301
+ includeVector
302
+ }) {
303
+ let createIndex;
304
+ try {
305
+ const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
306
+ if (schemaConfig) {
307
+ if (queryVector.length !== schemaConfig.dimensions) {
308
+ throw new Error(
309
+ `Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to query with queryVector.length=${queryVector.length}`
310
+ );
311
+ }
268
312
  }
269
- }
270
- const createIndex = this.createIndexCache.get(indexName);
271
- if (!createIndex) {
272
- throw new Error(`createIndex() not called for this index`);
313
+ createIndex = this.createIndexCache.get(indexName);
314
+ if (!createIndex) {
315
+ throw new Error(`createIndex() not called for this index`);
316
+ }
317
+ } catch (error$1) {
318
+ throw new error.MastraError(
319
+ {
320
+ id: "STORAGE_TURBOBUFFER_VECTOR_QUERY_INVALID_ARGS",
321
+ domain: error.ErrorDomain.STORAGE,
322
+ category: error.ErrorCategory.USER,
323
+ details: { indexName }
324
+ },
325
+ error$1
326
+ );
273
327
  }
274
328
  const distanceMetric = createIndex.tpufDistanceMetric;
275
329
  try {
@@ -291,16 +345,31 @@ var TurbopufferVector = class extends vector.MastraVector {
291
345
  metadata: item.attributes || {},
292
346
  ...includeVector && item.vector ? { vector: item.vector } : {}
293
347
  }));
294
- } catch (error) {
295
- throw new Error(`Failed to query Turbopuffer namespace ${indexName}: ${error}`);
348
+ } catch (error$1) {
349
+ throw new error.MastraError(
350
+ {
351
+ id: "STORAGE_TURBOBUFFER_VECTOR_QUERY_FAILED",
352
+ domain: error.ErrorDomain.STORAGE,
353
+ category: error.ErrorCategory.THIRD_PARTY,
354
+ details: { indexName }
355
+ },
356
+ error$1
357
+ );
296
358
  }
297
359
  }
298
360
  async listIndexes() {
299
361
  try {
300
362
  const namespacesResult = await this.client.namespaces({});
301
363
  return namespacesResult.namespaces.map((namespace) => namespace.id);
302
- } catch (error) {
303
- throw new Error(`Failed to list Turbopuffer namespaces: ${error}`);
364
+ } catch (error$1) {
365
+ throw new error.MastraError(
366
+ {
367
+ id: "STORAGE_TURBOBUFFER_VECTOR_LIST_INDEXES_FAILED",
368
+ domain: error.ErrorDomain.STORAGE,
369
+ category: error.ErrorCategory.THIRD_PARTY
370
+ },
371
+ error$1
372
+ );
304
373
  }
305
374
  }
306
375
  /**
@@ -324,8 +393,16 @@ var TurbopufferVector = class extends vector.MastraVector {
324
393
  count,
325
394
  metric: createIndex.metric
326
395
  };
327
- } catch (error) {
328
- throw new Error(`Failed to describe Turbopuffer namespace ${indexName}: ${error}`);
396
+ } catch (error$1) {
397
+ throw new error.MastraError(
398
+ {
399
+ id: "STORAGE_TURBOBUFFER_VECTOR_DESCRIBE_INDEX_FAILED",
400
+ domain: error.ErrorDomain.STORAGE,
401
+ category: error.ErrorCategory.THIRD_PARTY,
402
+ details: { indexName }
403
+ },
404
+ error$1
405
+ );
329
406
  }
330
407
  }
331
408
  async deleteIndex({ indexName }) {
@@ -333,8 +410,16 @@ var TurbopufferVector = class extends vector.MastraVector {
333
410
  const namespace = this.client.namespace(indexName);
334
411
  await namespace.deleteAll();
335
412
  this.createIndexCache.delete(indexName);
336
- } catch (error) {
337
- throw new Error(`Failed to delete Turbopuffer namespace ${indexName}: ${error.message}`);
413
+ } catch (error$1) {
414
+ throw new error.MastraError(
415
+ {
416
+ id: "STORAGE_TURBOBUFFER_VECTOR_DELETE_INDEX_FAILED",
417
+ domain: error.ErrorDomain.STORAGE,
418
+ category: error.ErrorCategory.THIRD_PARTY,
419
+ details: { indexName }
420
+ },
421
+ error$1
422
+ );
338
423
  }
339
424
  }
340
425
  /**
@@ -348,22 +433,46 @@ var TurbopufferVector = class extends vector.MastraVector {
348
433
  * @throws Will throw an error if no updates are provided or if the update operation fails.
349
434
  */
350
435
  async updateVector({ indexName, id, update }) {
436
+ let namespace;
437
+ let createIndex;
438
+ let distanceMetric;
439
+ let record;
351
440
  try {
352
- const namespace = this.client.namespace(indexName);
353
- const createIndex = this.createIndexCache.get(indexName);
441
+ namespace = this.client.namespace(indexName);
442
+ createIndex = this.createIndexCache.get(indexName);
354
443
  if (!createIndex) {
355
444
  throw new Error(`createIndex() not called for this index`);
356
445
  }
357
- const distanceMetric = createIndex.tpufDistanceMetric;
358
- const record = { id };
446
+ distanceMetric = createIndex.tpufDistanceMetric;
447
+ record = { id };
359
448
  if (update.vector) record.vector = update.vector;
360
449
  if (update.metadata) record.attributes = update.metadata;
450
+ } catch (error$1) {
451
+ throw new error.MastraError(
452
+ {
453
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
454
+ domain: error.ErrorDomain.STORAGE,
455
+ category: error.ErrorCategory.USER,
456
+ details: { indexName }
457
+ },
458
+ error$1
459
+ );
460
+ }
461
+ try {
361
462
  await namespace.upsert({
362
463
  vectors: [record],
363
464
  distance_metric: distanceMetric
364
465
  });
365
- } catch (error) {
366
- throw new Error(`Failed to update Turbopuffer namespace ${indexName}: ${error.message}`);
466
+ } catch (error$1) {
467
+ throw new error.MastraError(
468
+ {
469
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPDATE_VECTOR_FAILED",
470
+ domain: error.ErrorDomain.STORAGE,
471
+ category: error.ErrorCategory.THIRD_PARTY,
472
+ details: { indexName }
473
+ },
474
+ error$1
475
+ );
367
476
  }
368
477
  }
369
478
  /**
@@ -377,8 +486,16 @@ var TurbopufferVector = class extends vector.MastraVector {
377
486
  try {
378
487
  const namespace = this.client.namespace(indexName);
379
488
  await namespace.delete({ ids: [id] });
380
- } catch (error) {
381
- throw new Error(`Failed to delete Turbopuffer namespace ${indexName}: ${error.message}`);
489
+ } catch (error$1) {
490
+ throw new error.MastraError(
491
+ {
492
+ id: "STORAGE_TURBOBUFFER_VECTOR_DELETE_VECTOR_FAILED",
493
+ domain: error.ErrorDomain.STORAGE,
494
+ category: error.ErrorCategory.THIRD_PARTY,
495
+ details: { indexName }
496
+ },
497
+ error$1
498
+ );
382
499
  }
383
500
  }
384
501
  };
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
1
2
  import { MastraVector } from '@mastra/core/vector';
2
3
  import { Turbopuffer } from '@turbopuffer/turbopuffer';
3
4
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
@@ -186,28 +187,40 @@ var TurbopufferVector = class extends MastraVector {
186
187
  }
187
188
  async createIndex({ indexName, dimension, metric }) {
188
189
  metric = metric ?? "cosine";
189
- if (this.createIndexCache.has(indexName)) {
190
- const expected = this.createIndexCache.get(indexName);
191
- if (dimension !== expected.dimension || metric !== expected.metric) {
192
- throw new Error(
193
- `createIndex() called more than once with inconsistent inputs. Index ${indexName} expected dimensions=${expected.dimension} and metric=${expected.metric} but got dimensions=${dimension} and metric=${metric}`
194
- );
195
- }
196
- return;
197
- }
198
- if (dimension <= 0) {
199
- throw new Error("Dimension must be a positive integer");
200
- }
201
190
  let distanceMetric = "cosine_distance";
202
- switch (metric) {
203
- case "cosine":
204
- distanceMetric = "cosine_distance";
205
- break;
206
- case "euclidean":
207
- distanceMetric = "euclidean_squared";
208
- break;
209
- case "dotproduct":
210
- throw new Error("dotproduct is not supported in Turbopuffer");
191
+ try {
192
+ if (this.createIndexCache.has(indexName)) {
193
+ const expected = this.createIndexCache.get(indexName);
194
+ if (dimension !== expected.dimension || metric !== expected.metric) {
195
+ throw new Error(
196
+ `createIndex() called more than once with inconsistent inputs. Index ${indexName} expected dimensions=${expected.dimension} and metric=${expected.metric} but got dimensions=${dimension} and metric=${metric}`
197
+ );
198
+ }
199
+ return;
200
+ }
201
+ if (dimension <= 0) {
202
+ throw new Error("Dimension must be a positive integer");
203
+ }
204
+ switch (metric) {
205
+ case "cosine":
206
+ distanceMetric = "cosine_distance";
207
+ break;
208
+ case "euclidean":
209
+ distanceMetric = "euclidean_squared";
210
+ break;
211
+ case "dotproduct":
212
+ throw new Error("dotproduct is not supported in Turbopuffer");
213
+ }
214
+ } catch (error) {
215
+ throw new MastraError(
216
+ {
217
+ id: "STORAGE_TURBOBUFFER_VECTOR_CREATE_INDEX_INVALID_ARGS",
218
+ domain: ErrorDomain.STORAGE,
219
+ category: ErrorCategory.USER,
220
+ details: { indexName, dimension, metric }
221
+ },
222
+ error
223
+ );
211
224
  }
212
225
  this.createIndexCache.set(indexName, {
213
226
  indexName,
@@ -217,15 +230,29 @@ var TurbopufferVector = class extends MastraVector {
217
230
  });
218
231
  }
219
232
  async upsert({ indexName, vectors, metadata, ids }) {
233
+ let index;
234
+ let createIndex;
220
235
  try {
221
236
  if (vectors.length === 0) {
222
237
  throw new Error("upsert() called with empty vectors");
223
238
  }
224
- const index = this.client.namespace(indexName);
225
- const createIndex = this.createIndexCache.get(indexName);
239
+ index = this.client.namespace(indexName);
240
+ createIndex = this.createIndexCache.get(indexName);
226
241
  if (!createIndex) {
227
242
  throw new Error(`createIndex() not called for this index`);
228
243
  }
244
+ } catch (error) {
245
+ throw new MastraError(
246
+ {
247
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPSERT_INVALID_ARGS",
248
+ domain: ErrorDomain.STORAGE,
249
+ category: ErrorCategory.USER,
250
+ details: { indexName }
251
+ },
252
+ error
253
+ );
254
+ }
255
+ try {
229
256
  const distanceMetric = createIndex.tpufDistanceMetric;
230
257
  const vectorIds = ids || vectors.map(() => crypto.randomUUID());
231
258
  const records = vectors.map((vector, i) => ({
@@ -253,21 +280,48 @@ var TurbopufferVector = class extends MastraVector {
253
280
  }
254
281
  return vectorIds;
255
282
  } catch (error) {
256
- throw new Error(`Failed to upsert vectors into Turbopuffer namespace ${indexName}: ${error}`);
283
+ throw new MastraError(
284
+ {
285
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPSERT_FAILED",
286
+ domain: ErrorDomain.STORAGE,
287
+ category: ErrorCategory.THIRD_PARTY,
288
+ details: { indexName }
289
+ },
290
+ error
291
+ );
257
292
  }
258
293
  }
259
- async query({ indexName, queryVector, topK, filter, includeVector }) {
260
- const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
261
- if (schemaConfig) {
262
- if (queryVector.length !== schemaConfig.dimensions) {
263
- throw new Error(
264
- `Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to query with queryVector.length=${queryVector.length}`
265
- );
294
+ async query({
295
+ indexName,
296
+ queryVector,
297
+ topK,
298
+ filter,
299
+ includeVector
300
+ }) {
301
+ let createIndex;
302
+ try {
303
+ const schemaConfig = this.opts.schemaConfigForIndex?.(indexName);
304
+ if (schemaConfig) {
305
+ if (queryVector.length !== schemaConfig.dimensions) {
306
+ throw new Error(
307
+ `Turbopuffer index ${indexName} was configured with dimensions=${schemaConfig.dimensions} but attempting to query with queryVector.length=${queryVector.length}`
308
+ );
309
+ }
266
310
  }
267
- }
268
- const createIndex = this.createIndexCache.get(indexName);
269
- if (!createIndex) {
270
- throw new Error(`createIndex() not called for this index`);
311
+ createIndex = this.createIndexCache.get(indexName);
312
+ if (!createIndex) {
313
+ throw new Error(`createIndex() not called for this index`);
314
+ }
315
+ } catch (error) {
316
+ throw new MastraError(
317
+ {
318
+ id: "STORAGE_TURBOBUFFER_VECTOR_QUERY_INVALID_ARGS",
319
+ domain: ErrorDomain.STORAGE,
320
+ category: ErrorCategory.USER,
321
+ details: { indexName }
322
+ },
323
+ error
324
+ );
271
325
  }
272
326
  const distanceMetric = createIndex.tpufDistanceMetric;
273
327
  try {
@@ -290,7 +344,15 @@ var TurbopufferVector = class extends MastraVector {
290
344
  ...includeVector && item.vector ? { vector: item.vector } : {}
291
345
  }));
292
346
  } catch (error) {
293
- throw new Error(`Failed to query Turbopuffer namespace ${indexName}: ${error}`);
347
+ throw new MastraError(
348
+ {
349
+ id: "STORAGE_TURBOBUFFER_VECTOR_QUERY_FAILED",
350
+ domain: ErrorDomain.STORAGE,
351
+ category: ErrorCategory.THIRD_PARTY,
352
+ details: { indexName }
353
+ },
354
+ error
355
+ );
294
356
  }
295
357
  }
296
358
  async listIndexes() {
@@ -298,7 +360,14 @@ var TurbopufferVector = class extends MastraVector {
298
360
  const namespacesResult = await this.client.namespaces({});
299
361
  return namespacesResult.namespaces.map((namespace) => namespace.id);
300
362
  } catch (error) {
301
- throw new Error(`Failed to list Turbopuffer namespaces: ${error}`);
363
+ throw new MastraError(
364
+ {
365
+ id: "STORAGE_TURBOBUFFER_VECTOR_LIST_INDEXES_FAILED",
366
+ domain: ErrorDomain.STORAGE,
367
+ category: ErrorCategory.THIRD_PARTY
368
+ },
369
+ error
370
+ );
302
371
  }
303
372
  }
304
373
  /**
@@ -323,7 +392,15 @@ var TurbopufferVector = class extends MastraVector {
323
392
  metric: createIndex.metric
324
393
  };
325
394
  } catch (error) {
326
- throw new Error(`Failed to describe Turbopuffer namespace ${indexName}: ${error}`);
395
+ throw new MastraError(
396
+ {
397
+ id: "STORAGE_TURBOBUFFER_VECTOR_DESCRIBE_INDEX_FAILED",
398
+ domain: ErrorDomain.STORAGE,
399
+ category: ErrorCategory.THIRD_PARTY,
400
+ details: { indexName }
401
+ },
402
+ error
403
+ );
327
404
  }
328
405
  }
329
406
  async deleteIndex({ indexName }) {
@@ -332,7 +409,15 @@ var TurbopufferVector = class extends MastraVector {
332
409
  await namespace.deleteAll();
333
410
  this.createIndexCache.delete(indexName);
334
411
  } catch (error) {
335
- throw new Error(`Failed to delete Turbopuffer namespace ${indexName}: ${error.message}`);
412
+ throw new MastraError(
413
+ {
414
+ id: "STORAGE_TURBOBUFFER_VECTOR_DELETE_INDEX_FAILED",
415
+ domain: ErrorDomain.STORAGE,
416
+ category: ErrorCategory.THIRD_PARTY,
417
+ details: { indexName }
418
+ },
419
+ error
420
+ );
336
421
  }
337
422
  }
338
423
  /**
@@ -346,22 +431,46 @@ var TurbopufferVector = class extends MastraVector {
346
431
  * @throws Will throw an error if no updates are provided or if the update operation fails.
347
432
  */
348
433
  async updateVector({ indexName, id, update }) {
434
+ let namespace;
435
+ let createIndex;
436
+ let distanceMetric;
437
+ let record;
349
438
  try {
350
- const namespace = this.client.namespace(indexName);
351
- const createIndex = this.createIndexCache.get(indexName);
439
+ namespace = this.client.namespace(indexName);
440
+ createIndex = this.createIndexCache.get(indexName);
352
441
  if (!createIndex) {
353
442
  throw new Error(`createIndex() not called for this index`);
354
443
  }
355
- const distanceMetric = createIndex.tpufDistanceMetric;
356
- const record = { id };
444
+ distanceMetric = createIndex.tpufDistanceMetric;
445
+ record = { id };
357
446
  if (update.vector) record.vector = update.vector;
358
447
  if (update.metadata) record.attributes = update.metadata;
448
+ } catch (error) {
449
+ throw new MastraError(
450
+ {
451
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
452
+ domain: ErrorDomain.STORAGE,
453
+ category: ErrorCategory.USER,
454
+ details: { indexName }
455
+ },
456
+ error
457
+ );
458
+ }
459
+ try {
359
460
  await namespace.upsert({
360
461
  vectors: [record],
361
462
  distance_metric: distanceMetric
362
463
  });
363
464
  } catch (error) {
364
- throw new Error(`Failed to update Turbopuffer namespace ${indexName}: ${error.message}`);
465
+ throw new MastraError(
466
+ {
467
+ id: "STORAGE_TURBOBUFFER_VECTOR_UPDATE_VECTOR_FAILED",
468
+ domain: ErrorDomain.STORAGE,
469
+ category: ErrorCategory.THIRD_PARTY,
470
+ details: { indexName }
471
+ },
472
+ error
473
+ );
365
474
  }
366
475
  }
367
476
  /**
@@ -376,7 +485,15 @@ var TurbopufferVector = class extends MastraVector {
376
485
  const namespace = this.client.namespace(indexName);
377
486
  await namespace.delete({ ids: [id] });
378
487
  } catch (error) {
379
- throw new Error(`Failed to delete Turbopuffer namespace ${indexName}: ${error.message}`);
488
+ throw new MastraError(
489
+ {
490
+ id: "STORAGE_TURBOBUFFER_VECTOR_DELETE_VECTOR_FAILED",
491
+ domain: ErrorDomain.STORAGE,
492
+ category: ErrorCategory.THIRD_PARTY,
493
+ details: { indexName }
494
+ },
495
+ error
496
+ );
380
497
  }
381
498
  }
382
499
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/turbopuffer",
3
- "version": "0.10.3",
3
+ "version": "0.11.0-alpha.1",
4
4
  "description": "Turbopuffer vector store provider for Mastra",
5
5
  "type": "module",
6
6
  "files": [
@@ -29,15 +29,15 @@
29
29
  "@microsoft/api-extractor": "^7.52.8",
30
30
  "@types/node": "^20.19.0",
31
31
  "dotenv": "^16.5.0",
32
- "eslint": "^9.28.0",
32
+ "eslint": "^9.29.0",
33
33
  "tsup": "^8.5.0",
34
34
  "typescript": "^5.8.3",
35
35
  "vitest": "^3.2.3",
36
36
  "@internal/lint": "0.0.13",
37
- "@mastra/core": "0.10.6"
37
+ "@mastra/core": "0.10.7-alpha.3"
38
38
  },
39
39
  "peerDependencies": {
40
- "@mastra/core": ">=0.10.4-0 <0.11.0"
40
+ "@mastra/core": ">=0.10.7-0 <0.11.0-0"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",