@mastra/dynamodb 1.0.0-beta.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +812 -0
  2. package/README.md +1 -2
  3. package/dist/docs/README.md +31 -0
  4. package/dist/docs/SKILL.md +32 -0
  5. package/dist/docs/SOURCE_MAP.json +6 -0
  6. package/dist/docs/storage/01-reference.md +253 -0
  7. package/dist/entities/eval.d.ts +8 -0
  8. package/dist/entities/eval.d.ts.map +1 -1
  9. package/dist/entities/index.d.ts +61 -4
  10. package/dist/entities/index.d.ts.map +1 -1
  11. package/dist/entities/message.d.ts +8 -0
  12. package/dist/entities/message.d.ts.map +1 -1
  13. package/dist/entities/resource.d.ts +8 -0
  14. package/dist/entities/resource.d.ts.map +1 -1
  15. package/dist/entities/score.d.ts +13 -4
  16. package/dist/entities/score.d.ts.map +1 -1
  17. package/dist/entities/thread.d.ts +8 -0
  18. package/dist/entities/thread.d.ts.map +1 -1
  19. package/dist/entities/trace.d.ts +8 -0
  20. package/dist/entities/trace.d.ts.map +1 -1
  21. package/dist/entities/utils.d.ts +90 -0
  22. package/dist/entities/utils.d.ts.map +1 -1
  23. package/dist/entities/workflow-snapshot.d.ts +8 -0
  24. package/dist/entities/workflow-snapshot.d.ts.map +1 -1
  25. package/dist/index.cjs +154 -45
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +152 -47
  28. package/dist/index.js.map +1 -1
  29. package/dist/storage/db/index.d.ts +18 -2
  30. package/dist/storage/db/index.d.ts.map +1 -1
  31. package/dist/storage/domains/memory/index.d.ts +3 -2
  32. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  33. package/dist/storage/domains/scores/index.d.ts +1 -0
  34. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  35. package/dist/storage/domains/workflows/index.d.ts +1 -0
  36. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  37. package/dist/storage/index.d.ts +90 -2
  38. package/dist/storage/index.d.ts.map +1 -1
  39. package/dist/storage/ttl.d.ts +52 -0
  40. package/dist/storage/ttl.d.ts.map +1 -0
  41. package/package.json +9 -9
