@mastra/mongodb 0.11.1-alpha.0 → 0.11.1-alpha.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.
@@ -1,5 +1,6 @@
1
1
  import { MessageList } from '@mastra/core/agent';
2
2
  import type { MastraMessageContentV2 } from '@mastra/core/agent';
3
+ import { ErrorDomain, ErrorCategory, MastraError } from '@mastra/core/error';
3
4
  import type { MetricResult, TestInfo } from '@mastra/core/eval';
4
5
  import type { MastraMessageV1, MastraMessageV2, StorageThreadType } from '@mastra/core/memory';
5
6
  import type {
@@ -48,15 +49,27 @@ export class MongoDBStore extends MastraStorage {
48
49
  super({ name: 'MongoDBStore' });
49
50
  this.#isConnected = false;
50
51
 
51
- if (!config.url?.trim().length) {
52
- throw new Error(
53
- 'MongoDBStore: url must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults.',
54
- );
55
- }
52
+ try {
53
+ if (!config.url?.trim().length) {
54
+ throw new Error(
55
+ 'MongoDBStore: url must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults.',
56
+ );
57
+ }
56
58
 
57
- if (!config.dbName?.trim().length) {
58
- throw new Error(
59
- 'MongoDBStore: dbName must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults.',
59
+ if (!config.dbName?.trim().length) {
60
+ throw new Error(
61
+ 'MongoDBStore: dbName must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults.',
62
+ );
63
+ }
64
+ } catch (error) {
65
+ throw new MastraError(
66
+ {
67
+ id: 'STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED',
68
+ domain: ErrorDomain.STORAGE,
69
+ category: ErrorCategory.USER,
70
+ details: { url: config.url, dbName: config.dbName },
71
+ },
72
+ error,
60
73
  );
61
74
  }
62
75
 
@@ -104,7 +117,17 @@ export class MongoDBStore extends MastraStorage {
104
117
  await collection.deleteMany({});
105
118
  } catch (error) {
106
119
  if (error instanceof Error) {
107
- this.logger.error(error.message);
120
+ const matstraError = new MastraError(
121
+ {
122
+ id: 'STORAGE_MONGODB_STORE_CLEAR_TABLE_FAILED',
123
+ domain: ErrorDomain.STORAGE,
124
+ category: ErrorCategory.THIRD_PARTY,
125
+ details: { tableName },
126
+ },
127
+ error,
128
+ );
129
+ this.logger.error(matstraError.message);
130
+ this.logger?.trackException(matstraError);
108
131
  }
109
132
  }
110
133
  }
@@ -114,8 +137,19 @@ export class MongoDBStore extends MastraStorage {
114
137
  const collection = await this.getCollection(tableName);
115
138
  await collection.insertOne(record);
116
139
  } catch (error) {
117
- this.logger.error(`Error upserting into table ${tableName}: ${error}`);
118
- throw error;
140
+ if (error instanceof Error) {
141
+ const matstraError = new MastraError(
142
+ {
143
+ id: 'STORAGE_MONGODB_STORE_INSERT_FAILED',
144
+ domain: ErrorDomain.STORAGE,
145
+ category: ErrorCategory.THIRD_PARTY,
146
+ details: { tableName },
147
+ },
148
+ error,
149
+ );
150
+ this.logger.error(matstraError.message);
151
+ this.logger?.trackException(matstraError);
152
+ }
119
153
  }
120
154
  }
121
155
 
@@ -128,8 +162,15 @@ export class MongoDBStore extends MastraStorage {
128
162
  const collection = await this.getCollection(tableName);
129
163
  await collection.insertMany(records);
130
164
  } catch (error) {
131
- this.logger.error(`Error upserting into table ${tableName}: ${error}`);
132
- throw error;
165
+ throw new MastraError(
166
+ {
167
+ id: 'STORAGE_MONGODB_STORE_BATCH_INSERT_FAILED',
168
+ domain: ErrorDomain.STORAGE,
169
+ category: ErrorCategory.THIRD_PARTY,
170
+ details: { tableName },
171
+ },
172
+ error,
173
+ );
133
174
  }
134
175
  }
135
176
 
@@ -139,8 +180,15 @@ export class MongoDBStore extends MastraStorage {
139
180
  const collection = await this.getCollection(tableName);
140
181
  return (await collection.find(keys).toArray()) as R;
141
182
  } catch (error) {
142
- this.logger.error(`Error loading ${tableName} with keys ${JSON.stringify(keys)}: ${error}`);
143
- throw error;
183
+ throw new MastraError(
184
+ {
185
+ id: 'STORAGE_MONGODB_STORE_LOAD_FAILED',
186
+ domain: ErrorDomain.STORAGE,
187
+ category: ErrorCategory.THIRD_PARTY,
188
+ details: { tableName },
189
+ },
190
+ error,
191
+ );
144
192
  }
145
193
  }
