@mastra/dynamodb 0.0.0-taofeeqInngest-20250603090617 → 0.0.0-tsconfig-compile-20250703214351

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,7 +1,10 @@
1
1
  import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
2
2
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
3
- import type { StorageThreadType, WorkflowRunState, MastraMessageV1, MastraMessageV2 } from '@mastra/core';
3
+ import type { MastraMessageContentV2 } from '@mastra/core/agent';
4
4
  import { MessageList } from '@mastra/core/agent';
5
+ import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
6
+ import type { StorageThreadType, MastraMessageV2, MastraMessageV1 } from '@mastra/core/memory';
7
+
5
8
  import {
6
9
  MastraStorage,
7
10
  TABLE_THREADS,
@@ -10,7 +13,19 @@ import {
10
13
  TABLE_EVALS,
11
14
  TABLE_TRACES,
12
15
  } from '@mastra/core/storage';
13
- import type { EvalRow, StorageGetMessagesArg, WorkflowRun, WorkflowRuns, TABLE_NAMES } from '@mastra/core/storage';
16
+ import type {
17
+ EvalRow,
18
+ StorageGetMessagesArg,
19
+ WorkflowRun,
20
+ WorkflowRuns,
21
+ TABLE_NAMES,
22
+ StorageGetTracesArg,
23
+ PaginationInfo,
24
+ StorageColumn,
25
+ TABLE_RESOURCES,
26
+ } from '@mastra/core/storage';
27
+ import type { Trace } from '@mastra/core/telemetry';
28
+ import type { WorkflowRunState } from '@mastra/core/workflows';
14
29
  import type { Service } from 'electrodb';
15
30
  import { getElectroDbService } from '../entities';
16
31
 
@@ -24,6 +39,8 @@ export interface DynamoDBStoreConfig {
24
39
  };
25
40
  }
26
41
 
42
+ type SUPPORTED_TABLE_NAMES = Exclude<TABLE_NAMES, typeof TABLE_RESOURCES>;
43
+
27
44
  // Define a type for our service that allows string indexing
28
45
  type MastraService = Service<Record<string, any>> & {
29
46
  [key: string]: any;
@@ -50,25 +67,36 @@ export class DynamoDBStore extends MastraStorage {
50
67
  super({ name });
51
68
 
52
69
  // Validate required config
53
- if (!config.tableName || typeof config.tableName !== 'string' || config.tableName.trim() === '') {
54
- throw new Error('DynamoDBStore: config.tableName must be provided and cannot be empty.');
55
- }
56
- // Validate tableName characters (basic check)
57
- if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
58
- throw new Error(
59
- `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`,
60
- );
61
- }
70
+ try {
71
+ if (!config.tableName || typeof config.tableName !== 'string' || config.tableName.trim() === '') {
72
+ throw new Error('DynamoDBStore: config.tableName must be provided and cannot be empty.');
73
+ }
74
+ // Validate tableName characters (basic check)
75
+ if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
76
+ throw new Error(
77
+ `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`,
78
+ );
79
+ }
62
80
 
63
- const dynamoClient = new DynamoDBClient({
64
- region: config.region || 'us-east-1',
65
- endpoint: config.endpoint,
66
- credentials: config.credentials,
67
- });
81
+ const dynamoClient = new DynamoDBClient({
82
+ region: config.region || 'us-east-1',
83
+ endpoint: config.endpoint,
84
+ credentials: config.credentials,
85
+ });
68
86
 
69
- this.tableName = config.tableName;
70
- this.client = DynamoDBDocumentClient.from(dynamoClient);
71
- this.service = getElectroDbService(this.client, this.tableName) as MastraService;
87
+ this.tableName = config.tableName;
88
+ this.client = DynamoDBDocumentClient.from(dynamoClient);
89
+ this.service = getElectroDbService(this.client, this.tableName) as MastraService;
90
+ } catch (error) {
91
+ throw new MastraError(
92
+ {
93
+ id: 'STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED',
94
+ domain: ErrorDomain.STORAGE,
95
+ category: ErrorCategory.USER,
96
+ },
97
+ error,
98
+ );
99
+ }
72
100
 
