@mastra/mongodb 1.11.0 → 1.11.1-alpha.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.
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { v4 } from '@lukeed/uuid';
2
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
3
  import { createVectorErrorId, AgentsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS, BlobStore, TABLE_SKILL_BLOBS, DatasetsStorage, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, ensureDate, safelyParseJSON, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, ExperimentsStorage, MCPClientsStorage, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, NotificationsStorage, TABLE_NOTIFICATIONS, ObservabilityStorage, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, ScorerDefinitionsStorage, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, SkillsStorage, TABLE_SKILLS, TABLE_SKILL_VERSIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, MastraCompositeStore, TraceStatus, transformScoreRow as transformScoreRow$1 } from '@mastra/core/storage';
4
4
  import { MastraVector, validateUpsertInput, validateVectorValues } from '@mastra/core/vector';
5
- import { MongoClient } from 'mongodb';
5
+ import { MongoClient, MongoBulkWriteError } from 'mongodb';
6
6
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
7
7
  import { randomUUID } from 'crypto';
8
8
  import { MessageList } from '@mastra/core/agent';
@@ -13,7 +13,7 @@ import { skillSnapshotFieldValuesEqual } from '@mastra/core/storage/domains/skil
13
13
 
14
14
  // package.json
15
15
  var package_default = {
16
- version: "1.11.0"};
16
+ version: "1.11.1-alpha.0"};
17
17
  var MongoDBFilterTranslator = class extends BaseFilterTranslator {
18
18
  getSupportedOperators() {
19
19
  return {
@@ -110,7 +110,6 @@ var MongoDBVector = class extends MastraVector {
110
110
  embeddingFieldName;
111
111
  metadataFieldName = "metadata";
112
112
  documentFieldName = "document";
113
- collectionForValidation = null;
114
113
  mongoMetricMap = {
115
114
  cosine: "cosine",
116
115
  euclidean: "euclidean",
@@ -162,6 +161,17 @@ var MongoDBVector = class extends MastraVector {
162
161
  );
163
162
  }
164
163
  }
164
+ /**
165
+ * Creates a MongoDB collection and the Atlas Search indexes that back a
166
+ * Mastra index with the given name.
167
+ *
168
+ * **Async index lifecycle:** Atlas Search indexes transition through
169
+ * PENDING → BUILDING → READY after this method returns. If you need to
170
+ * `upsert` or `query` immediately after calling `createIndex`, call
171
+ * `waitForIndexReady({ indexName })` first to block until the index is
172
+ * queryable. Skipping that step on a real Atlas cluster may cause
173
+ * "index not found" or "index not ready" errors on subsequent operations.
174
+ */
165
175
  async createIndex({ indexName, dimension, metric = "cosine" }) {
166
176
  let mongoMetric;
167
177
  try {
@@ -209,6 +219,10 @@ var MongoDBVector = class extends MastraVector {
209
219
  {
210
220
  type: "filter",
211
221
  path: "_id"
222
+ },
223
+ {
224
+ type: "filter",
225
+ path: "document"
212
226
  }
213
227
  ]
214
228
  },
@@ -236,21 +250,6 @@ var MongoDBVector = class extends MastraVector {
236
250
  );
237
251
  }
238
252
  }
239
- try {
240
- await collection?.updateOne({ _id: "__index_metadata__" }, { $set: { dimension, metric } }, { upsert: true });
241
- } catch (error) {
242
- throw new MastraError(
243
- {
244
- id: createVectorErrorId("MONGODB", "CREATE_INDEX", "STORE_METADATA_FAILED"),
245
- domain: ErrorDomain.STORAGE,
246
- category: ErrorCategory.THIRD_PARTY,
247
- details: {
248
- indexName
249
- }
250
- },
251
- error
252
- );
253
- }
254
253
  }
255
254
  /**
256
255
  * Waits for the index to be ready.
@@ -279,12 +278,25 @@ var MongoDBVector = class extends MastraVector {
279
278
  }
280
279
  throw new Error(`Index "${indexNameInternal}" did not become ready within timeout`);
281
280
  }
281
+ /**
282
+ * Inserts or updates vectors in the specified index.
283
+ *
284
+ * @param indexName - Name of the index (MongoDB collection) to write into.
285
+ * @param vectors - Array of embedding vectors. Each must have the same
286
+ * dimension as declared when the index was created.
287
+ * @param metadata - Optional array of metadata objects, one per vector,
288
+ * stored in a nested `metadata` field alongside the embedding.
289
+ * @param ids - Optional string IDs for each vector, used as the MongoDB
290
+ * document `_id`. Auto-generated UUIDs are used when omitted.
291
+ * @param documents - Optional text strings associated with each vector,
292
+ * stored in a `document` field.
293
+ * @returns The IDs of the upserted vectors in input order.
294
+ */
282
295
  async upsert({ indexName, vectors, metadata, ids, documents }) {
283
296
  validateUpsertInput("MONGODB", vectors, metadata, ids);
284
297
  validateVectorValues("MONGODB", vectors);
285
298
  try {
286
299
  const collection = await this.getCollection(indexName);
287
- this.collectionForValidation = collection;
288
300
  const stats = await this.describeIndex({ indexName });
289
301
  await this.validateVectorDimensions(vectors, stats.dimension);
290
302
  const generatedIds = ids || vectors.map(() => v4());
@@ -331,13 +343,30 @@ var MongoDBVector = class extends MastraVector {
331
343
  );
332
344
  }
333
345
  }
346
+ /**
347
+ * Runs an approximate nearest-neighbor search against the specified index.
348
+ *
349
+ * @param indexName - Name of the index (MongoDB collection) to search.
350
+ * @param queryVector - The query embedding. Must match the index dimension.
351
+ * @param topK - Maximum number of results to return (default: 10).
352
+ * @param filter - Optional metadata filter. Fields are matched against the
353
+ * nested `metadata` subdocument; no `metadata.` prefix is needed.
354
+ * @param includeVector - When true, each result includes the stored embedding
355
+ * in a `vector` field (default: false).
356
+ * @param documentFilter - Optional filter applied to the `document` text
357
+ * field, independent of `filter`.
358
+ * @param numCandidates - HNSW candidate pool size. Higher values improve
359
+ * recall at the cost of latency. Defaults to 20 * topK, capped at 10000.
360
+ * @returns Array of results ordered by descending similarity score.
361
+ */
334
362
  async query({
335
363
  indexName,
336
364
  queryVector,
337
365
  topK = 10,
338
366
  filter,
339
367
  includeVector = false,
340
- documentFilter
368
+ documentFilter,
369
+ numCandidates
341
370
  }) {
342
371
  if (!queryVector) {
343
372
  throw new MastraError({
@@ -351,36 +380,21 @@ var MongoDBVector = class extends MastraVector {
351
380
  try {
352
381
  const collection = await this.getCollection(indexName, true);
353
382
  const indexNameInternal = `${indexName}_vector_index`;
354
- const mongoFilter = this.transformFilter(filter);
355
- const documentMongoFilter = documentFilter ? { [this.documentFieldName]: documentFilter } : {};
356
- const transformedMongoFilter = this.transformMetadataFilter(mongoFilter);
357
- let combinedFilter = {};
358
- if (Object.keys(transformedMongoFilter).length > 0 && Object.keys(documentMongoFilter).length > 0) {
359
- combinedFilter = { $and: [transformedMongoFilter, documentMongoFilter] };
360
- } else if (Object.keys(transformedMongoFilter).length > 0) {
361
- combinedFilter = transformedMongoFilter;
362
- } else if (Object.keys(documentMongoFilter).length > 0) {
363
- combinedFilter = documentMongoFilter;
364
- }
383
+ const metadataFilter = this.transformMetadataFilter(this.transformFilter(filter));
384
+ const hasMetadataFilter = Object.keys(metadataFilter).length > 0;
365
385
  const vectorSearch = {
366
386
  index: indexNameInternal,
367
387
  queryVector,
368
388
  path: this.embeddingFieldName,
369
- numCandidates: Math.min(1e4, Math.max(100, topK)),
389
+ numCandidates: Math.min(1e4, Math.max(topK, numCandidates ?? topK * 20)),
370
390
  limit: Math.min(1e4, topK)
371
391
  };
372
- if (Object.keys(combinedFilter).length > 0) {
373
- const filterWithExclusion = {
374
- $and: [{ _id: { $ne: "__index_metadata__" } }, combinedFilter]
375
- };
376
- const candidateIds = await collection.aggregate([{ $match: filterWithExclusion }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
377
- if (candidateIds.length > 0) {
378
- vectorSearch.filter = { _id: { $in: candidateIds } };
379
- } else {
380
- return [];
381
- }
382
- } else {
383
- vectorSearch.filter = { _id: { $ne: "__index_metadata__" } };
392
+ if (hasMetadataFilter) {
393
+ const candidateIds = await collection.aggregate([{ $match: metadataFilter }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
394
+ if (candidateIds.length === 0) return [];
395
+ vectorSearch.filter = documentFilter ? { $and: [{ _id: { $in: candidateIds } }, { [this.documentFieldName]: documentFilter }] } : { _id: { $in: candidateIds } };
396
+ } else if (documentFilter) {
397
+ vectorSearch.filter = { [this.documentFieldName]: documentFilter };
384
398
  }
385
399
  const pipeline = [
386
400
  {
@@ -446,23 +460,44 @@ var MongoDBVector = class extends MastraVector {
446
460
  try {
447
461
  const collection = await this.getCollection(indexName, true);
448
462
  const count = await collection.countDocuments({ _id: { $ne: "__index_metadata__" } });
449
- const metadataDoc = await collection.findOne({ _id: "__index_metadata__" });
450
- const dimension = metadataDoc?.dimension || 0;
451
- const metric = metadataDoc?.metric || "cosine";
452
- return {
453
- dimension,
454
- count,
455
- metric
463
+ const indexNameInternal = `${indexName}_vector_index`;
464
+ const indexInfo = await collection.listSearchIndexes().toArray();
465
+ const indexData = indexInfo.find((idx) => idx.name === indexNameInternal);
466
+ if (!indexData) {
467
+ throw new MastraError({
468
+ id: createVectorErrorId("MONGODB", "DESCRIBE_INDEX", "NOT_FOUND"),
469
+ domain: ErrorDomain.STORAGE,
470
+ category: ErrorCategory.USER,
471
+ details: { indexName },
472
+ text: `Atlas Search index "${indexNameInternal}" does not exist on collection "${indexName}". The collection may predate Mastra or the index may have been dropped externally.`
473
+ });
474
+ }
475
+ const vectorField = indexData.latestDefinition?.fields?.find((f) => f.type === "vector");
476
+ if (!vectorField) {
477
+ throw new MastraError({
478
+ id: createVectorErrorId("MONGODB", "DESCRIBE_INDEX", "INVALID"),
479
+ domain: ErrorDomain.STORAGE,
480
+ category: ErrorCategory.USER,
481
+ details: { indexName },
482
+ text: `Atlas Search index "${indexNameInternal}" exists but has no vector field. The index may have been created outside of Mastra or without vector configuration.`
483
+ });
484
+ }
485
+ const dimension = vectorField.numDimensions;
486
+ const reverseMetricMap = {
487
+ cosine: "cosine",
488
+ euclidean: "euclidean",
489
+ dotProduct: "dotproduct"
456
490
  };
491
+ const metric = reverseMetricMap[vectorField.similarity] ?? "cosine";
492
+ return { dimension, count, metric };
457
493
  } catch (error) {
494
+ if (error instanceof MastraError) throw error;
458
495
  throw new MastraError(
459
496
  {
460
497
  id: createVectorErrorId("MONGODB", "DESCRIBE_INDEX", "FAILED"),
461
498
  domain: ErrorDomain.STORAGE,
462
499
  category: ErrorCategory.THIRD_PARTY,
463
- details: {
464
- indexName
465
- }
500
+ details: { indexName }
466
501
  },
467
502
  error
468
503
  );
@@ -669,10 +704,7 @@ var MongoDBVector = class extends MastraVector {
669
704
  text: "Filter produced empty query"
670
705
  });
671
706
  }
672
- const finalFilter = {
673
- $and: [{ _id: { $ne: "__index_metadata__" } }, transformedFilter]
674
- };
675
- await collection.deleteMany(finalFilter);
707
+ await collection.deleteMany(transformedFilter);
676
708
  }
677
709
  } catch (error) {
678
710
  if (error instanceof MastraError) {
@@ -693,7 +725,26 @@ var MongoDBVector = class extends MastraVector {
693
725
  );
694
726
  }
695
727
  }
696
- // Private methods
728
+ /**
729
+ * Returns the MongoDB Collection that backs the given Mastra index.
730
+ *
731
+ * **Index vs. collection:** In this driver, each Mastra index is stored as a
732
+ * MongoDB collection whose name equals the index name. The Atlas Vector Search
733
+ * index (named `${indexName}_vector_index`) lives on that collection. The two
734
+ * terms are distinct: "index" is the Mastra concept; "collection" is the
735
+ * MongoDB storage primitive that implements it.
736
+ *
737
+ * **Caching:** Collection handles are cached on first successful lookup to
738
+ * avoid redundant `listCollections` round-trips. Only handles for collections
739
+ * that actually exist are cached; a handle for a missing collection is returned
740
+ * without being cached so the next call re-checks existence rather than
741
+ * returning a stale phantom.
742
+ *
743
+ * @param indexName - Mastra index name, which is also the MongoDB collection name.
744
+ * @param throwIfNotExists - When `true` (default), throws if no MongoDB
745
+ * collection exists for this index name. Pass `false` when absence is not an
746
+ * error (e.g., inside `deleteIndex`).
747
+ */
697
748
  async getCollection(indexName, throwIfNotExists = true) {
698
749
  if (this.collections.has(indexName)) {
699
750
  return this.collections.get(indexName);
@@ -701,9 +752,13 @@ var MongoDBVector = class extends MastraVector {
701
752
  const collection = this.db.collection(indexName);
702
753
  const collectionExists = await this.db.listCollections({ name: indexName }).hasNext();
703
754
  if (!collectionExists && throwIfNotExists) {
704
- throw new Error(`Index (Collection) "${indexName}" does not exist`);
755
+ throw new Error(
756
+ `Mastra index "${indexName}" has no backing MongoDB collection. Call createIndex first, or verify the collection was not dropped externally.`
757
+ );
758
+ }
759
+ if (collectionExists) {
760
+ this.collections.set(indexName, collection);
705
761
  }
706
- this.collections.set(indexName, collection);
707
762
  return collection;
708
763
  }
709
764
  async validateVectorDimensions(vectors, dimension) {
@@ -712,7 +767,6 @@ var MongoDBVector = class extends MastraVector {
712
767
  }
713
768
  if (dimension === 0) {
714
769
  dimension = vectors[0] ? vectors[0].length : 0;
715
- await this.setIndexDimension(dimension);
716
770
  }
717
771
  for (let i = 0; i < vectors.length; i++) {
718
772
  let v = vectors[i]?.length;
@@ -721,10 +775,6 @@ var MongoDBVector = class extends MastraVector {
721
775
  }
722
776
  }
723
777
  }
724
- async setIndexDimension(dimension) {
725
- const collection = this.collectionForValidation;
726
- await collection.updateOne({ _id: "__index_metadata__" }, { $set: { dimension } }, { upsert: true });
727
- }
728
778
  transformFilter(filter) {
729
779
  const translator = new MongoDBFilterTranslator();
730
780
  if (!filter) return {};
@@ -754,12 +804,7 @@ var MongoDBVector = class extends MastraVector {
754
804
  transformed[key] = value;
755
805
  }
756
806
  } else if (key.startsWith("metadata.")) {
757
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
758
- const hasOperator = Object.keys(value).some((k) => k.startsWith("$"));
759
- transformed[key] = hasOperator ? value : value;
760
- } else {
761
- transformed[key] = value;
762
- }
807
+ transformed[key] = value;
763
808
  } else if (this.isMetadataField(key)) {
764
809
  transformed[`metadata.${key}`] = value;
765
810
  } else {
@@ -786,6 +831,7 @@ var MongoDBConnector = class _MongoDBConnector {
786
831
  #handler;
787
832
  #isConnected;
788
833
  #db;
834
+ #supportsTransactions;
789
835
  constructor(options) {
790
836
  this.#client = options.client;
791
837
  this.#dbName = options.dbName;
@@ -842,6 +888,50 @@ var MongoDBConnector = class _MongoDBConnector {
842
888
  const db = await this.getConnection();
843
889
  return db.collection(collectionName);
844
890
  }
891
+ /**
892
+ * Returns true when the deployment supports multi-document transactions
893
+ * (replica set or sharded cluster). Standalone servers and custom connector
894
+ * handlers return false. Probed once and cached.
895
+ */
896
+ async supportsTransactions() {
897
+ if (this.#supportsTransactions !== void 0) {
898
+ return this.#supportsTransactions;
899
+ }
900
+ if (!this.#client) {
901
+ this.#supportsTransactions = false;
902
+ return false;
903
+ }
904
+ try {
905
+ const db = await this.getConnection();
906
+ const hello = await db.admin().command({ hello: 1 });
907
+ this.#supportsTransactions = Boolean(hello.setName) || hello.msg === "isdbgrid";
908
+ return this.#supportsTransactions;
909
+ } catch {
910
+ return false;
911
+ }
912
+ }
913
+ /**
914
+ * Runs `fn` inside a transaction when the deployment supports it, passing the
915
+ * session so callers can scope each operation with `{ session }`. On a
916
+ * standalone server (or custom handler) it degrades to running `fn` directly
917
+ * with an undefined session — best-effort sequential, no atomicity.
918
+ */
919
+ async withTransaction(fn) {
920
+ const supported = await this.supportsTransactions();
921
+ if (!supported || !this.#client) {
922
+ return fn(void 0);
923
+ }
924
+ const session = this.#client.startSession();
925
+ try {
926
+ let result;
927
+ await session.withTransaction(async () => {
928
+ result = await fn(session);
929
+ });
930
+ return result;
931
+ } finally {
932
+ await session.endSession();
933
+ }
934
+ }
845
935
  async close() {
846
936
  if (this.#client) {
847
937
  await this.#client.close();
@@ -1077,16 +1167,23 @@ var MongoDBAgentsStorage = class _MongoDBAgentsStorage extends AgentsStorage {
1077
1167
  createdAt: now,
1078
1168
  updatedAt: now
1079
1169
  };
1080
- await collection.insertOne(this.serializeAgent(newAgent));
1081
1170
  const { id: _id, authorId: _authorId, visibility: _visibility, metadata: _metadata, ...snapshotConfig } = agent;
1082
1171
  const versionId = randomUUID();
1083
- await this.createVersion({
1172
+ const versionDoc = {
1084
1173
  id: versionId,
1085
1174
  agentId: agent.id,
1086
1175
  versionNumber: 1,
1087
- ...snapshotConfig,
1088
1176
  changedFields: Object.keys(snapshotConfig),
1089
- changeMessage: "Initial version"
1177
+ changeMessage: "Initial version",
1178
+ createdAt: /* @__PURE__ */ new Date()
1179
+ };
1180
+ for (const field of SNAPSHOT_FIELDS) {
1181
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
1182
+ }
1183
+ await this.#connector.withTransaction(async (session) => {
1184
+ await collection.insertOne(this.serializeAgent(newAgent), { session });
1185
+ const versionsCol = await this.getCollection(TABLE_AGENT_VERSIONS);
1186
+ await versionsCol.insertOne(versionDoc, { session });
1090
1187
  });
1091
1188
  return newAgent;
1092
1189
  } catch (error) {
@@ -1171,9 +1268,12 @@ var MongoDBAgentsStorage = class _MongoDBAgentsStorage extends AgentsStorage {
1171
1268
  }
1172
1269
  async delete(id) {
1173
1270
  try {
1174
- await this.deleteVersionsByParentId(id);
1175
- const collection = await this.getCollection(TABLE_AGENTS);
1176
- await collection.deleteOne({ id });
1271
+ await this.#connector.withTransaction(async (session) => {
1272
+ const versionsCol = await this.getCollection(TABLE_AGENT_VERSIONS);
1273
+ await versionsCol.deleteMany({ agentId: id }, { session });
1274
+ const col = await this.getCollection(TABLE_AGENTS);
1275
+ await col.deleteOne({ id }, { session });
1276
+ });
1177
1277
  } catch (error) {
1178
1278
  throw new MastraError(
1179
1279
  {
@@ -2239,45 +2339,56 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2239
2339
  const datasetsCollection = await this.getCollection(TABLE_DATASETS);
2240
2340
  const itemsCollection = await this.getCollection(TABLE_DATASET_ITEMS);
2241
2341
  const versionsCollection = await this.getCollection(TABLE_DATASET_VERSIONS);
2242
- const result = await datasetsCollection.findOneAndUpdate(
2243
- { id: args.datasetId },
2244
- { $inc: { version: 1 } },
2245
- { returnDocument: "after" }
2246
- );
2247
- if (!result) {
2248
- throw new MastraError({
2249
- id: createStorageErrorId("MONGODB", "ADD_ITEM", "DATASET_NOT_FOUND"),
2250
- domain: ErrorDomain.STORAGE,
2251
- category: ErrorCategory.USER,
2252
- details: { datasetId: args.datasetId }
2253
- });
2254
- }
2255
- const newVersion = result.version;
2256
- const organizationId = result.organizationId ?? null;
2257
- const projectId = result.projectId ?? null;
2258
- await itemsCollection.insertOne({
2259
- id,
2260
- datasetId: args.datasetId,
2261
- datasetVersion: newVersion,
2262
- organizationId,
2263
- projectId,
2264
- validTo: null,
2265
- isDeleted: false,
2266
- input: args.input,
2267
- groundTruth: args.groundTruth ?? null,
2268
- expectedTrajectory: args.expectedTrajectory ?? null,
2269
- toolMocks: args.toolMocks ?? null,
2270
- requestContext: args.requestContext ?? null,
2271
- metadata: args.metadata ?? null,
2272
- source: args.source ?? null,
2273
- createdAt: now,
2274
- updatedAt: now
2275
- });
2276
- await versionsCollection.insertOne({
2277
- id: versionId,
2278
- datasetId: args.datasetId,
2279
- version: newVersion,
2280
- createdAt: now
2342
+ let newVersion = 0;
2343
+ let organizationId = null;
2344
+ let projectId = null;
2345
+ await this.#connector.withTransaction(async (session) => {
2346
+ const result = await datasetsCollection.findOneAndUpdate(
2347
+ { id: args.datasetId },
2348
+ { $inc: { version: 1 } },
2349
+ { session, returnDocument: "after" }
2350
+ );
2351
+ if (!result) {
2352
+ throw new MastraError({
2353
+ id: createStorageErrorId("MONGODB", "ADD_ITEM", "DATASET_NOT_FOUND"),
2354
+ domain: ErrorDomain.STORAGE,
2355
+ category: ErrorCategory.USER,
2356
+ details: { datasetId: args.datasetId }
2357
+ });
2358
+ }
2359
+ newVersion = result.version;
2360
+ organizationId = result.organizationId ?? null;
2361
+ projectId = result.projectId ?? null;
2362
+ await itemsCollection.insertOne(
2363
+ {
2364
+ id,
2365
+ datasetId: args.datasetId,
2366
+ datasetVersion: newVersion,
2367
+ organizationId,
2368
+ projectId,
2369
+ validTo: null,
2370
+ isDeleted: false,
2371
+ input: args.input,
2372
+ groundTruth: args.groundTruth ?? null,
2373
+ expectedTrajectory: args.expectedTrajectory ?? null,
2374
+ toolMocks: args.toolMocks ?? null,
2375
+ requestContext: args.requestContext ?? null,
2376
+ metadata: args.metadata ?? null,
2377
+ source: args.source ?? null,
2378
+ createdAt: now,
2379
+ updatedAt: now
2380
+ },
2381
+ { session }
2382
+ );
2383
+ await versionsCollection.insertOne(
2384
+ {
2385
+ id: versionId,
2386
+ datasetId: args.datasetId,
2387
+ version: newVersion,
2388
+ createdAt: now
2389
+ },
2390
+ { session }
2391
+ );
2281
2392
  });
2282
2393
  return {
2283
2394
  id,
@@ -2342,49 +2453,61 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2342
2453
  const datasetsCollection = await this.getCollection(TABLE_DATASETS);
2343
2454
  const itemsCollection = await this.getCollection(TABLE_DATASET_ITEMS);
2344
2455
  const versionsCollection = await this.getCollection(TABLE_DATASET_VERSIONS);
2345
- const result = await datasetsCollection.findOneAndUpdate(
2346
- { id: args.datasetId },
2347
- { $inc: { version: 1 } },
2348
- { returnDocument: "after" }
2349
- );
2350
- if (!result) {
2351
- throw new MastraError({
2352
- id: createStorageErrorId("MONGODB", "UPDATE_ITEM", "DATASET_NOT_FOUND"),
2353
- domain: ErrorDomain.STORAGE,
2354
- category: ErrorCategory.USER,
2355
- details: { datasetId: args.datasetId }
2356
- });
2357
- }
2358
- const newVersion = result.version;
2359
- const parentOrganizationId = result.organizationId ?? null;
2360
- const parentProjectId = result.projectId ?? null;
2361
- await itemsCollection.updateOne(
2362
- { id: args.id, validTo: null, isDeleted: false },
2363
- { $set: { validTo: newVersion } }
2364
- );
2365
- await itemsCollection.insertOne({
2366
- id: args.id,
2367
- datasetId: args.datasetId,
2368
- datasetVersion: newVersion,
2369
- organizationId: parentOrganizationId,
2370
- projectId: parentProjectId,
2371
- validTo: null,
2372
- isDeleted: false,
2373
- input: mergedInput,
2374
- groundTruth: mergedGroundTruth,
2375
- expectedTrajectory: mergedExpectedTrajectory ?? null,
2376
- toolMocks: mergedToolMocks ?? null,
2377
- requestContext: mergedRequestContext,
2378
- metadata: mergedMetadata,
2379
- source: mergedSource,
2380
- createdAt: existing.createdAt,
2381
- updatedAt: now
2382
- });
2383
- await versionsCollection.insertOne({
2384
- id: versionId,
2385
- datasetId: args.datasetId,
2386
- version: newVersion,
2387
- createdAt: now
2456
+ let newVersion = 0;
2457
+ let parentOrganizationId = null;
2458
+ let parentProjectId = null;
2459
+ await this.#connector.withTransaction(async (session) => {
2460
+ const result = await datasetsCollection.findOneAndUpdate(
2461
+ { id: args.datasetId },
2462
+ { $inc: { version: 1 } },
2463
+ { session, returnDocument: "after" }
2464
+ );
2465
+ if (!result) {
2466
+ throw new MastraError({
2467
+ id: createStorageErrorId("MONGODB", "UPDATE_ITEM", "DATASET_NOT_FOUND"),
2468
+ domain: ErrorDomain.STORAGE,
2469
+ category: ErrorCategory.USER,
2470
+ details: { datasetId: args.datasetId }
2471
+ });
2472
+ }
2473
+ newVersion = result.version;
2474
+ parentOrganizationId = result.organizationId ?? null;
2475
+ parentProjectId = result.projectId ?? null;
2476
+ await itemsCollection.updateOne(
2477
+ { id: args.id, validTo: null, isDeleted: false },
2478
+ { $set: { validTo: newVersion } },
2479
+ { session }
2480
+ );
2481
+ await itemsCollection.insertOne(
2482
+ {
2483
+ id: args.id,
2484
+ datasetId: args.datasetId,
2485
+ datasetVersion: newVersion,
2486
+ organizationId: parentOrganizationId,
2487
+ projectId: parentProjectId,
2488
+ validTo: null,
2489
+ isDeleted: false,
2490
+ input: mergedInput,
2491
+ groundTruth: mergedGroundTruth,
2492
+ expectedTrajectory: mergedExpectedTrajectory ?? null,
2493
+ toolMocks: mergedToolMocks ?? null,
2494
+ requestContext: mergedRequestContext,
2495
+ metadata: mergedMetadata,
2496
+ source: mergedSource,
2497
+ createdAt: existing.createdAt,
2498
+ updatedAt: now
2499
+ },
2500
+ { session }
2501
+ );
2502
+ await versionsCollection.insertOne(
2503
+ {
2504
+ id: versionId,
2505
+ datasetId: args.datasetId,
2506
+ version: newVersion,
2507
+ createdAt: now
2508
+ },
2509
+ { session }
2510
+ );
2388
2511
  });
2389
2512
  return {
2390
2513
  ...existing,
@@ -2429,46 +2552,58 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2429
2552
  const datasetsCollection = await this.getCollection(TABLE_DATASETS);
2430
2553
  const itemsCollection = await this.getCollection(TABLE_DATASET_ITEMS);
2431
2554
  const versionsCollection = await this.getCollection(TABLE_DATASET_VERSIONS);
2432
- const result = await datasetsCollection.findOneAndUpdate(
2433
- { id: datasetId },
2434
- { $inc: { version: 1 } },
2435
- { returnDocument: "after" }
2436
- );
2437
- if (!result) {
2438
- throw new MastraError({
2439
- id: createStorageErrorId("MONGODB", "DELETE_ITEM", "DATASET_NOT_FOUND"),
2440
- domain: ErrorDomain.STORAGE,
2441
- category: ErrorCategory.USER,
2442
- details: { datasetId }
2443
- });
2444
- }
2445
- const newVersion = result.version;
2446
- const parentOrganizationId = result.organizationId ?? null;
2447
- const parentProjectId = result.projectId ?? null;
2448
- await itemsCollection.updateOne({ id, validTo: null, isDeleted: false }, { $set: { validTo: newVersion } });
2449
- await itemsCollection.insertOne({
2450
- id,
2451
- datasetId,
2452
- datasetVersion: newVersion,
2453
- organizationId: parentOrganizationId,
2454
- projectId: parentProjectId,
2455
- validTo: null,
2456
- isDeleted: true,
2457
- input: existing.input,
2458
- groundTruth: existing.groundTruth,
2459
- expectedTrajectory: existing.expectedTrajectory ?? null,
2460
- toolMocks: existing.toolMocks ?? null,
2461
- requestContext: existing.requestContext,
2462
- metadata: existing.metadata,
2463
- source: existing.source,
2464
- createdAt: existing.createdAt,
2465
- updatedAt: now
2466
- });
2467
- await versionsCollection.insertOne({
2468
- id: versionId,
2469
- datasetId,
2470
- version: newVersion,
2471
- createdAt: now
2555
+ await this.#connector.withTransaction(async (session) => {
2556
+ const result = await datasetsCollection.findOneAndUpdate(
2557
+ { id: datasetId },
2558
+ { $inc: { version: 1 } },
2559
+ { session, returnDocument: "after" }
2560
+ );
2561
+ if (!result) {
2562
+ throw new MastraError({
2563
+ id: createStorageErrorId("MONGODB", "DELETE_ITEM", "DATASET_NOT_FOUND"),
2564
+ domain: ErrorDomain.STORAGE,
2565
+ category: ErrorCategory.USER,
2566
+ details: { datasetId }
2567
+ });
2568
+ }
2569
+ const newVersion = result.version;
2570
+ const parentOrganizationId = result.organizationId ?? null;
2571
+ const parentProjectId = result.projectId ?? null;
2572
+ await itemsCollection.updateOne(
2573
+ { id, validTo: null, isDeleted: false },
2574
+ { $set: { validTo: newVersion } },
2575
+ { session }
2576
+ );
2577
+ await itemsCollection.insertOne(
2578
+ {
2579
+ id,
2580
+ datasetId,
2581
+ datasetVersion: newVersion,
2582
+ organizationId: parentOrganizationId,
2583
+ projectId: parentProjectId,
2584
+ validTo: null,
2585
+ isDeleted: true,
2586
+ input: existing.input,
2587
+ groundTruth: existing.groundTruth,
2588
+ expectedTrajectory: existing.expectedTrajectory ?? null,
2589
+ toolMocks: existing.toolMocks ?? null,
2590
+ requestContext: existing.requestContext,
2591
+ metadata: existing.metadata,
2592
+ source: existing.source,
2593
+ createdAt: existing.createdAt,
2594
+ updatedAt: now
2595
+ },
2596
+ { session }
2597
+ );
2598
+ await versionsCollection.insertOne(
2599
+ {
2600
+ id: versionId,
2601
+ datasetId,
2602
+ version: newVersion,
2603
+ createdAt: now
2604
+ },
2605
+ { session }
2606
+ );
2472
2607
  });
2473
2608
  } catch (error) {
2474
2609
  if (error instanceof MastraError) throw error;
@@ -2506,23 +2641,26 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2506
2641
  const datasetsCollection = await this.getCollection(TABLE_DATASETS);
2507
2642
  const itemsCollection = await this.getCollection(TABLE_DATASET_ITEMS);
2508
2643
  const versionsCollection = await this.getCollection(TABLE_DATASET_VERSIONS);
2509
- const result = await datasetsCollection.findOneAndUpdate(
2510
- { id: input.datasetId },
2511
- { $inc: { version: 1 } },
2512
- { returnDocument: "after" }
2513
- );
2514
- if (!result) {
2515
- throw new MastraError({
2516
- id: createStorageErrorId("MONGODB", "BULK_ADD_ITEMS", "DATASET_NOT_FOUND"),
2517
- domain: ErrorDomain.STORAGE,
2518
- category: ErrorCategory.USER,
2519
- details: { datasetId: input.datasetId }
2520
- });
2521
- }
2522
- const newVersion = result.version;
2523
- const organizationId = result.organizationId ?? null;
2524
- const projectId = result.projectId ?? null;
2525
- if (itemsWithIds.length > 0) {
2644
+ let newVersion = 0;
2645
+ let organizationId = null;
2646
+ let projectId = null;
2647
+ await this.#connector.withTransaction(async (session) => {
2648
+ const result = await datasetsCollection.findOneAndUpdate(
2649
+ { id: input.datasetId },
2650
+ { $inc: { version: 1 } },
2651
+ { session, returnDocument: "after" }
2652
+ );
2653
+ if (!result) {
2654
+ throw new MastraError({
2655
+ id: createStorageErrorId("MONGODB", "BULK_ADD_ITEMS", "DATASET_NOT_FOUND"),
2656
+ domain: ErrorDomain.STORAGE,
2657
+ category: ErrorCategory.USER,
2658
+ details: { datasetId: input.datasetId }
2659
+ });
2660
+ }
2661
+ newVersion = result.version;
2662
+ organizationId = result.organizationId ?? null;
2663
+ projectId = result.projectId ?? null;
2526
2664
  const docs = itemsWithIds.map(({ generatedId, itemInput }) => ({
2527
2665
  id: generatedId,
2528
2666
  datasetId: input.datasetId,
@@ -2541,13 +2679,16 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2541
2679
  createdAt: now,
2542
2680
  updatedAt: now
2543
2681
  }));
2544
- await itemsCollection.insertMany(docs);
2545
- }
2546
- await versionsCollection.insertOne({
2547
- id: versionId,
2548
- datasetId: input.datasetId,
2549
- version: newVersion,
2550
- createdAt: now
2682
+ await itemsCollection.insertMany(docs, { session });
2683
+ await versionsCollection.insertOne(
2684
+ {
2685
+ id: versionId,
2686
+ datasetId: input.datasetId,
2687
+ version: newVersion,
2688
+ createdAt: now
2689
+ },
2690
+ { session }
2691
+ );
2551
2692
  });
2552
2693
  return itemsWithIds.map(({ generatedId, itemInput }) => ({
2553
2694
  id: generatedId,
@@ -2601,51 +2742,57 @@ var MongoDBDatasetsStorage = class extends DatasetsStorage {
2601
2742
  const versionId = randomUUID();
2602
2743
  const datasetsCollection = await this.getCollection(TABLE_DATASETS);
2603
2744
  const versionsCollection = await this.getCollection(TABLE_DATASET_VERSIONS);
2604
- const result = await datasetsCollection.findOneAndUpdate(
2605
- { id: input.datasetId },
2606
- { $inc: { version: 1 } },
2607
- { returnDocument: "after" }
2608
- );
2609
- if (!result) {
2610
- throw new MastraError({
2611
- id: createStorageErrorId("MONGODB", "BULK_DELETE_ITEMS", "DATASET_NOT_FOUND"),
2612
- domain: ErrorDomain.STORAGE,
2613
- category: ErrorCategory.USER,
2614
- details: { datasetId: input.datasetId }
2615
- });
2616
- }
2617
- const newVersion = result.version;
2618
- const parentOrganizationId = result.organizationId ?? null;
2619
- const parentProjectId = result.projectId ?? null;
2620
2745
  const currentIds = currentItems.map((i) => i.id);
2621
- await itemsCollection.updateMany(
2622
- { id: { $in: currentIds }, validTo: null, isDeleted: false },
2623
- { $set: { validTo: newVersion } }
2624
- );
2625
- const tombstones = currentItems.map((item) => ({
2626
- id: item.id,
2627
- datasetId: input.datasetId,
2628
- datasetVersion: newVersion,
2629
- organizationId: parentOrganizationId,
2630
- projectId: parentProjectId,
2631
- validTo: null,
2632
- isDeleted: true,
2633
- input: item.input,
2634
- groundTruth: item.groundTruth,
2635
- expectedTrajectory: item.expectedTrajectory ?? null,
2636
- toolMocks: item.toolMocks ?? null,
2637
- requestContext: item.requestContext,
2638
- metadata: item.metadata,
2639
- source: item.source,
2640
- createdAt: item.createdAt,
2641
- updatedAt: now
2642
- }));
2643
- await itemsCollection.insertMany(tombstones);
2644
- await versionsCollection.insertOne({
2645
- id: versionId,
2646
- datasetId: input.datasetId,
2647
- version: newVersion,
2648
- createdAt: now
2746
+ await this.#connector.withTransaction(async (session) => {
2747
+ const result = await datasetsCollection.findOneAndUpdate(
2748
+ { id: input.datasetId },
2749
+ { $inc: { version: 1 } },
2750
+ { session, returnDocument: "after" }
2751
+ );
2752
+ if (!result) {
2753
+ throw new MastraError({
2754
+ id: createStorageErrorId("MONGODB", "BULK_DELETE_ITEMS", "DATASET_NOT_FOUND"),
2755
+ domain: ErrorDomain.STORAGE,
2756
+ category: ErrorCategory.USER,
2757
+ details: { datasetId: input.datasetId }
2758
+ });
2759
+ }
2760
+ const newVersion = result.version;
2761
+ const parentOrganizationId = result.organizationId ?? null;
2762
+ const parentProjectId = result.projectId ?? null;
2763
+ const tombstones = currentItems.map((item) => ({
2764
+ id: item.id,
2765
+ datasetId: input.datasetId,
2766
+ datasetVersion: newVersion,
2767
+ organizationId: parentOrganizationId,
2768
+ projectId: parentProjectId,
2769
+ validTo: null,
2770
+ isDeleted: true,
2771
+ input: item.input,
2772
+ groundTruth: item.groundTruth,
2773
+ expectedTrajectory: item.expectedTrajectory ?? null,
2774
+ toolMocks: item.toolMocks ?? null,
2775
+ requestContext: item.requestContext,
2776
+ metadata: item.metadata,
2777
+ source: item.source,
2778
+ createdAt: item.createdAt,
2779
+ updatedAt: now
2780
+ }));
2781
+ await itemsCollection.updateMany(
2782
+ { id: { $in: currentIds }, validTo: null, isDeleted: false },
2783
+ { $set: { validTo: newVersion } },
2784
+ { session }
2785
+ );
2786
+ await itemsCollection.insertMany(tombstones, { session });
2787
+ await versionsCollection.insertOne(
2788
+ {
2789
+ id: versionId,
2790
+ datasetId: input.datasetId,
2791
+ version: newVersion,
2792
+ createdAt: now
2793
+ },
2794
+ { session }
2795
+ );
2649
2796
  });
2650
2797
  } catch (error) {
2651
2798
  if (error instanceof MastraError) throw error;
@@ -3544,27 +3691,27 @@ var MongoDBMCPClientsStorage = class _MongoDBMCPClientsStorage extends MCPClient
3544
3691
  createdAt: now,
3545
3692
  updatedAt: now
3546
3693
  };
3547
- await collection.insertOne(this.serializeMCPClient(newMCPClient));
3548
3694
  const snapshotConfig = {};
3549
3695
  for (const field of SNAPSHOT_FIELDS2) {
3550
- if (mcpClient[field] !== void 0) {
3551
- snapshotConfig[field] = mcpClient[field];
3552
- }
3696
+ if (mcpClient[field] !== void 0) snapshotConfig[field] = mcpClient[field];
3553
3697
  }
3554
3698
  const versionId = randomUUID();
3555
- try {
3556
- await this.createVersion({
3557
- id: versionId,
3558
- mcpClientId: mcpClient.id,
3559
- versionNumber: 1,
3560
- ...snapshotConfig,
3561
- changedFields: Object.keys(snapshotConfig),
3562
- changeMessage: "Initial version"
3563
- });
3564
- } catch (versionError) {
3565
- await collection.deleteOne({ id: mcpClient.id });
3566
- throw versionError;
3699
+ const versionDoc = {
3700
+ id: versionId,
3701
+ mcpClientId: mcpClient.id,
3702
+ versionNumber: 1,
3703
+ changedFields: Object.keys(snapshotConfig),
3704
+ changeMessage: "Initial version",
3705
+ createdAt: /* @__PURE__ */ new Date()
3706
+ };
3707
+ for (const field of SNAPSHOT_FIELDS2) {
3708
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
3567
3709
  }
3710
+ await this.#connector.withTransaction(async (session) => {
3711
+ await collection.insertOne(this.serializeMCPClient(newMCPClient), { session });
3712
+ const versionsCol = await this.getCollection(TABLE_MCP_CLIENT_VERSIONS);
3713
+ await versionsCol.insertOne(versionDoc, { session });
3714
+ });
3568
3715
  return newMCPClient;
3569
3716
  } catch (error) {
3570
3717
  if (error instanceof MastraError) {
@@ -3644,9 +3791,12 @@ var MongoDBMCPClientsStorage = class _MongoDBMCPClientsStorage extends MCPClient
3644
3791
  }
3645
3792
  async delete(id) {
3646
3793
  try {
3647
- await this.deleteVersionsByParentId(id);
3648
- const collection = await this.getCollection(TABLE_MCP_CLIENTS);
3649
- await collection.deleteOne({ id });
3794
+ await this.#connector.withTransaction(async (session) => {
3795
+ const versionsCol = await this.getCollection(TABLE_MCP_CLIENT_VERSIONS);
3796
+ await versionsCol.deleteMany({ mcpClientId: id }, { session });
3797
+ const col = await this.getCollection(TABLE_MCP_CLIENTS);
3798
+ await col.deleteOne({ id }, { session });
3799
+ });
3650
3800
  } catch (error) {
3651
3801
  throw new MastraError(
3652
3802
  {
@@ -4096,7 +4246,6 @@ var MongoDBMCPServersStorage = class _MongoDBMCPServersStorage extends MCPServer
4096
4246
  createdAt: now,
4097
4247
  updatedAt: now
4098
4248
  };
4099
- await collection.insertOne(this.serializeMCPServer(newMCPServer));
4100
4249
  const snapshotConfig = {};
4101
4250
  for (const field of SNAPSHOT_FIELDS3) {
4102
4251
  if (mcpServer[field] !== void 0) {
@@ -4104,19 +4253,22 @@ var MongoDBMCPServersStorage = class _MongoDBMCPServersStorage extends MCPServer
4104
4253
  }
4105
4254
  }
4106
4255
  const versionId = randomUUID();
4107
- try {
4108
- await this.createVersion({
4109
- id: versionId,
4110
- mcpServerId: mcpServer.id,
4111
- versionNumber: 1,
4112
- ...snapshotConfig,
4113
- changedFields: Object.keys(snapshotConfig),
4114
- changeMessage: "Initial version"
4115
- });
4116
- } catch (versionError) {
4117
- await collection.deleteOne({ id: mcpServer.id });
4118
- throw versionError;
4256
+ const versionDoc = {
4257
+ id: versionId,
4258
+ mcpServerId: mcpServer.id,
4259
+ versionNumber: 1,
4260
+ changedFields: Object.keys(snapshotConfig),
4261
+ changeMessage: "Initial version",
4262
+ createdAt: /* @__PURE__ */ new Date()
4263
+ };
4264
+ for (const field of SNAPSHOT_FIELDS3) {
4265
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
4119
4266
  }
4267
+ await this.#connector.withTransaction(async (session) => {
4268
+ await collection.insertOne(this.serializeMCPServer(newMCPServer), { session });
4269
+ const versionsCol = await this.getCollection(TABLE_MCP_SERVER_VERSIONS);
4270
+ await versionsCol.insertOne(versionDoc, { session });
4271
+ });
4120
4272
  return newMCPServer;
4121
4273
  } catch (error) {
4122
4274
  if (error instanceof MastraError) {
@@ -4196,9 +4348,12 @@ var MongoDBMCPServersStorage = class _MongoDBMCPServersStorage extends MCPServer
4196
4348
  }
4197
4349
  async delete(id) {
4198
4350
  try {
4199
- await this.deleteVersionsByParentId(id);
4200
- const collection = await this.getCollection(TABLE_MCP_SERVERS);
4201
- await collection.deleteOne({ id });
4351
+ await this.#connector.withTransaction(async (session) => {
4352
+ const versionsCol = await this.getCollection(TABLE_MCP_SERVER_VERSIONS);
4353
+ await versionsCol.deleteMany({ mcpServerId: id }, { session });
4354
+ const col = await this.getCollection(TABLE_MCP_SERVERS);
4355
+ await col.deleteOne({ id }, { session });
4356
+ });
4202
4357
  } catch (error) {
4203
4358
  if (error instanceof MastraError) throw error;
4204
4359
  throw new MastraError(
@@ -4554,24 +4709,24 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
4554
4709
  */
4555
4710
  getDefaultIndexDefinitions() {
4556
4711
  return [
4557
- // Threads collection indexes
4712
+ // Threads: point lookups (id) + resource-scoped listing sorted by createdAt or updatedAt.
4713
+ // A single descending compound serves both ASC and DESC sorts, and its resourceId prefix
4714
+ // covers resourceId-only filters. Unfiltered (no resourceId) listing is a rare admin path
4715
+ // left to an in-memory sort rather than carrying standalone single-field sort indexes.
4558
4716
  { collection: TABLE_THREADS, keys: { id: 1 }, options: { unique: true } },
4559
- { collection: TABLE_THREADS, keys: { resourceId: 1 } },
4560
- { collection: TABLE_THREADS, keys: { createdAt: -1 } },
4561
- { collection: TABLE_THREADS, keys: { updatedAt: -1 } },
4562
- // Messages collection indexes
4717
+ { collection: TABLE_THREADS, keys: { resourceId: 1, createdAt: -1 } },
4718
+ { collection: TABLE_THREADS, keys: { resourceId: 1, updatedAt: -1 } },
4719
+ // Messages: point lookups (id) + per-thread retrieval (listMessages) and per-resource
4720
+ // retrieval (listMessagesByResourceId), both sorted by createdAt. The compound prefixes
4721
+ // cover thread_id-only and resourceId-only filters.
4563
4722
  { collection: TABLE_MESSAGES, keys: { id: 1 }, options: { unique: true } },
4564
- { collection: TABLE_MESSAGES, keys: { thread_id: 1 } },
4565
- { collection: TABLE_MESSAGES, keys: { resourceId: 1 } },
4566
- { collection: TABLE_MESSAGES, keys: { createdAt: -1 } },
4567
4723
  { collection: TABLE_MESSAGES, keys: { thread_id: 1, createdAt: 1 } },
4568
- // Resources collection indexes
4724
+ { collection: TABLE_MESSAGES, keys: { resourceId: 1, createdAt: 1 } },
4725
+ // Resources: only ever fetched by id.
4569
4726
  { collection: TABLE_RESOURCES, keys: { id: 1 }, options: { unique: true } },
4570
- { collection: TABLE_RESOURCES, keys: { createdAt: -1 } },
4571
- { collection: TABLE_RESOURCES, keys: { updatedAt: -1 } },
4572
- // Observational Memory collection indexes
4727
+ // Observational Memory: point lookups (id) + latest-generation-per-lookupKey. The compound
4728
+ // prefix covers lookupKey-only filters.
4573
4729
  { collection: OM_TABLE, keys: { id: 1 }, options: { unique: true } },
4574
- { collection: OM_TABLE, keys: { lookupKey: 1 } },
4575
4730
  { collection: OM_TABLE, keys: { lookupKey: 1, generationCount: -1 } }
4576
4731
  ];
4577
4732
  }
@@ -4587,7 +4742,16 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
4587
4742
  const collection = await this.getCollection(indexDef.collection);
4588
4743
  await collection.createIndex(indexDef.keys, indexDef.options);
4589
4744
  } catch (error) {
4590
- this.logger?.warn?.(`Failed to create index on ${indexDef.collection}:`, error);
4745
+ throw new MastraError(
4746
+ {
4747
+ id: createStorageErrorId("MONGODB", "CREATE_DEFAULT_INDEXES", "FAILED"),
4748
+ domain: ErrorDomain.STORAGE,
4749
+ category: ErrorCategory.THIRD_PARTY,
4750
+ text: `Failed to create default index on collection "${indexDef.collection}". Set skipDefaultIndexes to manage indexes yourself.`,
4751
+ details: { collection: indexDef.collection }
4752
+ },
4753
+ error
4754
+ );
4591
4755
  }
4592
4756
  }
4593
4757
  }
@@ -4608,13 +4772,17 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
4608
4772
  }
4609
4773
  }
4610
4774
  async dangerouslyClearAll() {
4611
- const threadsCollection = await this.getCollection(TABLE_THREADS);
4612
- const messagesCollection = await this.getCollection(TABLE_MESSAGES);
4613
- const resourcesCollection = await this.getCollection(TABLE_RESOURCES);
4775
+ const [threadsCollection, messagesCollection, resourcesCollection, omCollection] = await Promise.all([
4776
+ this.getCollection(TABLE_THREADS),
4777
+ this.getCollection(TABLE_MESSAGES),
4778
+ this.getCollection(TABLE_RESOURCES),
4779
+ this.getCollection(OM_TABLE)
4780
+ ]);
4614
4781
  await Promise.all([
4615
4782
  threadsCollection.deleteMany({}),
4616
4783
  messagesCollection.deleteMany({}),
4617
- resourcesCollection.deleteMany({})
4784
+ resourcesCollection.deleteMany({}),
4785
+ omCollection.deleteMany({})
4618
4786
  ]);
4619
4787
  }
4620
4788
  parseRow(row) {
@@ -4988,10 +5156,14 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
4988
5156
  }
4989
5157
  };
4990
5158
  });
4991
- await Promise.all([
4992
- collection.bulkWrite(messagesToInsert),
4993
- threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
4994
- ]);
5159
+ const allThreadIds = new Set(messages.map((m) => m.threadId));
5160
+ const now = /* @__PURE__ */ new Date();
5161
+ await this.#connector.withTransaction(async (session) => {
5162
+ await collection.bulkWrite(messagesToInsert, { session });
5163
+ for (const tid of allThreadIds) {
5164
+ await threadsCollection.updateOne({ id: tid }, { $set: { updatedAt: now } }, { session });
5165
+ }
5166
+ });
4995
5167
  const list = new MessageList().add(messages, "memory");
4996
5168
  return { messages: list.get.all.db() };
4997
5169
  } catch (error) {
@@ -5110,10 +5282,7 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
5110
5282
  await collection.updateOne(
5111
5283
  { id: resource.id },
5112
5284
  {
5113
- $set: {
5114
- ...resource,
5115
- metadata: JSON.stringify(resource.metadata)
5116
- }
5285
+ $set: { ...resource }
5117
5286
  },
5118
5287
  { upsert: true }
5119
5288
  );
@@ -5159,7 +5328,7 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends MemoryStorage {
5159
5328
  updateDoc.workingMemory = workingMemory;
5160
5329
  }
5161
5330
  if (metadata) {
5162
- updateDoc.metadata = JSON.stringify(updatedResource.metadata);
5331
+ updateDoc.metadata = updatedResource.metadata;
5163
5332
  }
5164
5333
  await collection.updateOne({ id: resourceId }, { $set: updateDoc });
5165
5334
  return updatedResource;
@@ -7404,9 +7573,13 @@ Note: This migration may take some time for large collections.
7404
7573
  });
7405
7574
  if (records.length > 0) {
7406
7575
  const collection = await this.getCollection(TABLE_SPANS);
7407
- await collection.insertMany(records);
7576
+ await collection.insertMany(records, { ordered: false });
7408
7577
  }
7409
7578
  } catch (error) {
7579
+ if (error instanceof MongoBulkWriteError) {
7580
+ const writeErrors = Array.isArray(error.writeErrors) ? error.writeErrors : [error.writeErrors];
7581
+ if (writeErrors.length > 0 && writeErrors.every((e) => e.code === 11e3)) return;
7582
+ }
7410
7583
  throw new MastraError(
7411
7584
  {
7412
7585
  id: createStorageErrorId("MONGODB", "BATCH_CREATE_SPANS", "FAILED"),
@@ -7606,7 +7779,6 @@ var MongoDBPromptBlocksStorage = class _MongoDBPromptBlocksStorage extends Promp
7606
7779
  createdAt: now,
7607
7780
  updatedAt: now
7608
7781
  };
7609
- await collection.insertOne(this.serializeBlock(newBlock));
7610
7782
  const snapshotConfig = {};
7611
7783
  for (const field of SNAPSHOT_FIELDS4) {
7612
7784
  if (promptBlock[field] !== void 0) {
@@ -7614,13 +7786,21 @@ var MongoDBPromptBlocksStorage = class _MongoDBPromptBlocksStorage extends Promp
7614
7786
  }
7615
7787
  }
7616
7788
  const versionId = randomUUID();
7617
- await this.createVersion({
7789
+ const versionDoc = {
7618
7790
  id: versionId,
7619
7791
  blockId: promptBlock.id,
7620
7792
  versionNumber: 1,
7621
- ...snapshotConfig,
7622
7793
  changedFields: Object.keys(snapshotConfig),
7623
- changeMessage: "Initial version"
7794
+ changeMessage: "Initial version",
7795
+ createdAt: /* @__PURE__ */ new Date()
7796
+ };
7797
+ for (const field of SNAPSHOT_FIELDS4) {
7798
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
7799
+ }
7800
+ await this.#connector.withTransaction(async (session) => {
7801
+ await collection.insertOne(this.serializeBlock(newBlock), { session });
7802
+ const versionsCol = await this.getCollection(TABLE_PROMPT_BLOCK_VERSIONS);
7803
+ await versionsCol.insertOne(versionDoc, { session });
7624
7804
  });
7625
7805
  return newBlock;
7626
7806
  } catch (error) {
@@ -7701,9 +7881,12 @@ var MongoDBPromptBlocksStorage = class _MongoDBPromptBlocksStorage extends Promp
7701
7881
  }
7702
7882
  async delete(id) {
7703
7883
  try {
7704
- await this.deleteVersionsByParentId(id);
7705
- const collection = await this.getCollection(TABLE_PROMPT_BLOCKS);
7706
- await collection.deleteOne({ id });
7884
+ await this.#connector.withTransaction(async (session) => {
7885
+ const versionsCol = await this.getCollection(TABLE_PROMPT_BLOCK_VERSIONS);
7886
+ await versionsCol.deleteMany({ blockId: id }, { session });
7887
+ const col = await this.getCollection(TABLE_PROMPT_BLOCKS);
7888
+ await col.deleteOne({ id }, { session });
7889
+ });
7707
7890
  } catch (error) {
7708
7891
  throw new MastraError(
7709
7892
  {
@@ -8223,10 +8406,12 @@ var SchedulesMongoDB = class _SchedulesMongoDB extends SchedulesStorage {
8223
8406
  return result.matchedCount > 0;
8224
8407
  }
8225
8408
  async deleteSchedule(id) {
8226
- const triggers = await this.getTriggersCollection();
8227
- await triggers.deleteMany({ schedule_id: id });
8228
- const schedules = await this.getSchedulesCollection();
8229
- await schedules.deleteOne({ id });
8409
+ await this.#connector.withTransaction(async (session) => {
8410
+ const triggers = await this.getTriggersCollection();
8411
+ await triggers.deleteMany({ schedule_id: id }, { session });
8412
+ const schedules = await this.getSchedulesCollection();
8413
+ await schedules.deleteOne({ id }, { session });
8414
+ });
8230
8415
  }
8231
8416
  async recordTrigger(trigger) {
8232
8417
  const collection = await this.getTriggersCollection();
@@ -8373,7 +8558,6 @@ var MongoDBScorerDefinitionsStorage = class _MongoDBScorerDefinitionsStorage ext
8373
8558
  createdAt: now,
8374
8559
  updatedAt: now
8375
8560
  };
8376
- await collection.insertOne(this.serializeScorerDefinition(newScorerDefinition));
8377
8561
  const snapshotConfig = {};
8378
8562
  for (const field of SNAPSHOT_FIELDS5) {
8379
8563
  if (scorerDefinition[field] !== void 0) {
@@ -8381,13 +8565,21 @@ var MongoDBScorerDefinitionsStorage = class _MongoDBScorerDefinitionsStorage ext
8381
8565
  }
8382
8566
  }
8383
8567
  const versionId = randomUUID();
8384
- await this.createVersion({
8568
+ const versionDoc = {
8385
8569
  id: versionId,
8386
8570
  scorerDefinitionId: scorerDefinition.id,
8387
8571
  versionNumber: 1,
8388
- ...snapshotConfig,
8389
8572
  changedFields: Object.keys(snapshotConfig),
8390
- changeMessage: "Initial version"
8573
+ changeMessage: "Initial version",
8574
+ createdAt: /* @__PURE__ */ new Date()
8575
+ };
8576
+ for (const field of SNAPSHOT_FIELDS5) {
8577
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
8578
+ }
8579
+ await this.#connector.withTransaction(async (session) => {
8580
+ await collection.insertOne(this.serializeScorerDefinition(newScorerDefinition), { session });
8581
+ const versionsCol = await this.getCollection(TABLE_SCORER_DEFINITION_VERSIONS);
8582
+ await versionsCol.insertOne(versionDoc, { session });
8391
8583
  });
8392
8584
  return newScorerDefinition;
8393
8585
  } catch (error) {
@@ -8468,9 +8660,12 @@ var MongoDBScorerDefinitionsStorage = class _MongoDBScorerDefinitionsStorage ext
8468
8660
  }
8469
8661
  async delete(id) {
8470
8662
  try {
8471
- await this.deleteVersionsByParentId(id);
8472
- const collection = await this.getCollection(TABLE_SCORER_DEFINITIONS);
8473
- await collection.deleteOne({ id });
8663
+ await this.#connector.withTransaction(async (session) => {
8664
+ const versionsCol = await this.getCollection(TABLE_SCORER_DEFINITION_VERSIONS);
8665
+ await versionsCol.deleteMany({ scorerDefinitionId: id }, { session });
8666
+ const col = await this.getCollection(TABLE_SCORER_DEFINITIONS);
8667
+ await col.deleteOne({ id }, { session });
8668
+ });
8474
8669
  } catch (error) {
8475
8670
  throw new MastraError(
8476
8671
  {
@@ -9292,27 +9487,27 @@ var MongoDBSkillsStorage = class _MongoDBSkillsStorage extends SkillsStorage {
9292
9487
  createdAt: now,
9293
9488
  updatedAt: now
9294
9489
  };
9295
- await collection.insertOne(this.serializeSkill(newSkill));
9296
9490
  const snapshotConfig = {};
9297
9491
  for (const field of SNAPSHOT_FIELDS6) {
9298
- if (skill[field] !== void 0) {
9299
- snapshotConfig[field] = skill[field];
9300
- }
9492
+ if (skill[field] !== void 0) snapshotConfig[field] = skill[field];
9301
9493
  }
9302
9494
  const versionId = randomUUID();
9303
- try {
9304
- await this.createVersion({
9305
- id: versionId,
9306
- skillId: id,
9307
- versionNumber: 1,
9308
- ...snapshotConfig,
9309
- changedFields: Object.keys(snapshotConfig),
9310
- changeMessage: "Initial version"
9311
- });
9312
- } catch (versionError) {
9313
- await collection.deleteOne({ id });
9314
- throw versionError;
9495
+ const versionDoc = {
9496
+ id: versionId,
9497
+ skillId: id,
9498
+ versionNumber: 1,
9499
+ changedFields: Object.keys(snapshotConfig),
9500
+ changeMessage: "Initial version",
9501
+ createdAt: /* @__PURE__ */ new Date()
9502
+ };
9503
+ for (const field of SNAPSHOT_FIELDS6) {
9504
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
9315
9505
  }
9506
+ await this.#connector.withTransaction(async (session) => {
9507
+ await collection.insertOne(this.serializeSkill(newSkill), { session });
9508
+ const versionsCol = await this.getCollection(TABLE_SKILL_VERSIONS);
9509
+ await versionsCol.insertOne(versionDoc, { session });
9510
+ });
9316
9511
  return newSkill;
9317
9512
  } catch (error) {
9318
9513
  if (error instanceof MastraError) {
@@ -9358,6 +9553,18 @@ var MongoDBSkillsStorage = class _MongoDBSkillsStorage extends SkillsStorage {
9358
9553
  configFields[field] = updates[field];
9359
9554
  }
9360
9555
  }
9556
+ if (metadataFields.authorId !== void 0) updateDoc.authorId = metadataFields.authorId;
9557
+ if (metadataFields.visibility !== void 0) updateDoc.visibility = metadataFields.visibility;
9558
+ if (metadataFields.activeVersionId !== void 0) {
9559
+ updateDoc.activeVersionId = metadataFields.activeVersionId;
9560
+ if (metadataFields.status === void 0) {
9561
+ updateDoc.status = "published";
9562
+ }
9563
+ }
9564
+ if (metadataFields.status !== void 0) {
9565
+ updateDoc.status = metadataFields.status;
9566
+ }
9567
+ let newVersionDoc = null;
9361
9568
  if (Object.keys(configFields).length > 0) {
9362
9569
  const latestVersion = await this.getLatestVersion(id);
9363
9570
  if (!latestVersion) {
@@ -9377,29 +9584,28 @@ var MongoDBSkillsStorage = class _MongoDBSkillsStorage extends SkillsStorage {
9377
9584
  )
9378
9585
  );
9379
9586
  if (changedFields.length > 0) {
9380
- await this.createVersion({
9587
+ const mergedSnapshot = { ...existingSnapshot, ...configFields };
9588
+ newVersionDoc = {
9381
9589
  id: randomUUID(),
9382
9590
  skillId: id,
9383
9591
  versionNumber: latestVersion.versionNumber + 1,
9384
- ...existingSnapshot,
9385
- ...configFields,
9386
9592
  changedFields,
9387
- changeMessage: `Updated: ${changedFields.join(", ")}`
9388
- });
9593
+ changeMessage: `Updated: ${changedFields.join(", ")}`,
9594
+ createdAt: /* @__PURE__ */ new Date()
9595
+ };
9596
+ for (const field of SNAPSHOT_FIELDS6) {
9597
+ if (mergedSnapshot[field] !== void 0) newVersionDoc[field] = mergedSnapshot[field];
9598
+ }
9389
9599
  }
9390
9600
  }
9391
- if (metadataFields.authorId !== void 0) updateDoc.authorId = metadataFields.authorId;
9392
- if (metadataFields.visibility !== void 0) updateDoc.visibility = metadataFields.visibility;
9393
- if (metadataFields.activeVersionId !== void 0) {
9394
- updateDoc.activeVersionId = metadataFields.activeVersionId;
9395
- if (metadataFields.status === void 0) {
9396
- updateDoc.status = "published";
9601
+ await this.#connector.withTransaction(async (session) => {
9602
+ if (newVersionDoc) {
9603
+ const versionsCol = await this.getCollection(TABLE_SKILL_VERSIONS);
9604
+ await versionsCol.insertOne(newVersionDoc, { session });
9397
9605
  }
9398
- }
9399
- if (metadataFields.status !== void 0) {
9400
- updateDoc.status = metadataFields.status;
9401
- }
9402
- await collection.updateOne({ id }, { $set: updateDoc });
9606
+ const col = await this.getCollection(TABLE_SKILLS);
9607
+ await col.updateOne({ id }, { $set: updateDoc }, { session });
9608
+ });
9403
9609
  const updatedSkill = await collection.findOne({ id });
9404
9610
  if (!updatedSkill) {
9405
9611
  throw new MastraError({
@@ -9428,9 +9634,12 @@ var MongoDBSkillsStorage = class _MongoDBSkillsStorage extends SkillsStorage {
9428
9634
  }
9429
9635
  async delete(id) {
9430
9636
  try {
9431
- await this.deleteVersionsByParentId(id);
9432
- const collection = await this.getCollection(TABLE_SKILLS);
9433
- await collection.deleteOne({ id });
9637
+ await this.#connector.withTransaction(async (session) => {
9638
+ const versionsCol = await this.getCollection(TABLE_SKILL_VERSIONS);
9639
+ await versionsCol.deleteMany({ skillId: id }, { session });
9640
+ const col = await this.getCollection(TABLE_SKILLS);
9641
+ await col.deleteOne({ id }, { session });
9642
+ });
9434
9643
  } catch (error) {
9435
9644
  throw new MastraError(
9436
9645
  {
@@ -9920,16 +10129,10 @@ var WorkflowsStorageMongoDB = class _WorkflowsStorageMongoDB extends WorkflowsSt
9920
10129
  try {
9921
10130
  const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
9922
10131
  const updatedDoc = await collection.findOneAndUpdate(
9923
- {
9924
- workflow_name: workflowName,
9925
- run_id: runId,
9926
- // Only update if snapshot exists and has context
9927
- "snapshot.context": { $exists: true }
9928
- },
10132
+ { workflow_name: workflowName, run_id: runId },
9929
10133
  [
9930
10134
  {
9931
10135
  $set: {
9932
- // Merge the new options into the existing snapshot
9933
10136
  snapshot: {
9934
10137
  $mergeObjects: ["$snapshot", opts]
9935
10138
  },
@@ -9943,8 +10146,18 @@ var WorkflowsStorageMongoDB = class _WorkflowsStorageMongoDB extends WorkflowsSt
9943
10146
  return void 0;
9944
10147
  }
9945
10148
  const snapshot = typeof updatedDoc.snapshot === "string" ? JSON.parse(updatedDoc.snapshot) : updatedDoc.snapshot;
10149
+ if (!snapshot?.context) {
10150
+ throw new MastraError({
10151
+ id: createStorageErrorId("MONGODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
10152
+ domain: ErrorDomain.STORAGE,
10153
+ category: ErrorCategory.USER,
10154
+ text: `Snapshot not found for runId ${runId}`,
10155
+ details: { workflowName, runId }
10156
+ });
10157
+ }
9946
10158
  return snapshot;
9947
10159
  } catch (error) {
10160
+ if (error instanceof MastraError) throw error;
9948
10161
  throw new MastraError(
9949
10162
  {
9950
10163
  id: createStorageErrorId("MONGODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
@@ -10288,27 +10501,27 @@ var MongoDBWorkspacesStorage = class _MongoDBWorkspacesStorage extends Workspace
10288
10501
  createdAt: now,
10289
10502
  updatedAt: now
10290
10503
  };
10291
- await collection.insertOne(this.serializeWorkspace(newWorkspace));
10292
10504
  const snapshotConfig = {};
10293
10505
  for (const field of SNAPSHOT_FIELDS7) {
10294
- if (workspace[field] !== void 0) {
10295
- snapshotConfig[field] = workspace[field];
10296
- }
10506
+ if (workspace[field] !== void 0) snapshotConfig[field] = workspace[field];
10297
10507
  }
10298
10508
  const versionId = randomUUID();
10299
- try {
10300
- await this.createVersion({
10301
- id: versionId,
10302
- workspaceId: id,
10303
- versionNumber: 1,
10304
- ...snapshotConfig,
10305
- changedFields: Object.keys(snapshotConfig),
10306
- changeMessage: "Initial version"
10307
- });
10308
- } catch (versionError) {
10309
- await collection.deleteOne({ id });
10310
- throw versionError;
10509
+ const versionDoc = {
10510
+ id: versionId,
10511
+ workspaceId: id,
10512
+ versionNumber: 1,
10513
+ changedFields: Object.keys(snapshotConfig),
10514
+ changeMessage: "Initial version",
10515
+ createdAt: /* @__PURE__ */ new Date()
10516
+ };
10517
+ for (const field of SNAPSHOT_FIELDS7) {
10518
+ if (snapshotConfig[field] !== void 0) versionDoc[field] = snapshotConfig[field];
10311
10519
  }
10520
+ await this.#connector.withTransaction(async (session) => {
10521
+ await collection.insertOne(this.serializeWorkspace(newWorkspace), { session });
10522
+ const versionsCol = await this.getCollection(TABLE_WORKSPACE_VERSIONS);
10523
+ await versionsCol.insertOne(versionDoc, { session });
10524
+ });
10312
10525
  return newWorkspace;
10313
10526
  } catch (error) {
10314
10527
  if (error instanceof MastraError) {
@@ -10354,6 +10567,7 @@ var MongoDBWorkspacesStorage = class _MongoDBWorkspacesStorage extends Workspace
10354
10567
  configFields[field] = updates[field];
10355
10568
  }
10356
10569
  }
10570
+ let newVersionDoc = null;
10357
10571
  if (Object.keys(configFields).length > 0) {
10358
10572
  const latestVersion = await this.getLatestVersion(id);
10359
10573
  if (!latestVersion) {
@@ -10366,15 +10580,18 @@ var MongoDBWorkspacesStorage = class _MongoDBWorkspacesStorage extends Workspace
10366
10580
  });
10367
10581
  }
10368
10582
  const existingSnapshot = this.extractSnapshotFields(latestVersion);
10369
- await this.createVersion({
10583
+ const mergedSnapshot = { ...existingSnapshot, ...configFields };
10584
+ newVersionDoc = {
10370
10585
  id: randomUUID(),
10371
10586
  workspaceId: id,
10372
10587
  versionNumber: latestVersion.versionNumber + 1,
10373
- ...existingSnapshot,
10374
- ...configFields,
10375
10588
  changedFields: Object.keys(configFields),
10376
- changeMessage: `Updated: ${Object.keys(configFields).join(", ")}`
10377
- });
10589
+ changeMessage: `Updated: ${Object.keys(configFields).join(", ")}`,
10590
+ createdAt: /* @__PURE__ */ new Date()
10591
+ };
10592
+ for (const field of SNAPSHOT_FIELDS7) {
10593
+ if (mergedSnapshot[field] !== void 0) newVersionDoc[field] = mergedSnapshot[field];
10594
+ }
10378
10595
  }
10379
10596
  if (metadataFields.authorId !== void 0) updateDoc.authorId = metadataFields.authorId;
10380
10597
  if (metadataFields.activeVersionId !== void 0) {
@@ -10390,7 +10607,23 @@ var MongoDBWorkspacesStorage = class _MongoDBWorkspacesStorage extends Workspace
10390
10607
  const existingMetadata = existingWorkspace.metadata || {};
10391
10608
  updateDoc.metadata = { ...existingMetadata, ...metadataFields.metadata };
10392
10609
  }
10393
- await collection.updateOne({ id }, { $set: updateDoc });
10610
+ await this.#connector.withTransaction(async (session) => {
10611
+ if (newVersionDoc) {
10612
+ const versionsCol = await this.getCollection(TABLE_WORKSPACE_VERSIONS);
10613
+ await versionsCol.insertOne(newVersionDoc, { session });
10614
+ }
10615
+ const col = await this.getCollection(TABLE_WORKSPACES);
10616
+ const updateResult = await col.updateOne({ id }, { $set: updateDoc }, { session });
10617
+ if (updateResult.matchedCount === 0) {
10618
+ throw new MastraError({
10619
+ id: createStorageErrorId("MONGODB", "UPDATE_WORKSPACE", "NOT_FOUND_AFTER_UPDATE"),
10620
+ domain: ErrorDomain.STORAGE,
10621
+ category: ErrorCategory.SYSTEM,
10622
+ text: `Workspace with id ${id} was deleted during update`,
10623
+ details: { id }
10624
+ });
10625
+ }
10626
+ });
10394
10627
  const updatedWorkspace = await collection.findOne({ id });
10395
10628
  if (!updatedWorkspace) {
10396
10629
  throw new MastraError({
@@ -10419,9 +10652,12 @@ var MongoDBWorkspacesStorage = class _MongoDBWorkspacesStorage extends Workspace
10419
10652
  }
10420
10653
  async delete(id) {
10421
10654
  try {
10422
- await this.deleteVersionsByParentId(id);
10423
- const collection = await this.getCollection(TABLE_WORKSPACES);
10424
- await collection.deleteOne({ id });
10655
+ await this.#connector.withTransaction(async (session) => {
10656
+ const versionsCol = await this.getCollection(TABLE_WORKSPACE_VERSIONS);
10657
+ await versionsCol.deleteMany({ workspaceId: id }, { session });
10658
+ const col = await this.getCollection(TABLE_WORKSPACES);
10659
+ await col.deleteOne({ id }, { session });
10660
+ });
10425
10661
  } catch (error) {
10426
10662
  throw new MastraError(
10427
10663
  {