146
194
 
@@ -157,8 +205,15 @@ export class MongoDBStore extends MastraStorage {
157
205
  metadata: typeof result.metadata === 'string' ? JSON.parse(result.metadata) : result.metadata,
158
206
  };
159
207
  } catch (error) {
160
- this.logger.error(`Error loading thread with ID ${threadId}: ${error}`);
161
- throw error;
208
+ throw new MastraError(
209
+ {
210
+ id: 'STORAGE_MONGODB_STORE_GET_THREAD_BY_ID_FAILED',
211
+ domain: ErrorDomain.STORAGE,
212
+ category: ErrorCategory.THIRD_PARTY,
213
+ details: { threadId },
214
+ },
215
+ error,
216
+ );
162
217
  }
163
218
  }
164
219
 
@@ -175,8 +230,15 @@ export class MongoDBStore extends MastraStorage {
175
230
  metadata: typeof result.metadata === 'string' ? JSON.parse(result.metadata) : result.metadata,
176
231
  }));
177
232
  } catch (error) {
178
- this.logger.error(`Error loading threads by resourceId ${resourceId}: ${error}`);
179
- throw error;
233
+ throw new MastraError(
234
+ {
235
+ id: 'STORAGE_MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED',
236
+ domain: ErrorDomain.STORAGE,
237
+ category: ErrorCategory.THIRD_PARTY,
238
+ details: { resourceId },
239
+ },
240
+ error,
241
+ );
180
242
  }
181
243
  }
182
244
 
@@ -195,8 +257,15 @@ export class MongoDBStore extends MastraStorage {
195
257
  );
196
258
  return thread;
197
259
  } catch (error) {
198
- this.logger.error(`Error saving thread ${thread.id}: ${error}`);
199
- throw error;
260
+ throw new MastraError(
261
+ {
262
+ id: 'STORAGE_MONGODB_STORE_SAVE_THREAD_FAILED',
263
+ domain: ErrorDomain.STORAGE,
264
+ category: ErrorCategory.THIRD_PARTY,
265
+ details: { threadId: thread.id },
266
+ },
267
+ error,
268
+ );
200
269
  }
201
270
  }
202
271
 
@@ -211,7 +280,13 @@ export class MongoDBStore extends MastraStorage {
211
280
  }): Promise<StorageThreadType> {
212
281
  const thread = await this.getThreadById({ threadId: id });
213
282
  if (!thread) {
214
- throw new Error(`Thread ${id} not found`);
283
+ throw new MastraError({
284
+ id: 'STORAGE_MONGODB_STORE_UPDATE_THREAD_NOT_FOUND',
285
+ domain: ErrorDomain.STORAGE,
286
+ category: ErrorCategory.THIRD_PARTY,
287
+ details: { threadId: id },
288
+ text: `Thread ${id} not found`,
289
+ });
215
290
  }
216
291
 
217
292
  const updatedThread = {
@@ -235,8 +310,15 @@ export class MongoDBStore extends MastraStorage {
235
310
  },
236
311
  );
237
312
  } catch (error) {
238
- this.logger.error(`Error updating thread ${id}:) ${error}`);
239
- throw error;
313
+ throw new MastraError(
314
+ {
315
+ id: 'STORAGE_MONGODB_STORE_UPDATE_THREAD_FAILED',
316
+ domain: ErrorDomain.STORAGE,
317
+ category: ErrorCategory.THIRD_PARTY,
318
+ details: { threadId: id },
319
+ },
320
+ error,
321
+ );
240
322
  }