73
101
  // We're using a single table design with ElectroDB,
74
102
  // so we don't need to create multiple tables
@@ -100,7 +128,15 @@ export class DynamoDBStore extends MastraStorage {
100
128
  this.logger.debug(`Table ${this.tableName} exists and is accessible`);
101
129
  } catch (error) {
102
130
  this.logger.error('Error validating table access', { tableName: this.tableName, error });
103
- throw error;
131
+ throw new MastraError(
132
+ {
133
+ id: 'STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED',
134
+ domain: ErrorDomain.STORAGE,
135
+ category: ErrorCategory.THIRD_PARTY,
136
+ details: { tableName: this.tableName },
137
+ },
138
+ error,
139
+ );
104
140
  }
105
141
  }
106
142
 
@@ -126,7 +162,15 @@ export class DynamoDBStore extends MastraStorage {
126
162
  }
127
163
 
128
164
  // For other errors (like permissions issues), we should throw
129
- throw error;
165
+ throw new MastraError(
166
+ {
167
+ id: 'STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED',
168
+ domain: ErrorDomain.STORAGE,
169
+ category: ErrorCategory.THIRD_PARTY,
170
+ details: { tableName: this.tableName },
171
+ },
172
+ error,
173
+ );
130
174
  }
131
175
  }
132
176
 
@@ -153,7 +197,15 @@ export class DynamoDBStore extends MastraStorage {
153
197
  // The error has already been handled by _performInitializationAndStore
154
198
  // (i.e., this.hasInitialized was reset). Re-throwing here ensures
155
199
  // the caller of init() is aware of the failure.
156
- throw error;
200
+ throw new MastraError(
201
+ {
202
+ id: 'STORAGE_DYNAMODB_STORE_INIT_FAILED',
203
+ domain: ErrorDomain.STORAGE,
204
+ category: ErrorCategory.THIRD_PARTY,
205
+ details: { tableName: this.tableName },
206
+ },
207
+ error,
208
+ );
157
209
  }
158
210
  }
159
211
 
@@ -180,15 +232,52 @@ export class DynamoDBStore extends MastraStorage {
180
232
  });
181
233
  }
182
234
 
235
+ /**
236
+ * Pre-processes a record to ensure Date objects are converted to ISO strings
237
+ * This is necessary because ElectroDB validation happens before setters are applied
238
+ */
239
+ private preprocessRecord(record: Record<string, any>): Record<string, any> {
240
+ const processed = { ...record };
241
+
242
+ // Convert Date objects to ISO strings for date fields
243
+ // This prevents ElectroDB validation errors that occur when Date objects are passed
244
+ // to string-typed attributes, even when the attribute has a setter that converts dates
245
+ if (processed.createdAt instanceof Date) {
246
+ processed.createdAt = processed.createdAt.toISOString();
247
+ }
248
+ if (processed.updatedAt instanceof Date) {
249
+ processed.updatedAt = processed.updatedAt.toISOString();
250
+ }
251
+ if (processed.created_at instanceof Date) {
252
+ processed.created_at = processed.created_at.toISOString();
253
+ }
254
+
255
+ return processed;
256
+ }
257
+
258
+ async alterTable(_args: {
259
+ tableName: TABLE_NAMES;
260
+ schema: Record<string, StorageColumn>;
261
+ ifNotExists: string[];
262
+ }): Promise<void> {
263
+ // Nothing to do here, DynamoDB has a flexible schema and handles new attributes automatically upon insertion/update.
264
+ }
265
+
183
266
  /**
184
267
  * Clear all items from a logical "table" (entity type)
185
268
  */
