@mastra/redis 1.4.6-alpha.0 → 1.4.7-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.
@@ -3,7 +3,7 @@ name: mastra-redis
3
3
  description: Documentation for @mastra/redis. Use when working with @mastra/redis APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/redis"
6
- version: "1.4.6-alpha.0"
6
+ version: "1.4.7-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.4.6-alpha.0",
2
+ "version": "1.4.7-alpha.0",
3
3
  "package": "@mastra/redis",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -60,8 +60,7 @@ function processRecord(tableName, record) {
60
60
  else if (tableName === _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT) key = getKey(tableName, {
61
61
  namespace: record.namespace || "workflows",
62
62
  workflow_name: record.workflow_name,
63
- run_id: record.run_id,
64
- ...record.resourceId ? { resourceId: record.resourceId } : {}
63
+ run_id: record.run_id
65
64
  });
66
65
  else key = getKey(tableName, { id: record.id });
67
66
  const processedRecord = {
@@ -1195,6 +1194,22 @@ function parseWorkflowRun(row) {
1195
1194
  resourceId: row.resourceId
1196
1195
  };
1197
1196
  }
1197
+ function escapeGlob(value) {
1198
+ return value.replace(/[*?[\]\\]/g, "\\$&");
1199
+ }
1200
+ function snapshotKey(namespace, workflowName, runId) {
1201
+ return getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1202
+ namespace,
1203
+ workflow_name: workflowName,
1204
+ run_id: runId
1205
+ });
1206
+ }
1207
+ /**
1208
+ * Earlier versions appended `:resourceId:<id>` to snapshot keys. Matches those keys for a run.
1209
+ */
1210
+ function legacySnapshotKeyPattern(namespace, workflowName, runId) {
1211
+ return `${escapeGlob(snapshotKey(namespace, workflowName, runId))}:resourceId:*`;
1212
+ }
1198
1213
  var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1199
1214
  client;
1200
1215
  db;
@@ -1203,6 +1218,18 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1203
1218
  this.client = config.client;
1204
1219
  this.db = new RedisDB({ client: config.client });
1205
1220
  }
1221
+ /**
1222
+ * Reads a run's snapshot record by its canonical key, falling back to legacy
1223
+ * `:resourceId:`-suffixed keys only when the canonical key is missing.
1224
+ */
1225
+ async getSnapshotRecord(namespace, workflowName, runId) {
1226
+ const data = await this.client.get(snapshotKey(namespace, workflowName, runId));
1227
+ if (data) return JSON.parse(data);
1228
+ const legacyKeys = await this.db.scanKeys(legacySnapshotKeyPattern(namespace, workflowName, runId));
1229
+ if (legacyKeys.length === 0) return null;
1230
+ const legacyData = await this.client.get(legacyKeys[0]);
1231
+ return legacyData ? JSON.parse(legacyData) : null;
1232
+ }
1206
1233
  supportsConcurrentUpdates() {
1207
1234
  return false;
1208
1235
  }
@@ -1211,14 +1238,7 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1211
1238
  }
1212
1239
  async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
1213
1240
  try {
1214
- const existingRecord = await this.db.get({
1215
- tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1216
- keys: {
1217
- namespace: "workflows",
1218
- workflow_name: workflowName,
1219
- run_id: runId
1220
- }
1221
- });
1241
+ const existingRecord = await this.getSnapshotRecord("workflows", workflowName, runId);
1222
1242
  let snapshot = existingRecord?.snapshot;
1223
1243
  if (!snapshot) snapshot = {
1224
1244
  context: {},
@@ -1243,6 +1263,7 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1243
1263
  namespace: "workflows",
1244
1264
  workflowName,
1245
1265
  runId,
1266
+ resourceId: existingRecord?.resourceId,
1246
1267
  snapshot,
1247
1268
  createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
1248
1269
  });
@@ -1263,14 +1284,7 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1263
1284
  }
