@mastra/dynamodb 1.4.2 → 1.4.3

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 { DescribeTableCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";
2
2
  import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
3
3
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
4
- import { BackgroundTasksStorage, MastraCompositeStore, MemoryStorage, RunFenceConflictError, SCORERS_SCHEMA, ScoresStorage, TABLE_BACKGROUND_TASKS, TABLE_MEMORY_RUN_FENCES, TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_RUN_OWNERS, TABLE_WORKFLOW_SNAPSHOT, WorkflowsStorage, calculatePagination, createStorageErrorId, isRunFenceConflictError, matchesExpectedWorkflowStatus, matchesRunFence, normalizePerPage, resolveRunFence, storageMessageMatchesMetadataFilter, validateStorageMetadataFilter } from "@mastra/core/storage";
4
+ import { BackgroundTasksStorage, MastraCompositeStore, MemoryStorage, RunFenceConflictError, SCORERS_SCHEMA, ScoresStorage, TABLE_BACKGROUND_TASKS, TABLE_MEMORY_RUN_FENCES, TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_RUN_OWNERS, TABLE_WORKFLOW_SNAPSHOT, WorkflowsStorage, calculatePagination, createStorageErrorId, executeRetentionPrune, isRunFenceConflictError, matchesExpectedWorkflowStatus, matchesRunFence, normalizePerPage, resolveRetentionTargets, resolveRunFence, retentionCutoffMs, storageMessageMatchesMetadataFilter, validateStorageMetadataFilter } 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";
@@ -1686,9 +1686,52 @@ async function goWithRunFence(service, check, write) {
1686
1686
  await backoff(attempt);
1687
1687
  }
1688
1688
  }
1689
+ /**
1690
+ * Deletes up to `limit` items of a run claim entity whose epoch-ms `attribute`
1691
+ * is older than `cutoff`. These entities have no index on the anchor, so this
1692
+ * scans for them. Each delete repeats the cutoff as its condition, so an item
1693
+ * claimed or raised again since the scan is kept.
1694
+ */
1695
+ async function pruneRunClaims(service, entityName, attribute, cutoff, limit) {
1696
+ const entity = service.entities[entityName];
1697
+ const olderThanCutoff = (attr, op) => op.lt(attr[attribute], cutoff);
1698
+ let deleted = 0;
1699
+ let cursor = null;
1700
+ do {
1701
+ const page = await entity.scan.where(olderThanCutoff).go({
1702
+ cursor,
1703
+ limit: limit - deleted
1704
+ });
1705
+ for (const item of page.data) {
1706
+ try {
1707
+ await retryOnTransactionConflict(() => entity.delete({
1708
+ entity: entityName,
1709
+ run_id: item.run_id
1710
+ }).where(olderThanCutoff).go());
1711
+ deleted++;
1712
+ } catch (error) {
1713
+ if (!isConditionalCheckFailed(error)) throw error;
1714
+ }
1715
+ if (deleted >= limit) return deleted;
1716
+ }
1717
+ cursor = page.cursor;
1718
+ } while (cursor);
1719
+ return deleted;
1720
+ }
1689
1721
  //#endregion
1690
1722
  //#region src/storage/domains/memory/index.ts
1691
- var MemoryStorageDynamoDB = class extends MemoryStorage {
1723
+ var MemoryStorageDynamoDB = class MemoryStorageDynamoDB extends MemoryStorage {
1724
+ /**
1725
+ * Tables `prune()` can clean up. Run fences anchor on `retiredAt` (epoch ms), which stays unset until the
1726
+ * execution holding the fence settles, so a running execution's fence is
1727
+ * never pruned.
1728
+ */
1729
+ static retentionTables = { runFences: {
1730
+ table: TABLE_MEMORY_RUN_FENCES,
1731
+ column: "retiredAt",
1732
+ indexed: false,
1733
+ anchorType: "epoch-ms"
1734
+ } };
1692
1735
  supportsPartialThreadUpdate = true;
1693
1736
  service;
1694
1737
  ttlConfig;
@@ -1701,6 +1744,19 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
1701
1744
  supportsRunFencing() {
1702
1745
  return true;
1703
1746
  }
1747
+ async prune(policies, options) {
1748
+ return executeRetentionPrune({
1749
+ domain: "memory",
1750
+ targets: resolveRetentionTargets({
1751
+ policies,
1752
+ descriptor: MemoryStorageDynamoDB.retentionTables,
1753
+ order: ["runFences"]
1754
+ }),
1755
+ options,
1756
+ cutoffFor: (target, now) => retentionCutoffMs(target.policy, now),
1757
+ deleteBatch: (_target, cutoff, limit) => pruneRunClaims(this.service, "memory_run_fence", "retiredAt", Number(cutoff), limit)
1758
+ });
1759
+ }
1704
1760
  async dangerouslyClearAll() {
1705
1761
  await deleteTableData(this.service, TABLE_THREADS);
1706
1762
  await deleteTableData(this.service, TABLE_MESSAGES);
@@ -2832,7 +2888,18 @@ function toRunOwnershipRecord(item) {
2832
2888
  }
2833
2889
  const MAX_RETRIES = 5;
2834
2890
  const BASE_DELAY_MS = 50;
2835
- var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2891
+ var WorkflowStorageDynamoDB = class WorkflowStorageDynamoDB extends WorkflowsStorage {
2892
+ /**
2893
+ * Tables `prune()` can clean up. Run ownership records anchor on `updatedAt` (epoch ms), which every
2894
+ * claim, renewal and release refreshes, so a live execution's record is never
2895
+ * older than its renew interval.
2896
+ */
2897
+ static retentionTables = { runOwnership: {
2898
+ table: TABLE_WORKFLOW_RUN_OWNERS,
2899
+ column: "updatedAt",
2900
+ indexed: false,
2901
+ anchorType: "epoch-ms"
2902
+ } };
2836
2903
  service;
2837
2904
  ttlConfig;
2838
2905
  constructor(config) {
@@ -2847,6 +2914,19 @@ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2847
2914
  supportsRunFencing() {
2848
2915
  return true;
2849
2916
  }
2917
+ async prune(policies, options) {
2918
+ return executeRetentionPrune({
2919
+ domain: "workflows",
2920
+ targets: resolveRetentionTargets({
2921
+ policies,
2922
+ descriptor: WorkflowStorageDynamoDB.retentionTables,
2923
+ order: ["runOwnership"]
2924
+ }),
2925
+ options,
2926
+ cutoffFor: (target, now) => retentionCutoffMs(target.policy, now),
2927
+ deleteBatch: (_target, cutoff, limit) => pruneRunClaims(this.service, "workflow_run_owner", "updatedAt", Number(cutoff), limit)
2928
+ });
2929
+ }
2850
2930
  async dangerouslyClearAll() {
2851
2931
  await deleteTableData(this.service, TABLE_WORKFLOW_SNAPSHOT);
2852
2932
  await deleteTableData(this.service, TABLE_WORKFLOW_RUN_OWNERS);