186
- async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
269
+ async clearTable({ tableName }: { tableName: SUPPORTED_TABLE_NAMES }): Promise<void> {
187
270
  this.logger.debug('DynamoDB clearTable called', { tableName });
188
271
 
189
272
  const entityName = this.getEntityNameForTable(tableName);
190
273
  if (!entityName || !this.service.entities[entityName]) {
191
- throw new Error(`No entity defined for ${tableName}`);
274
+ throw new MastraError({
275
+ id: 'STORAGE_DYNAMODB_STORE_CLEAR_TABLE_INVALID_ARGS',
276
+ domain: ErrorDomain.STORAGE,
277
+ category: ErrorCategory.USER,
278
+ text: 'No entity defined for tableName',
279
+ details: { tableName },
280
+ });
192
281
  }
193
282
 
194
283
  try {
@@ -258,45 +347,83 @@ export class DynamoDBStore extends MastraStorage {
258
347
 
259
348
  this.logger.debug(`Successfully cleared all records for ${tableName}`);
260
349
  } catch (error) {
261
- this.logger.error('Failed to clear table', { tableName, error });
262
- throw error;
350
+ throw new MastraError(
351
+ {
352
+ id: 'STORAGE_DYNAMODB_STORE_CLEAR_TABLE_FAILED',
353
+ domain: ErrorDomain.STORAGE,
354
+ category: ErrorCategory.THIRD_PARTY,
355
+ details: { tableName },
356
+ },
357
+ error,
358
+ );
263
359
  }
264
360
  }
265
361
 
266
362
  /**
267
363
  * Insert a record into the specified "table" (entity)
268
364
  */
269
- async insert({ tableName, record }: { tableName: TABLE_NAMES; record: Record<string, any> }): Promise<void> {
365
+ async insert({
366
+ tableName,
367
+ record,
368
+ }: {
369
+ tableName: SUPPORTED_TABLE_NAMES;
370
+ record: Record<string, any>;
371
+ }): Promise<void> {
270
372
  this.logger.debug('DynamoDB insert called', { tableName });
271
373
 
272
374
  const entityName = this.getEntityNameForTable(tableName);
273
375
  if (!entityName || !this.service.entities[entityName]) {
274
- throw new Error(`No entity defined for ${tableName}`);
376
+ throw new MastraError({
377
+ id: 'STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS',
378
+ domain: ErrorDomain.STORAGE,
379
+ category: ErrorCategory.USER,
380
+ text: 'No entity defined for tableName',
381
+ details: { tableName },
382
+ });
275
383
  }
276
384
 
277
385
  try {
278
- // Add the entity type to the record before creating
279
- const dataToSave = { entity: entityName, ...record };
386
+ // Add the entity type to the record and preprocess before creating
387
+ const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
280
388
  await this.service.entities[entityName].create(dataToSave).go();
281
389
  } catch (error) {
282
- this.logger.error('Failed to insert record', { tableName, error });
283
- throw error;
390
+ throw new MastraError(
391
+ {
392
+ id: 'STORAGE_DYNAMODB_STORE_INSERT_FAILED',
393
+ domain: ErrorDomain.STORAGE,
394
+ category: ErrorCategory.THIRD_PARTY,
395
+ details: { tableName },
396
+ },
397
+ error,
398
+ );
284
399
  }
285
400
  }
286
401
 
287
402
  /**
288
403
  * Insert multiple records as a batch
289
404
  */
290
- async batchInsert({ tableName, records }: { tableName: TABLE_NAMES; records: Record<string, any>[] }): Promise<void> {
405
+ async batchInsert({
406
+ tableName,
407
+ records,
408
+ }: {
409
+ tableName: SUPPORTED_TABLE_NAMES;
410
+ records: Record<string, any>[];
411
+ }): Promise<void> {
291
412
  this.logger.debug('DynamoDB batchInsert called', { tableName, count: records.length });
292
413
 
293
414
  const entityName = this.getEntityNameForTable(tableName);
294
415
  if (!entityName || !this.service.entities[entityName]) {
295
- throw new Error(`No entity defined for ${tableName}`);
416
+ throw new MastraError({
417
+ id: 'STORAGE_DYNAMODB_STORE_BATCH_INSERT_INVALID_ARGS',
418
+ domain: ErrorDomain.STORAGE,
419
+ category: ErrorCategory.USER,
420
+ text: 'No entity defined for tableName',
421
+ details: { tableName },
422
+ });
296
423
  }
297
424
 
298
- // Add entity type to each record
299
- const recordsToSave = records.map(rec => ({ entity: entityName, ...rec }));
425
+ // Add entity type and preprocess each record
426
+ const recordsToSave = records.map(rec => ({ entity: entityName, ...this.preprocessRecord(rec) }));
300
427
 
301
428
  // ElectroDB has batch limits of 25 items, so we need to chunk
302
429
  const batchSize = 25;
@@ -322,20 +449,39 @@ export class DynamoDBStore extends MastraStorage {
322
449
  // Original batch call: await this.service.entities[entityName].create(batch).go();
323
450
  }
324
451
  } catch (error) {
325
- this.logger.error('Failed to batch insert records', { tableName, error });
326
- throw error;
452
+ throw new MastraError(
453
+ {
454
+ id: 'STORAGE_DYNAMODB_STORE_BATCH_INSERT_FAILED',
455
+ domain: ErrorDomain.STORAGE,
456
+ category: ErrorCategory.THIRD_PARTY,
457
+ details: { tableName },
458
+ },
459
+ error,
460
+ );
327
461
  }
328
462
  }
329
463
 
330
464
  /**
331
465
  * Load a record by its keys
332
466
  */
333
- async load<R>({ tableName, keys }: { tableName: TABLE_NAMES; keys: Record<string, string> }): Promise<R | null> {
467
+ async load<R>({
468
+ tableName,
469
+ keys,
470
+ }: {
471
+ tableName: SUPPORTED_TABLE_NAMES;
472
+ keys: Record<string, string>;
473
+ }): Promise<R | null> {
334
474
  this.logger.debug('DynamoDB load called', { tableName, keys });
335
475
 
336
476
  const entityName = this.getEntityNameForTable(tableName);
337
477
  if (!entityName || !this.service.entities[entityName]) {
338
- throw new Error(`No entity defined for ${tableName}`);
478
+ throw new MastraError({
479
+ id: 'STORAGE_DYNAMODB_STORE_LOAD_INVALID_ARGS',
480
+ domain: ErrorDomain.STORAGE,
481
+ category: ErrorCategory.USER,
482
+ text: 'No entity defined for tableName',
483
+ details: { tableName },
484
+ });
339
485
  }
340
486
 
341
487
  try {
@@ -360,8 +506,15 @@ export class DynamoDBStore extends MastraStorage {
360
506
 
361
507
  return data as R;
362
508
  } catch (error) {
363
- this.logger.error('Failed to load record', { tableName, keys, error });
364
- throw error;
509
+ throw new MastraError(
510
+ {
511
+ id: 'STORAGE_DYNAMODB_STORE_LOAD_FAILED',
512
+ domain: ErrorDomain.STORAGE,
513
+ category: ErrorCategory.THIRD_PARTY,
514
+ details: { tableName },
515
+ },
516
+ error,
517
+ );
365
518
  }
366
519
  }
367
520
 
@@ -379,12 +532,22 @@ export class DynamoDBStore extends MastraStorage {
379
532
  const data = result.data;
380
533
  return {
381
534
  ...data,
535
+ // Convert date strings back to Date objects for consistency
536
+ createdAt: typeof data.createdAt === 'string' ? new Date(data.createdAt) : data.createdAt,
537
+ updatedAt: typeof data.updatedAt === 'string' ? new Date(data.updatedAt) : data.updatedAt,
382
538
  // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
383
539
  // metadata is already transformed by the entity's getter
384
540
  } as StorageThreadType;
385
541
  } catch (error) {
386
- this.logger.error('Failed to get thread by ID', { threadId, error });
387
- throw error;
542
+ throw new MastraError(
543
+ {
544
+ id: 'STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED',
545
+ domain: ErrorDomain.STORAGE,
546
+ category: ErrorCategory.THIRD_PARTY,
547
+ details: { threadId },
548
+ },
549
+ error,
550
+ );
388
551
  }
389
552
  }
390
553
 
@@ -400,12 +563,22 @@ export class DynamoDBStore extends MastraStorage {
400
563
  // ElectroDB handles the transformation with attribute getters
401
564
  return result.data.map((data: any) => ({
402
565
  ...data,
566
+ // Convert date strings back to Date objects for consistency
567
+ createdAt: typeof data.createdAt === 'string' ? new Date(data.createdAt) : data.createdAt,
568
+ updatedAt: typeof data.updatedAt === 'string' ? new Date(data.updatedAt) : data.updatedAt,
403
569
  // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
404
570
  // metadata is already transformed by the entity's getter
405
571
  })) as StorageThreadType[];
406
572
  } catch (error) {
407
- this.logger.error('Failed to get threads by resource ID', { resourceId, error });
408
- throw error;
573
+ throw new MastraError(
574
+ {
575
+ id: 'STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED',
576
+ domain: ErrorDomain.STORAGE,
577
+ category: ErrorCategory.THIRD_PARTY,
578
+ details: { resourceId },
579
+ },
580
+ error,
581
+ );
409
582
  }
410
583
  }
411
584
 
@@ -436,8 +609,15 @@ export class DynamoDBStore extends MastraStorage {
436
609
  metadata: thread.metadata,
437
610
  };
438
611
  } catch (error) {
439
- this.logger.error('Failed to save thread', { threadId: thread.id, error });
440
- throw error;
612
+ throw new MastraError(
613
+ {
614
+ id: 'STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED',
615
+ domain: ErrorDomain.STORAGE,
616
+ category: ErrorCategory.THIRD_PARTY,
617
+ details: { threadId: thread.id },
618
+ },
619
+ error,
620
+ );
441
621
  }
442
622
  }
