@mastra/mssql 1.10.5 → 1.10.6-alpha.1

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.
@@ -3,7 +3,7 @@ name: mastra-mssql
3
3
  description: Documentation for @mastra/mssql. Use when working with @mastra/mssql APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/mssql"
6
- version: "1.10.5"
6
+ version: "1.10.6-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.10.5",
2
+ "version": "1.10.6-alpha.1",
3
3
  "package": "@mastra/mssql",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -294,7 +294,7 @@ const storage = new MongoDBStore({
294
294
 
295
295
  ## Reclaiming disk
296
296
 
297
- `prune()` deletes rows but doesn't shrink the database file. On SQLite/libSQL the freed pages go on a freelist and are reused by future writes, so the file stops growing: for most users this alone solves the unbounded-growth problem.
297
+ `prune()` deletes rows but doesn't shrink the database file. On SQLite/libSQL the freed pages go on a freelist for reuse by future writes. Reusing these pages prevents unbounded file growth for most users.
298
298
 
299
299
  Handing that free space back to the OS is a separate concern that Mastra doesn't manage. If you specifically need to shrink the file, run the underlying database's compaction (for example `VACUUM` on self-hosted libSQL) yourself in a maintenance window. A full `VACUUM` locks the file and needs roughly twice the file size in free disk. On PostgreSQL, autovacuum reclaims dead tuples for reuse automatically. A manual `VACUUM FULL` is only needed if you must return disk to the OS.
300
300
 
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region \0rolldown/runtime.js
2
+ // \0rolldown/runtime.js
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -20,7 +20,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
20
20
  value: mod,
21
21
  enumerable: true
22
22
  }) : target, mod));
23
- //#endregion
24
23
  let _mastra_core_error = require("@mastra/core/error");
25
24
  let _mastra_core_storage = require("@mastra/core/storage");
26
25
  let mssql = require("mssql");
@@ -29,7 +28,7 @@ let _mastra_core_utils = require("@mastra/core/utils");
29
28
  let _mastra_core_base = require("@mastra/core/base");
30
29
  let _mastra_core_agent = require("@mastra/core/agent");
31
30
  let _mastra_core_evals = require("@mastra/core/evals");
32
- //#region src/storage/db/utils.ts
31
+ // src/storage/db/utils.ts
33
32
  function getSchemaName$1(schema) {
34
33
  return schema ? `[${(0, _mastra_core_utils.parseSqlIdentifier)(schema, "schema name")}]` : void 0;
35
34
  }
@@ -38,8 +37,7 @@ function getTableName$1({ indexName, schemaName }) {
38
37
  const quotedSchemaName = schemaName;
39
38
  return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
40
39
  }
41
- //#endregion
42
- //#region src/storage/db/index.ts
40
+ // src/storage/db/index.ts
43
41
  /**
44
42
  * Resolves MssqlDomainConfig to pool and schema.
45
43
  * Domain classes create their own MssqlDB instance from the returned pool.
@@ -1057,8 +1055,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
1057
1055
  }
1058
1056
  }
1059
1057
  };
1060
- //#endregion
1061
- //#region src/storage/domains/utils.ts
1058
+ // src/storage/domains/utils.ts
1062
1059
  function getSchemaName(schema) {
1063
1060
  return schema ? `[${(0, _mastra_core_utils.parseSqlIdentifier)(schema, "schema name")}]` : void 0;
1064
1061
  }
@@ -1180,8 +1177,7 @@ function transformFromSqlRow({ tableName, sqlRow }) {
1180
1177
  });
1181
1178
  return result;
1182
1179
  }
1183
- //#endregion
1184
- //#region src/storage/domains/agents/index.ts
1180
+ // src/storage/domains/agents/index.ts
1185
1181
  var AgentsMSSQL = class AgentsMSSQL extends _mastra_core_storage.AgentsStorage {
1186
1182
  pool;
1187
1183
  schema;
@@ -1769,8 +1765,7 @@ var AgentsMSSQL = class AgentsMSSQL extends _mastra_core_storage.AgentsStorage {
1769
1765
  }
1770
1766
  }
1771
1767
  };
1772
- //#endregion
1773
- //#region src/storage/domains/background-tasks/index.ts
1768
+ // src/storage/domains/background-tasks/index.ts
1774
1769
  function serializeJson(v) {
1775
1770
  if (typeof v === "object" && v != null) return JSON.stringify(v);
1776
1771
  return v ?? null;
@@ -2131,8 +2126,7 @@ var BackgroundTasksMSSQL = class BackgroundTasksMSSQL extends _mastra_core_stora
2131
2126
  return Number(result.recordset[0]?.count ?? 0);
2132
2127
  }
2133
2128
  };
2134
- //#endregion
2135
- //#region src/storage/db/run-fencing.ts
2129
+ // src/storage/db/run-fencing.ts
2136
2130
  /**
2137
2131
  * Epoch milliseconds on the database clock. SQL Server evaluates
2138
2132
  * `SYSUTCDATETIME()` once when a statement starts, so a statement that waits
@@ -2191,16 +2185,23 @@ function withRunFence(pool, claimsTable, fence, operation, write) {
2191
2185
  * duplicate key if they don't. On retry the row exists and the claim
2192
2186
  * serializes behind its row lock.
2193
2187
  */