241
323
 
242
324
  return updatedThread;
@@ -251,8 +333,15 @@ export class MongoDBStore extends MastraStorage {
251
333
  const collectionThreads = await this.getCollection(TABLE_THREADS);
252
334
  await collectionThreads.deleteOne({ id: threadId });
253
335
  } catch (error) {
254
- this.logger.error(`Error deleting thread ${threadId}: ${error}`);
255
- throw error;
336
+ throw new MastraError(
337
+ {
338
+ id: 'STORAGE_MONGODB_STORE_DELETE_THREAD_FAILED',
339
+ domain: ErrorDomain.STORAGE,
340
+ category: ErrorCategory.THIRD_PARTY,
341
+ details: { threadId },
342
+ },
343
+ error,
344
+ );
256
345
  }
257
346
  }
258
347
 
@@ -266,7 +355,7 @@ export class MongoDBStore extends MastraStorage {
266
355
  format?: 'v1' | 'v2';
267
356
  }): Promise<MastraMessageV1[] | MastraMessageV2[]> {
268
357
  try {
269
- const limit = typeof selectBy?.last === 'number' ? selectBy.last : 40;
358
+ const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
270
359
  const include = selectBy?.include || [];
271
360
  let messages: MastraMessageV2[] = [];
272
361
  let allMessages: MastraMessageV2[] = [];
@@ -323,8 +412,15 @@ export class MongoDBStore extends MastraStorage {
323
412
  if (format === `v2`) return list.get.all.v2();
324
413
  return list.get.all.v1();
325
414
  } catch (error) {
326
- this.logger.error('Error getting messages:', error as Error);
327
- throw error;
415
+ throw new MastraError(
416
+ {
417
+ id: 'STORAGE_MONGODB_STORE_GET_MESSAGES_FAILED',
418
+ domain: ErrorDomain.STORAGE,
419
+ category: ErrorCategory.THIRD_PARTY,
420
+ details: { threadId },
421
+ },
422
+ error,
423
+ );
328
424
  }
329
425
  }
330
426
 
@@ -366,7 +462,15 @@ export class MongoDBStore extends MastraStorage {
366
462
  const threadsCollection = await this.getCollection(TABLE_THREADS);
367
463
 
368
464
  await Promise.all([
369
- collection.insertMany(messagesToInsert),
465
+ collection.bulkWrite(
466
+ messagesToInsert.map(msg => ({
467
+ updateOne: {
468
+ filter: { id: msg.id },
469
+ update: { $set: msg },
470
+ upsert: true,
471
+ },
472
+ })),
473
+ ),
370
474
  threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: new Date() } }),
371
475
  ]);
372
476
 