443
623
 
@@ -492,8 +672,15 @@ export class DynamoDBStore extends MastraStorage {
492
672
  updatedAt: now,
493
673
  };
494
674
  } catch (error) {
495
- this.logger.error('Failed to update thread', { threadId: id, error });
496
- throw error;
675
+ throw new MastraError(
676
+ {
677
+ id: 'STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED',
678
+ domain: ErrorDomain.STORAGE,
679
+ category: ErrorCategory.THIRD_PARTY,
680
+ details: { threadId: id },
681
+ },
682
+ error,
683
+ );
497
684
  }
498
685
  }
499
686
 
@@ -509,8 +696,15 @@ export class DynamoDBStore extends MastraStorage {
509
696
  // 2. Delete any vector embeddings related to this thread
510
697
  // These would be additional operations
511
698
  } catch (error) {
512
- this.logger.error('Failed to delete thread', { threadId, error });
513
- throw error;
699
+ throw new MastraError(
700
+ {
701
+ id: 'STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED',
702
+ domain: ErrorDomain.STORAGE,
703
+ category: ErrorCategory.THIRD_PARTY,
704
+ details: { threadId },
705
+ },
706
+ error,
707
+ );
514
708
  }
515
709
  }
516
710
 
@@ -530,12 +724,13 @@ export class DynamoDBStore extends MastraStorage {
530
724
  // Provide *all* composite key components for the 'byThread' index ('entity', 'threadId')
531
725
  const query = this.service.entities.message.query.byThread({ entity: 'message', threadId });
532
726
 
727
+ const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
533
728
  // Apply the 'last' limit if provided
534
- if (selectBy?.last && typeof selectBy.last === 'number') {
535
- // Use ElectroDB's limit parameter (descending sort assumed on GSI SK)
536
- // Ensure GSI sk (createdAt) is sorted descending for 'last' to work correctly
537
- // Assuming default sort is ascending on SK, use reverse: true for descending
538
- const results = await query.go({ limit: selectBy.last, reverse: true });
729
+ if (limit !== Number.MAX_SAFE_INTEGER) {
730
+ // Use ElectroDB's limit parameter
731
+ // DDB GSIs are sorted in ascending order
732
+ // Use ElectroDB's order parameter to sort in descending order to retrieve 'latest' messages
733
+ const results = await query.go({ limit, order: 'desc' });
539
734
  // Use arrow function in map to preserve 'this' context for parseMessageData
540
735
  const list = new MessageList({ threadId, resourceId }).add(
541
736
  results.data.map((data: any) => this.parseMessageData(data)),
@@ -555,8 +750,15 @@ export class DynamoDBStore extends MastraStorage {
555
750
  if (format === `v2`) return list.get.all.v2();
556
751
  return list.get.all.v1();
557
752
  } catch (error) {
558
- this.logger.error('Failed to get messages', { threadId, error });
559
- throw error;
753
+ throw new MastraError(
754
+ {
755
+ id: 'STORAGE_DYNAMODB_STORE_GET_MESSAGES_FAILED',
756
+ domain: ErrorDomain.STORAGE,
757
+ category: ErrorCategory.THIRD_PARTY,
758
+ details: { threadId },
759
+ },
760
+ error,
761
+ );
560
762
  }
561
763
  }
562
764
  async saveMessages(args: { messages: MastraMessageV1[]; format?: undefined | 'v1' }): Promise<MastraMessageV1[]>;
@@ -571,6 +773,11 @@ export class DynamoDBStore extends MastraStorage {
571
773
  return [];
572
774
  }
573
775
 
776
+ const threadId = messages[0]?.threadId;
777
+ if (!threadId) {
778
+ throw new Error('Thread ID is required');
779
+ }
780
+
574
781
  // Ensure 'entity' is added and complex fields are handled
575
782
  const messagesToSave = messages.map(msg => {
576
783
  const now = new Date().toISOString();
@@ -601,26 +808,41 @@ export class DynamoDBStore extends MastraStorage {
601
808
  batches.push(batch);
602
809
  }
603
810
 
604
- // Process each batch
605
- for (const batch of batches) {
606
- // Try creating each item individually instead of passing the whole batch
607
- for (const messageData of batch) {
608
- // Ensure each item has the entity property before sending
609
- if (!messageData.entity) {
610
- this.logger.error('Missing entity property in message data for create', { messageData });
611
- throw new Error('Internal error: Missing entity property during saveMessages');
811
+ // Process each batch and update thread's updatedAt in parallel for better performance
812
+ await Promise.all([
813
+ // Process message batches
814
+ ...batches.map(async batch => {
815
+ for (const messageData of batch) {
816
+ // Ensure each item has the entity property before sending
817
+ if (!messageData.entity) {
818
+ this.logger.error('Missing entity property in message data for create', { messageData });
819
+ throw new Error('Internal error: Missing entity property during saveMessages');
820
+ }
821
+ await this.service.entities.message.put(messageData).go();
612
822
  }
613
- await this.service.entities.message.create(messageData).go();
614
- }
615
- // Original batch call: await this.service.entities.message.create(batch).go();
616
- }
823
+ }),
824
+ // Update thread's updatedAt timestamp
825
+ this.service.entities.thread
826
+ .update({ entity: 'thread', id: threadId })
827
+ .set({
828
+ updatedAt: new Date().toISOString(),
829
+ })
830
+ .go(),
831
+ ]);
617
832
 
618
833
  const list = new MessageList().add(messages, 'memory');
619
834
  if (format === `v1`) return list.get.all.v1();
620
835
  return list.get.all.v2();
621
836
  } catch (error) {
622
- this.logger.error('Failed to save messages', { error });
623
- throw error;
837
+ throw new MastraError(
838
+ {
839
+ id: 'STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED',
840
+ domain: ErrorDomain.STORAGE,
841
+ category: ErrorCategory.THIRD_PARTY,
842
+ details: { count: messages.length },
843
+ },
844
+ error,
845
+ );
624
846
  }
625
847
  }
626
848
 
@@ -684,8 +906,14 @@ export class DynamoDBStore extends MastraStorage {
684
906
 
685
907
  return items;
686
908
  } catch (error) {
687
- this.logger.error('Failed to get traces', { error });
688
- throw error;
909
+ throw new MastraError(
910
+ {
911
+ id: 'STORAGE_DYNAMODB_STORE_GET_TRACES_FAILED',
912
+ domain: ErrorDomain.STORAGE,
913
+ category: ErrorCategory.THIRD_PARTY,
914
+ },
915
+ error,
916
+ );
689
917
  }
690
918
  }
691
919
 
@@ -704,8 +932,15 @@ export class DynamoDBStore extends MastraStorage {
704
932
  records: recordsToSave, // Pass records with 'entity' included
705
933
  });
706
934
  } catch (error) {
707
- this.logger.error('Failed to batch insert traces', { error });
708
- throw error;
935
+ throw new MastraError(
936
+ {
937
+ id: 'STORAGE_DYNAMODB_STORE_BATCH_TRACE_INSERT_FAILED',
938
+ domain: ErrorDomain.STORAGE,
939
+ category: ErrorCategory.THIRD_PARTY,
940
+ details: { count: records.length },
941
+ },
942
+ error,
943
+ );
709
944
  }
710
945
  }