1264
1285
  async updateWorkflowState({ workflowName, runId, opts }) {
1265
1286
  try {
1266
- const existingRecord = await this.db.get({
1267
- tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1268
- keys: {
1269
- namespace: "workflows",
1270
- workflow_name: workflowName,
1271
- run_id: runId
1272
- }
1273
- });
1287
+ const existingRecord = await this.getSnapshotRecord("workflows", workflowName, runId);
1274
1288
  const existingSnapshot = existingRecord?.snapshot;
1275
1289
  if (!existingSnapshot || !existingSnapshot.context) return;
1276
1290
  const { expectedStatus, ...state } = opts;
@@ -1283,6 +1297,7 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1283
1297
  namespace: "workflows",
1284
1298
  workflowName,
1285
1299
  runId,
1300
+ resourceId: existingRecord.resourceId,
1286
1301
  snapshot: updatedSnapshot,
1287
1302
  createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
1288
1303
  });
@@ -1304,16 +1319,13 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1304
1319
  const { namespace = "workflows", workflowName, runId, resourceId, snapshot, createdAt, updatedAt } = params;
1305
1320
  try {
1306
1321
  let finalCreatedAt = createdAt;
1307
- if (!finalCreatedAt) {
1308
- const existing = await this.db.get({
1309
- tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1310
- keys: {
1311
- namespace,
1312
- workflow_name: workflowName,
1313
- run_id: runId
1314
- }
1315
- });
1316
- finalCreatedAt = existing?.createdAt ? (0, _mastra_core_storage.ensureDate)(existing.createdAt) : /* @__PURE__ */ new Date();
1322
+ let finalResourceId = resourceId;
1323
+ if (!finalCreatedAt || !finalResourceId) {
1324
+ const canonicalKey = snapshotKey(namespace, workflowName, runId);
1325
+ const existingData = await this.client.get(canonicalKey) ?? (resourceId ? await this.client.get(`${canonicalKey}:resourceId:${resourceId}`) : null);
1326
+ const existing = existingData ? JSON.parse(existingData) : null;
1327
+ finalCreatedAt ??= existing?.createdAt ? (0, _mastra_core_storage.ensureDate)(existing.createdAt) : /* @__PURE__ */ new Date();
1328
+ finalResourceId ??= existing?.resourceId;
1317
1329
  }
1318
1330
  await this.db.insert({
1319
1331
  tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
@@ -1321,7 +1333,7 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1321
1333
  namespace,
1322
1334
  workflow_name: workflowName,
1323
1335
  run_id: runId,
1324
- resourceId,
1336
+ resourceId: finalResourceId,
1325
1337
  snapshot,
1326
1338
  createdAt: finalCreatedAt,
1327
1339
  updatedAt: updatedAt ?? /* @__PURE__ */ new Date()
@@ -1342,15 +1354,8 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1342
1354
  }
1343
1355
  async loadWorkflowSnapshot(params) {
1344
1356
  const { namespace = "workflows", workflowName, runId } = params;
1345
- const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1346
- namespace,
1347
- workflow_name: workflowName,
1348
- run_id: runId
1349
- });
1350
1357
  try {
1351
- const data = await this.client.get(key);
1352
- if (!data) return null;
1353
- return JSON.parse(data).snapshot;
1358
+ return (await this.getSnapshotRecord(namespace, workflowName, runId))?.snapshot ?? null;
1354
1359
  } catch (error) {
1355
1360
  throw new _mastra_core_error.MastraError({
1356
1361
  id: (0, _mastra_core_storage.createStorageErrorId)("REDIS", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
@@ -1366,12 +1371,9 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1366
1371
  }
1367
1372
  async getWorkflowRunById({ runId, workflowName }) {
1368
1373
  try {
1369
- const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1370
- namespace: "workflows",
1371
- workflow_name: workflowName,
1372
- run_id: runId
1373
- }) + "*";
1374
- const keys = await this.db.scanKeys(key);
1374
+ const workflowNamePattern = workflowName ? escapeGlob(workflowName) : "*";
1375
+ const canonicalPattern = `${escapeGlob(getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" }))}:workflow_name:${workflowNamePattern}:run_id:${escapeGlob(runId)}`;
1376
+ const keys = [...await this.db.scanKeys(canonicalPattern), ...await this.db.scanKeys(`${canonicalPattern}:resourceId:*`)];
1375
1377
  if (keys.length === 0) return null;
1376
1378
  const data = (await this.client.mGet(keys)).filter((data) => data !== null).map((data) => JSON.parse(data)).find((workflow) => {
1377
1379
  if (!workflow) return false;
@@ -1395,13 +1397,9 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1395
1397
  }
1396
1398
  }
1397
1399
  async deleteWorkflowRunById({ runId, workflowName }) {
1398
- const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1399
- namespace: "workflows",
1400
- workflow_name: workflowName,
1401
- run_id: runId
1402
- });
1403
1400
  try {
1404
- await this.client.del(key);
1401
+ const legacyKeys = await this.db.scanKeys(legacySnapshotKeyPattern("workflows", workflowName, runId));
1402
+ await this.client.del([snapshotKey("workflows", workflowName, runId), ...legacyKeys]);
1405
1403
  } catch (error) {
1406
1404
  throw new _mastra_core_error.MastraError({
1407
1405
  id: (0, _mastra_core_storage.createStorageErrorId)("REDIS", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
@@ -1425,29 +1423,30 @@ var WorkflowsRedis = class extends _mastra_core_storage.WorkflowsStorage {
1425
1423
  }, /* @__PURE__ */ new Error("page must be >= 0"));
1426
1424
  const normalizedFrom = fromDate ? (0, _mastra_core_storage.ensureDate)(fromDate) : void 0;
1427
1425
  const normalizedTo = toDate ? (0, _mastra_core_storage.ensureDate)(toDate) : void 0;
1428
- let pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" }) + ":*";
1429
- if (workflowName && resourceId) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1430
- namespace: "workflows",
1431
- workflow_name: workflowName,
1432
- run_id: "*",
1433
- resourceId
1434
- });
1435
- else if (workflowName) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1426
+ const pattern = workflowName ? `${escapeGlob(getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1436
1427
  namespace: "workflows",
1437
1428
  workflow_name: workflowName
1438
- }) + ":*";
1439
- else if (resourceId) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1440
- namespace: "workflows",
1441
- workflow_name: "*",
1442
- run_id: "*",
1443
- resourceId
1444
- });
1429
+ }))}:*` : `${getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" })}:*`;
1445
1430
  const keys = await this.db.scanKeys(pattern);
1446
1431
  if (keys.length === 0) return {
1447
1432
  runs: [],
1448
1433
  total: 0
1449
1434
  };
1450
- let runs = (await this.client.mGet(keys)).filter((data) => data !== null).map((data) => JSON.parse(data)).filter((record) => record !== null && record !== void 0 && typeof record === "object" && "workflow_name" in record).filter((record) => !workflowName || record.workflow_name === workflowName).map((w) => parseWorkflowRun(w)).filter((w) => {
1435
+ const results = await this.client.mGet(keys);
1436
+ const recordsByRun = /* @__PURE__ */ new Map();
1437
+ results.forEach((data, index) => {
1438
+ if (data === null) return;
1439
+ const record = JSON.parse(data);
1440
+ if (record === null || typeof record !== "object" || !("workflow_name" in record)) return;
1441
+ const legacy = keys[index] !== snapshotKey(record.namespace ?? "workflows", record.workflow_name, record.run_id);
1442
+ const runKey = `${record.workflow_name}\u0000${record.run_id}`;
1443
+ const current = recordsByRun.get(runKey);
1444
+ if (!current || current.legacy && !legacy) recordsByRun.set(runKey, {
1445
+ record,
1446
+ legacy
1447
+ });
1448
+ });
1449
+ let runs = [...recordsByRun.values()].map(({ record }) => record).filter((record) => !workflowName || record.workflow_name === workflowName).filter((record) => !resourceId || record.resourceId === resourceId).map((w) => parseWorkflowRun(w)).filter((w) => {
1451
1450
  if (normalizedFrom && w.createdAt < normalizedFrom) return false;
1452
1451
  if (normalizedTo && w.createdAt > normalizedTo) return false;
1453
1452
  if (status) {