@mastra/dynamodb 1.0.0-beta.6 → 1.0.0-beta.8

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.
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 { MastraStorage, createStorageErrorId, StoreOperations, WorkflowsStorage, normalizePerPage, MemoryStorage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_SPANS, TABLE_RESOURCES, TABLE_TRACES, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
4
+ import { MemoryStorage, createStorageErrorId, normalizePerPage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, WorkflowsStorage, MastraStorage, 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';
@@ -937,11 +937,113 @@ function getElectroDbService(client, tableName) {
937
937
  }
938
938
  );
939
939
  }
940
+ function resolveDynamoDBConfig(config) {
941
+ if ("service" in config) {
942
+ return config.service;
943
+ }
944
+ const dynamoClient = new DynamoDBClient({
945
+ region: config.region || "us-east-1",
946
+ endpoint: config.endpoint,
947
+ credentials: config.credentials
948
+ });
949
+ const client = DynamoDBDocumentClient.from(dynamoClient);
950
+ return getElectroDbService(client, config.tableName);
951
+ }
952
+ var ENTITY_MAP = {
953
+ [TABLE_THREADS]: "thread",
954
+ [TABLE_MESSAGES]: "message",
955
+ [TABLE_RESOURCES]: "resource",
956
+ [TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
957
+ [TABLE_SCORERS]: "score"
958
+ };
959
+ function getDeleteKey(entityName, item) {
960
+ const key = { entity: entityName };
961
+ switch (entityName) {
962
+ case "thread":
963
+ case "message":
964
+ case "resource":
965
+ case "score":
966
+ key.id = item.id;
967
+ break;
968
+ case "workflow_snapshot":
969
+ key.workflow_name = item.workflow_name;
970
+ key.run_id = item.run_id;
971
+ break;
972
+ default:
973
+ key.id = item.id;
974
+ }
975
+ return key;
976
+ }
977
+ async function deleteTableData(service, tableName) {
978
+ const entityName = ENTITY_MAP[tableName];
979
+ if (!entityName || !service.entities[entityName]) {
980
+ throw new Error(`No entity mapping found for table: ${tableName}`);
981
+ }
982
+ const entity = service.entities[entityName];
983
+ const result = await entity.scan.go({ pages: "all" });
984
+ if (!result.data.length) {
985
+ return;
986
+ }
987
+ const batchSize = 25;
988
+ for (let i = 0; i < result.data.length; i += batchSize) {
989
+ const batch = result.data.slice(i, i + batchSize);
990
+ const keysToDelete = batch.map((item) => getDeleteKey(entityName, item));
991
+ await entity.delete(keysToDelete).go();
992
+ }
993
+ }
994
+
995
+ // src/storage/domains/memory/index.ts
940
996
  var MemoryStorageDynamoDB = class extends MemoryStorage {
941
997
  service;
942
- constructor({ service }) {
998
+ constructor(config) {
943
999
  super();
944
- this.service = service;
1000
+ this.service = resolveDynamoDBConfig(config);
1001
+ }
1002
+ async dangerouslyClearAll() {
1003
+ await deleteTableData(this.service, TABLE_THREADS);
1004
+ await deleteTableData(this.service, TABLE_MESSAGES);
1005
+ await deleteTableData(this.service, TABLE_RESOURCES);
1006
+ }
1007
+ async deleteMessages(messageIds) {
1008
+ if (!messageIds || messageIds.length === 0) {
1009
+ return;
1010
+ }
1011
+ this.logger.debug("Deleting messages", { count: messageIds.length });
1012
+ try {
1013
+ const threadIds = /* @__PURE__ */ new Set();
1014
+ const batchSize = 25;
1015
+ for (let i = 0; i < messageIds.length; i += batchSize) {
1016
+ const batch = messageIds.slice(i, i + batchSize);
1017
+ const messagesToDelete = await Promise.all(
1018
+ batch.map(async (id) => {
1019
+ const result = await this.service.entities.message.get({ entity: "message", id }).go();
1020
+ return result.data;
1021
+ })
1022
+ );
1023
+ for (const message of messagesToDelete) {
1024
+ if (message) {
1025
+ if (message.threadId) {
1026
+ threadIds.add(message.threadId);
1027
+ }
1028
+ await this.service.entities.message.delete({ entity: "message", id: message.id }).go();
1029
+ }
1030
+ }
1031
+ }
1032
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1033
+ for (const threadId of threadIds) {
1034
+ await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({ updatedAt: now }).go();
1035
+ }
1036
+ } catch (error) {
1037
+ throw new MastraError(
1038
+ {
1039
+ id: createStorageErrorId("DYNAMODB", "DELETE_MESSAGES", "FAILED"),
1040
+ domain: ErrorDomain.STORAGE,
1041
+ category: ErrorCategory.THIRD_PARTY,
1042
+ details: { count: messageIds.length }
1043
+ },
1044
+ error
1045
+ );
1046
+ }
945
1047
  }
946
1048
  // Helper function to parse message data (handle JSON fields)
947
1049
  parseMessageData(data) {
@@ -1635,334 +1737,14 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1635
1737
  }
1636
1738
  }
1637
1739
  };
1638
- var StoreOperationsDynamoDB = class extends StoreOperations {
1639
- client;
1640
- tableName;
1641
- service;
1642
- constructor({
1643
- service,
1644
- tableName,
1645
- client
1646
- }) {
1647
- super();
1648
- this.service = service;
1649
- this.client = client;
1650
- this.tableName = tableName;
1651
- }
1652
- async hasColumn() {
1653
- return true;
1654
- }
1655
- async dropTable() {
1656
- }
1657
- // Helper methods for entity/table mapping
1658
- getEntityNameForTable(tableName) {
1659
- const mapping = {
1660
- [TABLE_THREADS]: "thread",
1661
- [TABLE_MESSAGES]: "message",
1662
- [TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
1663
- [TABLE_SCORERS]: "score",
1664
- [TABLE_TRACES]: "trace",
1665
- [TABLE_RESOURCES]: "resource",
1666
- [TABLE_SPANS]: "ai_span",
1667
- mastra_agents: "agent"
1668
- };
1669
- return mapping[tableName] || null;
1670
- }
1671
- /**
1672
- * Pre-processes a record to ensure Date objects are converted to ISO strings
1673
- * This is necessary because ElectroDB validation happens before setters are applied
1674
- */
1675
- preprocessRecord(record) {
1676
- const processed = { ...record };
1677
- if (processed.createdAt instanceof Date) {
1678
- processed.createdAt = processed.createdAt.toISOString();
1679
- }
1680
- if (processed.updatedAt instanceof Date) {
1681
- processed.updatedAt = processed.updatedAt.toISOString();
1682
- }
1683
- if (processed.created_at instanceof Date) {
1684
- processed.created_at = processed.created_at.toISOString();
1685
- }
1686
- if (processed.result && typeof processed.result === "object") {
1687
- processed.result = JSON.stringify(processed.result);
1688
- }
1689
- if (processed.test_info && typeof processed.test_info === "object") {
1690
- processed.test_info = JSON.stringify(processed.test_info);
1691
- } else if (processed.test_info === void 0 || processed.test_info === null) {
1692
- delete processed.test_info;
1693
- }
1694
- if (processed.snapshot && typeof processed.snapshot === "object") {
1695
- processed.snapshot = JSON.stringify(processed.snapshot);
1696
- }
1697
- if (processed.attributes && typeof processed.attributes === "object") {
1698
- processed.attributes = JSON.stringify(processed.attributes);
1699
- }
1700
- if (processed.status && typeof processed.status === "object") {
1701
- processed.status = JSON.stringify(processed.status);
1702
- }
1703
- if (processed.events && typeof processed.events === "object") {
1704
- processed.events = JSON.stringify(processed.events);
1705
- }
1706
- if (processed.links && typeof processed.links === "object") {
1707
- processed.links = JSON.stringify(processed.links);
1708
- }
1709
- return processed;
1710
- }
1711
- /**
1712
- * Validates that the required DynamoDB table exists and is accessible.
1713
- * This does not check the table structure - it assumes the table
1714
- * was created with the correct structure via CDK/CloudFormation.
1715
- */
1716
- async validateTableExists() {
1717
- try {
1718
- const command = new DescribeTableCommand({
1719
- TableName: this.tableName
1720
- });
1721
- await this.client.send(command);
1722
- return true;
1723
- } catch (error) {
1724
- if (error.name === "ResourceNotFoundException") {
1725
- return false;
1726
- }
1727
- throw new MastraError(
1728
- {
1729
- id: createStorageErrorId("DYNAMODB", "VALIDATE_TABLE_EXISTS", "FAILED"),
1730
- domain: ErrorDomain.STORAGE,
1731
- category: ErrorCategory.THIRD_PARTY,
1732
- details: { tableName: this.tableName }
1733
- },
1734
- error
1735
- );
1736
- }
1737
- }
1738
- /**
1739
- * This method is modified for DynamoDB with ElectroDB single-table design.
1740
- * It assumes the table is created and managed externally via CDK/CloudFormation.
1741
- *
1742
- * This implementation only validates that the required table exists and is accessible.
1743
- * No table creation is attempted - we simply check if we can access the table.
1744
- */
1745
- async createTable({ tableName }) {
1746
- this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
1747
- try {
1748
- const tableExists = await this.validateTableExists();
1749
- if (!tableExists) {
1750
- this.logger.error(
1751
- `Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
1752
- );
1753
- throw new Error(
1754
- `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
1755
- );
1756
- }
1757
- this.logger.debug(`Table ${this.tableName} exists and is accessible`);
1758
- } catch (error) {
1759
- this.logger.error("Error validating table access", { tableName: this.tableName, error });
1760
- throw new MastraError(
1761
- {
1762
- id: createStorageErrorId("DYNAMODB", "VALIDATE_TABLE_ACCESS", "FAILED"),
1763
- domain: ErrorDomain.STORAGE,
1764
- category: ErrorCategory.THIRD_PARTY,
1765
- details: { tableName: this.tableName }
1766
- },
1767
- error
1768
- );
1769
- }
1770
- }
1771
- async insert({ tableName, record }) {
1772
- this.logger.debug("DynamoDB insert called", { tableName });
1773
- const entityName = this.getEntityNameForTable(tableName);
1774
- if (!entityName || !this.service.entities[entityName]) {
1775
- throw new MastraError({
1776
- id: createStorageErrorId("DYNAMODB", "INSERT", "INVALID_ARGS"),
1777
- domain: ErrorDomain.STORAGE,
1778
- category: ErrorCategory.USER,
1779
- text: "No entity defined for tableName",
1780
- details: { tableName }
1781
- });
1782
- }
1783
- try {
1784
- const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
1785
- await this.service.entities[entityName].create(dataToSave).go();
1786
- } catch (error) {
1787
- throw new MastraError(
1788
- {
1789
- id: createStorageErrorId("DYNAMODB", "INSERT", "FAILED"),
1790
- domain: ErrorDomain.STORAGE,
1791
- category: ErrorCategory.THIRD_PARTY,
1792
- details: { tableName }
1793
- },
1794
- error
1795
- );
1796
- }
1797
- }
1798
- async alterTable(_args) {
1799
- }
1800
- /**
1801
- * Clear all items from a logical "table" (entity type)
1802
- */
1803
- async clearTable({ tableName }) {
1804
- this.logger.debug("DynamoDB clearTable called", { tableName });
1805
- const entityName = this.getEntityNameForTable(tableName);
1806
- if (!entityName || !this.service.entities[entityName]) {
1807
- throw new MastraError({
1808
- id: createStorageErrorId("DYNAMODB", "CLEAR_TABLE", "INVALID_ARGS"),
1809
- domain: ErrorDomain.STORAGE,
1810
- category: ErrorCategory.USER,
1811
- text: "No entity defined for tableName",
1812
- details: { tableName }
1813
- });
1814
- }
1815
- try {
1816
- const result = await this.service.entities[entityName].scan.go({ pages: "all" });
1817
- if (!result.data.length) {
1818
- this.logger.debug(`No records found to clear for ${tableName}`);
1819
- return;
1820
- }
1821
- this.logger.debug(`Found ${result.data.length} records to delete for ${tableName}`);
1822
- const keysToDelete = result.data.map((item) => {
1823
- const key = { entity: entityName };
1824
- switch (entityName) {
1825
- case "thread":
1826
- if (!item.id) throw new Error(`Missing required key 'id' for entity 'thread'`);
1827
- key.id = item.id;
1828
- break;
1829
- case "message":
1830
- if (!item.id) throw new Error(`Missing required key 'id' for entity 'message'`);
1831
- key.id = item.id;
1832
- break;
1833
- case "workflow_snapshot":
1834
- if (!item.workflow_name)
1835
- throw new Error(`Missing required key 'workflow_name' for entity 'workflow_snapshot'`);
1836
- if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflow_snapshot'`);
1837
- key.workflow_name = item.workflow_name;
1838
- key.run_id = item.run_id;
1839
- break;
1840
- case "eval":
1841
- if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'eval'`);
1842
- key.run_id = item.run_id;
1843
- break;
1844
- case "trace":
1845
- if (!item.id) throw new Error(`Missing required key 'id' for entity 'trace'`);
1846
- key.id = item.id;
1847
- break;
1848
- case "score":
1849
- if (!item.id) throw new Error(`Missing required key 'id' for entity 'score'`);
1850
- key.id = item.id;
1851
- break;
1852
- case "resource":
1853
- if (!item.id) throw new Error(`Missing required key 'id' for entity 'resource'`);
1854
- key.id = item.id;
1855
- break;
1856
- default:
1857
- this.logger.warn(`Unknown entity type encountered during clearTable: ${entityName}`);
1858
- throw new Error(`Cannot construct delete key for unknown entity type: ${entityName}`);
1859
- }
1860
- return key;
1861
- });
1862
- const batchSize = 25;
1863
- for (let i = 0; i < keysToDelete.length; i += batchSize) {
1864
- const batchKeys = keysToDelete.slice(i, i + batchSize);
1865
- await this.service.entities[entityName].delete(batchKeys).go();
1866
- }
1867
- this.logger.debug(`Successfully cleared all records for ${tableName}`);
1868
- } catch (error) {
1869
- throw new MastraError(
1870
- {
1871
- id: createStorageErrorId("DYNAMODB", "CLEAR_TABLE", "FAILED"),
1872
- domain: ErrorDomain.STORAGE,
1873
- category: ErrorCategory.THIRD_PARTY,
1874
- details: { tableName }
1875
- },
1876
- error
1877
- );
1878
- }
1879
- }
1880
- /**
1881
- * Insert multiple records as a batch
1882
- */
1883
- async batchInsert({ tableName, records }) {
1884
- this.logger.debug("DynamoDB batchInsert called", { tableName, count: records.length });
1885
- const entityName = this.getEntityNameForTable(tableName);
1886
- if (!entityName || !this.service.entities[entityName]) {
1887
- throw new MastraError({
1888
- id: createStorageErrorId("DYNAMODB", "BATCH_INSERT", "INVALID_ARGS"),
1889
- domain: ErrorDomain.STORAGE,
1890
- category: ErrorCategory.USER,
1891
- text: "No entity defined for tableName",
1892
- details: { tableName }
1893
- });
1894
- }
1895
- const recordsToSave = records.map((rec) => ({ entity: entityName, ...this.preprocessRecord(rec) }));
1896
- const batchSize = 25;
1897
- const batches = [];
1898
- for (let i = 0; i < recordsToSave.length; i += batchSize) {
1899
- const batch = recordsToSave.slice(i, i + batchSize);
1900
- batches.push(batch);
1901
- }
1902
- try {
1903
- for (const batch of batches) {
1904
- for (const recordData of batch) {
1905
- if (!recordData.entity) {
1906
- this.logger.error("Missing entity property in record data for batchInsert", { recordData, tableName });
1907
- throw new Error(`Internal error: Missing entity property during batchInsert for ${tableName}`);
1908
- }
1909
- this.logger.debug("Attempting to create record in batchInsert:", { entityName, recordData });
1910
- await this.service.entities[entityName].create(recordData).go();
1911
- }
1912
- }
1913
- } catch (error) {
1914
- throw new MastraError(
1915
- {
1916
- id: createStorageErrorId("DYNAMODB", "BATCH_INSERT", "FAILED"),
1917
- domain: ErrorDomain.STORAGE,
1918
- category: ErrorCategory.THIRD_PARTY,
1919
- details: { tableName }
1920
- },
1921
- error
1922
- );
1923
- }
1924
- }
1925
- /**
1926
- * Load a record by its keys
1927
- */
1928
- async load({ tableName, keys }) {
1929
- this.logger.debug("DynamoDB load called", { tableName, keys });
1930
- const entityName = this.getEntityNameForTable(tableName);
1931
- if (!entityName || !this.service.entities[entityName]) {
1932
- throw new MastraError({
1933
- id: createStorageErrorId("DYNAMODB", "LOAD", "INVALID_ARGS"),
1934
- domain: ErrorDomain.STORAGE,
1935
- category: ErrorCategory.USER,
1936
- text: "No entity defined for tableName",
1937
- details: { tableName }
1938
- });
1939
- }
1940
- try {
1941
- const keyObject = { entity: entityName, ...keys };
1942
- const result = await this.service.entities[entityName].get(keyObject).go();
1943
- if (!result.data) {
1944
- return null;
1945
- }
1946
- let data = result.data;
1947
- return data;
1948
- } catch (error) {
1949
- throw new MastraError(
1950
- {
1951
- id: createStorageErrorId("DYNAMODB", "LOAD", "FAILED"),
1952
- domain: ErrorDomain.STORAGE,
1953
- category: ErrorCategory.THIRD_PARTY,
1954
- details: { tableName }
1955
- },
1956
- error
1957
- );
1958
- }
1959
- }
1960
- };
1961
1740
  var ScoresStorageDynamoDB = class extends ScoresStorage {
1962
1741
  service;
1963
- constructor({ service }) {
1742
+ constructor(config) {
1964
1743
  super();
1965
- this.service = service;
1744
+ this.service = resolveDynamoDBConfig(config);
1745
+ }
1746
+ async dangerouslyClearAll() {
1747
+ await deleteTableData(this.service, TABLE_SCORERS);
1966
1748
  }
1967
1749
  /**
1968
1750
  * DynamoDB-specific score row transformation.
@@ -2019,7 +1801,7 @@ var ScoresStorageDynamoDB = class extends ScoresStorage {
2019
1801
  domain: ErrorDomain.STORAGE,
2020
1802
  category: ErrorCategory.USER,
2021
1803
  details: {
2022
- scorer: score.scorer?.id ?? "unknown",
1804
+ scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
2023
1805
  entityId: score.entityId ?? "unknown",
2024
1806
  entityType: score.entityType ?? "unknown",
2025
1807
  traceId: score.traceId ?? "",
@@ -2262,44 +2044,104 @@ function formatWorkflowRun(snapshotData) {
2262
2044
  }
2263
2045
  var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2264
2046
  service;
2265
- constructor({ service }) {
2047
+ constructor(config) {
2266
2048
  super();
2267
- this.service = service;
2049
+ this.service = resolveDynamoDBConfig(config);
2268
2050
  }
2269
- updateWorkflowResults({
2270
- // workflowName,
2271
- // runId,
2272
- // stepId,
2273
- // result,
2274
- // requestContext,
2051
+ async dangerouslyClearAll() {
2052
+ await deleteTableData(this.service, TABLE_WORKFLOW_SNAPSHOT);
2053
+ }
2054
+ async updateWorkflowResults({
2055
+ workflowName,
2056
+ runId,
2057
+ stepId,
2058
+ result,
2059
+ requestContext
2275
2060
  }) {
2276
- throw new Error("Method not implemented.");
2061
+ try {
2062
+ const existingSnapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
2063
+ let snapshot;
2064
+ if (!existingSnapshot) {
2065
+ snapshot = {
2066
+ context: {},
2067
+ activePaths: [],
2068
+ timestamp: Date.now(),
2069
+ suspendedPaths: {},
2070
+ activeStepsPath: {},
2071
+ resumeLabels: {},
2072
+ serializedStepGraph: [],
2073
+ status: "pending",
2074
+ value: {},
2075
+ waitingPaths: {},
2076
+ runId,
2077
+ requestContext: {}
2078
+ };
2079
+ } else {
2080
+ snapshot = existingSnapshot;
2081
+ }
2082
+ snapshot.context[stepId] = result;
2083
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
2084
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2085
+ return snapshot.context;
2086
+ } catch (error) {
2087
+ if (error instanceof MastraError) throw error;
2088
+ throw new MastraError(
2089
+ {
2090
+ id: createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
2091
+ domain: ErrorDomain.STORAGE,
2092
+ category: ErrorCategory.THIRD_PARTY,
2093
+ details: { workflowName, runId, stepId }
2094
+ },
2095
+ error
2096
+ );
2097
+ }
2277
2098
  }
2278
- updateWorkflowState({
2279
- // workflowName,
2280
- // runId,
2281
- // opts,
2099
+ async updateWorkflowState({
2100
+ workflowName,
2101
+ runId,
2102
+ opts
2282
2103
  }) {
2283
- throw new Error("Method not implemented.");
2104
+ try {
2105
+ const existingSnapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
2106
+ if (!existingSnapshot || !existingSnapshot.context) {
2107
+ return void 0;
2108
+ }
2109
+ const updatedSnapshot = { ...existingSnapshot, ...opts };
2110
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
2111
+ return updatedSnapshot;
2112
+ } catch (error) {
2113
+ if (error instanceof MastraError) throw error;
2114
+ throw new MastraError(
2115
+ {
2116
+ id: createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
2117
+ domain: ErrorDomain.STORAGE,
2118
+ category: ErrorCategory.THIRD_PARTY,
2119
+ details: { workflowName, runId }
2120
+ },
2121
+ error
2122
+ );
2123
+ }
2284
2124
  }
2285
2125
  // Workflow operations
2286
2126
  async persistWorkflowSnapshot({
2287
2127
  workflowName,
2288
2128
  runId,
2289
2129
  resourceId,
2290
- snapshot
2130
+ snapshot,
2131
+ createdAt,
2132
+ updatedAt
2291
2133
  }) {
2292
2134
  this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
2293
2135
  try {
2294
- const now = (/* @__PURE__ */ new Date()).toISOString();
2136
+ const now = /* @__PURE__ */ new Date();
2295
2137
  const data = {
2296
2138
  entity: "workflow_snapshot",
2297
2139
  // Add entity type
2298
2140
  workflow_name: workflowName,
2299
2141
  run_id: runId,
2300
2142
  snapshot: JSON.stringify(snapshot),
2301
- createdAt: now,
2302
- updatedAt: now,
2143
+ createdAt: (createdAt ?? now).toISOString(),
2144
+ updatedAt: (updatedAt ?? now).toISOString(),
2303
2145
  resourceId
2304
2146
  };
2305
2147
  await this.service.entities.workflow_snapshot.upsert(data).go();
@@ -2507,6 +2349,9 @@ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2507
2349
  };
2508
2350
 
2509
2351
  // src/storage/index.ts
2352
+ var isClientConfig = (config) => {
2353
+ return "client" in config;
2354
+ };
2510
2355
  var DynamoDBStore = class extends MastraStorage {
2511
2356
  tableName;
2512
2357
  client;
@@ -2524,24 +2369,23 @@ var DynamoDBStore = class extends MastraStorage {
2524
2369
  `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
2525
2370
  );
2526
2371
  }
2527
- const dynamoClient = new DynamoDBClient({
2528
- region: config.region || "us-east-1",
2529
- endpoint: config.endpoint,
2530
- credentials: config.credentials
2531
- });
2532
2372
  this.tableName = config.tableName;
2533
- this.client = DynamoDBDocumentClient.from(dynamoClient);
2373
+ if (isClientConfig(config)) {
2374
+ this.client = config.client;
2375
+ } else {
2376
+ const dynamoClient = new DynamoDBClient({
2377
+ region: config.region || "us-east-1",
2378
+ endpoint: config.endpoint,
2379
+ credentials: config.credentials
2380
+ });
2381
+ this.client = DynamoDBDocumentClient.from(dynamoClient);
2382
+ }
2534
2383
  this.service = getElectroDbService(this.client, this.tableName);
2535
- const operations = new StoreOperationsDynamoDB({
2536
- service: this.service,
2537
- tableName: this.tableName,
2538
- client: this.client
2539
- });
2540
- const workflows = new WorkflowStorageDynamoDB({ service: this.service });
2541
- const memory = new MemoryStorageDynamoDB({ service: this.service });
2542
- const scores = new ScoresStorageDynamoDB({ service: this.service });
2384
+ const domainConfig = { service: this.service };
2385
+ const workflows = new WorkflowStorageDynamoDB(domainConfig);
2386
+ const memory = new MemoryStorageDynamoDB(domainConfig);
2387
+ const scores = new ScoresStorageDynamoDB(domainConfig);
2543
2388
  this.stores = {
2544
- operations,
2545
2389
  workflows,
2546
2390
  memory,
2547
2391
  scores
@@ -2557,16 +2401,6 @@ var DynamoDBStore = class extends MastraStorage {
2557
2401
  );
2558
2402
  }
2559
2403
  }
2560
- get supports() {
2561
- return {
2562
- selectByIncludeResourceScope: true,
2563
- resourceWorkingMemory: true,
2564
- hasColumn: false,
2565
- createTable: false,
2566
- deleteMessages: false,
2567
- listScoresBySpan: true
2568
- };
2569
- }
2570
2404
  /**
2571
2405
  * Validates that the required DynamoDB table exists and is accessible.
2572
2406
  * This does not check the table structure - it assumes the table
@@ -2634,109 +2468,10 @@ var DynamoDBStore = class extends MastraStorage {
2634
2468
  throw err;
2635
2469
  });
2636
2470
  }
2637
- async createTable({ tableName, schema }) {
2638
- return this.stores.operations.createTable({ tableName, schema });
2639
- }
2640
- async alterTable(_args) {
2641
- return this.stores.operations.alterTable(_args);
2642
- }
2643
- async clearTable({ tableName }) {
2644
- return this.stores.operations.clearTable({ tableName });
2645
- }
2646
- async dropTable({ tableName }) {
2647
- return this.stores.operations.dropTable({ tableName });
2648
- }
2649
- async insert({ tableName, record }) {
2650
- return this.stores.operations.insert({ tableName, record });
2651
- }
2652
- async batchInsert({ tableName, records }) {
2653
- return this.stores.operations.batchInsert({ tableName, records });
2654
- }
2655
- async load({ tableName, keys }) {
2656
- return this.stores.operations.load({ tableName, keys });
2657
- }
2658
- // Thread operations
2659
- async getThreadById({ threadId }) {
2660
- return this.stores.memory.getThreadById({ threadId });
2661
- }
2662
- async saveThread({ thread }) {
2663
- return this.stores.memory.saveThread({ thread });
2664
- }
2665
- async updateThread({
2666
- id,
2667
- title,
2668
- metadata
2669
- }) {
2670
- return this.stores.memory.updateThread({ id, title, metadata });
2671
- }
2672
- async deleteThread({ threadId }) {
2673
- return this.stores.memory.deleteThread({ threadId });
2674
- }
2675
- async listMessagesById(args) {
2676
- return this.stores.memory.listMessagesById(args);
2677
- }
2678
- async saveMessages(args) {
2679
- return this.stores.memory.saveMessages(args);
2680
- }
2681
- async updateMessages(_args) {
2682
- return this.stores.memory.updateMessages(_args);
2683
- }
2684
- // Workflow operations
2685
- async updateWorkflowResults({
2686
- workflowName,
2687
- runId,
2688
- stepId,
2689
- result,
2690
- requestContext
2691
- }) {
2692
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2693
- }
2694
- async updateWorkflowState({
2695
- workflowName,
2696
- runId,
2697
- opts
2698
- }) {
2699
- return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2700
- }
2701
- async persistWorkflowSnapshot({
2702
- workflowName,
2703
- runId,
2704
- resourceId,
2705
- snapshot
2706
- }) {
2707
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2708
- }
2709
- async loadWorkflowSnapshot({
2710
- workflowName,
2711
- runId
2712
- }) {
2713
- return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2714
- }
2715
- async listWorkflowRuns(args) {
2716
- return this.stores.workflows.listWorkflowRuns(args);
2717
- }
2718
- async getWorkflowRunById(args) {
2719
- return this.stores.workflows.getWorkflowRunById(args);
2720
- }
2721
- async deleteWorkflowRunById({ runId, workflowName }) {
2722
- return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
2723
- }
2724
- async getResourceById({ resourceId }) {
2725
- return this.stores.memory.getResourceById({ resourceId });
2726
- }
2727
- async saveResource({ resource }) {
2728
- return this.stores.memory.saveResource({ resource });
2729
- }
2730
- async updateResource({
2731
- resourceId,
2732
- workingMemory,
2733
- metadata
2734
- }) {
2735
- return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2736
- }
2737
2471
  /**
2738
2472
  * Closes the DynamoDB client connection and cleans up resources.
2739
- * Should be called when the store is no longer needed, e.g., at the end of tests or application shutdown.
2473
+ *
2474
+ * This will close the DynamoDB client, including pre-configured clients.
2740
2475
  */
2741
2476
  async close() {
2742
2477
  this.logger.debug("Closing DynamoDB client for store:", { name: this.name });
@@ -2754,50 +2489,8 @@ var DynamoDBStore = class extends MastraStorage {
2754
2489
  );
2755
2490
  }
2756
2491
  }
2757
- /**
2758
- * SCORERS - Not implemented
2759
- */
2760
- async getScoreById({ id: _id }) {
2761
- return this.stores.scores.getScoreById({ id: _id });
2762
- }
2763
- async saveScore(score) {
2764
- return this.stores.scores.saveScore(score);
2765
- }
2766
- async listScoresByRunId({
2767
- runId: _runId,
2768
- pagination: _pagination
2769
- }) {
2770
- return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2771
- }
2772
- async listScoresByEntityId({
2773
- entityId: _entityId,
2774
- entityType: _entityType,
2775
- pagination: _pagination
2776
- }) {
2777
- return this.stores.scores.listScoresByEntityId({
2778
- entityId: _entityId,
2779
- entityType: _entityType,
2780
- pagination: _pagination
2781
- });
2782
- }
2783
- async listScoresByScorerId({
2784
- scorerId,
2785
- source,
2786
- entityId,
2787
- entityType,
2788
- pagination
2789
- }) {
2790
- return this.stores.scores.listScoresByScorerId({ scorerId, source, entityId, entityType, pagination });
2791
- }
2792
- async listScoresBySpan({
2793
- traceId,
2794
- spanId,
2795
- pagination
2796
- }) {
2797
- return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2798
- }
2799
2492
  };
2800
2493
 
2801
- export { DynamoDBStore };
2494
+ export { DynamoDBStore, MemoryStorageDynamoDB, ScoresStorageDynamoDB, WorkflowStorageDynamoDB };
2802
2495
  //# sourceMappingURL=index.js.map
2803
2496
  //# sourceMappingURL=index.js.map