711
946
 
@@ -734,11 +969,18 @@ export class DynamoDBStore extends MastraStorage {
734
969
  updatedAt: now,
735
970
  resourceId,
736
971
  };
737
- // Pass the data including 'entity'
738
- await this.service.entities.workflowSnapshot.create(data).go();
972
+ // Use upsert instead of create to handle both create and update cases
973
+ await this.service.entities.workflowSnapshot.upsert(data).go();
739
974
  } catch (error) {
740
- this.logger.error('Failed to persist workflow snapshot', { workflowName, runId, error });
741
- throw error;
975
+ throw new MastraError(
976
+ {
977
+ id: 'STORAGE_DYNAMODB_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
978
+ domain: ErrorDomain.STORAGE,
979
+ category: ErrorCategory.THIRD_PARTY,
980
+ details: { workflowName, runId },
981
+ },
982
+ error,
983
+ );
742
984
  }
743
985
  }
744
986
 
@@ -769,8 +1011,15 @@ export class DynamoDBStore extends MastraStorage {
769
1011
  // Parse the snapshot string
770
1012
  return result.data.snapshot as WorkflowRunState;
771
1013
  } catch (error) {
772
- this.logger.error('Failed to load workflow snapshot', { workflowName, runId, error });
773
- throw error;
1014
+ throw new MastraError(
1015
+ {
1016
+ id: 'STORAGE_DYNAMODB_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
1017
+ domain: ErrorDomain.STORAGE,
1018
+ category: ErrorCategory.THIRD_PARTY,
1019
+ details: { workflowName, runId },
1020
+ },
1021
+ error,
1022
+ );
774
1023
  }
