@mastra/valkey 0.0.0 → 0.2.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.cjs ADDED
@@ -0,0 +1,1786 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _mastra_core_agent = require("@mastra/core/agent");
25
+ let _mastra_core_error = require("@mastra/core/error");
26
+ let _mastra_core_storage = require("@mastra/core/storage");
27
+ let crypto$1 = require("crypto");
28
+ crypto$1 = __toESM(crypto$1, 1);
29
+ let _mastra_core_evals = require("@mastra/core/evals");
30
+ let _valkey_valkey_glide = require("@valkey/valkey-glide");
31
+ let _mastra_core_cache = require("@mastra/core/cache");
32
+ //#region src/storage/domains/utils.ts
33
+ /**
34
+ * Generate a Valkey key from table name and key parts.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * getKey('mastra_threads', { id: 'thread-123' });
39
+ * // Returns: 'mastra_threads:id:thread-123'
40
+ *
41
+ * getKey('mastra_messages', { threadId: 'thread-123', id: 'msg-456' });
42
+ * // Returns: 'mastra_messages:threadId:thread-123:id:msg-456'
43
+ * ```
44
+ */
45
+ function getKey(tableName, keys) {
46
+ return `${tableName}:${Object.entries(keys).filter(([_, value]) => value !== void 0).map(([key, value]) => {
47
+ if (value && typeof value === "object") return `${key}:${JSON.stringify(value)}`;
48
+ return `${key}:${value}`;
49
+ }).join(":")}`;
50
+ }
51
+ /**
52
+ * Process a record for storage, generating the appropriate key and serializing dates.
53
+ */
54
+ function processRecord(tableName, record) {
55
+ let key;
56
+ if (tableName === _mastra_core_storage.TABLE_MESSAGES) key = getKey(tableName, {
57
+ threadId: record.threadId,
58
+ id: record.id
59
+ });
60
+ else if (tableName === _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT) key = getKey(tableName, {
61
+ namespace: record.namespace || "workflows",
62
+ workflow_name: record.workflow_name,
63
+ run_id: record.run_id,
64
+ ...record.resourceId ? { resourceId: record.resourceId } : {}
65
+ });
66
+ else key = getKey(tableName, { id: record.id });
67
+ const processedRecord = {
68
+ ...record,
69
+ createdAt: (0, _mastra_core_storage.serializeDate)(record.createdAt),
70
+ updatedAt: (0, _mastra_core_storage.serializeDate)(record.updatedAt)
71
+ };
72
+ return {
73
+ key,
74
+ processedRecord
75
+ };
76
+ }
77
+ //#endregion
78
+ //#region src/storage/db/index.ts
79
+ var ValkeyDB = class {
80
+ client;
81
+ constructor({ client }) {
82
+ this.client = client;
83
+ }
84
+ getClient() {
85
+ return this.client;
86
+ }
87
+ async insert({ tableName, record }) {
88
+ const { key, processedRecord } = processRecord(tableName, record);
89
+ try {
90
+ await this.client.set(key, JSON.stringify(processedRecord));
91
+ } catch (error) {
92
+ throw new _mastra_core_error.MastraError({
93
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "INSERT", "FAILED"),
94
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
95
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
96
+ details: { tableName }
97
+ }, error);
98
+ }
99
+ }
100
+ async get({ tableName, keys }) {
101
+ const key = getKey(tableName, keys);
102
+ try {
103
+ const data = await this.client.get(key);
104
+ if (!data) return null;
105
+ return JSON.parse(data);
106
+ } catch (error) {
107
+ throw new _mastra_core_error.MastraError({
108
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LOAD", "FAILED"),
109
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
110
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
111
+ details: { tableName }
112
+ }, error);
113
+ }
114
+ }
115
+ async scanAndDelete(pattern, batchSize = 1e4) {
116
+ let cursor = "0";
117
+ let totalDeleted = 0;
118
+ do {
119
+ const result = await this.client.scan(cursor, {
120
+ MATCH: pattern,
121
+ COUNT: batchSize
122
+ });
123
+ if (result.keys.length > 0) {
124
+ await this.client.del(result.keys);
125
+ totalDeleted += result.keys.length;
126
+ }
127
+ cursor = result.cursor;
128
+ } while (cursor !== "0");
129
+ return totalDeleted;
130
+ }
131
+ async scanKeys(pattern, batchSize = 1e4) {
132
+ let cursor = "0";
133
+ const keys = [];
134
+ do {
135
+ const result = await this.client.scan(cursor, {
136
+ MATCH: pattern,
137
+ COUNT: batchSize
138
+ });
139
+ keys.push(...result.keys);
140
+ cursor = result.cursor;
141
+ } while (cursor !== "0");
142
+ return keys;
143
+ }
144
+ async deleteData({ tableName }) {
145
+ const pattern = `${tableName}:*`;
146
+ try {
147
+ await this.scanAndDelete(pattern);
148
+ } catch (error) {
149
+ throw new _mastra_core_error.MastraError({
150
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "CLEAR_TABLE", "FAILED"),
151
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
152
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
153
+ details: { tableName }
154
+ }, error);
155
+ }
156
+ }
157
+ };
158
+ //#endregion
159
+ //#region src/storage/domains/memory/index.ts
160
+ var StoreMemoryValkey = class extends _mastra_core_storage.MemoryStorage {
161
+ supportsPartialThreadUpdate = true;
162
+ client;
163
+ db;
164
+ constructor(config) {
165
+ super();
166
+ this.client = config.client;
167
+ this.db = new ValkeyDB({ client: config.client });
168
+ }
169
+ async dangerouslyClearAll() {
170
+ await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_THREADS });
171
+ await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_MESSAGES });
172
+ await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_RESOURCES });
173
+ await this.db.scanAndDelete("msg-idx:*");
174
+ await this.db.scanAndDelete("thread:*:messages");
175
+ }
176
+ async getThreadById({ threadId, resourceId }) {
177
+ try {
178
+ const thread = await this.db.get({
179
+ tableName: _mastra_core_storage.TABLE_THREADS,
180
+ keys: { id: threadId }
181
+ });
182
+ if (!thread || resourceId !== void 0 && thread.resourceId !== resourceId) return null;
183
+ return {
184
+ ...thread,
185
+ createdAt: (0, _mastra_core_storage.ensureDate)(thread.createdAt),
186
+ updatedAt: (0, _mastra_core_storage.ensureDate)(thread.updatedAt),
187
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
188
+ };
189
+ } catch (error) {
190
+ throw new _mastra_core_error.MastraError({
191
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "GET_THREAD_BY_ID", "FAILED"),
192
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
193
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
194
+ details: { threadId }
195
+ }, error);
196
+ }
197
+ }
198
+ async listThreadsByResourceId(args) {
199
+ return this.listThreads(args);
200
+ }
201
+ async listThreads(args) {
202
+ const { page = 0, perPage: perPageInput, orderBy, filter } = args;
203
+ const { field, direction } = this.parseOrderBy(orderBy);
204
+ try {
205
+ this.validatePaginationInput(page, perPageInput ?? 100);
206
+ } catch (error) {
207
+ throw new _mastra_core_error.MastraError({
208
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_THREADS", "INVALID_PAGE"),
209
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
210
+ category: _mastra_core_error.ErrorCategory.USER,
211
+ details: {
212
+ page,
213
+ ...perPageInput !== void 0 && { perPage: perPageInput }
214
+ }
215
+ }, error instanceof Error ? error : /* @__PURE__ */ new Error("Invalid pagination parameters"));
216
+ }
217
+ const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 100);
218
+ try {
219
+ this.validateMetadataKeys(filter?.metadata);
220
+ } catch (error) {
221
+ throw new _mastra_core_error.MastraError({
222
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_THREADS", "INVALID_METADATA_KEY"),
223
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
224
+ category: _mastra_core_error.ErrorCategory.USER,
225
+ details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
226
+ }, error instanceof Error ? error : /* @__PURE__ */ new Error("Invalid metadata key"));
227
+ }
228
+ const { offset, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
229
+ try {
230
+ let allThreads = [];
231
+ const pattern = `${_mastra_core_storage.TABLE_THREADS}:*`;
232
+ const keys = await this.db.scanKeys(pattern);
233
+ if (keys.length === 0) return {
234
+ threads: [],
235
+ total: 0,
236
+ page,
237
+ perPage: perPageForResponse,
238
+ hasMore: false
239
+ };
240
+ const results = await this.client.mGet(keys);
241
+ for (let i = 0; i < results.length; i++) {
242
+ const data = results[i];
243
+ if (!data) continue;
244
+ const thread = JSON.parse(data);
245
+ if (filter?.resourceId && thread.resourceId !== filter.resourceId) continue;
246
+ if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
247
+ const threadMetadata = typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata;
248
+ if (!Object.entries(filter.metadata).every(([key, value]) => (0, _mastra_core_storage.jsonValueEquals)(threadMetadata?.[key], value))) continue;
249
+ }
250
+ allThreads.push({
251
+ ...thread,
252
+ createdAt: (0, _mastra_core_storage.ensureDate)(thread.createdAt),
253
+ updatedAt: (0, _mastra_core_storage.ensureDate)(thread.updatedAt),
254
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
255
+ });
256
+ }
257
+ const sortedThreads = this.sortThreads(allThreads, field, direction);
258
+ const total = sortedThreads.length;
259
+ const end = perPageInput === false ? total : offset + perPage;
260
+ return {
261
+ threads: sortedThreads.slice(offset, end),
262
+ total,
263
+ page,
264
+ perPage: perPageForResponse,
265
+ hasMore: perPageInput === false ? false : end < total
266
+ };
267
+ } catch (error) {
268
+ if (error instanceof _mastra_core_error.MastraError && error.category === _mastra_core_error.ErrorCategory.USER) throw error;
269
+ const mastraError = new _mastra_core_error.MastraError({
270
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_THREADS", "FAILED"),
271
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
272
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
273
+ details: {
274
+ ...filter?.resourceId && { resourceId: filter.resourceId },
275
+ hasMetadataFilter: !!filter?.metadata,
276
+ page,
277
+ perPage
278
+ }
279
+ }, error);
280
+ this.logger.trackException(mastraError);
281
+ this.logger.error(mastraError.toString());
282
+ throw mastraError;
283
+ }
284
+ }
285
+ async saveThread({ thread }) {
286
+ try {
287
+ await this.db.insert({
288
+ tableName: _mastra_core_storage.TABLE_THREADS,
289
+ record: thread
290
+ });
291
+ return thread;
292
+ } catch (error) {
293
+ const mastraError = new _mastra_core_error.MastraError({
294
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "SAVE_THREAD", "FAILED"),
295
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
296
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
297
+ details: { threadId: thread.id }
298
+ }, error);
299
+ this.logger.trackException(mastraError);
300
+ this.logger.error(mastraError.toString());
301
+ throw mastraError;
302
+ }
303
+ }
304
+ async updateThread({ id, title, metadata }) {
305
+ const thread = await this.getThreadById({ threadId: id });
306
+ if (!thread) throw new _mastra_core_error.MastraError({
307
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "UPDATE_THREAD", "FAILED"),
308
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
309
+ category: _mastra_core_error.ErrorCategory.USER,
310
+ text: `Thread ${id} not found`,
311
+ details: { threadId: id }
312
+ });
313
+ const updatedThread = {
314
+ ...thread,
315
+ title: title ?? thread.title,
316
+ metadata: {
317
+ ...thread.metadata,
318
+ ...metadata
319
+ },
320
+ updatedAt: /* @__PURE__ */ new Date()
321
+ };
322
+ try {
323
+ await this.saveThread({ thread: updatedThread });
324
+ return updatedThread;
325
+ } catch (error) {
326
+ throw new _mastra_core_error.MastraError({
327
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "UPDATE_THREAD", "FAILED"),
328
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
329
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
330
+ details: { threadId: id }
331
+ }, error);
332
+ }
333
+ }
334
+ async deleteThread({ threadId }) {
335
+ const threadKey = getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId });
336
+ const threadMessagesKey = getThreadMessagesKey(threadId);
337
+ try {
338
+ const messageIds = await this.client.zRange(threadMessagesKey, 0, -1);
339
+ const multi = this.client.multi();
340
+ multi.del(threadKey);
341
+ multi.del(threadMessagesKey);
342
+ for (const messageId of messageIds) {
343
+ const messageKey = getMessageKey(threadId, messageId);
344
+ multi.del(messageKey);
345
+ multi.del(getMessageIndexKey(messageId));
346
+ }
347
+ await multi.exec();
348
+ await this.db.scanAndDelete(getMessageKey(threadId, "*"));
349
+ } catch (error) {
350
+ throw new _mastra_core_error.MastraError({
351
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "DELETE_THREAD", "FAILED"),
352
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
353
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
354
+ details: { threadId }
355
+ }, error);
356
+ }
357
+ }
358
+ async saveMessages(args) {
359
+ const { messages } = args;
360
+ if (messages.length === 0) return { messages: [] };
361
+ const threadId = messages[0]?.threadId;
362
+ try {
363
+ if (!threadId) throw new Error("Thread ID is required");
364
+ if (!await this.getThreadById({ threadId })) throw new Error(`Thread ${threadId} not found`);
365
+ } catch (error) {
366
+ throw new _mastra_core_error.MastraError({
367
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "SAVE_MESSAGES", "INVALID_ARGS"),
368
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
369
+ category: _mastra_core_error.ErrorCategory.USER
370
+ }, error);
371
+ }
372
+ const messagesWithIndex = messages.map((message, index) => {
373
+ if (!message.threadId) throw new Error(`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`);
374
+ if (!message.resourceId) throw new Error(`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`);
375
+ return {
376
+ ...message,
377
+ _index: index
378
+ };
379
+ });
380
+ const threadKey = getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId });
381
+ const existingThreadData = await this.client.get(threadKey);
382
+ const existingThread = existingThreadData ? JSON.parse(existingThreadData) : null;
383
+ try {
384
+ const batchSize = 1e3;
385
+ const existingThreadIds = await this.client.mGet(messagesWithIndex.map((message) => getMessageIndexKey(message.id)));
386
+ for (let i = 0; i < messagesWithIndex.length; i += batchSize) {
387
+ const batch = messagesWithIndex.slice(i, i + batchSize);
388
+ const batchExistingThreadIds = existingThreadIds.slice(i, i + batch.length);
389
+ const multi = this.client.multi();
390
+ for (const [batchIndex, message] of batch.entries()) {
391
+ const key = getMessageKey(message.threadId, message.id);
392
+ const score = getMessageScore(message);
393
+ const existingThreadId = batchExistingThreadIds[batchIndex];
394
+ if (existingThreadId && existingThreadId !== message.threadId) {
395
+ const existingMessageKey = getMessageKey(existingThreadId, message.id);
396
+ multi.del(existingMessageKey);
397
+ multi.zRem(getThreadMessagesKey(existingThreadId), message.id);
398
+ }
399
+ multi.set(key, JSON.stringify(message));
400
+ multi.set(getMessageIndexKey(message.id), message.threadId);
401
+ multi.zAdd(getThreadMessagesKey(message.threadId), {
402
+ score,
403
+ value: message.id
404
+ });
405
+ }
406
+ if (i === 0 && existingThread) {
407
+ const updatedThread = {
408
+ ...existingThread,
409
+ updatedAt: /* @__PURE__ */ new Date()
410
+ };
411
+ multi.set(threadKey, JSON.stringify(processRecord(_mastra_core_storage.TABLE_THREADS, updatedThread).processedRecord));
412
+ }
413
+ await multi.exec();
414
+ }
415
+ return { messages: new _mastra_core_agent.MessageList().add(messages, "memory").get.all.db() };
416
+ } catch (error) {
417
+ throw new _mastra_core_error.MastraError({
418
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "SAVE_MESSAGES", "FAILED"),
419
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
420
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
421
+ details: { threadId }
422
+ }, error);
423
+ }
424
+ }
425
+ async getThreadIdForMessage(messageId) {
426
+ const indexedThreadId = await this.client.get(getMessageIndexKey(messageId));
427
+ if (indexedThreadId) return indexedThreadId;
428
+ const keys = await this.db.scanKeys(getMessageKey("*", messageId));
429
+ if (keys.length === 0) return null;
430
+ const messageData = await this.client.get(keys[0]);
431
+ if (!messageData) return null;
432
+ const message = JSON.parse(messageData);
433
+ if (message.threadId) await this.client.set(getMessageIndexKey(messageId), message.threadId);
434
+ return message.threadId || null;
435
+ }
436
+ /**
437
+ * Fetches the messages named by `include` together with their surrounding context.
438
+ *
439
+ * @param include - Message ids to pin, each with an optional before/after window.
440
+ * @param resourceId - When set, drops any pinned or context message owned by another
441
+ * resource so an id from another resource returns nothing.
442
+ */
443
+ async getIncludedMessages(include, resourceId) {
444
+ if (!include?.length) return [];
445
+ const messageIds = /* @__PURE__ */ new Set();
446
+ const messageIdToThreadIds = {};
447
+ for (const item of include) {
448
+ const itemThreadId = await this.getThreadIdForMessage(item.id);
449
+ if (!itemThreadId) continue;
450
+ const itemThreadMessagesKey = getThreadMessagesKey(itemThreadId);
451
+ if (resourceId !== void 0) {
452
+ const threadMessageIds = await this.client.zRange(itemThreadMessagesKey, 0, -1);
453
+ const threadMessages = (await this.client.mGet(threadMessageIds.map((id) => getMessageKey(itemThreadId, id)))).filter((data) => data !== null).map((data) => JSON.parse(data)).filter((message) => message.resourceId === resourceId);
454
+ const targetIndex = threadMessages.findIndex((message) => message.id === item.id);
455
+ if (targetIndex === -1) continue;
456
+ const start = Math.max(0, targetIndex - (item.withPreviousMessages ?? 0));
457
+ const end = Math.min(threadMessages.length, targetIndex + (item.withNextMessages ?? 0) + 1);
458
+ for (const message of threadMessages.slice(start, end)) {
459
+ messageIds.add(message.id);
460
+ messageIdToThreadIds[message.id] = itemThreadId;
461
+ }
462
+ continue;
463
+ }
464
+ messageIds.add(item.id);
465
+ messageIdToThreadIds[item.id] = itemThreadId;
466
+ const rank = await this.client.zRank(itemThreadMessagesKey, item.id);
467
+ if (rank === null) continue;
468
+ if (item.withPreviousMessages) {
469
+ const start = Math.max(0, rank - item.withPreviousMessages);
470
+ (rank === 0 ? [] : await this.client.zRange(itemThreadMessagesKey, start, rank - 1)).forEach((id) => {
471
+ messageIds.add(id);
472
+ messageIdToThreadIds[id] = itemThreadId;
473
+ });
474
+ }
475
+ if (item.withNextMessages) (await this.client.zRange(itemThreadMessagesKey, rank + 1, rank + item.withNextMessages)).forEach((id) => {
476
+ messageIds.add(id);
477
+ messageIdToThreadIds[id] = itemThreadId;
478
+ });
479
+ }
480
+ if (messageIds.size === 0) return [];
481
+ const keysToFetch = Array.from(messageIds).map((id) => getMessageKey(messageIdToThreadIds[id], id));
482
+ const includedMessages = (await this.client.mGet(keysToFetch)).filter((data) => data !== null).map((data) => JSON.parse(data));
483
+ return resourceId ? includedMessages.filter((message) => message.resourceId === resourceId) : includedMessages;
484
+ }
485
+ parseStoredMessage(storedMessage) {
486
+ const defaultMessageContent = {
487
+ format: 2,
488
+ parts: [{
489
+ type: "text",
490
+ text: ""
491
+ }]
492
+ };
493
+ const { _index, ...rest } = storedMessage;
494
+ return {
495
+ ...rest,
496
+ createdAt: new Date(rest.createdAt),
497
+ content: rest.content || defaultMessageContent
498
+ };
499
+ }
500
+ async listMessagesById({ messageIds }) {
501
+ if (messageIds.length === 0) return { messages: [] };
502
+ try {
503
+ const rawMessages = [];
504
+ const indexKeys = messageIds.map((id) => getMessageIndexKey(id));
505
+ const indexResults = await this.client.mGet(indexKeys);
506
+ const indexedIds = [];
507
+ const unindexedIds = [];
508
+ messageIds.forEach((id, i) => {
509
+ const threadId = indexResults[i];
510
+ if (threadId) {
511
+ indexedIds.push({
512
+ messageId: id,
513
+ threadId
514
+ });
515
+ return;
516
+ }
517
+ unindexedIds.push(id);
518
+ });
519
+ if (indexedIds.length > 0) {
520
+ const messageKeys = indexedIds.map(({ messageId, threadId }) => getMessageKey(threadId, messageId));
521
+ const messageResults = await this.client.mGet(messageKeys);
522
+ for (const data of messageResults) if (data) rawMessages.push(JSON.parse(data));
523
+ }
524
+ if (unindexedIds.length > 0) {
525
+ const threadKeys = await this.db.scanKeys("thread:*:messages");
526
+ const foundMessages = (await Promise.all(threadKeys.map(async (threadKey) => {
527
+ const threadId = threadKey.split(":")[1];
528
+ if (!threadId) throw new Error(`Failed to parse thread ID from thread key "${threadKey}"`);
529
+ const msgKeys = unindexedIds.map((id) => getMessageKey(threadId, id));
530
+ return this.client.mGet(msgKeys);
531
+ }))).flat(1).filter((data) => !!data).map((data) => JSON.parse(data));
532
+ rawMessages.push(...foundMessages);
533
+ if (foundMessages.length > 0) {
534
+ const multi = this.client.multi();
535
+ foundMessages.forEach((msg) => {
536
+ if (msg.threadId) multi.set(getMessageIndexKey(msg.id), msg.threadId);
537
+ });
538
+ await multi.exec();
539
+ }
540
+ }
541
+ return { messages: new _mastra_core_agent.MessageList().add(rawMessages.map(this.parseStoredMessage), "memory").get.all.db() };
542
+ } catch (error) {
543
+ throw new _mastra_core_error.MastraError({
544
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_MESSAGES_BY_ID", "FAILED"),
545
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
546
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
547
+ details: { messageIds: JSON.stringify(messageIds) }
548
+ }, error);
549
+ }
550
+ }
551
+ async listMessages(args) {
552
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
553
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
554
+ const threadIdsSet = new Set(threadIds);
555
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) throw new _mastra_core_error.MastraError({
556
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_MESSAGES", "INVALID_THREAD_ID"),
557
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
558
+ category: _mastra_core_error.ErrorCategory.USER,
559
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
560
+ }, /* @__PURE__ */ new Error("threadId must be a non-empty string or array of non-empty strings"));
561
+ const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 40);
562
+ const { offset, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
563
+ const metadataFilter = (0, _mastra_core_storage.validateStorageMetadataFilter)(filter?.metadata);
564
+ try {
565
+ if (page < 0) throw new _mastra_core_error.MastraError({
566
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_MESSAGES", "INVALID_PAGE"),
567
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
568
+ category: _mastra_core_error.ErrorCategory.USER,
569
+ details: { page }
570
+ }, /* @__PURE__ */ new Error("page must be >= 0"));
571
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
572
+ const getFieldValue = (msg) => {
573
+ if (field === "createdAt") return new Date(msg.createdAt).getTime();
574
+ const value = msg[field];
575
+ if (typeof value === "number") return value;
576
+ if (value instanceof Date) return value.getTime();
577
+ return 0;
578
+ };
579
+ if (perPage === 0 && (!include || include.length === 0)) return {
580
+ messages: [],
581
+ total: 0,
582
+ page,
583
+ perPage: perPageForResponse,
584
+ hasMore: false
585
+ };
586
+ let includedMessages = [];
587
+ if (include && include.length > 0) includedMessages = (await this.getIncludedMessages(include, resourceId)).map(this.parseStoredMessage);
588
+ if (perPage === 0 && include && include.length > 0) return {
589
+ messages: new _mastra_core_agent.MessageList().add(includedMessages, "memory").get.all.db().sort((a, b) => {
590
+ const aValue = getFieldValue(a);
591
+ const bValue = getFieldValue(b);
592
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
593
+ }),
594
+ total: 0,
595
+ page,
596
+ perPage: perPageForResponse,
597
+ hasMore: false
598
+ };
599
+ const allMessageIdsWithThreads = [];
600
+ for (const tid of threadIds) {
601
+ const threadMessagesKey = getThreadMessagesKey(tid);
602
+ const msgIds = await this.client.zRange(threadMessagesKey, 0, -1);
603
+ for (const mid of msgIds) allMessageIdsWithThreads.push({
604
+ threadId: tid,
605
+ messageId: mid
606
+ });
607
+ }
608
+ if (allMessageIdsWithThreads.length === 0) return {
609
+ messages: [],
610
+ total: 0,
611
+ page,
612
+ perPage: perPageForResponse,
613
+ hasMore: false
614
+ };
615
+ const messageKeys = allMessageIdsWithThreads.map(({ threadId: tid, messageId }) => getMessageKey(tid, messageId));
616
+ let messagesData = (await this.client.mGet(messageKeys)).filter((data) => data !== null).map((data) => JSON.parse(data)).map(this.parseStoredMessage);
617
+ if (resourceId) messagesData = messagesData.filter((msg) => msg.resourceId === resourceId);
618
+ messagesData = (0, _mastra_core_storage.filterByDateRange)(messagesData, (msg) => new Date(msg.createdAt), filter?.dateRange);
619
+ messagesData = messagesData.filter((message) => (0, _mastra_core_storage.storageMessageMatchesMetadataFilter)(message.content, metadataFilter));
620
+ messagesData.sort((a, b) => {
621
+ const aValue = getFieldValue(a);
622
+ const bValue = getFieldValue(b);
623
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
624
+ });
625
+ const total = messagesData.length;
626
+ const start = offset;
627
+ const end = perPageInput === false ? total : start + perPage;
628
+ const paginatedMessages = messagesData.slice(start, end);
629
+ const messageIdsSet = /* @__PURE__ */ new Set();
630
+ const allMessages = [];
631
+ for (const msg of paginatedMessages) {
632
+ if (messageIdsSet.has(msg.id)) continue;
633
+ allMessages.push(msg);
634
+ messageIdsSet.add(msg.id);
635
+ }
636
+ for (const msg of includedMessages) {
637
+ if (messageIdsSet.has(msg.id)) continue;
638
+ allMessages.push(msg);
639
+ messageIdsSet.add(msg.id);
640
+ }
641
+ let finalMessages = new _mastra_core_agent.MessageList().add(allMessages, "memory").get.all.db();
642
+ finalMessages = finalMessages.sort((a, b) => {
643
+ const aValue = getFieldValue(a);
644
+ const bValue = getFieldValue(b);
645
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
646
+ });
647
+ const returnedThreadMessageIds = new Set(finalMessages.filter((message) => message.threadId && threadIdsSet.has(message.threadId)).map((message) => message.id));
648
+ const hasMore = perPageInput !== false && (metadataFilter || returnedThreadMessageIds.size < total) && offset + paginatedMessages.length < total;
649
+ return {
650
+ messages: finalMessages,
651
+ total,
652
+ page,
653
+ perPage: perPageForResponse,
654
+ hasMore
655
+ };
656
+ } catch (error) {
657
+ if (error instanceof _mastra_core_error.MastraError && error.category === _mastra_core_error.ErrorCategory.USER) throw error;
658
+ const mastraError = new _mastra_core_error.MastraError({
659
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_MESSAGES", "FAILED"),
660
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
661
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
662
+ details: {
663
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
664
+ resourceId: resourceId ?? ""
665
+ }
666
+ }, error);
667
+ this.logger.error(mastraError.toString());
668
+ this.logger.trackException(mastraError);
669
+ throw mastraError;
670
+ }
671
+ }
672
+ async getResourceById({ resourceId }) {
673
+ try {
674
+ const key = `${_mastra_core_storage.TABLE_RESOURCES}:${resourceId}`;
675
+ const data = await this.client.get(key);
676
+ if (!data) return null;
677
+ const resource = JSON.parse(data);
678
+ return {
679
+ ...resource,
680
+ createdAt: new Date(resource.createdAt),
681
+ updatedAt: new Date(resource.updatedAt),
682
+ workingMemory: typeof resource.workingMemory === "object" ? JSON.stringify(resource.workingMemory) : resource.workingMemory,
683
+ metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata) : resource.metadata
684
+ };
685
+ } catch (error) {
686
+ this.logger.error("Error getting resource by ID:", error);
687
+ throw error;
688
+ }
689
+ }
690
+ async saveResource({ resource }) {
691
+ try {
692
+ const key = `${_mastra_core_storage.TABLE_RESOURCES}:${resource.id}`;
693
+ const serializedResource = {
694
+ ...resource,
695
+ metadata: JSON.stringify(resource.metadata),
696
+ createdAt: resource.createdAt.toISOString(),
697
+ updatedAt: resource.updatedAt.toISOString()
698
+ };
699
+ await this.client.set(key, JSON.stringify(serializedResource));
700
+ return resource;
701
+ } catch (error) {
702
+ this.logger.error("Error saving resource:", error);
703
+ throw error;
704
+ }
705
+ }
706
+ async updateResource({ resourceId, workingMemory, metadata }) {
707
+ try {
708
+ const existingResource = await this.getResourceById({ resourceId });
709
+ if (!existingResource) {
710
+ const newResource = {
711
+ id: resourceId,
712
+ workingMemory,
713
+ metadata: metadata || {},
714
+ createdAt: /* @__PURE__ */ new Date(),
715
+ updatedAt: /* @__PURE__ */ new Date()
716
+ };
717
+ return this.saveResource({ resource: newResource });
718
+ }
719
+ const updatedResource = {
720
+ ...existingResource,
721
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
722
+ metadata: {
723
+ ...existingResource.metadata,
724
+ ...metadata
725
+ },
726
+ updatedAt: /* @__PURE__ */ new Date()
727
+ };
728
+ await this.saveResource({ resource: updatedResource });
729
+ return updatedResource;
730
+ } catch (error) {
731
+ this.logger.error("Error updating resource:", error);
732
+ throw error;
733
+ }
734
+ }
735
+ async updateMessages(args) {
736
+ const { messages } = args;
737
+ if (messages.length === 0) return [];
738
+ try {
739
+ const messageIds = messages.map((m) => m.id);
740
+ const existingMessages = [];
741
+ const messageIdToKey = {};
742
+ for (const messageId of messageIds) {
743
+ const pattern = getMessageKey("*", messageId);
744
+ const keys = await this.db.scanKeys(pattern);
745
+ for (const key of keys) {
746
+ const data = await this.client.get(key);
747
+ if (!data) continue;
748
+ const message = JSON.parse(data);
749
+ if (message && message.id === messageId) {
750
+ existingMessages.push(message);
751
+ messageIdToKey[messageId] = key;
752
+ break;
753
+ }
754
+ }
755
+ }
756
+ if (existingMessages.length === 0) return [];
757
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
758
+ const multi = this.client.multi();
759
+ for (const existingMessage of existingMessages) {
760
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
761
+ if (!updatePayload) continue;
762
+ const { id, ...fieldsToUpdate } = updatePayload;
763
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
764
+ threadIdsToUpdate.add(existingMessage.threadId);
765
+ if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) threadIdsToUpdate.add(updatePayload.threadId);
766
+ const updatedMessage = { ...existingMessage };
767
+ if (fieldsToUpdate.content) {
768
+ const existingContent = existingMessage.content;
769
+ updatedMessage.content = {
770
+ ...existingContent,
771
+ ...fieldsToUpdate.content,
772
+ ...existingContent?.metadata && fieldsToUpdate.content.metadata ? { metadata: {
773
+ ...existingContent.metadata,
774
+ ...fieldsToUpdate.content.metadata
775
+ } } : {}
776
+ };
777
+ }
778
+ for (const key in fieldsToUpdate) if (Object.prototype.hasOwnProperty.call(fieldsToUpdate, key) && key !== "content") updatedMessage[key] = fieldsToUpdate[key];
779
+ const key = messageIdToKey[id];
780
+ if (!key) continue;
781
+ if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
782
+ multi.zRem(getThreadMessagesKey(existingMessage.threadId), id);
783
+ multi.del(key);
784
+ const newKey = getMessageKey(updatePayload.threadId, id);
785
+ multi.set(newKey, JSON.stringify(updatedMessage));
786
+ multi.set(getMessageIndexKey(id), updatePayload.threadId);
787
+ const score = getMessageScore(updatedMessage);
788
+ multi.zAdd(getThreadMessagesKey(updatePayload.threadId), {
789
+ score,
790
+ value: id
791
+ });
792
+ messageIdToKey[id] = newKey;
793
+ continue;
794
+ }
795
+ multi.set(key, JSON.stringify(updatedMessage));
796
+ }
797
+ const now = /* @__PURE__ */ new Date();
798
+ for (const threadId of threadIdsToUpdate) if (threadId) {
799
+ const threadKey = getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId });
800
+ const existingThreadData = await this.client.get(threadKey);
801
+ if (existingThreadData) {
802
+ const updatedThread = {
803
+ ...JSON.parse(existingThreadData),
804
+ updatedAt: now
805
+ };
806
+ multi.set(threadKey, JSON.stringify(processRecord(_mastra_core_storage.TABLE_THREADS, updatedThread).processedRecord));
807
+ }
808
+ }
809
+ await multi.exec();
810
+ const updatedMessages = [];
811
+ for (const messageId of messageIds) {
812
+ const key = messageIdToKey[messageId];
813
+ if (key) {
814
+ const data = await this.client.get(key);
815
+ if (data) updatedMessages.push(JSON.parse(data));
816
+ }
817
+ }
818
+ return updatedMessages;
819
+ } catch (error) {
820
+ throw new _mastra_core_error.MastraError({
821
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "UPDATE_MESSAGES", "FAILED"),
822
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
823
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
824
+ details: { messageIds: messages.map((m) => m.id).join(",") }
825
+ }, error);
826
+ }
827
+ }
828
+ async deleteMessages(messageIds) {
829
+ if (!messageIds || messageIds.length === 0) return;
830
+ try {
831
+ const threadIds = /* @__PURE__ */ new Set();
832
+ const messageKeys = [];
833
+ const foundMessageIds = [];
834
+ const messageIdToThreadId = /* @__PURE__ */ new Map();
835
+ const indexKeys = messageIds.map((id) => getMessageIndexKey(id));
836
+ const indexResults = await this.client.mGet(indexKeys);
837
+ const indexedMessages = [];
838
+ const unindexedMessageIds = [];
839
+ messageIds.forEach((id, i) => {
840
+ const threadId = indexResults[i];
841
+ if (threadId) {
842
+ indexedMessages.push({
843
+ messageId: id,
844
+ threadId
845
+ });
846
+ return;
847
+ }
848
+ unindexedMessageIds.push(id);
849
+ });
850
+ for (const { messageId, threadId } of indexedMessages) {
851
+ messageKeys.push(getMessageKey(threadId, messageId));
852
+ foundMessageIds.push(messageId);
853
+ messageIdToThreadId.set(messageId, threadId);
854
+ threadIds.add(threadId);
855
+ }
856
+ for (const messageId of unindexedMessageIds) {
857
+ const pattern = getMessageKey("*", messageId);
858
+ const keys = await this.db.scanKeys(pattern);
859
+ for (const key of keys) {
860
+ const data = await this.client.get(key);
861
+ if (!data) continue;
862
+ const message = JSON.parse(data);
863
+ if (message && message.id === messageId) {
864
+ messageKeys.push(key);
865
+ foundMessageIds.push(messageId);
866
+ if (message.threadId) {
867
+ messageIdToThreadId.set(messageId, message.threadId);
868
+ threadIds.add(message.threadId);
869
+ }
870
+ break;
871
+ }
872
+ }
873
+ }
874
+ if (messageKeys.length === 0) return;
875
+ const multi = this.client.multi();
876
+ for (const key of messageKeys) multi.del(key);
877
+ for (const messageId of foundMessageIds) multi.del(getMessageIndexKey(messageId));
878
+ if (threadIds.size > 0) for (const threadId of threadIds) {
879
+ for (const [msgId, msgThreadId] of messageIdToThreadId) if (msgThreadId === threadId) multi.zRem(getThreadMessagesKey(threadId), msgId);
880
+ const threadKey = getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId });
881
+ const threadData = await this.client.get(threadKey);
882
+ if (!threadData) continue;
883
+ const updatedThread = {
884
+ ...JSON.parse(threadData),
885
+ updatedAt: /* @__PURE__ */ new Date()
886
+ };
887
+ multi.set(threadKey, JSON.stringify(processRecord(_mastra_core_storage.TABLE_THREADS, updatedThread).processedRecord));
888
+ }
889
+ await multi.exec();
890
+ } catch (error) {
891
+ throw new _mastra_core_error.MastraError({
892
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "DELETE_MESSAGES", "FAILED"),
893
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
894
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
895
+ details: { messageIds: messageIds.join(", ") }
896
+ }, error);
897
+ }
898
+ }
899
+ sortThreads(threads, field, direction) {
900
+ return threads.sort((a, b) => {
901
+ const aValue = new Date(a[field]).getTime();
902
+ const bValue = new Date(b[field]).getTime();
903
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
904
+ });
905
+ }
906
+ async cloneThread(args) {
907
+ const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;
908
+ const sourceThread = await this.getThreadById({ threadId: sourceThreadId });
909
+ if (!sourceThread) throw new _mastra_core_error.MastraError({
910
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "CLONE_THREAD", "SOURCE_NOT_FOUND"),
911
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
912
+ category: _mastra_core_error.ErrorCategory.USER,
913
+ text: `Source thread with id ${sourceThreadId} not found`,
914
+ details: { sourceThreadId }
915
+ });
916
+ const newThreadId = providedThreadId || crypto.randomUUID();
917
+ if (await this.getThreadById({ threadId: newThreadId })) throw new _mastra_core_error.MastraError({
918
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "CLONE_THREAD", "THREAD_EXISTS"),
919
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
920
+ category: _mastra_core_error.ErrorCategory.USER,
921
+ text: `Thread with id ${newThreadId} already exists`,
922
+ details: { newThreadId }
923
+ });
924
+ try {
925
+ const threadMessagesKey = getThreadMessagesKey(sourceThreadId);
926
+ const messageKeys = (await this.client.zRange(threadMessagesKey, 0, -1)).map((mid) => getMessageKey(sourceThreadId, mid));
927
+ let sourceMessages = [];
928
+ if (messageKeys.length > 0) sourceMessages = (await this.client.mGet(messageKeys)).filter((data) => data !== null).map((data) => {
929
+ const msg = JSON.parse(data);
930
+ return {
931
+ ...msg,
932
+ createdAt: new Date(msg.createdAt)
933
+ };
934
+ });
935
+ if (options?.messageFilter?.startDate || options?.messageFilter?.endDate) sourceMessages = (0, _mastra_core_storage.filterByDateRange)(sourceMessages, (msg) => new Date(msg.createdAt), {
936
+ start: options.messageFilter?.startDate,
937
+ end: options.messageFilter?.endDate
938
+ });
939
+ if (options?.messageFilter?.messageIds && options.messageFilter.messageIds.length > 0) {
940
+ const messageIdSet = new Set(options.messageFilter.messageIds);
941
+ sourceMessages = sourceMessages.filter((msg) => messageIdSet.has(msg.id));
942
+ }
943
+ sourceMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
944
+ if (options?.messageLimit && options.messageLimit > 0 && sourceMessages.length > options.messageLimit) sourceMessages = sourceMessages.slice(-options.messageLimit);
945
+ const now = /* @__PURE__ */ new Date();
946
+ const lastMessageId = sourceMessages.length > 0 ? sourceMessages[sourceMessages.length - 1].id : void 0;
947
+ const cloneMetadata = {
948
+ sourceThreadId,
949
+ clonedAt: now,
950
+ ...lastMessageId && { lastMessageId }
951
+ };
952
+ const newThread = {
953
+ id: newThreadId,
954
+ resourceId: resourceId || sourceThread.resourceId,
955
+ title: title || (sourceThread.title ? `Clone of ${sourceThread.title}` : void 0),
956
+ metadata: {
957
+ ...metadata,
958
+ clone: cloneMetadata
959
+ },
960
+ createdAt: now,
961
+ updatedAt: now
962
+ };
963
+ const multi = this.client.multi();
964
+ const threadKey = getKey(_mastra_core_storage.TABLE_THREADS, { id: newThreadId });
965
+ multi.set(threadKey, JSON.stringify(processRecord(_mastra_core_storage.TABLE_THREADS, newThread).processedRecord));
966
+ const clonedMessages = [];
967
+ const targetResourceId = resourceId || sourceThread.resourceId;
968
+ const newThreadMessagesKey = getThreadMessagesKey(newThreadId);
969
+ for (let i = 0; i < sourceMessages.length; i++) {
970
+ const sourceMsg = sourceMessages[i];
971
+ const newMessageId = crypto.randomUUID();
972
+ const { _index, ...restMsg } = sourceMsg;
973
+ const newMessage = {
974
+ ...restMsg,
975
+ id: newMessageId,
976
+ threadId: newThreadId,
977
+ resourceId: targetResourceId
978
+ };
979
+ const messageKey = getMessageKey(newThreadId, newMessageId);
980
+ multi.set(messageKey, JSON.stringify(newMessage));
981
+ multi.set(getMessageIndexKey(newMessageId), newThreadId);
982
+ const score = getMessageScore({
983
+ createdAt: newMessage.createdAt,
984
+ _index: i
985
+ });
986
+ multi.zAdd(newThreadMessagesKey, {
987
+ score,
988
+ value: newMessageId
989
+ });
990
+ clonedMessages.push(newMessage);
991
+ }
992
+ await multi.exec();
993
+ return {
994
+ thread: newThread,
995
+ clonedMessages
996
+ };
997
+ } catch (error) {
998
+ if (error instanceof _mastra_core_error.MastraError) throw error;
999
+ throw new _mastra_core_error.MastraError({
1000
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "CLONE_THREAD", "FAILED"),
1001
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1002
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1003
+ details: {
1004
+ sourceThreadId,
1005
+ newThreadId
1006
+ }
1007
+ }, error);
1008
+ }
1009
+ }
1010
+ };
1011
+ function getThreadMessagesKey(threadId) {
1012
+ return `thread:${threadId}:messages`;
1013
+ }
1014
+ function getMessageKey(threadId, messageId) {
1015
+ return getKey(_mastra_core_storage.TABLE_MESSAGES, {
1016
+ threadId,
1017
+ id: messageId
1018
+ });
1019
+ }
1020
+ function getMessageIndexKey(messageId) {
1021
+ return `msg-idx:${messageId}`;
1022
+ }
1023
+ function getMessageScore(message) {
1024
+ const createdAtScore = new Date(message.createdAt).getTime();
1025
+ const index = typeof message._index === "number" ? message._index : 0;
1026
+ return createdAtScore * 1e3 + index;
1027
+ }
1028
+ //#endregion
1029
+ //#region src/storage/domains/scores/index.ts
1030
+ /** Returns true when a row matches the multi-tenant scope filters (or none provided). */
1031
+ function matchesTenancy(row, filters) {
1032
+ if (filters?.organizationId !== void 0 && row.organizationId !== filters.organizationId) return false;
1033
+ if (filters?.projectId !== void 0 && row.projectId !== filters.projectId) return false;
1034
+ return true;
1035
+ }
1036
+ var ScoresValkey = class extends _mastra_core_storage.ScoresStorage {
1037
+ client;
1038
+ db;
1039
+ constructor(config) {
1040
+ super();
1041
+ this.client = config.client;
1042
+ this.db = new ValkeyDB({ client: config.client });
1043
+ }
1044
+ async dangerouslyClearAll() {
1045
+ await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_SCORERS });
1046
+ }
1047
+ async getScoreById({ id }) {
1048
+ try {
1049
+ const data = await this.db.get({
1050
+ tableName: _mastra_core_storage.TABLE_SCORERS,
1051
+ keys: { id }
1052
+ });
1053
+ if (!data) return null;
1054
+ return (0, _mastra_core_storage.transformScoreRow)(data);
1055
+ } catch (error) {
1056
+ throw new _mastra_core_error.MastraError({
1057
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "GET_SCORE_BY_ID", "FAILED"),
1058
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1059
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1060
+ details: { ...id && { id } }
1061
+ }, error);
1062
+ }
1063
+ }
1064
+ async listScoresByScorerId({ scorerId, entityId, entityType, source, pagination = {
1065
+ page: 0,
1066
+ perPage: 20
1067
+ }, filters }) {
1068
+ return this.fetchAndFilterScores(pagination, (row) => {
1069
+ if (row.scorerId !== scorerId) return false;
1070
+ if (entityId && row.entityId !== entityId) return false;
1071
+ if (entityType && row.entityType !== entityType) return false;
1072
+ if (source && row.source !== source) return false;
1073
+ if (!matchesTenancy(row, filters)) return false;
1074
+ return true;
1075
+ });
1076
+ }
1077
+ async saveScore(score) {
1078
+ let validatedScore;
1079
+ try {
1080
+ validatedScore = _mastra_core_evals.saveScorePayloadSchema.parse(score);
1081
+ } catch (error) {
1082
+ throw new _mastra_core_error.MastraError({
1083
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "SAVE_SCORE", "VALIDATION_FAILED"),
1084
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1085
+ category: _mastra_core_error.ErrorCategory.USER,
1086
+ details: {
1087
+ scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
1088
+ entityId: score.entityId ?? "unknown",
1089
+ entityType: score.entityType ?? "unknown",
1090
+ traceId: score.traceId ?? "",
1091
+ spanId: score.spanId ?? ""
1092
+ }
1093
+ }, error);
1094
+ }
1095
+ const now = /* @__PURE__ */ new Date();
1096
+ const id = crypto$1.default.randomUUID();
1097
+ const { key, processedRecord } = processRecord(_mastra_core_storage.TABLE_SCORERS, {
1098
+ ...validatedScore,
1099
+ id,
1100
+ createdAt: now,
1101
+ updatedAt: now
1102
+ });
1103
+ try {
1104
+ await this.client.set(key, JSON.stringify(processedRecord));
1105
+ return { score: {
1106
+ ...validatedScore,
1107
+ id,
1108
+ createdAt: now,
1109
+ updatedAt: now
1110
+ } };
1111
+ } catch (error) {
1112
+ throw new _mastra_core_error.MastraError({
1113
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "SAVE_SCORE", "FAILED"),
1114
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1115
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1116
+ details: { id }
1117
+ }, error);
1118
+ }
1119
+ }
1120
+ async listScoresByRunId({ runId, pagination = {
1121
+ page: 0,
1122
+ perPage: 20
1123
+ }, filters }) {
1124
+ return this.fetchAndFilterScores(pagination, (row) => row.runId === runId && matchesTenancy(row, filters));
1125
+ }
1126
+ async listScoresByEntityId({ entityId, entityType, pagination = {
1127
+ page: 0,
1128
+ perPage: 20
1129
+ }, filters }) {
1130
+ return this.fetchAndFilterScores(pagination, (row) => {
1131
+ if (row.entityId !== entityId) return false;
1132
+ if (entityType && row.entityType !== entityType) return false;
1133
+ if (!matchesTenancy(row, filters)) return false;
1134
+ return true;
1135
+ });
1136
+ }
1137
+ async listScoresBySpan({ traceId, spanId, pagination = {
1138
+ page: 0,
1139
+ perPage: 20
1140
+ }, filters }) {
1141
+ return this.fetchAndFilterScores(pagination, (row) => row.traceId === traceId && row.spanId === spanId && matchesTenancy(row, filters));
1142
+ }
1143
+ async fetchAndFilterScores(pagination, filterFn) {
1144
+ const { page, perPage: perPageInput } = pagination;
1145
+ const keys = await this.db.scanKeys(`${_mastra_core_storage.TABLE_SCORERS}:*`);
1146
+ if (keys.length === 0) return {
1147
+ scores: [],
1148
+ pagination: {
1149
+ total: 0,
1150
+ page,
1151
+ perPage: perPageInput,
1152
+ hasMore: false
1153
+ }
1154
+ };
1155
+ const filtered = (await this.client.mGet(keys)).map((data) => {
1156
+ if (!data) return null;
1157
+ try {
1158
+ return JSON.parse(data);
1159
+ } catch {
1160
+ return null;
1161
+ }
1162
+ }).filter((row) => !!row && typeof row === "object" && filterFn(row));
1163
+ const total = filtered.length;
1164
+ const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 100);
1165
+ const { offset: start, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
1166
+ const end = perPageInput === false ? total : start + perPage;
1167
+ return {
1168
+ scores: filtered.slice(start, end).map((row) => (0, _mastra_core_storage.transformScoreRow)(row)),
1169
+ pagination: {
1170
+ total,
1171
+ page,
1172
+ perPage: perPageForResponse,
1173
+ hasMore: end < total
1174
+ }
1175
+ };
1176
+ }
1177
+ };
1178
+ //#endregion
1179
+ //#region src/storage/domains/workflows/index.ts
1180
+ function parseWorkflowRun(row) {
1181
+ let parsedSnapshot = row.snapshot;
1182
+ if (typeof parsedSnapshot === "string") try {
1183
+ parsedSnapshot = JSON.parse(row.snapshot);
1184
+ } catch (e) {
1185
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1186
+ }
1187
+ return {
1188
+ workflowName: row.workflow_name,
1189
+ runId: row.run_id,
1190
+ snapshot: parsedSnapshot,
1191
+ createdAt: (0, _mastra_core_storage.ensureDate)(row.createdAt),
1192
+ updatedAt: (0, _mastra_core_storage.ensureDate)(row.updatedAt),
1193
+ resourceId: row.resourceId
1194
+ };
1195
+ }
1196
+ var WorkflowsValkey = class extends _mastra_core_storage.WorkflowsStorage {
1197
+ client;
1198
+ db;
1199
+ constructor(config) {
1200
+ super();
1201
+ this.client = config.client;
1202
+ this.db = new ValkeyDB({ client: config.client });
1203
+ }
1204
+ supportsConcurrentUpdates() {
1205
+ return false;
1206
+ }
1207
+ async dangerouslyClearAll() {
1208
+ await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT });
1209
+ }
1210
+ async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
1211
+ try {
1212
+ const existingRecord = await this.db.get({
1213
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1214
+ keys: {
1215
+ namespace: "workflows",
1216
+ workflow_name: workflowName,
1217
+ run_id: runId
1218
+ }
1219
+ });
1220
+ let snapshot = existingRecord?.snapshot;
1221
+ if (!snapshot) snapshot = {
1222
+ context: {},
1223
+ activePaths: [],
1224
+ timestamp: Date.now(),
1225
+ suspendedPaths: {},
1226
+ activeStepsPath: {},
1227
+ resumeLabels: {},
1228
+ serializedStepGraph: [],
1229
+ status: "pending",
1230
+ value: {},
1231
+ waitingPaths: {},
1232
+ runId,
1233
+ requestContext: {}
1234
+ };
1235
+ snapshot.context[stepId] = result;
1236
+ snapshot.requestContext = {
1237
+ ...snapshot.requestContext,
1238
+ ...requestContext
1239
+ };
1240
+ await this.persistWorkflowSnapshot({
1241
+ namespace: "workflows",
1242
+ workflowName,
1243
+ runId,
1244
+ snapshot,
1245
+ createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
1246
+ });
1247
+ return snapshot.context;
1248
+ } catch (error) {
1249
+ if (error instanceof _mastra_core_error.MastraError) throw error;
1250
+ throw new _mastra_core_error.MastraError({
1251
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
1252
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1253
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1254
+ details: {
1255
+ workflowName,
1256
+ runId,
1257
+ stepId
1258
+ }
1259
+ }, error);
1260
+ }
1261
+ }
1262
+ async updateWorkflowState({ workflowName, runId, opts }) {
1263
+ try {
1264
+ const existingRecord = await this.db.get({
1265
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1266
+ keys: {
1267
+ namespace: "workflows",
1268
+ workflow_name: workflowName,
1269
+ run_id: runId
1270
+ }
1271
+ });
1272
+ const existingSnapshot = existingRecord?.snapshot;
1273
+ if (!existingSnapshot || !existingSnapshot.context) return;
1274
+ const { expectedStatus, ...state } = opts;
1275
+ if (!(0, _mastra_core_storage.matchesExpectedWorkflowStatus)(existingSnapshot.status, expectedStatus)) return;
1276
+ const updatedSnapshot = {
1277
+ ...existingSnapshot,
1278
+ ...state
1279
+ };
1280
+ await this.persistWorkflowSnapshot({
1281
+ namespace: "workflows",
1282
+ workflowName,
1283
+ runId,
1284
+ snapshot: updatedSnapshot,
1285
+ createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
1286
+ });
1287
+ return updatedSnapshot;
1288
+ } catch (error) {
1289
+ if (error instanceof _mastra_core_error.MastraError) throw error;
1290
+ throw new _mastra_core_error.MastraError({
1291
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "UPDATE_WORKFLOW_STATE", "FAILED"),
1292
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1293
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1294
+ details: {
1295
+ workflowName,
1296
+ runId
1297
+ }
1298
+ }, error);
1299
+ }
1300
+ }
1301
+ async persistWorkflowSnapshot(params) {
1302
+ const { namespace = "workflows", workflowName, runId, resourceId, snapshot, createdAt, updatedAt } = params;
1303
+ try {
1304
+ let finalCreatedAt = createdAt;
1305
+ if (!finalCreatedAt) {
1306
+ const existing = await this.db.get({
1307
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1308
+ keys: {
1309
+ namespace,
1310
+ workflow_name: workflowName,
1311
+ run_id: runId
1312
+ }
1313
+ });
1314
+ finalCreatedAt = existing?.createdAt ? (0, _mastra_core_storage.ensureDate)(existing.createdAt) : /* @__PURE__ */ new Date();
1315
+ }
1316
+ await this.db.insert({
1317
+ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
1318
+ record: {
1319
+ namespace,
1320
+ workflow_name: workflowName,
1321
+ run_id: runId,
1322
+ resourceId,
1323
+ snapshot,
1324
+ createdAt: finalCreatedAt,
1325
+ updatedAt: updatedAt ?? /* @__PURE__ */ new Date()
1326
+ }
1327
+ });
1328
+ } catch (error) {
1329
+ throw new _mastra_core_error.MastraError({
1330
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1331
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1332
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1333
+ details: {
1334
+ namespace,
1335
+ workflowName,
1336
+ runId
1337
+ }
1338
+ }, error);
1339
+ }
1340
+ }
1341
+ async loadWorkflowSnapshot(params) {
1342
+ const { namespace = "workflows", workflowName, runId } = params;
1343
+ const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1344
+ namespace,
1345
+ workflow_name: workflowName,
1346
+ run_id: runId
1347
+ });
1348
+ try {
1349
+ const data = await this.client.get(key);
1350
+ if (!data) return null;
1351
+ return JSON.parse(data).snapshot;
1352
+ } catch (error) {
1353
+ throw new _mastra_core_error.MastraError({
1354
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1355
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1356
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1357
+ details: {
1358
+ namespace,
1359
+ workflowName,
1360
+ runId
1361
+ }
1362
+ }, error);
1363
+ }
1364
+ }
1365
+ async getWorkflowRunById({ runId, workflowName }) {
1366
+ try {
1367
+ const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1368
+ namespace: "workflows",
1369
+ workflow_name: workflowName,
1370
+ run_id: runId
1371
+ }) + "*";
1372
+ const keys = await this.db.scanKeys(key);
1373
+ if (keys.length === 0) return null;
1374
+ const data = (await this.client.mGet(keys)).filter((data) => data !== null).map((data) => JSON.parse(data)).find((workflow) => {
1375
+ if (!workflow) return false;
1376
+ const runIdMatch = workflow.run_id === runId;
1377
+ if (workflowName) return runIdMatch && workflow.workflow_name === workflowName;
1378
+ return runIdMatch;
1379
+ });
1380
+ if (!data) return null;
1381
+ return parseWorkflowRun(data);
1382
+ } catch (error) {
1383
+ throw new _mastra_core_error.MastraError({
1384
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1385
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1386
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1387
+ details: {
1388
+ namespace: "workflows",
1389
+ runId,
1390
+ workflowName: workflowName || ""
1391
+ }
1392
+ }, error);
1393
+ }
1394
+ }
1395
+ async deleteWorkflowRunById({ runId, workflowName }) {
1396
+ const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1397
+ namespace: "workflows",
1398
+ workflow_name: workflowName,
1399
+ run_id: runId
1400
+ });
1401
+ try {
1402
+ await this.client.del(key);
1403
+ } catch (error) {
1404
+ throw new _mastra_core_error.MastraError({
1405
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
1406
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1407
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1408
+ details: {
1409
+ namespace: "workflows",
1410
+ runId,
1411
+ workflowName
1412
+ }
1413
+ }, error);
1414
+ }
1415
+ }
1416
+ async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, status } = {}) {
1417
+ try {
1418
+ if (page !== void 0 && page < 0) throw new _mastra_core_error.MastraError({
1419
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_WORKFLOW_RUNS", "INVALID_PAGE"),
1420
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1421
+ category: _mastra_core_error.ErrorCategory.USER,
1422
+ details: { page }
1423
+ }, /* @__PURE__ */ new Error("page must be >= 0"));
1424
+ const normalizedFrom = fromDate ? (0, _mastra_core_storage.ensureDate)(fromDate) : void 0;
1425
+ const normalizedTo = toDate ? (0, _mastra_core_storage.ensureDate)(toDate) : void 0;
1426
+ let pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" }) + ":*";
1427
+ if (workflowName && resourceId) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1428
+ namespace: "workflows",
1429
+ workflow_name: workflowName,
1430
+ run_id: "*",
1431
+ resourceId
1432
+ });
1433
+ else if (workflowName) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1434
+ namespace: "workflows",
1435
+ workflow_name: workflowName
1436
+ }) + ":*";
1437
+ else if (resourceId) pattern = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
1438
+ namespace: "workflows",
1439
+ workflow_name: "*",
1440
+ run_id: "*",
1441
+ resourceId
1442
+ });
1443
+ const keys = await this.db.scanKeys(pattern);
1444
+ if (keys.length === 0) return {
1445
+ runs: [],
1446
+ total: 0
1447
+ };
1448
+ 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) => {
1449
+ if (normalizedFrom && w.createdAt < normalizedFrom) return false;
1450
+ if (normalizedTo && w.createdAt > normalizedTo) return false;
1451
+ if (status) {
1452
+ let snapshot = w.snapshot;
1453
+ if (typeof snapshot === "string") try {
1454
+ snapshot = JSON.parse(snapshot);
1455
+ } catch (e) {
1456
+ console.warn(`Failed to parse snapshot for workflow ${w.workflowName}: ${e}`);
1457
+ return false;
1458
+ }
1459
+ return snapshot.status === status;
1460
+ }
1461
+ return true;
1462
+ }).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
1463
+ const total = runs.length;
1464
+ if (typeof perPage === "number" && typeof page === "number") {
1465
+ const normalizedPerPage = (0, _mastra_core_storage.normalizePerPage)(perPage, Number.MAX_SAFE_INTEGER);
1466
+ const offset = page * normalizedPerPage;
1467
+ runs = runs.slice(offset, offset + normalizedPerPage);
1468
+ }
1469
+ return {
1470
+ runs,
1471
+ total
1472
+ };
1473
+ } catch (error) {
1474
+ if (error instanceof _mastra_core_error.MastraError) throw error;
1475
+ throw new _mastra_core_error.MastraError({
1476
+ id: (0, _mastra_core_storage.createStorageErrorId)("VALKEY", "LIST_WORKFLOW_RUNS", "FAILED"),
1477
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
1478
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
1479
+ details: {
1480
+ namespace: "workflows",
1481
+ workflowName: workflowName || "",
1482
+ resourceId: resourceId || ""
1483
+ }
1484
+ }, error);
1485
+ }
1486
+ }
1487
+ };
1488
+ //#endregion
1489
+ //#region src/client.ts
1490
+ const asString = (value) => {
1491
+ if (typeof value === "string") return value;
1492
+ if (Buffer.isBuffer(value)) return value.toString();
1493
+ return String(value);
1494
+ };
1495
+ const asNullableString = (value) => value === null ? null : asString(value);
1496
+ const asNumber = (value) => Number(value);
1497
+ var GlideMultiAdapter = class {
1498
+ getClient;
1499
+ batch = new _valkey_valkey_glide.Batch(true);
1500
+ constructor(getClient) {
1501
+ this.getClient = getClient;
1502
+ }
1503
+ del(key) {
1504
+ this.batch.customCommand(["DEL", key]);
1505
+ return this;
1506
+ }
1507
+ set(key, value) {
1508
+ this.batch.customCommand([
1509
+ "SET",
1510
+ key,
1511
+ value
1512
+ ]);
1513
+ return this;
1514
+ }
1515
+ zAdd(key, value) {
1516
+ this.batch.customCommand([
1517
+ "ZADD",
1518
+ key,
1519
+ String(value.score),
1520
+ value.value
1521
+ ]);
1522
+ return this;
1523
+ }
1524
+ zRem(key, value) {
1525
+ this.batch.customCommand([
1526
+ "ZREM",
1527
+ key,
1528
+ value
1529
+ ]);
1530
+ return this;
1531
+ }
1532
+ async exec() {
1533
+ return (await this.getClient()).exec(this.batch, true, { decoder: _valkey_valkey_glide.Decoder.String });
1534
+ }
1535
+ };
1536
+ var GlideValkeyClient = class {
1537
+ config;
1538
+ suppliedClient;
1539
+ clientPromise;
1540
+ constructor(config, suppliedClient) {
1541
+ this.config = config;
1542
+ this.suppliedClient = suppliedClient;
1543
+ }
1544
+ get isOpen() {
1545
+ return this.clientPromise !== void 0 || this.suppliedClient !== void 0;
1546
+ }
1547
+ connect() {
1548
+ return this.getClient().then(() => void 0);
1549
+ }
1550
+ async quit() {
1551
+ (await this.getClient()).close();
1552
+ }
1553
+ async get(key) {
1554
+ return asNullableString(await this.command(["GET", key]));
1555
+ }
1556
+ async set(key, value) {
1557
+ return this.command([
1558
+ "SET",
1559
+ key,
1560
+ value
1561
+ ]);
1562
+ }
1563
+ async mGet(keys) {
1564
+ if (keys.length === 0) return [];
1565
+ return (await this.command(["MGET", ...keys])).map(asNullableString);
1566
+ }
1567
+ async del(keys) {
1568
+ const values = Array.isArray(keys) ? keys : [keys];
1569
+ if (values.length === 0) return 0;
1570
+ return asNumber(await this.command(["DEL", ...values]));
1571
+ }
1572
+ async scan(cursor, options) {
1573
+ const result = await this.command([
1574
+ "SCAN",
1575
+ cursor,
1576
+ "MATCH",
1577
+ options.MATCH,
1578
+ "COUNT",
1579
+ String(options.COUNT)
1580
+ ]);
1581
+ return {
1582
+ cursor: asString(result[0]),
1583
+ keys: result[1].map(asString)
1584
+ };
1585
+ }
1586
+ async zRange(key, start, stop) {
1587
+ return (await this.command([
1588
+ "ZRANGE",
1589
+ key,
1590
+ String(start),
1591
+ String(stop)
1592
+ ])).map(asString);
1593
+ }
1594
+ async zRank(key, value) {
1595
+ const result = await this.command([
1596
+ "ZRANK",
1597
+ key,
1598
+ value
1599
+ ]);
1600
+ return result === null ? null : asNumber(result);
1601
+ }
1602
+ async zAdd(key, value) {
1603
+ return asNumber(await this.command([
1604
+ "ZADD",
1605
+ key,
1606
+ String(value.score),
1607
+ value.value
1608
+ ]));
1609
+ }
1610
+ async zRem(key, value) {
1611
+ return asNumber(await this.command([
1612
+ "ZREM",
1613
+ key,
1614
+ value
1615
+ ]));
1616
+ }
1617
+ multi() {
1618
+ return new GlideMultiAdapter(() => this.getClient());
1619
+ }
1620
+ getClient() {
1621
+ if (this.suppliedClient) return Promise.resolve(this.suppliedClient);
1622
+ this.clientPromise ??= _valkey_valkey_glide.GlideClient.createClient(this.config);
1623
+ return this.clientPromise;
1624
+ }
1625
+ async command(args) {
1626
+ return (await this.getClient()).customCommand(args, { decoder: _valkey_valkey_glide.Decoder.String });
1627
+ }
1628
+ };
1629
+ //#endregion
1630
+ //#region src/storage/store.ts
1631
+ /** GLIDE-backed Valkey storage adapter for Mastra. */
1632
+ var ValkeyStore = class extends _mastra_core_storage.MastraStorage {
1633
+ client;
1634
+ shouldManageConnection;
1635
+ stores;
1636
+ constructor(config) {
1637
+ super({
1638
+ id: config.id,
1639
+ name: "Valkey",
1640
+ disableInit: config.disableInit
1641
+ });
1642
+ if ("client" in config) {
1643
+ this.client = new GlideValkeyClient(void 0, config.client);
1644
+ this.shouldManageConnection = false;
1645
+ } else {
1646
+ const glideConfig = "config" in config ? config.config : {
1647
+ addresses: [{
1648
+ host: config.host,
1649
+ port: config.port ?? 6379
1650
+ }],
1651
+ databaseId: config.db ?? 0,
1652
+ credentials: config.password ? {
1653
+ username: config.username ?? "default",
1654
+ password: config.password
1655
+ } : void 0,
1656
+ useTLS: config.useTLS
1657
+ };
1658
+ this.client = new GlideValkeyClient(glideConfig);
1659
+ this.shouldManageConnection = true;
1660
+ }
1661
+ this.stores = {
1662
+ scores: new ScoresValkey({ client: this.client }),
1663
+ workflows: new WorkflowsValkey({ client: this.client }),
1664
+ memory: new StoreMemoryValkey({ client: this.client })
1665
+ };
1666
+ }
1667
+ async init() {
1668
+ if (this.shouldManageConnection) await this.client.connect();
1669
+ await super.init();
1670
+ }
1671
+ getClient() {
1672
+ return this.client;
1673
+ }
1674
+ async close() {
1675
+ if (this.shouldManageConnection) await this.client.quit();
1676
+ }
1677
+ };
1678
+ //#endregion
1679
+ //#region src/cache.ts
1680
+ const stringValue = (value) => Buffer.isBuffer(value) ? value.toString() : String(value);
1681
+ /** GLIDE-backed Valkey cache for Mastra server state. */
1682
+ var ValkeyServerCache = class extends _mastra_core_cache.MastraServerCache {
1683
+ client;
1684
+ keyPrefix;
1685
+ ttlSeconds;
1686
+ constructor(config, options = {}) {
1687
+ super({ name: "ValkeyServerCache" });
1688
+ this.client = config.client;
1689
+ this.keyPrefix = options.keyPrefix ?? "mastra:cache:";
1690
+ this.ttlSeconds = options.ttlSeconds ?? 300;
1691
+ }
1692
+ getKey(key) {
1693
+ return `${this.keyPrefix}${key}`;
1694
+ }
1695
+ async command(args) {
1696
+ return this.client.customCommand(args, { decoder: _valkey_valkey_glide.Decoder.String });
1697
+ }
1698
+ async get(key) {
1699
+ const value = await this.command(["GET", this.getKey(key)]);
1700
+ if (value === null) return null;
1701
+ const serialized = stringValue(value);
1702
+ try {
1703
+ return JSON.parse(serialized);
1704
+ } catch {
1705
+ return serialized;
1706
+ }
1707
+ }
1708
+ async set(key, value, ttlMs) {
1709
+ const args = [
1710
+ "SET",
1711
+ this.getKey(key),
1712
+ JSON.stringify(value)
1713
+ ];
1714
+ const seconds = ttlMs === void 0 ? this.ttlSeconds : Math.max(1, Math.ceil(ttlMs / 1e3));
1715
+ if (seconds > 0) args.push("EX", String(seconds));
1716
+ await this.command(args);
1717
+ }
1718
+ async listLength(key) {
1719
+ return Number(await this.command(["LLEN", this.getKey(key)]));
1720
+ }
1721
+ async listPush(key, value) {
1722
+ const fullKey = this.getKey(key);
1723
+ await this.command([
1724
+ "RPUSH",
1725
+ fullKey,
1726
+ JSON.stringify(value)
1727
+ ]);
1728
+ if (this.ttlSeconds > 0) await this.command([
1729
+ "EXPIRE",
1730
+ fullKey,
1731
+ String(this.ttlSeconds)
1732
+ ]);
1733
+ }
1734
+ async listFromTo(key, from, to = -1) {
1735
+ return (await this.command([
1736
+ "LRANGE",
1737
+ this.getKey(key),
1738
+ String(from),
1739
+ String(to)
1740
+ ])).map((value) => {
1741
+ const serialized = stringValue(value);
1742
+ try {
1743
+ return JSON.parse(serialized);
1744
+ } catch {
1745
+ return serialized;
1746
+ }
1747
+ });
1748
+ }
1749
+ async delete(key) {
1750
+ await this.command(["DEL", this.getKey(key)]);
1751
+ }
1752
+ async clear() {
1753
+ let cursor = "0";
1754
+ do {
1755
+ const result = await this.command([
1756
+ "SCAN",
1757
+ cursor,
1758
+ "MATCH",
1759
+ `${this.keyPrefix}*`,
1760
+ "COUNT",
1761
+ "100"
1762
+ ]);
1763
+ cursor = stringValue(result[0]);
1764
+ const keys = result[1].map(stringValue);
1765
+ if (keys.length > 0) await this.command(["DEL", ...keys]);
1766
+ } while (cursor !== "0");
1767
+ }
1768
+ async increment(key) {
1769
+ const fullKey = this.getKey(key);
1770
+ const value = Number(await this.command(["INCR", fullKey]));
1771
+ if (this.ttlSeconds > 0) await this.command([
1772
+ "EXPIRE",
1773
+ fullKey,
1774
+ String(this.ttlSeconds)
1775
+ ]);
1776
+ return value;
1777
+ }
1778
+ };
1779
+ //#endregion
1780
+ exports.ScoresValkey = ScoresValkey;
1781
+ exports.StoreMemoryValkey = StoreMemoryValkey;
1782
+ exports.ValkeyServerCache = ValkeyServerCache;
1783
+ exports.ValkeyStore = ValkeyStore;
1784
+ exports.WorkflowsValkey = WorkflowsValkey;
1785
+
1786
+ //# sourceMappingURL=index.cjs.map