@mastra/dynamodb 1.0.0-beta.9 → 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 +763 -0
  2. package/README.md +1 -2
  3. package/dist/docs/README.md +1 -1
  4. package/dist/docs/SKILL.md +1 -1
  5. package/dist/docs/SOURCE_MAP.json +1 -1
  6. package/dist/docs/storage/01-reference.md +93 -2
  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 +149 -30
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +147 -32
  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 +5 -5
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
2
2
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
3
3
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
4
- import { MemoryStorage, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, ScoresStorage, SCORERS_SCHEMA, WorkflowsStorage, MastraStorage, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_RESOURCES, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
4
+ import { MemoryStorage, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, ScoresStorage, SCORERS_SCHEMA, WorkflowsStorage, MastraCompositeStore, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_RESOURCES, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
5
5
  import { Entity, Service } from 'electrodb';
6
6
  import { MessageList } from '@mastra/core/agent';
7
7
  import { saveScorePayloadSchema } from '@mastra/core/evals';
@@ -58,6 +58,25 @@ var baseAttributes = {
58
58
  }
59
59
  return value;
60
60
  }
61
+ },
62
+ /**
63
+ * TTL attribute for DynamoDB automatic item expiration.
64
+ * This is a Unix timestamp (epoch seconds) that indicates when the item should be deleted.
65
+ *
66
+ * Note: For TTL to work, you must enable TTL on your DynamoDB table
67
+ * specifying this attribute name (default: 'ttl').
68
+ */
69
+ ttl: {
70
+ type: "number",
71
+ required: false
72
+ },
73
+ /**
74
+ * Alternative TTL attribute with configurable name.
75
+ * Use this if you've configured TTL on your DynamoDB table with 'expiresAt' as the attribute name.
76
+ */
77
+ expiresAt: {
78
+ type: "number",
79
+ required: false
61
80
  }
62
81
  };
63
82
 
@@ -566,6 +585,28 @@ var scoreEntity = new Entity({
566
585
  return value;
567
586
  }
568
587
  },