775
1024
  }
776
1025
 
@@ -860,8 +1109,15 @@ export class DynamoDBStore extends MastraStorage {
860
1109
  total,
861
1110
  };
862
1111
  } catch (error) {
863
- this.logger.error('Failed to get workflow runs', { error });
864
- throw error;
1112
+ throw new MastraError(
1113
+ {
1114
+ id: 'STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUNS_FAILED',
1115
+ domain: ErrorDomain.STORAGE,
1116
+ category: ErrorCategory.THIRD_PARTY,
1117
+ details: { workflowName: args?.workflowName || '', resourceId: args?.resourceId || '' },
1118
+ },
1119
+ error,
1120
+ );
865
1121
  }
866
1122
  }
867
1123
 
@@ -932,8 +1188,15 @@ export class DynamoDBStore extends MastraStorage {
932
1188
  resourceId: matchingRunDbItem.resourceId,
933
1189
  };
934
1190
  } catch (error) {
935
- this.logger.error('Failed to get workflow run by ID', { runId, workflowName, error });
936
- throw error;
1191
+ throw new MastraError(
1192
+ {
1193
+ id: 'STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
1194
+ domain: ErrorDomain.STORAGE,
1195
+ category: ErrorCategory.THIRD_PARTY,
1196
+ details: { runId, workflowName: args?.workflowName || '' },
1197
+ },
1198
+ error,
1199
+ );
937
1200
  }