@@ -404,7 +508,7 @@ export class MongoDBStore extends MastraStorage {
404
508
 
405
509
  const query: any = {};
406
510
  if (name) {
407
- query['name'] = `%${name}%`;
511
+ query['name'] = new RegExp(name);
408
512
  }
409
513
 
410
514
  if (scope) {
@@ -412,9 +516,9 @@ export class MongoDBStore extends MastraStorage {
412
516
  }
413
517
 
414
518
  if (attributes) {
415
- Object.keys(attributes).forEach(key => {
416
- query[`attributes.${key}`] = attributes[key];
417
- });
519
+ query['$and'] = Object.entries(attributes).map(([key, value]) => ({
520
+ attributes: new RegExp(`\"${key}\":\"${value}\"`),
521
+ }));
418
522
  }
419
523
 
420
524
  if (filters) {
@@ -423,31 +527,42 @@ export class MongoDBStore extends MastraStorage {
423
527
  });
424
528
  }
425
529
 
426
- const collection = await this.getCollection(TABLE_TRACES);
427
- const result = await collection
428
- .find(query, {
429
- sort: { startTime: -1 },
430
- })
431
- .limit(limit)
432
- .skip(offset)
433
- .toArray();
434
-
435
- return result.map(row => ({
436
- id: row.id,
437
- parentSpanId: row.parentSpanId,
438
- traceId: row.traceId,
439
- name: row.name,
440
- scope: row.scope,
441
- kind: row.kind,
442
- status: safelyParseJSON(row.status as string),
443
- events: safelyParseJSON(row.events as string),
444
- links: safelyParseJSON(row.links as string),
445
- attributes: safelyParseJSON(row.attributes as string),
446
- startTime: row.startTime,
447
- endTime: row.endTime,
448
- other: safelyParseJSON(row.other as string),
449
- createdAt: row.createdAt,
450
- })) as any;
530
+ try {
531
+ const collection = await this.getCollection(TABLE_TRACES);
532
+ const result = await collection
533
+ .find(query, {
534
+ sort: { startTime: -1 },
535
+ })
536
+ .limit(limit)
537
+ .skip(offset)
538
+ .toArray();
539
+
540
+ return result.map(row => ({
541
+ id: row.id,
542
+ parentSpanId: row.parentSpanId,
543
+ traceId: row.traceId,
544
+ name: row.name,
545
+ scope: row.scope,
546
+ kind: row.kind,
547
+ status: safelyParseJSON(row.status as string),
548
+ events: safelyParseJSON(row.events as string),
549
+ links: safelyParseJSON(row.links as string),
550
+ attributes: safelyParseJSON(row.attributes as string),
551
+ startTime: row.startTime,
552
+ endTime: row.endTime,
553
+ other: safelyParseJSON(row.other as string),
554
+ createdAt: row.createdAt,
555
+ })) as any;
556
+ } catch (error) {
557
+ throw new MastraError(
558
+ {
559
+ id: 'STORAGE_MONGODB_STORE_GET_TRACES_FAILED',
560
+ domain: ErrorDomain.STORAGE,
561
+ category: ErrorCategory.THIRD_PARTY,
562
+ },
563
+ error,
564
+ );
565
+ }
451
566
  }
452
567
 