2194
- async function claimTransaction(pool, fn) {
2188
+ function claimTransaction(pool, fn) {
2189
+ return retryWriteRace(() => inTransaction(pool, fn));
2190
+ }
2191
+ /**
2192
+ * Runs `write` again when it lost a race to insert the same row: a deadlock
2193
+ * victim or a duplicate key. `write` must be a whole statement or
2194
+ * transaction, since a deadlock victim's transaction has already ended.
2195
+ */
2196
+ async function retryWriteRace(write) {
2195
2197
  for (let attempt = 1;; attempt++) try {
2196
- return await inTransaction(pool, fn);
2198
+ return await write();
2197
2199
  } catch (error) {
2198
2200
  const number = error.number;
2199
2201
  if (attempt >= MAX_CLAIM_ATTEMPTS || !(number === ERR_DEADLOCK_VICTIM || number === ERR_PRIMARY_KEY || number === ERR_UNIQUE_INDEX)) throw error;
2200
2202
  }
2201
2203
  }
2202
- //#endregion
2203
- //#region src/storage/domains/memory/index.ts
2204
+ // src/storage/domains/memory/index.ts
2204
2205
  function bindMssqlMetadataParams(request, params) {
2205
2206
  for (const [paramName, paramValue] of Object.entries(params)) request.input(paramName, paramValue);
2206
2207
  }
@@ -3360,8 +3361,7 @@ var MemoryMSSQL = class MemoryMSSQL extends _mastra_core_storage.MemoryStorage {
3360
3361
  }
3361
3362
  }
3362
3363
  };
3363
- //#endregion
3364
- //#region src/storage/domains/observability/index.ts
3364
+ // src/storage/domains/observability/index.ts
3365
3365
  var ObservabilityMSSQL = class ObservabilityMSSQL extends _mastra_core_storage.ObservabilityStorage {
3366
3366
  static retentionTables = { spans: {
3367
3367
  table: _mastra_core_storage.TABLE_SPANS,
@@ -4002,8 +4002,7 @@ var ObservabilityMSSQL = class ObservabilityMSSQL extends _mastra_core_storage.O
4002
4002
  }
4003
4003
  }
4004
4004
  };
4005
- //#endregion
4006
- //#region src/storage/domains/scores/index.ts
4005
+ // src/storage/domains/scores/index.ts
4007
4006
  /**
4008
4007
  * MSSQL-specific score row transformation.
4009
4008
  * Converts timestamp strings to Date objects.
@@ -4419,8 +4418,7 @@ var ScoresMSSQL = class ScoresMSSQL extends _mastra_core_storage.ScoresStorage {
4419
4418
  }
4420
4419
  }
4421
4420
  };
4422
- //#endregion
4423
- //#region src/storage/domains/workflow-definitions/index.ts
4421
+ // src/storage/domains/workflow-definitions/index.ts
4424
4422
  function parseJson(value, column, rowId) {
4425
4423
  if (value == null) return null;
4426
4424
  if (typeof value === "string") try {
@@ -4623,8 +4621,7 @@ var WorkflowDefinitionsMSSQL = class WorkflowDefinitionsMSSQL extends _mastra_co
4623
4621
  await request.query(`DELETE FROM ${tableName} WHERE [id] = @id`);
4624
4622
  }
4625
4623
  };
4626
- //#endregion
4627
- //#region src/storage/domains/workflows/index.ts
4624
+ // src/storage/domains/workflows/index.ts
4628
4625
  const RUN_OWNER_COLUMNS = `[generation], [ownerId], [leaseExpiresAt], ${DB_NOW_MS} AS [nowMs]`;
4629
4626
  function toRunOwnershipRecord(runId, row) {
4630
4627
  const leaseExpiresAt = row.leaseExpiresAt === null ? null : Number(row.leaseExpiresAt);
@@ -4670,6 +4667,9 @@ var WorkflowsMSSQL = class WorkflowsMSSQL extends _mastra_core_storage.Workflows
4670
4667
  this.skipDefaultIndexes = skipDefaultIndexes;
4671
4668
  this.indexes = indexes?.filter((idx) => WorkflowsMSSQL.MANAGED_TABLES.includes(idx.table));
4672
4669
  }
4670
+ supportsGuardedSnapshotWrites() {
4671
+ return true;
4672
+ }
4673
4673
  supportsConcurrentUpdates() {
4674
4674
  return true;
4675
4675
  }
@@ -4979,14 +4979,16 @@ var WorkflowsMSSQL = class WorkflowsMSSQL extends _mastra_core_storage.Workflows
4979
4979
  }, error);
4980
4980
  }
4981
4981
  }
4982
- async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, fence }) {
4982
+ async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, fence, expectedStatus }) {
4983
4983
  const table = getTableName({
4984
4984
  indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
4985
4985
  schemaName: getSchemaName(this.schema)
4986
4986
  });
4987
4987
  const now = (/* @__PURE__ */ new Date()).toISOString();