@@ -1,3 +1,74 @@
1
+ /**
2
+ * Base fields shared by all entities
3
+ */
4
+ export interface BaseEntityData {
5
+ entity: string;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ metadata?: string;
9
+ ttl?: number;
10
+ expiresAt?: number;
11
+ }
12
+ export interface ThreadEntityData extends BaseEntityData {
13
+ entity: 'thread';
14
+ id: string;
15
+ resourceId: string;
16
+ title: string;
17
+ }
18
+ export interface MessageEntityData extends BaseEntityData {
19
+ entity: 'message';
20
+ id: string;
21
+ threadId?: string;
22
+ role: string;
23
+ type?: string;
24
+ content: string;
25
+ resourceId?: string;
26
+ toolCallIds?: string;
27
+ toolCallArgs?: string;
28
+ toolNames?: string;
29
+ }
30
+ export interface ResourceEntityData extends BaseEntityData {
31
+ entity: 'resource';
32
+ id: string;
33
+ workingMemory?: string;
34
+ }
35
+ export interface WorkflowSnapshotEntityData extends BaseEntityData {
36
+ entity: 'workflow_snapshot';
37
+ workflow_name: string;
38
+ run_id: string;
39
+ snapshot: string;
40
+ resourceId?: string;
41
+ }
42
+ export interface ScoreEntityData extends BaseEntityData {
43
+ entity: 'score';
44
+ id: string;
45
+ scorerId: string;
46
+ runId: string;
47
+ scorer: string;
48
+ score: number;
49
+ input: string;
50
+ output: string;
51
+ source: string;
52
+ traceId?: string;
53
+ spanId?: string;
54
+ reason?: string;
55
+ extractPrompt?: string;
56
+ analyzePrompt?: string;
57
+ reasonPrompt?: string;
58
+ generateScorePrompt?: string;
59
+ generateReasonPrompt?: string;
60
+ preprocessPrompt?: string;
61
+ extractStepResult?: string;
62
+ preprocessStepResult?: string;
63
+ analyzeStepResult?: string;
64
+ additionalContext?: string;
65
+ requestContext?: string;
66
+ entityType?: string;
67
+ entityData?: string;
68
+ entityId?: string;
69
+ resourceId?: string;
70
+ threadId?: string;
71
+ }
1
72
  export declare const baseAttributes: {
2
73
  readonly createdAt: {
3
74
  readonly type: "string";
@@ -17,5 +88,24 @@ export declare const baseAttributes: {
17
88
  readonly set: (value?: Record<string, unknown> | string) => string | undefined;
18
89
  readonly get: (value?: string) => any;
19
90
  };
91
+ /**
92
+ * TTL attribute for DynamoDB automatic item expiration.
93
+ * This is a Unix timestamp (epoch seconds) that indicates when the item should be deleted.
94
+ *
95
+ * Note: For TTL to work, you must enable TTL on your DynamoDB table
96
+ * specifying this attribute name (default: 'ttl').
97
+ */
98
+ readonly ttl: {
99
+ readonly type: "number";
100
+ readonly required: false;
101
+ };
102
+ /**
103
+ * Alternative TTL attribute with configurable name.
104
+ * Use this if you've configured TTL on your DynamoDB table with 'expiresAt' as the attribute name.
105
+ */
106
+ readonly expiresAt: {
107
+ readonly type: "number";
108
+ readonly required: false;
109
+ };
20
110
  };
21
111
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/entities/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;+BAMT,IAAI,GAAG,MAAM;;;;;;+BAab,IAAI,GAAG,MAAM;;;;;+BAYb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;+BAOhC,MAAM;;CAYd,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/entities/utils.ts"],"names":[],"mappings":"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"}
@@ -42,6 +42,14 @@ export declare const workflowSnapshotEntity: Entity<string, string, string, {
42
42
  readonly set: (value?: Record<string, unknown> | string) => string | undefined;
43
43
  readonly get: (value?: string) => any;
44
44
  };
45
+ ttl: {
46
+ readonly type: "number";
47
+ readonly required: false;
48
+ };
49
+ expiresAt: {
50
+ readonly type: "number";
51
+ readonly required: false;
52
+ };
45
53
  entity: {
46
54
  type: "string";
47
55
  required: true;
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-snapshot.d.ts","sourceRoot":"","sources":["../../src/entities/workflow-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;0BAwBf,GAAG;0BAOH,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqBxB,CAAC"}
1
+ {"version":3,"file":"workflow-snapshot.d.ts","sourceRoot":"","sources":["../../src/entities/workflow-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;0BAwBf,GAAG;0BAOH,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqBxB,CAAC"}
package/dist/index.cjs CHANGED
@@ -60,6 +60,25 @@ var baseAttributes = {
60
60
  }
61
61
  return value;
62
62
  }
63
+ },
64
+ /**
65
+ * TTL attribute for DynamoDB automatic item expiration.
66
+ * This is a Unix timestamp (epoch seconds) that indicates when the item should be deleted.
67
+ *
68
+ * Note: For TTL to work, you must enable TTL on your DynamoDB table
69
+ * specifying this attribute name (default: 'ttl').
70
+ */
71
+ ttl: {
72
+ type: "number",
73
+ required: false
74
+ },
75
+ /**
76
+ * Alternative TTL attribute with configurable name.
77
+ * Use this if you've configured TTL on your DynamoDB table with 'expiresAt' as the attribute name.
78
+ */
79
+ expiresAt: {
80
+ type: "number",
81
+ required: false
63
82
  }
64
83
  };
65
84
 
@@ -568,6 +587,28 @@ var scoreEntity = new electrodb.Entity({
568
587
  return value;
569
588
  }
570
589
  },