453
568
  async getWorkflowRuns({
@@ -487,46 +602,57 @@ export class MongoDBStore extends MastraStorage {
487
602
  }
488
603
  }
489
604
 
490
- const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
491
- let total = 0;
492
- // Only get total count when using pagination
493
- if (limit !== undefined && offset !== undefined) {
494
- total = await collection.countDocuments(query);
495
- }
605
+ try {
606
+ const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
607
+ let total = 0;
608
+ // Only get total count when using pagination
609
+ if (limit !== undefined && offset !== undefined) {
610
+ total = await collection.countDocuments(query);
611
+ }
496
612
 
497
- // Get results
498
- const request = collection.find(query).sort({ createdAt: 'desc' });
499
- if (limit) {
500
- request.limit(limit);
501
- }
613
+ // Get results
614
+ const request = collection.find(query).sort({ createdAt: 'desc' });
615
+ if (limit) {
616
+ request.limit(limit);
617
+ }
502
618
 
503
- if (offset) {
504
- request.skip(offset);
505
- }
619
+ if (offset) {
620
+ request.skip(offset);
621
+ }
506
622
 
507
- const result = await request.toArray();
508
- const runs = result.map(row => {
509
- let parsedSnapshot: WorkflowRunState | string = row.snapshot;
510
- if (typeof parsedSnapshot === 'string') {
511
- try {
512
- parsedSnapshot = JSON.parse(row.snapshot as string) as WorkflowRunState;
513
- } catch (e) {
514
- // If parsing fails, return the raw snapshot string
515
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
623
+ const result = await request.toArray();
624
+ const runs = result.map(row => {
625
+ let parsedSnapshot: WorkflowRunState | string = row.snapshot;
626
+ if (typeof parsedSnapshot === 'string') {
627
+ try {
628
+ parsedSnapshot = JSON.parse(row.snapshot as string) as WorkflowRunState;
629
+ } catch (e) {
630
+ // If parsing fails, return the raw snapshot string
631
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
632
+ }
516
633
  }
517
- }
518
634
 
519
- return {
520
- workflowName: row.workflow_name as string,
521
- runId: row.run_id as string,
522
- snapshot: parsedSnapshot,
523
- createdAt: new Date(row.createdAt as string),
524
- updatedAt: new Date(row.updatedAt as string),
525
- };
526
- });
635
+ return {
636
+ workflowName: row.workflow_name as string,
637
+ runId: row.run_id as string,
638
+ snapshot: parsedSnapshot,
639
+ createdAt: new Date(row.createdAt as string),
640
+ updatedAt: new Date(row.updatedAt as string),
641
+ };
642
+ });
527
643
 
528
- // Use runs.length as total when not paginating
529
- return { runs, total: total || runs.length };
644
+ // Use runs.length as total when not paginating
645
+ return { runs, total: total || runs.length };
646
+ } catch (error) {
647
+ throw new MastraError(
648
+ {
649
+ id: 'STORAGE_MONGODB_STORE_GET_WORKFLOW_RUNS_FAILED',
650
+ domain: ErrorDomain.STORAGE,
651
+ category: ErrorCategory.THIRD_PARTY,
652
+ },
653
+ error,
654
+ );
655
+ }
530
656
  }
531
657
 
532
658
  async getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]> {
@@ -565,8 +691,15 @@ export class MongoDBStore extends MastraStorage {
565
691
  if (error instanceof Error && error.message.includes('no such table')) {
566
692
  return [];
567
693
  }
568
- this.logger.error('Failed to get evals for the specified agent: ' + (error as any)?.message);
569
- throw error;
694
+ throw new MastraError(
695
+ {
696
+ id: 'STORAGE_MONGODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED',
697
+ domain: ErrorDomain.STORAGE,
698
+ category: ErrorCategory.THIRD_PARTY,
699
+ details: { agentName },
700
+ },
701
+ error,
702
+ );
570
703
  }
571
704
  }
572
705
 
@@ -596,8 +729,15 @@ export class MongoDBStore extends MastraStorage {
596
729
  { upsert: true },
597
730
  );
598
731
  } catch (error) {
599
- this.logger.error(`Error persisting workflow snapshot: ${error}`);
600
- throw error;
732
+ throw new MastraError(
733
+ {
734
+ id: 'STORAGE_MONGODB_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
735
+ domain: ErrorDomain.STORAGE,
736
+ category: ErrorCategory.THIRD_PARTY,
737
+ details: { workflowName, runId },
738
+ },
739
+ error,
740
+ );
601
741
  }
602
742
  }
603
743
 
@@ -623,8 +763,15 @@ export class MongoDBStore extends MastraStorage {
623
763
 
624
764
  return JSON.parse(result[0].snapshot);
625
765
  } catch (error) {
626
- console.error('Error loading workflow snapshot:', error);
627
- throw error;
766
+ throw new MastraError(
767
+ {
768
+ id: 'STORAGE_MONGODB_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
769
+ domain: ErrorDomain.STORAGE,
770
+ category: ErrorCategory.THIRD_PARTY,
771
+ details: { workflowName, runId },
772
+ },
773
+ error,
774
+ );
628
775
  }