938
1201
  }
939
1202
 
@@ -950,8 +1213,8 @@ export class DynamoDBStore extends MastraStorage {
950
1213
  }
951
1214
 
952
1215
  // Helper methods for entity/table mapping
953
- private getEntityNameForTable(tableName: TABLE_NAMES): string | null {
954
- const mapping: Record<TABLE_NAMES, string> = {
1216
+ private getEntityNameForTable(tableName: SUPPORTED_TABLE_NAMES): string | null {
1217
+ const mapping: Record<SUPPORTED_TABLE_NAMES, string> = {
955
1218
  [TABLE_THREADS]: 'thread',
956
1219
  [TABLE_MESSAGES]: 'message',
957
1220
  [TABLE_WORKFLOW_SNAPSHOT]: 'workflowSnapshot',
@@ -1035,11 +1298,57 @@ export class DynamoDBStore extends MastraStorage {
1035
1298
  }
1036
1299
  });
1037
1300
  } catch (error) {
1038
- this.logger.error('Failed to get evals by agent name', { agentName, type, error });
1039
- throw error;
1301
+ throw new MastraError(
1302
+ {
1303
+ id: 'STORAGE_DYNAMODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED',
1304
+ domain: ErrorDomain.STORAGE,
1305
+ category: ErrorCategory.THIRD_PARTY,
1306
+ details: { agentName },
1307
+ },
1308
+ error,
1309
+ );
1040
1310
  }
1041
1311
  }