590
+ metadata: {
591
+ type: "string",
592
+ required: false,
593
+ set: (value) => {
594
+ if (value && typeof value !== "string") {
595
+ return JSON.stringify(value);
596
+ }
597
+ return value;
598
+ },
599
+ get: (value) => {
600
+ if (value && typeof value === "string") {
601
+ try {
602
+ if (value.startsWith("{") || value.startsWith("[")) {
603
+ return JSON.parse(value);
604
+ }
605
+ } catch {
606
+ return value;
607
+ }
608
+ }
609
+ return value;
610
+ }
611
+ },
571
612
  requestContext: {
572
613
  type: "string",
573
614
  required: false,
@@ -941,7 +982,7 @@ function getElectroDbService(client, tableName) {
941
982
  }
942
983
  function resolveDynamoDBConfig(config) {
943
984
  if ("service" in config) {
944
- return config.service;
985
+ return { service: config.service, ttl: config.ttl };
945
986
  }
946
987
  const dynamoClient = new clientDynamodb.DynamoDBClient({
947
988
  region: config.region || "us-east-1",
@@ -949,7 +990,36 @@ function resolveDynamoDBConfig(config) {
949
990
  credentials: config.credentials
950
991
  });
951
992
  const client = libDynamodb.DynamoDBDocumentClient.from(dynamoClient);
952
- return getElectroDbService(client, config.tableName);
993
+ return {
994
+ service: getElectroDbService(client, config.tableName),
995
+ ttl: config.ttl
996
+ };
997
+ }
998
+
999
+ // src/storage/ttl.ts
1000
+ function calculateTtl(entityName, ttlConfig, customTtlSeconds) {
1001
+ const entityConfig = ttlConfig?.[entityName];
1002
+ if (!entityConfig?.enabled) {
1003
+ return void 0;
1004
+ }
1005
+ const ttlSeconds = customTtlSeconds ?? entityConfig.defaultTtlSeconds;
1006
+ if (ttlSeconds === void 0 || ttlSeconds <= 0) {
1007
+ return void 0;
1008
+ }
1009
+ return Math.floor(Date.now() / 1e3) + ttlSeconds;
1010
+ }
1011
+ function getTtlAttributeName(entityName, ttlConfig) {
1012
+ const entityConfig = ttlConfig?.[entityName];
1013
+ return entityConfig?.attributeName ?? "ttl";
1014
+ }
1015
+ function isTtlEnabled(entityName, ttlConfig) {
1016
+ return ttlConfig?.[entityName]?.enabled === true;
1017
+ }
1018
+ function getTtlProps(entityName, ttlConfig, customTtlSeconds) {
1019
+ const ttlValue = calculateTtl(entityName, ttlConfig, customTtlSeconds);
1020
+ if (ttlValue === void 0) return {};
1021
+ const attributeName = getTtlAttributeName(entityName, ttlConfig);
1022
+ return { [attributeName]: ttlValue };
953
1023
  }
954
1024
  var ENTITY_MAP = {
955
1025
  [storage.TABLE_THREADS]: "thread",
@@ -997,9 +1067,12 @@ async function deleteTableData(service, tableName) {
997
1067
  // src/storage/domains/memory/index.ts
998
1068
  var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
999
1069
  service;
1070
+ ttlConfig;
1000
1071
  constructor(config) {
1001
1072
  super();
1002
- this.service = resolveDynamoDBConfig(config);
1073
+ const resolved = resolveDynamoDBConfig(config);
1074
+ this.service = resolved.service;
1075
+ this.ttlConfig = resolved.ttl;
1003
1076
  }
1004
1077
  async dangerouslyClearAll() {
1005
1078
  await deleteTableData(this.service, storage.TABLE_THREADS);
@@ -1110,7 +1183,8 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1110
1183
  title: thread.title || `Thread ${thread.id}`,
1111
1184
  createdAt: thread.createdAt?.toISOString() || now.toISOString(),
1112
1185
  updatedAt: thread.updatedAt?.toISOString() || now.toISOString(),
1113
- metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
1186
+ metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0,
1187
+ ...getTtlProps("thread", this.ttlConfig)
1114
1188
  };
1115
1189
  try {
1116
1190
  await this.service.entities.thread.upsert(threadData).go();
@@ -1279,21 +1353,11 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1279
1353
  if (resourceId) {
1280
1354
  allThreadMessages = allThreadMessages.filter((msg) => msg.resourceId === resourceId);
1281
1355
  }
1282
- if (filter?.dateRange) {
1283
- const dateRange = filter.dateRange;
1284
- allThreadMessages = allThreadMessages.filter((msg) => {
1285
- const createdAt = new Date(msg.createdAt).getTime();
1286
- if (dateRange.start) {
1287
- const startTime = dateRange.start instanceof Date ? dateRange.start.getTime() : new Date(dateRange.start).getTime();
1288
- if (createdAt < startTime) return false;
1289
- }
1290
- if (dateRange.end) {
1291
- const endTime = dateRange.end instanceof Date ? dateRange.end.getTime() : new Date(dateRange.end).getTime();
1292
- if (createdAt > endTime) return false;
1293
- }
1294
- return true;
1295
- });
1296
- }
1356
+ allThreadMessages = storage.filterByDateRange(
1357
+ allThreadMessages,
1358
+ (msg) => new Date(msg.createdAt),
1359
+ filter?.dateRange
1360
+ );
1297
1361
  allThreadMessages.sort((a, b) => {
1298
1362
  const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
1299
1363
  const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
@@ -1387,20 +1451,18 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1387
1451
  const now = (/* @__PURE__ */ new Date()).toISOString();
1388
1452
  return {
1389
1453
  entity: "message",
1390
- // Add entity type
1391
1454
  id: msg.id,
1392
1455
  threadId: msg.threadId,
1393
1456
  role: msg.role,
1394
1457
  type: msg.type,
1395
1458
  resourceId: msg.resourceId,
1396
- // Ensure complex fields are stringified if not handled by attribute setters
1397
1459
  content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
1398
1460
  toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
1399
1461
  toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
1400
1462
  toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
1401
1463
  createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
1402
- updatedAt: now
1403
- // Add updatedAt
1464
+ updatedAt: now,
1465
+ ...getTtlProps("message", this.ttlConfig)
1404
1466
  };
1405
1467
  });
1406
1468
  try {
@@ -1444,33 +1506,57 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1444
1506
  );
1445
1507
  }
1446
1508
  }
1447
- async listThreadsByResourceId(args) {
1448
- const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
1449
- const perPage = storage.normalizePerPage(perPageInput, 100);
1450
- if (page < 0) {
1509
+ async listThreads(args) {
1510
+ const { page = 0, perPage: perPageInput, orderBy, filter } = args;
1511
+ try {
1512
+ this.validatePaginationInput(page, perPageInput ?? 100);
1513
+ } catch (error$1) {
1451
1514
  throw new error.MastraError(
1452
1515
  {
1453
- id: storage.createStorageErrorId("DYNAMODB", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
1516
+ id: storage.createStorageErrorId("DYNAMODB", "LIST_THREADS", "INVALID_PAGE"),
1454
1517
  domain: error.ErrorDomain.STORAGE,
1455
1518
  category: error.ErrorCategory.USER,
1456
- details: { page }
1519
+ details: {
1520
+ page,
1521
+ ...perPageInput !== void 0 && { perPage: perPageInput }
1522
+ }
1457
1523
  },
1458
- new Error("page must be >= 0")
1524
+ error$1 instanceof Error ? error$1 : new Error("Invalid pagination parameters")
1459
1525
  );
1460
1526
  }
1527
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1461
1528
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1462
1529
  const { field, direction } = this.parseOrderBy(orderBy);
1463
- this.logger.debug("Getting threads by resource ID with pagination", {
1464
- resourceId,
1530
+ this.logger.debug("Listing threads with filters", {
1531
+ resourceId: filter?.resourceId,
1532
+ metadataKeys: filter?.metadata ? Object.keys(filter.metadata) : [],
1465
1533
  page,
1466
1534
  perPage,
1467
1535
  field,
1468
1536
  direction
1469
1537
  });
1470
1538
  try {
1471
- const query = this.service.entities.thread.query.byResource({ entity: "thread", resourceId });
1472
- const results = await query.go();
1473
- const allThreads = this.transformAndSortThreads(results.data, field, direction);
1539
+ const rawThreads = filter?.resourceId ? (await this.service.entities.thread.query.byResource({
1540
+ entity: "thread",
1541
+ resourceId: filter.resourceId
1542
+ }).go({ pages: "all" })).data : (await this.service.entities.thread.scan.go({ pages: "all" })).data;
1543
+ let allThreads = this.transformAndSortThreads(rawThreads, field, direction);
1544
+ if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
1545
+ allThreads = allThreads.filter((thread) => {
1546
+ let threadMeta = null;
1547
+ if (typeof thread.metadata === "string") {
1548
+ try {
1549
+ threadMeta = JSON.parse(thread.metadata);
1550
+ } catch {
1551
+ return false;
1552
+ }
1553
+ } else if (thread.metadata && typeof thread.metadata === "object") {
1554
+ threadMeta = thread.metadata;
1555
+ }
1556
+ if (!threadMeta) return false;
1557
+ return Object.entries(filter.metadata).every(([key, value]) => threadMeta[key] === value);
1558
+ });
1559
+ }
1474
1560
  const endIndex = offset + perPage;
1475
1561
  const paginatedThreads = allThreads.slice(offset, endIndex);
1476
1562
  const total = allThreads.length;
@@ -1485,10 +1571,15 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1485
1571
  } catch (error$1) {
1486
1572
  throw new error.MastraError(
1487
1573
  {
1488
- id: storage.createStorageErrorId("DYNAMODB", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
1574
+ id: storage.createStorageErrorId("DYNAMODB", "LIST_THREADS", "FAILED"),
1489
1575
  domain: error.ErrorDomain.STORAGE,
1490
1576
  category: error.ErrorCategory.THIRD_PARTY,
1491
- details: { resourceId, page, perPage }
1577
+ details: {
1578
+ ...filter?.resourceId && { resourceId: filter.resourceId },
1579
+ hasMetadataFilter: !!(filter?.metadata && Object.keys(filter.metadata).length),
1580
+ page,
1581
+ perPage: perPageForResponse
1582
+ }
1492
1583
  },
1493
1584
  error$1
1494
1585
  );
@@ -1666,7 +1757,8 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1666
1757
  workingMemory: resource.workingMemory,
1667
1758
  metadata: resource.metadata ? JSON.stringify(resource.metadata) : void 0,
1668
1759
  createdAt: resource.createdAt?.toISOString() || now.toISOString(),
1669
- updatedAt: now.toISOString()
1760
+ updatedAt: now.toISOString(),
1761
+ ...getTtlProps("resource", this.ttlConfig)
1670
1762
  };
1671
1763
  try {
1672
1764
  await this.service.entities.resource.upsert(resourceData).go();
@@ -1741,9 +1833,12 @@ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
1741
1833
  };
1742
1834
  var ScoresStorageDynamoDB = class extends storage.ScoresStorage {
1743
1835
  service;
1836
+ ttlConfig;
1744
1837
  constructor(config) {
1745
1838
  super();
1746
- this.service = resolveDynamoDBConfig(config);
1839
+ const resolved = resolveDynamoDBConfig(config);
1840
+ this.service = resolved.service;
1841
+ this.ttlConfig = resolved.ttl;
1747
1842
  }
1748
1843
  async dangerouslyClearAll() {
1749
1844
  await deleteTableData(this.service, storage.TABLE_SCORERS);
@@ -1822,6 +1917,8 @@ var ScoresStorageDynamoDB = class extends storage.ScoresStorage {
1822
1917
  const output = typeof validatedScore.output === "string" ? validatedScore.output : JSON.stringify(validatedScore.output);
1823
1918
  const requestContext = typeof validatedScore.requestContext === "string" ? validatedScore.requestContext : JSON.stringify(validatedScore.requestContext);
1824
1919
  const entity = typeof validatedScore.entity === "string" ? validatedScore.entity : JSON.stringify(validatedScore.entity);
1920
+ const metadata = typeof validatedScore.metadata === "string" ? validatedScore.metadata : validatedScore.metadata ? JSON.stringify(validatedScore.metadata) : void 0;
1921
+ const additionalContext = typeof validatedScore.additionalContext === "string" ? validatedScore.additionalContext : validatedScore.additionalContext ? JSON.stringify(validatedScore.additionalContext) : void 0;
1825
1922
  const scoreData = Object.fromEntries(
1826
1923
  Object.entries({
1827
1924
  ...validatedScore,
@@ -1833,13 +1930,16 @@ var ScoresStorageDynamoDB = class extends storage.ScoresStorage {
1833
1930
  input,
1834
1931
  output,
1835
1932
  requestContext,
1933
+ metadata,
1934
+ additionalContext,
1836
1935
  entityData: entity,
1837
1936
  traceId: validatedScore.traceId || "",
1838
1937
  resourceId: validatedScore.resourceId || "",
1839
1938
  threadId: validatedScore.threadId || "",
1840
1939
  spanId: validatedScore.spanId || "",
1841
1940
  createdAt: now.toISOString(),
1842
- updatedAt: now.toISOString()
1941
+ updatedAt: now.toISOString(),
1942
+ ...getTtlProps("score", this.ttlConfig)
1843
1943
  }).filter(([_, value]) => value !== void 0 && value !== null)
1844
1944
  );
1845
1945
  try {
@@ -2046,9 +2146,12 @@ function formatWorkflowRun(snapshotData) {
2046
2146
  }
2047
2147
  var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
2048
2148
  service;
2149
+ ttlConfig;
2049
2150
  constructor(config) {
2050
2151
  super();
2051
- this.service = resolveDynamoDBConfig(config);
2152
+ const resolved = resolveDynamoDBConfig(config);
2153
+ this.service = resolved.service;
2154
+ this.ttlConfig = resolved.ttl;
2052
2155
  }
2053
2156
  async dangerouslyClearAll() {
2054
2157
  await deleteTableData(this.service, storage.TABLE_WORKFLOW_SNAPSHOT);
@@ -2138,13 +2241,13 @@ var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
2138
2241
  const now = /* @__PURE__ */ new Date();
2139
2242
  const data = {
2140
2243
  entity: "workflow_snapshot",
2141
- // Add entity type
2142
2244
  workflow_name: workflowName,
2143
2245
  run_id: runId,
2144
2246
  snapshot: JSON.stringify(snapshot),
2145
2247
  createdAt: (createdAt ?? now).toISOString(),
2146
2248
  updatedAt: (updatedAt ?? now).toISOString(),
2147
- resourceId
2249
+ resourceId,
2250
+ ...getTtlProps("workflow_snapshot", this.ttlConfig)
2148
2251
  };
2149
2252
  await this.service.entities.workflow_snapshot.upsert(data).go();
2150
2253
  } catch (error$1) {
@@ -2354,10 +2457,11 @@ var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
2354
2457
  var isClientConfig = (config) => {
2355
2458
  return "client" in config;
2356
2459
  };
2357
- var DynamoDBStore = class extends storage.MastraStorage {
2460
+ var DynamoDBStore = class extends storage.MastraCompositeStore {
2358
2461
  tableName;
2359
2462
  client;
2360
2463
  service;
2464
+ ttlConfig;
2361
2465
  hasInitialized = null;
2362
2466
  stores;
2363
2467
  constructor({ name, config }) {
@@ -2372,6 +2476,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
2372
2476
  );
2373
2477
  }
2374
2478
  this.tableName = config.tableName;
2479
+ this.ttlConfig = config.ttl;
2375
2480
  if (isClientConfig(config)) {
2376
2481
  this.client = config.client;
2377
2482
  } else {
@@ -2383,7 +2488,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
2383
2488
  this.client = libDynamodb.DynamoDBDocumentClient.from(dynamoClient);
2384
2489
  }
2385
2490
  this.service = getElectroDbService(this.client, this.tableName);
2386
- const domainConfig = { service: this.service };
2491
+ const domainConfig = { service: this.service, ttl: this.ttlConfig };
2387
2492
  const workflows = new WorkflowStorageDynamoDB(domainConfig);
2388
2493
  const memory = new MemoryStorageDynamoDB(domainConfig);
2389
2494
  const scores = new ScoresStorageDynamoDB(domainConfig);
@@ -2497,5 +2602,9 @@ exports.DynamoDBStore = DynamoDBStore;
2497
2602
  exports.MemoryStorageDynamoDB = MemoryStorageDynamoDB;
2498
2603
  exports.ScoresStorageDynamoDB = ScoresStorageDynamoDB;
2499
2604
  exports.WorkflowStorageDynamoDB = WorkflowStorageDynamoDB;
2605
+ exports.calculateTtl = calculateTtl;
2606
+ exports.getTtlAttributeName = getTtlAttributeName;
2607
+ exports.getTtlProps = getTtlProps;
2608
+ exports.isTtlEnabled = isTtlEnabled;
2500
2609
  //# sourceMappingURL=index.cjs.map
2501
2610
  //# sourceMappingURL=index.cjs.map