629
776
  }
630
777
 
@@ -653,8 +800,15 @@ export class MongoDBStore extends MastraStorage {
653
800
 
654
801
  return this.parseWorkflowRun(result);
655
802
  } catch (error) {
656
- console.error('Error getting workflow run by ID:', error);
657
- throw error;
803
+ throw new MastraError(
804
+ {
805
+ id: 'STORAGE_MONGODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
806
+ domain: ErrorDomain.STORAGE,
807
+ category: ErrorCategory.THIRD_PARTY,
808
+ details: { runId },
809
+ },
810
+ error,
811
+ );
658
812
  }
659
813
  }
660
814
 
@@ -706,11 +860,20 @@ export class MongoDBStore extends MastraStorage {
706
860
  console.warn('Failed to parse test_info:', e);
707
861
  }
708
862
  }
863
+ const resultValue = JSON.parse(row.result as string);
864
+ if (!resultValue || typeof resultValue !== 'object' || !('score' in resultValue)) {
865
+ throw new MastraError({
866
+ id: 'STORAGE_MONGODB_STORE_INVALID_METRIC_FORMAT',
867
+ text: `Invalid MetricResult format: ${JSON.stringify(resultValue)}`,
868
+ domain: ErrorDomain.STORAGE,
869
+ category: ErrorCategory.USER,
870
+ });
871
+ }
709
872
 
710
873
  return {
711
874
  input: row.input as string,
712
875
  output: row.output as string,
713
- result: row.result as MetricResult,
876
+ result: resultValue as MetricResult,
714
877
  agentName: row.agent_name as string,
715
878
  metricName: row.metric_name as string,
716
879
  instructions: row.instructions as string,
@@ -722,7 +885,12 @@ export class MongoDBStore extends MastraStorage {
722
885
  }
723
886
 
724
887
  async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
725
- throw new Error('Method not implemented.');
888
+ throw new MastraError({
889
+ id: 'STORAGE_MONGODB_STORE_GET_TRACES_PAGINATED_FAILED',
890
+ domain: ErrorDomain.STORAGE,
891
+ category: ErrorCategory.THIRD_PARTY,
892
+ text: 'Method not implemented.',
893
+ });
726
894
  }
727
895
 
728
896
  async getThreadsByResourceIdPaginated(_args: {
@@ -730,17 +898,38 @@ export class MongoDBStore extends MastraStorage {
730
898
  page?: number;
731
899
  perPage?: number;
732
900
  }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
733
- throw new Error('Method not implemented.');
901
+ throw new MastraError({
902
+ id: 'STORAGE_MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
903
+ domain: ErrorDomain.STORAGE,
904
+ category: ErrorCategory.THIRD_PARTY,
905
+ text: 'Method not implemented.',
906
+ });
734
907
  }
735
908
 
736
909
  async getMessagesPaginated(
737
910
  _args: StorageGetMessagesArg,
738
911
  ): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
739
- throw new Error('Method not implemented.');
912
+ throw new MastraError({
913
+ id: 'STORAGE_MONGODB_STORE_GET_MESSAGES_PAGINATED_FAILED',
914
+ domain: ErrorDomain.STORAGE,
915
+ category: ErrorCategory.THIRD_PARTY,
916
+ text: 'Method not implemented.',
917
+ });
740
918
  }
741
919
 
742
920
  async close(): Promise<void> {
743
- await this.#client.close();
921
+ try {
922
+ await this.#client.close();
923
+ } catch (error) {
924
+ throw new MastraError(
925
+ {
926
+ id: 'STORAGE_MONGODB_STORE_CLOSE_FAILED',
927
+ domain: ErrorDomain.STORAGE,
928
+ category: ErrorCategory.USER,
929
+ },
930
+ error,
931
+ );
932
+ }
744
933
  }
745
934
 
746
935
  async updateMessages(_args: {