1042
1312
 
1313
+ async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
1314
+ throw new MastraError(
1315
+ {
1316
+ id: 'STORAGE_DYNAMODB_STORE_GET_TRACES_PAGINATED_FAILED',
1317
+ domain: ErrorDomain.STORAGE,
1318
+ category: ErrorCategory.THIRD_PARTY,
1319
+ },
1320
+ new Error('Method not implemented.'),
1321
+ );
1322
+ }
1323
+
1324
+ async getThreadsByResourceIdPaginated(_args: {
1325
+ resourceId: string;
1326
+ page?: number;
1327
+ perPage?: number;
1328
+ }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
1329
+ throw new MastraError(
1330
+ {
1331
+ id: 'STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
1332
+ domain: ErrorDomain.STORAGE,
1333
+ category: ErrorCategory.THIRD_PARTY,
1334
+ },
1335
+ new Error('Method not implemented.'),
1336
+ );
1337
+ }
1338
+
1339
+ async getMessagesPaginated(
1340
+ _args: StorageGetMessagesArg,
1341
+ ): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
1342
+ throw new MastraError(
1343
+ {
1344
+ id: 'STORAGE_DYNAMODB_STORE_GET_MESSAGES_PAGINATED_FAILED',
1345
+ domain: ErrorDomain.STORAGE,
1346
+ category: ErrorCategory.THIRD_PARTY,
1347
+ },
1348
+ new Error('Method not implemented.'),
1349
+ );
1350
+ }
1351
+
1043
1352
  /**
1044
1353
  * Closes the DynamoDB client connection and cleans up resources.
1045
1354
  * Should be called when the store is no longer needed, e.g., at the end of tests or application shutdown.
@@ -1050,9 +1359,25 @@ export class DynamoDBStore extends MastraStorage {
1050
1359
  this.client.destroy();
1051
1360
  this.logger.debug('DynamoDB client closed successfully for store:', { name: this.name });
1052
1361
  } catch (error) {
1053
- this.logger.error('Error closing DynamoDB client for store:', { name: this.name, error });
1054
- // Optionally re-throw or handle as appropriate for your application's error handling strategy
1055
- throw error;
1362
+ throw new MastraError(
1363
+ {
1364
+ id: 'STORAGE_DYNAMODB_STORE_CLOSE_FAILED',
1365
+ domain: ErrorDomain.STORAGE,
1366
+ category: ErrorCategory.THIRD_PARTY,
1367
+ },
1368
+ error,
1369
+ );
1056
1370
  }
1057
1371
  }
1372
+
1373
+ async updateMessages(_args: {
1374
+ messages: Partial<Omit<MastraMessageV2, 'createdAt'>> &
1375
+ {
1376
+ id: string;
1377
+ content?: { metadata?: MastraMessageContentV2['metadata']; content?: MastraMessageContentV2['content'] };
1378
+ }[];
1379
+ }): Promise<MastraMessageV2[]> {
1380
+ this.logger.error('updateMessages is not yet implemented in DynamoDBStore');
1381
+ throw new Error('Method not implemented');
1382
+ }
1058
1383
  }