588
+ metadata: {
589
+ type: "string",
590
+ required: false,
591
+ set: (value) => {
592
+ if (value && typeof value !== "string") {
593
+ return JSON.stringify(value);
594
+ }
595
+ return value;
596
+ },
597
+ get: (value) => {
598
+ if (value && typeof value === "string") {
599
+ try {
600
+ if (value.startsWith("{") || value.startsWith("[")) {
601
+ return JSON.parse(value);
602
+ }
603
+ } catch {
604
+ return value;
605
+ }
606
+ }
607
+ return value;
608
+ }
609
+ },
569
610
  requestContext: {
570
611
  type: "string",
571
612
  required: false,
@@ -939,7 +980,7 @@ function getElectroDbService(client, tableName) {
939
980
  }
940
981
  function resolveDynamoDBConfig(config) {
941
982
  if ("service" in config) {
942
- return config.service;
983
+ return { service: config.service, ttl: config.ttl };
943
984
  }
944
985
  const dynamoClient = new DynamoDBClient({
945
986
  region: config.region || "us-east-1",
@@ -947,7 +988,36 @@ function resolveDynamoDBConfig(config) {
947
988
  credentials: config.credentials
948
989
  });
949
990
  const client = DynamoDBDocumentClient.from(dynamoClient);
950
- return getElectroDbService(client, config.tableName);
991
+ return {
992
+ service: getElectroDbService(client, config.tableName),
993
+ ttl: config.ttl
994
+ };
995
+ }
996
+
997
+ // src/storage/ttl.ts
998
+ function calculateTtl(entityName, ttlConfig, customTtlSeconds) {
999
+ const entityConfig = ttlConfig?.[entityName];
1000
+ if (!entityConfig?.enabled) {
1001
+ return void 0;
1002
+ }
1003
+ const ttlSeconds = customTtlSeconds ?? entityConfig.defaultTtlSeconds;
1004
+ if (ttlSeconds === void 0 || ttlSeconds <= 0) {
1005
+ return void 0;
1006
+ }
1007
+ return Math.floor(Date.now() / 1e3) + ttlSeconds;
1008
+ }
1009
+ function getTtlAttributeName(entityName, ttlConfig) {
1010
+ const entityConfig = ttlConfig?.[entityName];
1011
+ return entityConfig?.attributeName ?? "ttl";
1012
+ }
1013
+ function isTtlEnabled(entityName, ttlConfig) {
1014
+ return ttlConfig?.[entityName]?.enabled === true;
1015
+ }
1016
+ function getTtlProps(entityName, ttlConfig, customTtlSeconds) {
1017
+ const ttlValue = calculateTtl(entityName, ttlConfig, customTtlSeconds);
1018
+ if (ttlValue === void 0) return {};
1019
+ const attributeName = getTtlAttributeName(entityName, ttlConfig);
1020
+ return { [attributeName]: ttlValue };
951
1021
  }
952
1022
  var ENTITY_MAP = {
953
1023
  [TABLE_THREADS]: "thread",
@@ -995,9 +1065,12 @@ async function deleteTableData(service, tableName) {
995
1065
  // src/storage/domains/memory/index.ts
996
1066
  var MemoryStorageDynamoDB = class extends MemoryStorage {
997
1067
  service;
1068
+ ttlConfig;
998
1069
  constructor(config) {
999
1070
  super();
1000
- this.service = resolveDynamoDBConfig(config);
1071
+ const resolved = resolveDynamoDBConfig(config);
1072
+ this.service = resolved.service;
1073
+ this.ttlConfig = resolved.ttl;
1001
1074
  }
1002
1075
  async dangerouslyClearAll() {
1003
1076
  await deleteTableData(this.service, TABLE_THREADS);
@@ -1108,7 +1181,8 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1108
1181
  title: thread.title || `Thread ${thread.id}`,
1109
1182
  createdAt: thread.createdAt?.toISOString() || now.toISOString(),
1110
1183
  updatedAt: thread.updatedAt?.toISOString() || now.toISOString(),
1111
- metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
1184
+ metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0,
1185
+ ...getTtlProps("thread", this.ttlConfig)
1112
1186
  };
1113
1187
  try {
1114
1188
  await this.service.entities.thread.upsert(threadData).go();
@@ -1375,20 +1449,18 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1375
1449
  const now = (/* @__PURE__ */ new Date()).toISOString();
1376
1450
  return {
1377
1451
  entity: "message",
1378
- // Add entity type
1379
1452
  id: msg.id,
1380
1453
  threadId: msg.threadId,
1381
1454
  role: msg.role,
1382
1455
  type: msg.type,
1383
1456
  resourceId: msg.resourceId,
1384
- // Ensure complex fields are stringified if not handled by attribute setters
1385
1457
  content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
1386
1458
  toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
1387
1459
  toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
1388
1460
  toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
1389
1461
  createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
1390
- updatedAt: now
1391
- // Add updatedAt
1462
+ updatedAt: now,
1463
+ ...getTtlProps("message", this.ttlConfig)
1392
1464
  };
1393
1465
  });
1394
1466
  try {
@@ -1432,33 +1504,57 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1432
1504
  );
1433
1505
  }
1434
1506
  }
1435
- async listThreadsByResourceId(args) {
1436
- const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
1437
- const perPage = normalizePerPage(perPageInput, 100);
1438
- if (page < 0) {
1507
+ async listThreads(args) {
1508
+ const { page = 0, perPage: perPageInput, orderBy, filter } = args;
1509
+ try {
1510
+ this.validatePaginationInput(page, perPageInput ?? 100);
1511
+ } catch (error) {
1439
1512
  throw new MastraError(
1440
1513
  {
1441
- id: createStorageErrorId("DYNAMODB", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
1514
+ id: createStorageErrorId("DYNAMODB", "LIST_THREADS", "INVALID_PAGE"),
1442
1515
  domain: ErrorDomain.STORAGE,
1443
1516
  category: ErrorCategory.USER,
1444
- details: { page }
1517
+ details: {
1518
+ page,
1519
+ ...perPageInput !== void 0 && { perPage: perPageInput }
1520
+ }
1445
1521
  },
1446
- new Error("page must be >= 0")
1522
+ error instanceof Error ? error : new Error("Invalid pagination parameters")
1447
1523
  );
1448
1524
  }
1525
+ const perPage = normalizePerPage(perPageInput, 100);
1449
1526
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1450
1527
  const { field, direction } = this.parseOrderBy(orderBy);
1451
- this.logger.debug("Getting threads by resource ID with pagination", {
1452
- resourceId,
1528
+ this.logger.debug("Listing threads with filters", {
1529
+ resourceId: filter?.resourceId,
1530
+ metadataKeys: filter?.metadata ? Object.keys(filter.metadata) : [],
1453
1531
  page,
1454
1532
  perPage,
1455
1533
  field,
1456
1534
  direction
1457
1535
  });
1458
1536
  try {
1459
- const query = this.service.entities.thread.query.byResource({ entity: "thread", resourceId });
1460
- const results = await query.go();
1461
- const allThreads = this.transformAndSortThreads(results.data, field, direction);
1537
+ const rawThreads = filter?.resourceId ? (await this.service.entities.thread.query.byResource({
1538
+ entity: "thread",
1539
+ resourceId: filter.resourceId
1540
+ }).go({ pages: "all" })).data : (await this.service.entities.thread.scan.go({ pages: "all" })).data;
1541
+ let allThreads = this.transformAndSortThreads(rawThreads, field, direction);
1542
+ if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
1543
+ allThreads = allThreads.filter((thread) => {
1544
+ let threadMeta = null;
1545
+ if (typeof thread.metadata === "string") {
1546
+ try {
1547
+ threadMeta = JSON.parse(thread.metadata);
1548
+ } catch {
1549
+ return false;
1550
+ }
1551
+ } else if (thread.metadata && typeof thread.metadata === "object") {
1552
+ threadMeta = thread.metadata;
1553
+ }
1554
+ if (!threadMeta) return false;
1555
+ return Object.entries(filter.metadata).every(([key, value]) => threadMeta[key] === value);
1556
+ });
1557
+ }
1462
1558
  const endIndex = offset + perPage;
1463
1559
  const paginatedThreads = allThreads.slice(offset, endIndex);
1464
1560
  const total = allThreads.length;
@@ -1473,10 +1569,15 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1473
1569
  } catch (error) {
1474
1570
  throw new MastraError(
1475
1571
  {
1476
- id: createStorageErrorId("DYNAMODB", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
1572
+ id: createStorageErrorId("DYNAMODB", "LIST_THREADS", "FAILED"),
1477
1573
  domain: ErrorDomain.STORAGE,
1478
1574
  category: ErrorCategory.THIRD_PARTY,
1479
- details: { resourceId, page, perPage }
1575
+ details: {
1576
+ ...filter?.resourceId && { resourceId: filter.resourceId },
1577
+ hasMetadataFilter: !!(filter?.metadata && Object.keys(filter.metadata).length),
1578
+ page,
1579
+ perPage: perPageForResponse
1580
+ }
1480
1581
  },
1481
1582
  error
1482
1583
  );
@@ -1654,7 +1755,8 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1654
1755
  workingMemory: resource.workingMemory,
1655
1756
  metadata: resource.metadata ? JSON.stringify(resource.metadata) : void 0,
1656
1757
  createdAt: resource.createdAt?.toISOString() || now.toISOString(),
1657
- updatedAt: now.toISOString()
1758
+ updatedAt: now.toISOString(),
1759
+ ...getTtlProps("resource", this.ttlConfig)
1658
1760
  };
1659
1761
  try {
1660
1762
  await this.service.entities.resource.upsert(resourceData).go();
@@ -1729,9 +1831,12 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1729
1831
  };
1730
1832
  var ScoresStorageDynamoDB = class extends ScoresStorage {
1731
1833
  service;
1834
+ ttlConfig;
1732
1835
  constructor(config) {
1733
1836
  super();
1734
- this.service = resolveDynamoDBConfig(config);
1837
+ const resolved = resolveDynamoDBConfig(config);
1838
+ this.service = resolved.service;
1839
+ this.ttlConfig = resolved.ttl;
1735
1840
  }
1736
1841
  async dangerouslyClearAll() {
1737
1842
  await deleteTableData(this.service, TABLE_SCORERS);
@@ -1810,6 +1915,8 @@ var ScoresStorageDynamoDB = class extends ScoresStorage {
1810
1915
  const output = typeof validatedScore.output === "string" ? validatedScore.output : JSON.stringify(validatedScore.output);
1811
1916
  const requestContext = typeof validatedScore.requestContext === "string" ? validatedScore.requestContext : JSON.stringify(validatedScore.requestContext);
1812
1917
  const entity = typeof validatedScore.entity === "string" ? validatedScore.entity : JSON.stringify(validatedScore.entity);
1918
+ const metadata = typeof validatedScore.metadata === "string" ? validatedScore.metadata : validatedScore.metadata ? JSON.stringify(validatedScore.metadata) : void 0;
1919
+ const additionalContext = typeof validatedScore.additionalContext === "string" ? validatedScore.additionalContext : validatedScore.additionalContext ? JSON.stringify(validatedScore.additionalContext) : void 0;
1813
1920
  const scoreData = Object.fromEntries(
1814
1921
  Object.entries({
1815
1922
  ...validatedScore,
@@ -1821,13 +1928,16 @@ var ScoresStorageDynamoDB = class extends ScoresStorage {
1821
1928
  input,
1822
1929
  output,
1823
1930
  requestContext,
1931
+ metadata,
1932
+ additionalContext,
1824
1933
  entityData: entity,
1825
1934
  traceId: validatedScore.traceId || "",
1826
1935
  resourceId: validatedScore.resourceId || "",
1827
1936
  threadId: validatedScore.threadId || "",
1828
1937
  spanId: validatedScore.spanId || "",
1829
1938
  createdAt: now.toISOString(),
1830
- updatedAt: now.toISOString()
1939
+ updatedAt: now.toISOString(),
1940
+ ...getTtlProps("score", this.ttlConfig)
1831
1941
  }).filter(([_, value]) => value !== void 0 && value !== null)
1832
1942
  );
1833
1943
  try {
@@ -2034,9 +2144,12 @@ function formatWorkflowRun(snapshotData) {
2034
2144
  }
2035
2145
  var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2036
2146
  service;
2147
+ ttlConfig;
2037
2148
  constructor(config) {
2038
2149
  super();
2039
- this.service = resolveDynamoDBConfig(config);
2150
+ const resolved = resolveDynamoDBConfig(config);
2151
+ this.service = resolved.service;
2152
+ this.ttlConfig = resolved.ttl;
2040
2153
  }
2041
2154
  async dangerouslyClearAll() {
2042
2155
  await deleteTableData(this.service, TABLE_WORKFLOW_SNAPSHOT);
@@ -2126,13 +2239,13 @@ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2126
2239
  const now = /* @__PURE__ */ new Date();
2127
2240
  const data = {
2128
2241
  entity: "workflow_snapshot",
2129
- // Add entity type
2130
2242
  workflow_name: workflowName,
2131
2243
  run_id: runId,
2132
2244
  snapshot: JSON.stringify(snapshot),
2133
2245
  createdAt: (createdAt ?? now).toISOString(),
2134
2246
  updatedAt: (updatedAt ?? now).toISOString(),
2135
- resourceId
2247
+ resourceId,
2248
+ ...getTtlProps("workflow_snapshot", this.ttlConfig)
2136
2249
  };
2137
2250
  await this.service.entities.workflow_snapshot.upsert(data).go();
2138
2251
  } catch (error) {
@@ -2342,10 +2455,11 @@ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2342
2455
  var isClientConfig = (config) => {
2343
2456
  return "client" in config;
2344
2457
  };
2345
- var DynamoDBStore = class extends MastraStorage {
2458
+ var DynamoDBStore = class extends MastraCompositeStore {
2346
2459
  tableName;
2347
2460
  client;
2348
2461
  service;
2462
+ ttlConfig;
2349
2463
  hasInitialized = null;
2350
2464
  stores;
2351
2465
  constructor({ name, config }) {
@@ -2360,6 +2474,7 @@ var DynamoDBStore = class extends MastraStorage {
2360
2474
  );
2361
2475
  }
2362
2476
  this.tableName = config.tableName;
2477
+ this.ttlConfig = config.ttl;
2363
2478
  if (isClientConfig(config)) {
2364
2479
  this.client = config.client;
2365
2480
  } else {
@@ -2371,7 +2486,7 @@ var DynamoDBStore = class extends MastraStorage {
2371
2486
  this.client = DynamoDBDocumentClient.from(dynamoClient);
2372
2487
  }
2373
2488
  this.service = getElectroDbService(this.client, this.tableName);
2374
- const domainConfig = { service: this.service };
2489
+ const domainConfig = { service: this.service, ttl: this.ttlConfig };
2375
2490
  const workflows = new WorkflowStorageDynamoDB(domainConfig);
2376
2491
  const memory = new MemoryStorageDynamoDB(domainConfig);
2377
2492
  const scores = new ScoresStorageDynamoDB(domainConfig);
@@ -2481,6 +2596,6 @@ var DynamoDBStore = class extends MastraStorage {
2481
2596
  }
2482
2597
  };
2483
2598
 
2484
- export { DynamoDBStore, MemoryStorageDynamoDB, ScoresStorageDynamoDB, WorkflowStorageDynamoDB };
2599
+ export { DynamoDBStore, MemoryStorageDynamoDB, ScoresStorageDynamoDB, WorkflowStorageDynamoDB, calculateTtl, getTtlAttributeName, getTtlProps, isTtlEnabled };
2485
2600
  //# sourceMappingURL=index.js.map
2486
2601
  //# sourceMappingURL=index.js.map