4988
+ const expectedStatuses = expectedStatus === void 0 ? void 0 : Array.isArray(expectedStatus) ? expectedStatus : [expectedStatus];
4989
+ const guard = expectedStatuses === void 0 ? "" : expectedStatuses.length === 0 ? " AND 1 = 0" : ` AND JSON_VALUE(target.[snapshot], '$.status') IN (${expectedStatuses.map((_, i) => `@expectedStatus${i}`).join(", ")})`;
4988
4990
  try {
4989
- await withRunFence(this.pool, this.#runOwnersTable, (0, _mastra_core_storage.resolveRunFence)(this, fence, runId), "persistWorkflowSnapshot", async (q) => {
4991
+ return await retryWriteRace(() => withRunFence(this.pool, this.#runOwnersTable, (0, _mastra_core_storage.resolveRunFence)(this, fence, runId), "persistWorkflowSnapshot", async (q) => {
4990
4992
  const request = q.request();
4991
4993
  request.input("workflow_name", workflowName);
4992
4994
  request.input("run_id", runId);
@@ -4994,17 +4996,18 @@ var WorkflowsMSSQL = class WorkflowsMSSQL extends _mastra_core_storage.Workflows
4994
4996
  request.input("snapshot", JSON.stringify(snapshot));
4995
4997
  request.input("createdAt", mssql.default.DateTime2, new Date(now));
4996
4998
  request.input("updatedAt", mssql.default.DateTime2, new Date(now));
4999
+ expectedStatuses?.forEach((status, i) => request.input(`expectedStatus${i}`, status));
4997
5000
  const mergeSql = `MERGE INTO ${table} AS target
4998
5001
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
4999
5002
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
5000
- WHEN MATCHED THEN UPDATE SET
5003
+ WHEN MATCHED${guard} THEN UPDATE SET
5001
5004
  resourceId = @resourceId,
5002
5005
  snapshot = @snapshot,
5003
5006
  [updatedAt] = @updatedAt
5004
5007
  WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
5005
5008
  VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
5006
- await request.query(mergeSql);
5007
- });
5009
+ return ((await request.query(mergeSql)).rowsAffected[0] ?? 0) > 0;
5010
+ }));
5008
5011
  } catch (error) {
5009
5012
  if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
5010
5013
  throw new _mastra_core_error.MastraError({
@@ -5018,6 +5021,27 @@ var WorkflowsMSSQL = class WorkflowsMSSQL extends _mastra_core_storage.Workflows
5018
5021
  }, error);
5019
5022
  }
5020
5023
  }
5024
+ async loadWorkflowRunStatus({ workflowName, runId }) {
5025
+ try {
5026
+ const request = this.pool.request();
5027
+ request.input("workflow_name", workflowName);
5028
+ request.input("run_id", runId);
5029
+ return (await request.query(`SELECT TOP 1 JSON_VALUE([snapshot], '$.status') AS status FROM ${getTableName({
5030
+ indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
5031
+ schemaName: getSchemaName(this.schema)
5032
+ })} WHERE workflow_name = @workflow_name AND run_id = @run_id`)).recordset?.[0]?.status ?? null;
5033
+ } catch (error) {
5034
+ throw new _mastra_core_error.MastraError({
5035
+ id: (0, _mastra_core_storage.createStorageErrorId)("MSSQL", "LOAD_WORKFLOW_RUN_STATUS", "FAILED"),
5036
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
5037
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
5038
+ details: {
5039
+ workflowName,
5040
+ runId
5041
+ }
5042
+ }, error);
5043
+ }
5044
+ }
5021
5045
  async loadWorkflowSnapshot({ workflowName, runId }) {
5022
5046
  try {
5023
5047
  const result = await this.db.load({
@@ -5161,8 +5185,7 @@ var WorkflowsMSSQL = class WorkflowsMSSQL extends _mastra_core_storage.Workflows
5161
5185
  }
5162
5186
  }
5163
5187
  };
5164
- //#endregion
5165
- //#region src/storage/index.ts
5188
+ // src/storage/index.ts
5166
5189
  /**
5167
5190
  * Type guard for pre-configured pool config
5168
5191
  */
@@ -5275,12 +5298,8 @@ var MSSQLStore = class extends _mastra_core_storage.MastraCompositeStore {
5275
5298
  }
5276
5299
  }
5277
5300
  async _performInitializationAndStore() {
5278
- try {
5279
- await this.pool.connect();
5280
- return true;
5281
- } catch (err) {
5282
- throw err;
5283
- }
5301
+ await this.pool.connect();
5302
+ return true;
5284
5303
  }
5285
5304
  /**
5286
5305
  * Closes the MSSQL connection pool.
@@ -5291,7 +5310,6 @@ var MSSQLStore = class extends _mastra_core_storage.MastraCompositeStore {
5291
5310
  await this.pool.close();
5292
5311
  }
5293
5312
  };
5294
- //#endregion
5295
5313
  exports.AgentsMSSQL = AgentsMSSQL;
5296
5314
  exports.BackgroundTasksMSSQL = BackgroundTasksMSSQL;
5297
5315
  exports.MSSQLStore = MSSQLStore;