@mastra/cloudflare 0.0.0-tsconfig-compile-20250703214351 → 0.0.0-update-stores-peerDeps-20250723031338

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 CHANGED
@@ -1,200 +1,999 @@
1
1
  'use strict';
2
2
 
3
- var agent = require('@mastra/core/agent');
4
3
  var error = require('@mastra/core/error');
5
4
  var storage = require('@mastra/core/storage');
6
5
  var Cloudflare = require('cloudflare');
6
+ var agent = require('@mastra/core/agent');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
10
  var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
11
11
 
12
12
  // src/storage/index.ts
13
-
14
- // src/storage/types.ts
15
- function isWorkersConfig(config) {
16
- return "bindings" in config;
17
- }
18
-
19
- // src/storage/index.ts
20
- var CloudflareStore = class extends storage.MastraStorage {
21
- client;
22
- accountId;
23
- namespacePrefix;
24
- bindings;
25
- validateWorkersConfig(config) {
26
- if (!isWorkersConfig(config)) {
27
- throw new Error("Invalid Workers API configuration");
13
+ var LegacyEvalsStorageCloudflare = class extends storage.LegacyEvalsStorage {
14
+ operations;
15
+ constructor({ operations }) {
16
+ super();
17
+ this.operations = operations;
18
+ }
19
+ async getEvalsByAgentName(agentName, type) {
20
+ try {
21
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
22
+ const keyObjs = await this.operations.listKV(storage.TABLE_EVALS, { prefix: `${prefix}${storage.TABLE_EVALS}` });
23
+ const evals = [];
24
+ for (const { name: key } of keyObjs) {
25
+ const data = await this.operations.getKV(storage.TABLE_EVALS, key);
26
+ if (!data) continue;
27
+ if (data.agent_name !== agentName) continue;
28
+ if (type) {
29
+ const isTest = data.test_info !== null && data.test_info !== void 0;
30
+ const evalType = isTest ? "test" : "live";
31
+ if (evalType !== type) continue;
32
+ }
33
+ const mappedData = {
34
+ ...data,
35
+ runId: data.run_id,
36
+ testInfo: data.test_info
37
+ };
38
+ evals.push(mappedData);
39
+ }
40
+ evals.sort((a, b) => {
41
+ const aTime = new Date(a.createdAt || 0).getTime();
42
+ const bTime = new Date(b.createdAt || 0).getTime();
43
+ return bTime - aTime;
44
+ });
45
+ return evals;
46
+ } catch (error$1) {
47
+ throw new error.MastraError(
48
+ {
49
+ id: "CLOUDFLARE_STORAGE_GET_EVALS_BY_AGENT_NAME_FAILED",
50
+ domain: error.ErrorDomain.STORAGE,
51
+ category: error.ErrorCategory.THIRD_PARTY,
52
+ text: "Failed to get evals by agent name"
53
+ },
54
+ error$1
55
+ );
28
56
  }
29
- if (!config.bindings) {
30
- throw new Error("KV bindings are required when using Workers Binding API");
57
+ }
58
+ async getEvals(options) {
59
+ try {
60
+ const { agentName, type, page = 0, perPage = 100, dateRange } = options;
61
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
62
+ const keyObjs = await this.operations.listKV(storage.TABLE_EVALS, { prefix: `${prefix}${storage.TABLE_EVALS}` });
63
+ const evals = [];
64
+ for (const { name: key } of keyObjs) {
65
+ const data = await this.operations.getKV(storage.TABLE_EVALS, key);
66
+ if (!data) continue;
67
+ if (agentName && data.agent_name !== agentName) continue;
68
+ if (type) {
69
+ const isTest = data.test_info !== null && data.test_info !== void 0;
70
+ const evalType = isTest ? "test" : "live";
71
+ if (evalType !== type) continue;
72
+ }
73
+ if (dateRange?.start || dateRange?.end) {
74
+ const evalDate = new Date(data.createdAt || data.created_at || 0);
75
+ if (dateRange.start && evalDate < dateRange.start) continue;
76
+ if (dateRange.end && evalDate > dateRange.end) continue;
77
+ }
78
+ const mappedData = {
79
+ ...data,
80
+ runId: data.run_id,
81
+ testInfo: data.test_info
82
+ };
83
+ evals.push(mappedData);
84
+ }
85
+ evals.sort((a, b) => {
86
+ const aTime = new Date(a.createdAt || 0).getTime();
87
+ const bTime = new Date(b.createdAt || 0).getTime();
88
+ return bTime - aTime;
89
+ });
90
+ const start = page * perPage;
91
+ const end = start + perPage;
92
+ const paginatedEvals = evals.slice(start, end);
93
+ return {
94
+ page,
95
+ perPage,
96
+ total: evals.length,
97
+ hasMore: start + perPage < evals.length,
98
+ evals: paginatedEvals
99
+ };
100
+ } catch (error$1) {
101
+ throw new error.MastraError(
102
+ {
103
+ id: "CLOUDFLARE_STORAGE_GET_EVALS_FAILED",
104
+ domain: error.ErrorDomain.STORAGE,
105
+ category: error.ErrorCategory.THIRD_PARTY,
106
+ text: "Failed to get evals"
107
+ },
108
+ error$1
109
+ );
31
110
  }
32
- const requiredTables = [storage.TABLE_THREADS, storage.TABLE_MESSAGES, storage.TABLE_WORKFLOW_SNAPSHOT, storage.TABLE_EVALS, storage.TABLE_TRACES];
33
- for (const table of requiredTables) {
34
- if (!(table in config.bindings)) {
35
- throw new Error(`Missing KV binding for table: ${table}`);
111
+ }
112
+ };
113
+ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
114
+ operations;
115
+ constructor({ operations }) {
116
+ super();
117
+ this.operations = operations;
118
+ }
119
+ ensureMetadata(metadata) {
120
+ if (!metadata) return void 0;
121
+ return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
122
+ }
123
+ async getThreadById({ threadId }) {
124
+ const thread = await this.operations.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
125
+ if (!thread) return null;
126
+ try {
127
+ return {
128
+ ...thread,
129
+ createdAt: storage.ensureDate(thread.createdAt),
130
+ updatedAt: storage.ensureDate(thread.updatedAt),
131
+ metadata: this.ensureMetadata(thread.metadata)
132
+ };
133
+ } catch (error$1) {
134
+ const mastraError = new error.MastraError(
135
+ {
136
+ id: "CLOUDFLARE_STORAGE_GET_THREAD_BY_ID_FAILED",
137
+ domain: error.ErrorDomain.STORAGE,
138
+ category: error.ErrorCategory.THIRD_PARTY,
139
+ details: {
140
+ threadId
141
+ }
142
+ },
143
+ error$1
144
+ );
145
+ this.logger?.trackException(mastraError);
146
+ this.logger?.error(mastraError.toString());
147
+ return null;
148
+ }
149
+ }
150
+ async getThreadsByResourceId({ resourceId }) {
151
+ try {
152
+ const keyList = await this.operations.listKV(storage.TABLE_THREADS);
153
+ const threads = await Promise.all(
154
+ keyList.map(async (keyObj) => {
155
+ try {
156
+ const data = await this.operations.getKV(storage.TABLE_THREADS, keyObj.name);
157
+ if (!data) return null;
158
+ const thread = typeof data === "string" ? JSON.parse(data) : data;
159
+ if (!thread || !thread.resourceId || thread.resourceId !== resourceId) return null;
160
+ return {
161
+ ...thread,
162
+ createdAt: storage.ensureDate(thread.createdAt),
163
+ updatedAt: storage.ensureDate(thread.updatedAt),
164
+ metadata: this.ensureMetadata(thread.metadata)
165
+ };
166
+ } catch (error$1) {
167
+ const mastraError = new error.MastraError(
168
+ {
169
+ id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
170
+ domain: error.ErrorDomain.STORAGE,
171
+ category: error.ErrorCategory.THIRD_PARTY,
172
+ details: {
173
+ resourceId
174
+ }
175
+ },
176
+ error$1
177
+ );
178
+ this.logger?.trackException(mastraError);
179
+ this.logger?.error(mastraError.toString());
180
+ return null;
181
+ }
182
+ })
183
+ );
184
+ return threads.filter((thread) => thread !== null);
185
+ } catch (error$1) {
186
+ const mastraError = new error.MastraError(
187
+ {
188
+ id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
189
+ domain: error.ErrorDomain.STORAGE,
190
+ category: error.ErrorCategory.THIRD_PARTY,
191
+ details: {
192
+ resourceId
193
+ }
194
+ },
195
+ error$1
196
+ );
197
+ this.logger?.trackException(mastraError);
198
+ this.logger?.error(mastraError.toString());
199
+ return [];
200
+ }
201
+ }
202
+ async getThreadsByResourceIdPaginated(args) {
203
+ try {
204
+ const { resourceId, page = 0, perPage = 100 } = args;
205
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
206
+ const keyObjs = await this.operations.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
207
+ const threads = [];
208
+ for (const { name: key } of keyObjs) {
209
+ const data = await this.operations.getKV(storage.TABLE_THREADS, key);
210
+ if (!data) continue;
211
+ if (data.resourceId !== resourceId) continue;
212
+ threads.push(data);
36
213
  }
214
+ threads.sort((a, b) => {
215
+ const aTime = new Date(a.createdAt || 0).getTime();
216
+ const bTime = new Date(b.createdAt || 0).getTime();
217
+ return bTime - aTime;
218
+ });
219
+ const start = page * perPage;
220
+ const end = start + perPage;
221
+ const paginatedThreads = threads.slice(start, end);
222
+ return {
223
+ page,
224
+ perPage,
225
+ total: threads.length,
226
+ hasMore: start + perPage < threads.length,
227
+ threads: paginatedThreads
228
+ };
229
+ } catch (error$1) {
230
+ throw new error.MastraError(
231
+ {
232
+ id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
233
+ domain: error.ErrorDomain.STORAGE,
234
+ category: error.ErrorCategory.THIRD_PARTY,
235
+ text: "Failed to get threads by resource ID with pagination"
236
+ },
237
+ error$1
238
+ );
37
239
  }
38
240
  }
39
- validateRestConfig(config) {
40
- if (isWorkersConfig(config)) {
41
- throw new Error("Invalid REST API configuration");
241
+ async saveThread({ thread }) {
242
+ try {
243
+ await this.operations.insert({ tableName: storage.TABLE_THREADS, record: thread });
244
+ return thread;
245
+ } catch (error$1) {
246
+ throw new error.MastraError(
247
+ {
248
+ id: "CLOUDFLARE_STORAGE_SAVE_THREAD_FAILED",
249
+ domain: error.ErrorDomain.STORAGE,
250
+ category: error.ErrorCategory.THIRD_PARTY,
251
+ details: {
252
+ threadId: thread.id
253
+ }
254
+ },
255
+ error$1
256
+ );
42
257
  }
43
- if (!config.accountId?.trim()) {
44
- throw new Error("accountId is required for REST API");
258
+ }
259
+ async updateThread({
260
+ id,
261
+ title,
262
+ metadata
263
+ }) {
264
+ try {
265
+ const thread = await this.getThreadById({ threadId: id });
266
+ if (!thread) {
267
+ throw new Error(`Thread ${id} not found`);
268
+ }
269
+ const updatedThread = {
270
+ ...thread,
271
+ title,
272
+ metadata: this.ensureMetadata({
273
+ ...thread.metadata ?? {},
274
+ ...metadata
275
+ }),
276
+ updatedAt: /* @__PURE__ */ new Date()
277
+ };
278
+ await this.operations.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
279
+ return updatedThread;
280
+ } catch (error$1) {
281
+ throw new error.MastraError(
282
+ {
283
+ id: "CLOUDFLARE_STORAGE_UPDATE_THREAD_FAILED",
284
+ domain: error.ErrorDomain.STORAGE,
285
+ category: error.ErrorCategory.THIRD_PARTY,
286
+ details: {
287
+ threadId: id,
288
+ title
289
+ }
290
+ },
291
+ error$1
292
+ );
45
293
  }
46
- if (!config.apiToken?.trim()) {
47
- throw new Error("apiToken is required for REST API");
294
+ }
295
+ getMessageKey(threadId, messageId) {
296
+ try {
297
+ return this.operations.getKey(storage.TABLE_MESSAGES, { threadId, id: messageId });
298
+ } catch (error) {
299
+ const message = error instanceof Error ? error.message : String(error);
300
+ this.logger.error(`Error getting message key for thread ${threadId} and message ${messageId}:`, { message });
301
+ throw error;
48
302
  }
49
303
  }
50
- constructor(config) {
51
- super({ name: "Cloudflare" });
304
+ getThreadMessagesKey(threadId) {
52
305
  try {
53
- if (isWorkersConfig(config)) {
54
- this.validateWorkersConfig(config);
55
- this.bindings = config.bindings;
56
- this.namespacePrefix = config.keyPrefix?.trim() || "";
57
- this.logger.info("Using Cloudflare KV Workers Binding API");
58
- } else {
59
- this.validateRestConfig(config);
60
- this.accountId = config.accountId.trim();
61
- this.namespacePrefix = config.namespacePrefix?.trim() || "";
62
- this.client = new Cloudflare__default.default({
63
- apiToken: config.apiToken.trim()
64
- });
65
- this.logger.info("Using Cloudflare KV REST API");
306
+ return this.operations.getKey(storage.TABLE_MESSAGES, { threadId, id: "messages" });
307
+ } catch (error) {
308
+ const message = error instanceof Error ? error.message : String(error);
309
+ this.logger.error(`Error getting thread messages key for thread ${threadId}:`, { message });
310
+ throw error;
311
+ }
312
+ }
313
+ async deleteThread({ threadId }) {
314
+ try {
315
+ const thread = await this.getThreadById({ threadId });
316
+ if (!thread) {
317
+ throw new Error(`Thread ${threadId} not found`);
318
+ }
319
+ const messageKeys = await this.operations.listKV(storage.TABLE_MESSAGES);
320
+ const threadMessageKeys = messageKeys.filter((key) => key.name.includes(`${storage.TABLE_MESSAGES}:${threadId}:`));
321
+ await Promise.all([
322
+ // Delete message order
323
+ this.operations.deleteKV(storage.TABLE_MESSAGES, this.getThreadMessagesKey(threadId)),
324
+ // Delete all messages
325
+ ...threadMessageKeys.map((key) => this.operations.deleteKV(storage.TABLE_MESSAGES, key.name)),
326
+ // Delete thread
327
+ this.operations.deleteKV(storage.TABLE_THREADS, this.operations.getKey(storage.TABLE_THREADS, { id: threadId }))
328
+ ]);
329
+ } catch (error$1) {
330
+ throw new error.MastraError(
331
+ {
332
+ id: "CLOUDFLARE_STORAGE_DELETE_THREAD_FAILED",
333
+ domain: error.ErrorDomain.STORAGE,
334
+ category: error.ErrorCategory.THIRD_PARTY,
335
+ details: {
336
+ threadId
337
+ }
338
+ },
339
+ error$1
340
+ );
341
+ }
342
+ }
343
+ async findMessageInAnyThread(messageId) {
344
+ try {
345
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
346
+ const threadKeys = await this.operations.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
347
+ for (const { name: threadKey } of threadKeys) {
348
+ const threadId = threadKey.split(":").pop();
349
+ if (!threadId || threadId === "messages") continue;
350
+ const messageKey = this.getMessageKey(threadId, messageId);
351
+ const message = await this.operations.getKV(storage.TABLE_MESSAGES, messageKey);
352
+ if (message) {
353
+ return { ...message, threadId };
354
+ }
355
+ }
356
+ return null;
357
+ } catch (error) {
358
+ this.logger?.error(`Error finding message ${messageId} in any thread:`, error);
359
+ return null;
360
+ }
361
+ }
362
+ /**
363
+ * Queue for serializing sorted order updates.
364
+ * Updates the sorted order for a given key. This operation is eventually consistent.
365
+ */
366
+ updateQueue = /* @__PURE__ */ new Map();
367
+ async updateSorting(threadMessages) {
368
+ return threadMessages.map((msg) => ({
369
+ message: msg,
370
+ // Use _index if available, otherwise timestamp, matching Upstash
371
+ score: msg._index !== void 0 ? msg._index : msg.createdAt.getTime()
372
+ })).sort((a, b) => a.score - b.score).map((item) => ({
373
+ id: item.message.id,
374
+ score: item.score
375
+ }));
376
+ }
377
+ /**
378
+ * Updates the sorted order for a given key. This operation is eventually consistent.
379
+ * Note: Operations on the same orderKey are serialized using a queue to prevent
380
+ * concurrent updates from conflicting with each other.
381
+ */
382
+ async updateSortedMessages(orderKey, newEntries) {
383
+ const currentPromise = this.updateQueue.get(orderKey) || Promise.resolve();
384
+ const nextPromise = currentPromise.then(async () => {
385
+ try {
386
+ const currentOrder = await this.getSortedMessages(orderKey);
387
+ const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
388
+ for (const entry of newEntries) {
389
+ orderMap.set(entry.id, entry);
390
+ }
391
+ const updatedOrder = Array.from(orderMap.values()).sort((a, b) => a.score - b.score);
392
+ await this.operations.putKV({
393
+ tableName: storage.TABLE_MESSAGES,
394
+ key: orderKey,
395
+ value: JSON.stringify(updatedOrder)
396
+ });
397
+ } catch (error) {
398
+ const message = error instanceof Error ? error.message : String(error);
399
+ this.logger.error(`Error updating sorted order for key ${orderKey}:`, { message });
400
+ throw error;
401
+ } finally {
402
+ if (this.updateQueue.get(orderKey) === nextPromise) {
403
+ this.updateQueue.delete(orderKey);
404
+ }
405
+ }
406
+ });
407
+ this.updateQueue.set(orderKey, nextPromise);
408
+ return nextPromise;
409
+ }
410
+ async getSortedMessages(orderKey) {
411
+ const raw = await this.operations.getKV(storage.TABLE_MESSAGES, orderKey);
412
+ if (!raw) return [];
413
+ try {
414
+ const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
415
+ return Array.isArray(arr) ? arr : [];
416
+ } catch (e) {
417
+ this.logger.error(`Error parsing order data for key ${orderKey}:`, { e });
418
+ return [];
419
+ }
420
+ }
421
+ async migrateMessage(messageId, fromThreadId, toThreadId) {
422
+ try {
423
+ const oldMessageKey = this.getMessageKey(fromThreadId, messageId);
424
+ const message = await this.operations.getKV(storage.TABLE_MESSAGES, oldMessageKey);
425
+ if (!message) return;
426
+ const updatedMessage = {
427
+ ...message,
428
+ threadId: toThreadId
429
+ };
430
+ const newMessageKey = this.getMessageKey(toThreadId, messageId);
431
+ await this.operations.putKV({ tableName: storage.TABLE_MESSAGES, key: newMessageKey, value: updatedMessage });
432
+ const oldOrderKey = this.getThreadMessagesKey(fromThreadId);
433
+ const oldEntries = await this.getSortedMessages(oldOrderKey);
434
+ const filteredEntries = oldEntries.filter((entry) => entry.id !== messageId);
435
+ await this.updateSortedMessages(oldOrderKey, filteredEntries);
436
+ const newOrderKey = this.getThreadMessagesKey(toThreadId);
437
+ const newEntries = await this.getSortedMessages(newOrderKey);
438
+ const newEntry = { id: messageId, score: Date.now() };
439
+ newEntries.push(newEntry);
440
+ await this.updateSortedMessages(newOrderKey, newEntries);
441
+ await this.operations.deleteKV(storage.TABLE_MESSAGES, oldMessageKey);
442
+ } catch (error) {
443
+ this.logger?.error(`Error migrating message ${messageId} from ${fromThreadId} to ${toThreadId}:`, error);
444
+ throw error;
445
+ }
446
+ }
447
+ async saveMessages(args) {
448
+ const { messages, format = "v1" } = args;
449
+ if (!Array.isArray(messages) || messages.length === 0) return [];
450
+ try {
451
+ const validatedMessages = messages.map((message, index) => {
452
+ const errors = [];
453
+ if (!message.id) errors.push("id is required");
454
+ if (!message.threadId) errors.push("threadId is required");
455
+ if (!message.content) errors.push("content is required");
456
+ if (!message.role) errors.push("role is required");
457
+ if (!message.createdAt) errors.push("createdAt is required");
458
+ if (message.resourceId === null || message.resourceId === void 0) errors.push("resourceId is required");
459
+ if (errors.length > 0) {
460
+ throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
461
+ }
462
+ return {
463
+ ...message,
464
+ createdAt: storage.ensureDate(message.createdAt),
465
+ type: message.type || "v2",
466
+ _index: index
467
+ };
468
+ }).filter((m) => !!m);
469
+ const messageMigrationTasks = [];
470
+ for (const message of validatedMessages) {
471
+ const existingMessage = await this.findMessageInAnyThread(message.id);
472
+ console.log(`Checking message ${message.id}: existing=${existingMessage?.threadId}, new=${message.threadId}`);
473
+ if (existingMessage && existingMessage.threadId && existingMessage.threadId !== message.threadId) {
474
+ console.log(`Migrating message ${message.id} from ${existingMessage.threadId} to ${message.threadId}`);
475
+ messageMigrationTasks.push(this.migrateMessage(message.id, existingMessage.threadId, message.threadId));
476
+ }
477
+ }
478
+ await Promise.all(messageMigrationTasks);
479
+ const messagesByThread = validatedMessages.reduce((acc, message) => {
480
+ if (message.threadId && !acc.has(message.threadId)) {
481
+ acc.set(message.threadId, []);
482
+ }
483
+ if (message.threadId) {
484
+ acc.get(message.threadId).push(message);
485
+ }
486
+ return acc;
487
+ }, /* @__PURE__ */ new Map());
488
+ await Promise.all(
489
+ Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
490
+ try {
491
+ const thread = await this.getThreadById({ threadId });
492
+ if (!thread) {
493
+ throw new Error(`Thread ${threadId} not found`);
494
+ }
495
+ await Promise.all(
496
+ threadMessages.map(async (message) => {
497
+ const key = this.getMessageKey(threadId, message.id);
498
+ const { _index, ...cleanMessage } = message;
499
+ const serializedMessage = {
500
+ ...cleanMessage,
501
+ createdAt: storage.serializeDate(cleanMessage.createdAt)
502
+ };
503
+ console.log(`Saving message ${message.id} with content:`, {
504
+ content: serializedMessage.content,
505
+ contentType: typeof serializedMessage.content,
506
+ isArray: Array.isArray(serializedMessage.content)
507
+ });
508
+ await this.operations.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
509
+ })
510
+ );
511
+ const orderKey = this.getThreadMessagesKey(threadId);
512
+ const entries = await this.updateSorting(threadMessages);
513
+ await this.updateSortedMessages(orderKey, entries);
514
+ const updatedThread = {
515
+ ...thread,
516
+ updatedAt: /* @__PURE__ */ new Date()
517
+ };
518
+ await this.operations.putKV({
519
+ tableName: storage.TABLE_THREADS,
520
+ key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
521
+ value: updatedThread
522
+ });
523
+ } catch (error$1) {
524
+ throw new error.MastraError(
525
+ {
526
+ id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
527
+ domain: error.ErrorDomain.STORAGE,
528
+ category: error.ErrorCategory.THIRD_PARTY,
529
+ details: {
530
+ threadId
531
+ }
532
+ },
533
+ error$1
534
+ );
535
+ }
536
+ })
537
+ );
538
+ const prepared = validatedMessages.map(
539
+ ({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
540
+ );
541
+ const list = new agent.MessageList().add(prepared, "memory");
542
+ if (format === `v2`) return list.get.all.v2();
543
+ return list.get.all.v1();
544
+ } catch (error$1) {
545
+ throw new error.MastraError(
546
+ {
547
+ id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
548
+ domain: error.ErrorDomain.STORAGE,
549
+ category: error.ErrorCategory.THIRD_PARTY
550
+ },
551
+ error$1
552
+ );
553
+ }
554
+ }
555
+ async getRank(orderKey, id) {
556
+ const order = await this.getSortedMessages(orderKey);
557
+ const index = order.findIndex((item) => item.id === id);
558
+ return index >= 0 ? index : null;
559
+ }
560
+ async getRange(orderKey, start, end) {
561
+ const order = await this.getSortedMessages(orderKey);
562
+ const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
563
+ const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
564
+ const sliced = order.slice(actualStart, actualEnd + 1);
565
+ return sliced.map((item) => item.id);
566
+ }
567
+ async getLastN(orderKey, n) {
568
+ return this.getRange(orderKey, -n, -1);
569
+ }
570
+ async getFullOrder(orderKey) {
571
+ return this.getRange(orderKey, 0, -1);
572
+ }
573
+ async getIncludedMessagesWithContext(threadId, include, messageIds) {
574
+ await Promise.all(
575
+ include.map(async (item) => {
576
+ const targetThreadId = item.threadId || threadId;
577
+ if (!targetThreadId) return;
578
+ const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
579
+ messageIds.add(item.id);
580
+ if (!item.withPreviousMessages && !item.withNextMessages) return;
581
+ const rank = await this.getRank(threadMessagesKey, item.id);
582
+ if (rank === null) return;
583
+ if (item.withPreviousMessages) {
584
+ const prevIds = await this.getRange(
585
+ threadMessagesKey,
586
+ Math.max(0, rank - item.withPreviousMessages),
587
+ rank - 1
588
+ );
589
+ prevIds.forEach((id) => messageIds.add(id));
590
+ }
591
+ if (item.withNextMessages) {
592
+ const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
593
+ nextIds.forEach((id) => messageIds.add(id));
594
+ }
595
+ })
596
+ );
597
+ }
598
+ async getRecentMessages(threadId, limit, messageIds) {
599
+ if (limit <= 0) return;
600
+ try {
601
+ const threadMessagesKey = this.getThreadMessagesKey(threadId);
602
+ const latestIds = await this.getLastN(threadMessagesKey, limit);
603
+ latestIds.forEach((id) => messageIds.add(id));
604
+ } catch {
605
+ console.log(`No message order found for thread ${threadId}, skipping latest messages`);
606
+ }
607
+ }
608
+ async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
609
+ const messageIdToThreadId = /* @__PURE__ */ new Map();
610
+ if (include) {
611
+ for (const item of include) {
612
+ if (item.threadId) {
613
+ messageIdToThreadId.set(item.id, item.threadId);
614
+ }
615
+ }
616
+ }
617
+ const messages = await Promise.all(
618
+ messageIds.map(async (id) => {
619
+ try {
620
+ let threadId = messageIdToThreadId.get(id);
621
+ if (!threadId) {
622
+ if (targetThreadId) {
623
+ threadId = targetThreadId;
624
+ } else {
625
+ const foundMessage = await this.findMessageInAnyThread(id);
626
+ if (foundMessage) {
627
+ threadId = foundMessage.threadId;
628
+ }
629
+ }
630
+ }
631
+ if (!threadId) return null;
632
+ const key = this.getMessageKey(threadId, id);
633
+ const data = await this.operations.getKV(storage.TABLE_MESSAGES, key);
634
+ if (!data) return null;
635
+ const parsed = typeof data === "string" ? JSON.parse(data) : data;
636
+ console.log(`Retrieved message ${id} from thread ${threadId} with content:`, {
637
+ content: parsed.content,
638
+ contentType: typeof parsed.content,
639
+ isArray: Array.isArray(parsed.content)
640
+ });
641
+ return parsed;
642
+ } catch (error) {
643
+ const message = error instanceof Error ? error.message : String(error);
644
+ this.logger.error(`Error retrieving message ${id}:`, { message });
645
+ return null;
646
+ }
647
+ })
648
+ );
649
+ return messages.filter((msg) => msg !== null);
650
+ }
651
+ async getMessages({
652
+ threadId,
653
+ resourceId,
654
+ selectBy,
655
+ format
656
+ }) {
657
+ console.log(`getMessages called with format: ${format}, threadId: ${threadId}`);
658
+ if (!threadId) throw new Error("threadId is required");
659
+ const actualFormat = format || "v1";
660
+ console.log(`Using format: ${actualFormat}`);
661
+ if (!threadId) throw new Error("threadId is required");
662
+ const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
663
+ const messageIds = /* @__PURE__ */ new Set();
664
+ if (limit === 0 && !selectBy?.include?.length) return [];
665
+ try {
666
+ await Promise.all([
667
+ selectBy?.include?.length ? this.getIncludedMessagesWithContext(threadId, selectBy.include, messageIds) : Promise.resolve(),
668
+ limit > 0 ? this.getRecentMessages(threadId, limit, messageIds) : Promise.resolve()
669
+ ]);
670
+ const targetThreadId = selectBy?.include?.length ? void 0 : threadId;
671
+ const messages = await this.fetchAndParseMessagesFromMultipleThreads(
672
+ Array.from(messageIds),
673
+ selectBy?.include,
674
+ targetThreadId
675
+ );
676
+ if (!messages.length) return [];
677
+ try {
678
+ const threadMessagesKey = this.getThreadMessagesKey(threadId);
679
+ const messageOrder = await this.getFullOrder(threadMessagesKey);
680
+ const orderMap = new Map(messageOrder.map((id, index) => [id, index]));
681
+ messages.sort((a, b) => {
682
+ const indexA = orderMap.get(a.id);
683
+ const indexB = orderMap.get(b.id);
684
+ if (indexA !== void 0 && indexB !== void 0) return orderMap.get(a.id) - orderMap.get(b.id);
685
+ return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
686
+ });
687
+ } catch (error$1) {
688
+ const mastraError = new error.MastraError(
689
+ {
690
+ id: "CLOUDFLARE_STORAGE_SORT_MESSAGES_FAILED",
691
+ domain: error.ErrorDomain.STORAGE,
692
+ category: error.ErrorCategory.THIRD_PARTY,
693
+ text: `Error sorting messages for thread ${threadId} falling back to creation time`,
694
+ details: {
695
+ threadId
696
+ }
697
+ },
698
+ error$1
699
+ );
700
+ this.logger?.trackException(mastraError);
701
+ this.logger?.error(mastraError.toString());
702
+ messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
703
+ }
704
+ const prepared = messages.map(({ _index, ...message }) => ({
705
+ ...message,
706
+ type: message.type === `v2` ? void 0 : message.type,
707
+ createdAt: storage.ensureDate(message.createdAt)
708
+ }));
709
+ if (actualFormat === `v1`) {
710
+ console.log(`Processing ${prepared.length} messages for v1 format - returning directly without MessageList`);
711
+ return prepared.map((msg) => ({
712
+ ...msg,
713
+ createdAt: new Date(msg.createdAt)
714
+ }));
715
+ }
716
+ const list = new agent.MessageList({ threadId, resourceId }).add(prepared, "memory");
717
+ return list.get.all.v2();
718
+ } catch (error$1) {
719
+ const mastraError = new error.MastraError(
720
+ {
721
+ id: "CLOUDFLARE_STORAGE_GET_MESSAGES_FAILED",
722
+ domain: error.ErrorDomain.STORAGE,
723
+ category: error.ErrorCategory.THIRD_PARTY,
724
+ text: `Error retrieving messages for thread ${threadId}`,
725
+ details: {
726
+ threadId
727
+ }
728
+ },
729
+ error$1
730
+ );
731
+ this.logger?.trackException(mastraError);
732
+ this.logger?.error(mastraError.toString());
733
+ return [];
734
+ }
735
+ }
736
+ async getMessagesPaginated(args) {
737
+ try {
738
+ const { threadId, selectBy, format = "v1" } = args;
739
+ const { page = 0, perPage = 100 } = selectBy?.pagination || {};
740
+ const messages = format === "v2" ? await this.getMessages({ threadId, selectBy, format: "v2" }) : await this.getMessages({ threadId, selectBy, format: "v1" });
741
+ let filteredMessages = messages;
742
+ if (selectBy?.pagination?.dateRange) {
743
+ const { start: dateStart, end: dateEnd } = selectBy.pagination.dateRange;
744
+ filteredMessages = messages.filter((message) => {
745
+ const messageDate = new Date(message.createdAt);
746
+ if (dateStart && messageDate < dateStart) return false;
747
+ if (dateEnd && messageDate > dateEnd) return false;
748
+ return true;
749
+ });
750
+ }
751
+ const start = page * perPage;
752
+ const end = start + perPage;
753
+ const paginatedMessages = filteredMessages.slice(start, end);
754
+ return {
755
+ page,
756
+ perPage,
757
+ total: filteredMessages.length,
758
+ hasMore: start + perPage < filteredMessages.length,
759
+ messages: paginatedMessages
760
+ };
761
+ } catch (error$1) {
762
+ throw new error.MastraError(
763
+ {
764
+ id: "CLOUDFLARE_STORAGE_GET_MESSAGES_PAGINATED_FAILED",
765
+ domain: error.ErrorDomain.STORAGE,
766
+ category: error.ErrorCategory.THIRD_PARTY,
767
+ text: "Failed to get messages with pagination"
768
+ },
769
+ error$1
770
+ );
771
+ }
772
+ }
773
+ async updateMessages(args) {
774
+ try {
775
+ const { messages } = args;
776
+ const updatedMessages = [];
777
+ for (const messageUpdate of messages) {
778
+ const { id, content, ...otherFields } = messageUpdate;
779
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
780
+ const keyObjs = await this.operations.listKV(storage.TABLE_MESSAGES, { prefix: `${prefix}${storage.TABLE_MESSAGES}` });
781
+ let existingMessage = null;
782
+ let messageKey = "";
783
+ for (const { name: key } of keyObjs) {
784
+ const data = await this.operations.getKV(storage.TABLE_MESSAGES, key);
785
+ if (data && data.id === id) {
786
+ existingMessage = data;
787
+ messageKey = key;
788
+ break;
789
+ }
790
+ }
791
+ if (!existingMessage) {
792
+ continue;
793
+ }
794
+ const updatedMessage = {
795
+ ...existingMessage,
796
+ ...otherFields,
797
+ id
798
+ };
799
+ if (content) {
800
+ if (content.metadata !== void 0) {
801
+ updatedMessage.content = {
802
+ ...updatedMessage.content,
803
+ metadata: {
804
+ ...updatedMessage.content?.metadata,
805
+ ...content.metadata
806
+ }
807
+ };
808
+ }
809
+ if (content.content !== void 0) {
810
+ updatedMessage.content = {
811
+ ...updatedMessage.content,
812
+ content: content.content
813
+ };
814
+ }
815
+ }
816
+ if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
817
+ await this.operations.deleteKV(storage.TABLE_MESSAGES, messageKey);
818
+ updatedMessage.threadId = messageUpdate.threadId;
819
+ const newMessageKey = this.getMessageKey(messageUpdate.threadId, id);
820
+ await this.operations.putKV({
821
+ tableName: storage.TABLE_MESSAGES,
822
+ key: newMessageKey,
823
+ value: updatedMessage
824
+ });
825
+ if (existingMessage.threadId) {
826
+ const sourceOrderKey = this.getThreadMessagesKey(existingMessage.threadId);
827
+ const sourceEntries = await this.getSortedMessages(sourceOrderKey);
828
+ const filteredEntries = sourceEntries.filter((entry) => entry.id !== id);
829
+ await this.updateSortedMessages(sourceOrderKey, filteredEntries);
830
+ }
831
+ const destOrderKey = this.getThreadMessagesKey(messageUpdate.threadId);
832
+ const destEntries = await this.getSortedMessages(destOrderKey);
833
+ const newEntry = { id, score: Date.now() };
834
+ destEntries.push(newEntry);
835
+ await this.updateSortedMessages(destOrderKey, destEntries);
836
+ } else {
837
+ await this.operations.putKV({
838
+ tableName: storage.TABLE_MESSAGES,
839
+ key: messageKey,
840
+ value: updatedMessage
841
+ });
842
+ }
843
+ const threadsToUpdate = /* @__PURE__ */ new Set();
844
+ if (updatedMessage.threadId) {
845
+ threadsToUpdate.add(updatedMessage.threadId);
846
+ }
847
+ if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
848
+ if (existingMessage.threadId) {
849
+ threadsToUpdate.add(existingMessage.threadId);
850
+ }
851
+ threadsToUpdate.add(messageUpdate.threadId);
852
+ }
853
+ for (const threadId of threadsToUpdate) {
854
+ const thread = await this.getThreadById({ threadId });
855
+ if (thread) {
856
+ const updatedThread = {
857
+ ...thread,
858
+ updatedAt: /* @__PURE__ */ new Date()
859
+ };
860
+ await this.operations.putKV({
861
+ tableName: storage.TABLE_THREADS,
862
+ key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
863
+ value: updatedThread
864
+ });
865
+ }
866
+ }
867
+ updatedMessages.push(updatedMessage);
66
868
  }
869
+ return updatedMessages;
67
870
  } catch (error$1) {
68
871
  throw new error.MastraError(
69
872
  {
70
- id: "CLOUDFLARE_STORAGE_INIT_FAILED",
873
+ id: "CLOUDFLARE_STORAGE_UPDATE_MESSAGES_FAILED",
71
874
  domain: error.ErrorDomain.STORAGE,
72
- category: error.ErrorCategory.THIRD_PARTY
875
+ category: error.ErrorCategory.THIRD_PARTY,
876
+ text: "Failed to update messages"
73
877
  },
74
878
  error$1
75
879
  );
76
880
  }
77
881
  }
78
- getBinding(tableName) {
79
- if (!this.bindings) {
80
- throw new Error(`Cannot use Workers API binding for ${tableName}: Store initialized with REST API configuration`);
81
- }
82
- const binding = this.bindings[tableName];
83
- if (!binding) throw new Error(`No binding found for namespace ${tableName}`);
84
- return binding;
85
- }
86
- async listNamespaces() {
87
- if (this.bindings) {
882
+ async getResourceById({ resourceId }) {
883
+ try {
884
+ const data = await this.operations.getKV(storage.TABLE_RESOURCES, resourceId);
885
+ if (!data) return null;
886
+ const resource = typeof data === "string" ? JSON.parse(data) : data;
88
887
  return {
89
- result: Object.keys(this.bindings).map((name) => ({
90
- id: name,
91
- title: name,
92
- supports_url_encoding: true
93
- }))
888
+ ...resource,
889
+ createdAt: storage.ensureDate(resource.createdAt),
890
+ updatedAt: storage.ensureDate(resource.updatedAt),
891
+ metadata: this.ensureMetadata(resource.metadata)
94
892
  };
893
+ } catch (error$1) {
894
+ const mastraError = new error.MastraError(
895
+ {
896
+ id: "CLOUDFLARE_STORAGE_GET_RESOURCE_BY_ID_FAILED",
897
+ domain: error.ErrorDomain.STORAGE,
898
+ category: error.ErrorCategory.THIRD_PARTY,
899
+ details: {
900
+ resourceId
901
+ }
902
+ },
903
+ error$1
904
+ );
905
+ this.logger?.trackException(mastraError);
906
+ this.logger?.error(mastraError.toString());
907
+ return null;
95
908
  }
96
- let allNamespaces = [];
97
- let currentPage = 1;
98
- const perPage = 50;
99
- let morePagesExist = true;
100
- while (morePagesExist) {
101
- const response = await this.client.kv.namespaces.list({
102
- account_id: this.accountId,
103
- page: currentPage,
104
- per_page: perPage
105
- });
106
- if (response.result) {
107
- allNamespaces = allNamespaces.concat(response.result);
108
- }
109
- morePagesExist = response.result ? response.result.length === perPage : false;
110
- if (morePagesExist) {
111
- currentPage++;
112
- }
113
- }
114
- return { result: allNamespaces };
115
909
  }
116
- async getNamespaceValue(tableName, key) {
910
+ async saveResource({ resource }) {
117
911
  try {
118
- if (this.bindings) {
119
- const binding = this.getBinding(tableName);
120
- const result = await binding.getWithMetadata(key, "text");
121
- if (!result) return null;
122
- return JSON.stringify(result);
123
- } else {
124
- const namespaceId = await this.getNamespaceId(tableName);
125
- const response = await this.client.kv.namespaces.values.get(namespaceId, key, {
126
- account_id: this.accountId
127
- });
128
- return await response.text();
129
- }
130
- } catch (error) {
131
- if (error.message && error.message.includes("key not found")) {
132
- return null;
133
- }
134
- const message = error instanceof Error ? error.message : String(error);
135
- this.logger.error(`Failed to get value for ${tableName} ${key}:`, { message });
136
- throw error;
912
+ const resourceToSave = {
913
+ ...resource,
914
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : null
915
+ };
916
+ await this.operations.putKV({
917
+ tableName: storage.TABLE_RESOURCES,
918
+ key: resource.id,
919
+ value: resourceToSave
920
+ });
921
+ return resource;
922
+ } catch (error$1) {
923
+ throw new error.MastraError(
924
+ {
925
+ id: "CLOUDFLARE_STORAGE_SAVE_RESOURCE_FAILED",
926
+ domain: error.ErrorDomain.STORAGE,
927
+ category: error.ErrorCategory.THIRD_PARTY,
928
+ details: {
929
+ resourceId: resource.id
930
+ }
931
+ },
932
+ error$1
933
+ );
137
934
  }
138
935
  }
139
- async putNamespaceValue({
140
- tableName,
141
- key,
142
- value,
936
+ async updateResource({
937
+ resourceId,
938
+ workingMemory,
143
939
  metadata
144
940
  }) {
145
- try {
146
- const serializedValue = this.safeSerialize(value);
147
- const serializedMetadata = metadata ? this.safeSerialize(metadata) : "";
148
- if (this.bindings) {
149
- const binding = this.getBinding(tableName);
150
- await binding.put(key, serializedValue, { metadata: serializedMetadata });
151
- } else {
152
- const namespaceId = await this.getNamespaceId(tableName);
153
- await this.client.kv.namespaces.values.update(namespaceId, key, {
154
- account_id: this.accountId,
155
- value: serializedValue,
156
- metadata: serializedMetadata
157
- });
158
- }
159
- } catch (error) {
160
- const message = error instanceof Error ? error.message : String(error);
161
- this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
162
- throw error;
941
+ const existingResource = await this.getResourceById({ resourceId });
942
+ if (!existingResource) {
943
+ const newResource = {
944
+ id: resourceId,
945
+ workingMemory,
946
+ metadata: metadata || {},
947
+ createdAt: /* @__PURE__ */ new Date(),
948
+ updatedAt: /* @__PURE__ */ new Date()
949
+ };
950
+ return this.saveResource({ resource: newResource });
163
951
  }
952
+ const updatedAt = /* @__PURE__ */ new Date();
953
+ const updatedResource = {
954
+ ...existingResource,
955
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
956
+ metadata: {
957
+ ...existingResource.metadata,
958
+ ...metadata
959
+ },
960
+ updatedAt
961
+ };
962
+ return this.saveResource({ resource: updatedResource });
164
963
  }
165
- async deleteNamespaceValue(tableName, key) {
166
- if (this.bindings) {
167
- const binding = this.getBinding(tableName);
168
- await binding.delete(key);
169
- } else {
170
- const namespaceId = await this.getNamespaceId(tableName);
171
- await this.client.kv.namespaces.values.delete(namespaceId, key, {
172
- account_id: this.accountId
173
- });
174
- }
964
+ };
965
+ var StoreOperationsCloudflare = class extends storage.StoreOperations {
966
+ bindings;
967
+ client;
968
+ accountId;
969
+ namespacePrefix;
970
+ constructor({
971
+ namespacePrefix,
972
+ bindings,
973
+ client,
974
+ accountId
975
+ }) {
976
+ super();
977
+ this.bindings = bindings;
978
+ this.namespacePrefix = namespacePrefix;
979
+ this.client = client;
980
+ this.accountId = accountId;
175
981
  }
176
- async listNamespaceKeys(tableName, options) {
982
+ async hasColumn() {
983
+ return true;
984
+ }
985
+ async alterTable(_args) {
986
+ }
987
+ async clearTable({ tableName }) {
177
988
  try {
178
- if (this.bindings) {
179
- const binding = this.getBinding(tableName);
180
- const response = await binding.list({
181
- limit: options?.limit || 1e3,
182
- prefix: options?.prefix
183
- });
184
- return response.keys;
185
- } else {
186
- const namespaceId = await this.getNamespaceId(tableName);
187
- const response = await this.client.kv.namespaces.keys.list(namespaceId, {
188
- account_id: this.accountId,
189
- limit: options?.limit || 1e3,
190
- prefix: options?.prefix
191
- });
192
- return response.result;
989
+ const keys = await this.listKV(tableName);
990
+ if (keys.length > 0) {
991
+ await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
193
992
  }
194
993
  } catch (error$1) {
195
994
  throw new error.MastraError(
196
995
  {
197
- id: "CLOUDFLARE_STORAGE_LIST_NAMESPACE_KEYS_FAILED",
996
+ id: "CLOUDFLARE_STORAGE_CLEAR_TABLE_FAILED",
198
997
  domain: error.ErrorDomain.STORAGE,
199
998
  category: error.ErrorCategory.THIRD_PARTY,
200
999
  details: {
@@ -205,110 +1004,69 @@ var CloudflareStore = class extends storage.MastraStorage {
205
1004
  );
206
1005
  }
207
1006
  }
208
- async createNamespaceById(title) {
209
- if (this.bindings) {
210
- return {
211
- id: title,
212
- // Use title as ID since that's what we need
213
- title,
214
- supports_url_encoding: true
215
- };
216
- }
217
- return await this.client.kv.namespaces.create({
218
- account_id: this.accountId,
219
- title
220
- });
221
- }
222
- async getNamespaceIdByName(namespaceName) {
223
- try {
224
- const response = await this.listNamespaces();
225
- const namespace = response.result.find((ns) => ns.title === namespaceName);
226
- return namespace ? namespace.id : null;
227
- } catch (error) {
228
- this.logger.error(`Failed to get namespace ID for ${namespaceName}:`, error);
229
- return null;
230
- }
231
- }
232
- async createNamespace(namespaceName) {
1007
+ async dropTable({ tableName }) {
233
1008
  try {
234
- const response = await this.createNamespaceById(namespaceName);
235
- return response.id;
236
- } catch (error) {
237
- if (error.message && error.message.includes("already exists")) {
238
- const namespaces = await this.listNamespaces();
239
- const namespace = namespaces.result.find((ns) => ns.title === namespaceName);
240
- if (namespace) return namespace.id;
1009
+ const keys = await this.listKV(tableName);
1010
+ if (keys.length > 0) {
1011
+ await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
241
1012
  }
242
- this.logger.error("Error creating namespace:", error);
243
- throw new Error(`Failed to create namespace ${namespaceName}: ${error.message}`);
244
- }
245
- }
246
- async getOrCreateNamespaceId(namespaceName) {
247
- let namespaceId = await this.getNamespaceIdByName(namespaceName);
248
- if (!namespaceId) {
249
- namespaceId = await this.createNamespace(namespaceName);
1013
+ } catch (error$1) {
1014
+ throw new error.MastraError(
1015
+ {
1016
+ id: "CLOUDFLARE_STORAGE_DROP_TABLE_FAILED",
1017
+ domain: error.ErrorDomain.STORAGE,
1018
+ category: error.ErrorCategory.THIRD_PARTY,
1019
+ details: {
1020
+ tableName
1021
+ }
1022
+ },
1023
+ error$1
1024
+ );
250
1025
  }
251
- return namespaceId;
252
1026
  }
253
- async getNamespaceId(tableName) {
254
- const prefix = this.namespacePrefix ? `${this.namespacePrefix}_` : "";
255
- try {
256
- const legacyNamespaceId = await this.checkLegacyNamespace(tableName, prefix);
257
- if (legacyNamespaceId) {
258
- return legacyNamespaceId;
259
- }
260
- return await this.getOrCreateNamespaceId(`${prefix}${tableName}`);
261
- } catch (error) {
262
- this.logger.error("Error fetching namespace ID:", error);
263
- throw new Error(`Failed to fetch namespace ID for table ${tableName}: ${error.message}`);
1027
+ getBinding(tableName) {
1028
+ if (!this.bindings) {
1029
+ throw new Error(`Cannot use Workers API binding for ${tableName}: Store initialized with REST API configuration`);
264
1030
  }
1031
+ const binding = this.bindings[tableName];
1032
+ if (!binding) throw new Error(`No binding found for namespace ${tableName}`);
1033
+ return binding;
265
1034
  }
266
- LEGACY_NAMESPACE_MAP = {
267
- [storage.TABLE_MESSAGES]: storage.TABLE_THREADS,
268
- [storage.TABLE_WORKFLOW_SNAPSHOT]: "mastra_workflows",
269
- [storage.TABLE_TRACES]: storage.TABLE_EVALS
270
- };
271
- /**
272
- * There were a few legacy mappings for tables such as
273
- * - messages -> threads
274
- * - workflow_snapshot -> mastra_workflows
275
- * - traces -> evals
276
- * This has been updated to use dedicated namespaces for each table.
277
- * In the case of data for a table existing in the legacy namespace, warn the user to migrate to the new namespace.
278
- *
279
- * @param tableName The table name to check for legacy data
280
- * @param prefix The namespace prefix
281
- * @returns The legacy namespace ID if data exists; otherwise, null
282
- */
283
- async checkLegacyNamespace(tableName, prefix) {
284
- const legacyNamespaceBase = this.LEGACY_NAMESPACE_MAP[tableName];
285
- if (legacyNamespaceBase) {
286
- const legacyNamespace = `${prefix}${legacyNamespaceBase}`;
287
- const keyPrefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
288
- const prefixKey = `${keyPrefix}${tableName}:`;
289
- const legacyId = await this.getNamespaceIdByName(legacyNamespace);
290
- if (legacyId) {
291
- const response = await this.client.kv.namespaces.keys.list(legacyId, {
292
- account_id: this.accountId,
293
- prefix: prefixKey
294
- });
295
- const keys = response.result;
296
- const hasTableData = keys.length > 0;
297
- if (hasTableData) {
298
- this.logger.warn(
299
- `Using legacy namespace "${legacyNamespace}" for ${tableName}. Consider migrating to a dedicated namespace "${prefix}${tableName}".`
300
- );
301
- return legacyId;
1035
+ getKey(tableName, record) {
1036
+ const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
1037
+ switch (tableName) {
1038
+ case storage.TABLE_THREADS:
1039
+ if (!record.id) throw new Error("Thread ID is required");
1040
+ return `${prefix}${tableName}:${record.id}`;
1041
+ case storage.TABLE_MESSAGES:
1042
+ if (!record.threadId || !record.id) throw new Error("Thread ID and Message ID are required");
1043
+ return `${prefix}${tableName}:${record.threadId}:${record.id}`;
1044
+ case storage.TABLE_WORKFLOW_SNAPSHOT:
1045
+ if (!record.workflow_name || !record.run_id) {
1046
+ throw new Error("Workflow name, and run ID are required");
302
1047
  }
303
- }
1048
+ let key = `${prefix}${tableName}:${record.workflow_name}:${record.run_id}`;
1049
+ if (record.resourceId) {
1050
+ key = `${key}:${record.resourceId}`;
1051
+ }
1052
+ return key;
1053
+ case storage.TABLE_TRACES:
1054
+ if (!record.id) throw new Error("Trace ID is required");
1055
+ return `${prefix}${tableName}:${record.id}`;
1056
+ case storage.TABLE_EVALS:
1057
+ const evalId = record.id || record.run_id;
1058
+ if (!evalId) throw new Error("Eval ID or run_id is required");
1059
+ return `${prefix}${tableName}:${evalId}`;
1060
+ case storage.TABLE_SCORERS:
1061
+ if (!record.id) throw new Error("Score ID is required");
1062
+ return `${prefix}${tableName}:${record.id}`;
1063
+ default:
1064
+ throw new Error(`Unsupported table: ${tableName}`);
304
1065
  }
305
- return null;
306
1066
  }
307
- /**
308
- * Helper to safely serialize data for KV storage
309
- */
310
- safeSerialize(data) {
311
- return typeof data === "string" ? data : JSON.stringify(data);
1067
+ getSchemaKey(tableName) {
1068
+ const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
1069
+ return `${prefix}schema:${tableName}`;
312
1070
  }
313
1071
  /**
314
1072
  * Helper to safely parse data from KV storage
@@ -334,203 +1092,121 @@ var CloudflareStore = class extends storage.MastraStorage {
334
1092
  return null;
335
1093
  }
336
1094
  }
337
- async putKV({
338
- tableName,
339
- key,
340
- value,
341
- metadata
342
- }) {
343
- try {
344
- await this.putNamespaceValue({ tableName, key, value, metadata });
345
- } catch (error) {
346
- this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
347
- throw new Error(`Failed to put KV value: ${error.message}`);
1095
+ async createNamespaceById(title) {
1096
+ if (this.bindings) {
1097
+ return {
1098
+ id: title,
1099
+ // Use title as ID since that's what we need
1100
+ title,
1101
+ supports_url_encoding: true
1102
+ };
348
1103
  }
1104
+ return await this.client.kv.namespaces.create({
1105
+ account_id: this.accountId,
1106
+ title
1107
+ });
349
1108
  }
350
- async getKV(tableName, key) {
1109
+ async createNamespace(namespaceName) {
351
1110
  try {
352
- const text = await this.getNamespaceValue(tableName, key);
353
- return this.safeParse(text);
1111
+ const response = await this.createNamespaceById(namespaceName);
1112
+ return response.id;
354
1113
  } catch (error) {
355
- this.logger.error(`Failed to get KV value for ${tableName}:${key}:`, error);
356
- throw new Error(`Failed to get KV value: ${error.message}`);
1114
+ if (error.message && error.message.includes("already exists")) {
1115
+ const namespaces = await this.listNamespaces();
1116
+ const namespace = namespaces.result.find((ns) => ns.title === namespaceName);
1117
+ if (namespace) return namespace.id;
1118
+ }
1119
+ this.logger.error("Error creating namespace:", error);
1120
+ throw new Error(`Failed to create namespace ${namespaceName}: ${error.message}`);
357
1121
  }
358
1122
  }
359
- async deleteKV(tableName, key) {
360
- try {
361
- await this.deleteNamespaceValue(tableName, key);
362
- } catch (error) {
363
- this.logger.error(`Failed to delete KV value for ${tableName}:${key}:`, error);
364
- throw new Error(`Failed to delete KV value: ${error.message}`);
1123
+ async listNamespaces() {
1124
+ if (this.bindings) {
1125
+ return {
1126
+ result: Object.keys(this.bindings).map((name) => ({
1127
+ id: name,
1128
+ title: name,
1129
+ supports_url_encoding: true
1130
+ }))
1131
+ };
1132
+ }
1133
+ let allNamespaces = [];
1134
+ let currentPage = 1;
1135
+ const perPage = 50;
1136
+ let morePagesExist = true;
1137
+ while (morePagesExist) {
1138
+ const response = await this.client.kv.namespaces.list({
1139
+ account_id: this.accountId,
1140
+ page: currentPage,
1141
+ per_page: perPage
1142
+ });
1143
+ if (response.result) {
1144
+ allNamespaces = allNamespaces.concat(response.result);
1145
+ }
1146
+ morePagesExist = response.result ? response.result.length === perPage : false;
1147
+ if (morePagesExist) {
1148
+ currentPage++;
1149
+ }
365
1150
  }
1151
+ return { result: allNamespaces };
366
1152
  }
367
- async listKV(tableName, options) {
1153
+ async getNamespaceIdByName(namespaceName) {
368
1154
  try {
369
- return await this.listNamespaceKeys(tableName, options);
1155
+ const response = await this.listNamespaces();
1156
+ const namespace = response.result.find((ns) => ns.title === namespaceName);
1157
+ return namespace ? namespace.id : null;
370
1158
  } catch (error) {
371
- this.logger.error(`Failed to list KV for ${tableName}:`, error);
372
- throw new Error(`Failed to list KV: ${error.message}`);
1159
+ this.logger.error(`Failed to get namespace ID for ${namespaceName}:`, error);
1160
+ return null;
373
1161
  }
374
1162
  }
375
- /*---------------------------------------------------------------------------
376
- Sorted set simulation helpers for message ordering.
377
- We store an array of objects { id, score } as JSON under a dedicated key.
378
- ---------------------------------------------------------------------------*/
379
- async getSortedMessages(orderKey) {
380
- const raw = await this.getKV(storage.TABLE_MESSAGES, orderKey);
381
- if (!raw) return [];
382
- try {
383
- const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
384
- return Array.isArray(arr) ? arr : [];
385
- } catch (e) {
386
- this.logger.error(`Error parsing order data for key ${orderKey}:`, { e });
387
- return [];
1163
+ async getOrCreateNamespaceId(namespaceName) {
1164
+ let namespaceId = await this.getNamespaceIdByName(namespaceName);
1165
+ if (!namespaceId) {
1166
+ namespaceId = await this.createNamespace(namespaceName);
388
1167
  }
1168
+ return namespaceId;
389
1169
  }
390
- async updateSorting(threadMessages) {
391
- return threadMessages.map((msg) => ({
392
- message: msg,
393
- // Use _index if available, otherwise timestamp, matching Upstash
394
- score: msg._index !== void 0 ? msg._index : msg.createdAt.getTime()
395
- })).sort((a, b) => a.score - b.score).map((item) => ({
396
- id: item.message.id,
397
- score: item.score
398
- }));
399
- }
400
- async getIncludedMessagesWithContext(threadId, include, messageIds) {
401
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
402
- await Promise.all(
403
- include.map(async (item) => {
404
- messageIds.add(item.id);
405
- if (!item.withPreviousMessages && !item.withNextMessages) return;
406
- const rank = await this.getRank(threadMessagesKey, item.id);
407
- if (rank === null) return;
408
- if (item.withPreviousMessages) {
409
- const prevIds = await this.getRange(
410
- threadMessagesKey,
411
- Math.max(0, rank - item.withPreviousMessages),
412
- rank - 1
413
- );
414
- prevIds.forEach((id) => messageIds.add(id));
415
- }
416
- if (item.withNextMessages) {
417
- const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
418
- nextIds.forEach((id) => messageIds.add(id));
419
- }
420
- })
421
- );
422
- }
423
- async getRecentMessages(threadId, limit, messageIds) {
424
- if (limit <= 0) return;
1170
+ async getNamespaceId(tableName) {
1171
+ const prefix = this.namespacePrefix ? `${this.namespacePrefix}_` : "";
425
1172
  try {
426
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
427
- const latestIds = await this.getLastN(threadMessagesKey, limit);
428
- latestIds.forEach((id) => messageIds.add(id));
429
- } catch {
430
- console.log(`No message order found for thread ${threadId}, skipping latest messages`);
1173
+ return await this.getOrCreateNamespaceId(`${prefix}${tableName}`);
1174
+ } catch (error) {
1175
+ this.logger.error("Error fetching namespace ID:", error);
1176
+ throw new Error(`Failed to fetch namespace ID for table ${tableName}: ${error.message}`);
431
1177
  }
432
1178
  }
433
- async fetchAndParseMessages(threadId, messageIds) {
434
- const messages = await Promise.all(
435
- messageIds.map(async (id) => {
436
- try {
437
- const key = this.getMessageKey(threadId, id);
438
- const data = await this.getKV(storage.TABLE_MESSAGES, key);
439
- if (!data) return null;
440
- return typeof data === "string" ? JSON.parse(data) : data;
441
- } catch (error) {
442
- const message = error instanceof Error ? error.message : String(error);
443
- this.logger.error(`Error retrieving message ${id}:`, { message });
444
- return null;
445
- }
446
- })
447
- );
448
- return messages.filter((msg) => msg !== null);
449
- }
450
- /**
451
- * Queue for serializing sorted order updates.
452
- * Updates the sorted order for a given key. This operation is eventually consistent.
453
- */
454
- updateQueue = /* @__PURE__ */ new Map();
455
- /**
456
- * Updates the sorted order for a given key. This operation is eventually consistent.
457
- * Note: Operations on the same orderKey are serialized using a queue to prevent
458
- * concurrent updates from conflicting with each other.
459
- */
460
- async updateSortedMessages(orderKey, newEntries) {
461
- const currentPromise = this.updateQueue.get(orderKey) || Promise.resolve();
462
- const nextPromise = currentPromise.then(async () => {
463
- try {
464
- const currentOrder = await this.getSortedMessages(orderKey);
465
- const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
466
- for (const entry of newEntries) {
467
- orderMap.set(entry.id, entry);
468
- }
469
- const updatedOrder = Array.from(orderMap.values()).sort((a, b) => a.score - b.score);
470
- await this.putKV({
471
- tableName: storage.TABLE_MESSAGES,
472
- key: orderKey,
473
- value: JSON.stringify(updatedOrder)
1179
+ async getNamespaceValue(tableName, key) {
1180
+ try {
1181
+ if (this.bindings) {
1182
+ const binding = this.getBinding(tableName);
1183
+ const result = await binding.getWithMetadata(key, "text");
1184
+ if (!result) return null;
1185
+ return JSON.stringify(result);
1186
+ } else {
1187
+ const namespaceId = await this.getNamespaceId(tableName);
1188
+ const response = await this.client.kv.namespaces.values.get(namespaceId, key, {
1189
+ account_id: this.accountId
474
1190
  });
475
- } catch (error) {
476
- const message = error instanceof Error ? error.message : String(error);
477
- this.logger.error(`Error updating sorted order for key ${orderKey}:`, { message });
478
- throw error;
479
- } finally {
480
- if (this.updateQueue.get(orderKey) === nextPromise) {
481
- this.updateQueue.delete(orderKey);
482
- }
1191
+ return await response.text();
483
1192
  }
484
- });
485
- this.updateQueue.set(orderKey, nextPromise);
486
- return nextPromise;
487
- }
488
- async getRank(orderKey, id) {
489
- const order = await this.getSortedMessages(orderKey);
490
- const index = order.findIndex((item) => item.id === id);
491
- return index >= 0 ? index : null;
492
- }
493
- async getRange(orderKey, start, end) {
494
- const order = await this.getSortedMessages(orderKey);
495
- const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
496
- const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
497
- const sliced = order.slice(actualStart, actualEnd + 1);
498
- return sliced.map((item) => item.id);
499
- }
500
- async getLastN(orderKey, n) {
501
- return this.getRange(orderKey, -n, -1);
502
- }
503
- async getFullOrder(orderKey) {
504
- return this.getRange(orderKey, 0, -1);
505
- }
506
- getKey(tableName, record) {
507
- const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
508
- switch (tableName) {
509
- case storage.TABLE_THREADS:
510
- if (!record.id) throw new Error("Thread ID is required");
511
- return `${prefix}${tableName}:${record.id}`;
512
- case storage.TABLE_MESSAGES:
513
- if (!record.threadId || !record.id) throw new Error("Thread ID and Message ID are required");
514
- return `${prefix}${tableName}:${record.threadId}:${record.id}`;
515
- case storage.TABLE_WORKFLOW_SNAPSHOT:
516
- if (!record.namespace || !record.workflow_name || !record.run_id) {
517
- throw new Error("Namespace, workflow name, and run ID are required");
518
- }
519
- let key = `${prefix}${tableName}:${record.namespace}:${record.workflow_name}:${record.run_id}`;
520
- if (record.resourceId) {
521
- key = `${key}:${record.resourceId}`;
522
- }
523
- return key;
524
- case storage.TABLE_TRACES:
525
- if (!record.id) throw new Error("Trace ID is required");
526
- return `${prefix}${tableName}:${record.id}`;
527
- default:
528
- throw new Error(`Unsupported table: ${tableName}`);
1193
+ } catch (error) {
1194
+ if (error.message && error.message.includes("key not found")) {
1195
+ return null;
1196
+ }
1197
+ const message = error instanceof Error ? error.message : String(error);
1198
+ this.logger.error(`Failed to get value for ${tableName} ${key}:`, { message });
1199
+ throw error;
529
1200
  }
530
1201
  }
531
- getSchemaKey(tableName) {
532
- const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
533
- return `${prefix}schema:${tableName}`;
1202
+ async getKV(tableName, key) {
1203
+ try {
1204
+ const text = await this.getNamespaceValue(tableName, key);
1205
+ return this.safeParse(text);
1206
+ } catch (error) {
1207
+ this.logger.error(`Failed to get KV value for ${tableName}:${key}:`, error);
1208
+ throw new Error(`Failed to get KV value: ${error.message}`);
1209
+ }
534
1210
  }
535
1211
  async getTableSchema(tableName) {
536
1212
  try {
@@ -611,7 +1287,7 @@ var CloudflareStore = class extends storage.MastraStorage {
611
1287
  }
612
1288
  break;
613
1289
  case storage.TABLE_WORKFLOW_SNAPSHOT:
614
- if (!("namespace" in recordTyped) || !("workflow_name" in recordTyped) || !("run_id" in recordTyped)) {
1290
+ if (!("workflow_name" in recordTyped) || !("run_id" in recordTyped)) {
615
1291
  throw new Error("Workflow record missing required fields");
616
1292
  }
617
1293
  break;
@@ -620,6 +1296,16 @@ var CloudflareStore = class extends storage.MastraStorage {
620
1296
  throw new Error("Trace record missing required fields");
621
1297
  }
622
1298
  break;
1299
+ case storage.TABLE_EVALS:
1300
+ if (!("agent_name" in recordTyped) || !("run_id" in recordTyped)) {
1301
+ throw new Error("Eval record missing required fields");
1302
+ }
1303
+ break;
1304
+ case storage.TABLE_SCORERS:
1305
+ if (!("id" in recordTyped) || !("scorerId" in recordTyped)) {
1306
+ throw new Error("Score record missing required fields");
1307
+ }
1308
+ break;
623
1309
  default:
624
1310
  throw new Error(`Unknown table type: ${tableName}`);
625
1311
  }
@@ -629,26 +1315,21 @@ var CloudflareStore = class extends storage.MastraStorage {
629
1315
  throw error;
630
1316
  }
631
1317
  }
632
- ensureMetadata(metadata) {
633
- if (!metadata) return {};
634
- return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
635
- }
636
- async createTable({
637
- tableName,
638
- schema
639
- }) {
1318
+ async insert({ tableName, record }) {
640
1319
  try {
641
- const schemaKey = this.getSchemaKey(tableName);
642
- const metadata = {
643
- type: "table_schema",
644
- tableName,
645
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1320
+ const key = this.getKey(tableName, record);
1321
+ const processedRecord = {
1322
+ ...record,
1323
+ createdAt: record.createdAt ? storage.serializeDate(record.createdAt) : void 0,
1324
+ updatedAt: record.updatedAt ? storage.serializeDate(record.updatedAt) : void 0,
1325
+ metadata: record.metadata ? JSON.stringify(record.metadata) : ""
646
1326
  };
647
- await this.putKV({ tableName, key: schemaKey, value: schema, metadata });
1327
+ await this.validateRecord(processedRecord, tableName);
1328
+ await this.putKV({ tableName, key, value: processedRecord });
648
1329
  } catch (error$1) {
649
1330
  throw new error.MastraError(
650
1331
  {
651
- id: "CLOUDFLARE_STORAGE_CREATE_TABLE_FAILED",
1332
+ id: "CLOUDFLARE_STORAGE_INSERT_FAILED",
652
1333
  domain: error.ErrorDomain.STORAGE,
653
1334
  category: error.ErrorCategory.THIRD_PARTY,
654
1335
  details: {
@@ -659,24 +1340,26 @@ var CloudflareStore = class extends storage.MastraStorage {
659
1340
  );
660
1341
  }
661
1342
  }
662
- /**
663
- * No-op: This backend is schemaless and does not require schema changes.
664
- * @param tableName Name of the table
665
- * @param schema Schema of the table
666
- * @param ifNotExists Array of column names to add if they don't exist
667
- */
668
- async alterTable(_args) {
1343
+ ensureMetadata(metadata) {
1344
+ if (!metadata) return {};
1345
+ return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
669
1346
  }
670
- async clearTable({ tableName }) {
1347
+ async load({ tableName, keys }) {
671
1348
  try {
672
- const keys = await this.listKV(tableName);
673
- if (keys.length > 0) {
674
- await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
675
- }
1349
+ const key = this.getKey(tableName, keys);
1350
+ const data = await this.getKV(tableName, key);
1351
+ if (!data) return null;
1352
+ const processed = {
1353
+ ...data,
1354
+ createdAt: storage.ensureDate(data.createdAt),
1355
+ updatedAt: storage.ensureDate(data.updatedAt),
1356
+ metadata: this.ensureMetadata(data.metadata)
1357
+ };
1358
+ return processed;
676
1359
  } catch (error$1) {
677
- throw new error.MastraError(
1360
+ const mastraError = new error.MastraError(
678
1361
  {
679
- id: "CLOUDFLARE_STORAGE_CLEAR_TABLE_FAILED",
1362
+ id: "CLOUDFLARE_STORAGE_LOAD_FAILED",
680
1363
  domain: error.ErrorDomain.STORAGE,
681
1364
  category: error.ErrorCategory.THIRD_PARTY,
682
1365
  details: {
@@ -685,52 +1368,102 @@ var CloudflareStore = class extends storage.MastraStorage {
685
1368
  },
686
1369
  error$1
687
1370
  );
1371
+ this.logger?.trackException(mastraError);
1372
+ this.logger?.error(mastraError.toString());
1373
+ return null;
688
1374
  }
689
1375
  }
690
- async insert({
691
- tableName,
692
- record
693
- }) {
1376
+ async batchInsert(input) {
1377
+ if (!input.records || input.records.length === 0) return;
694
1378
  try {
695
- const key = this.getKey(tableName, record);
696
- const processedRecord = {
697
- ...record,
698
- createdAt: record.createdAt ? this.serializeDate(record.createdAt) : void 0,
699
- updatedAt: record.updatedAt ? this.serializeDate(record.updatedAt) : void 0,
700
- metadata: record.metadata ? JSON.stringify(record.metadata) : ""
701
- };
702
- await this.validateRecord(processedRecord, tableName);
703
- await this.putKV({ tableName, key, value: processedRecord });
1379
+ await Promise.all(
1380
+ input.records.map(async (record) => {
1381
+ const key = this.getKey(input.tableName, record);
1382
+ const processedRecord = {
1383
+ ...record,
1384
+ createdAt: record.createdAt ? storage.serializeDate(record.createdAt) : void 0,
1385
+ updatedAt: record.updatedAt ? storage.serializeDate(record.updatedAt) : void 0,
1386
+ metadata: record.metadata ? JSON.stringify(record.metadata) : void 0
1387
+ };
1388
+ await this.putKV({ tableName: input.tableName, key, value: processedRecord });
1389
+ })
1390
+ );
704
1391
  } catch (error$1) {
705
1392
  throw new error.MastraError(
706
1393
  {
707
- id: "CLOUDFLARE_STORAGE_INSERT_FAILED",
1394
+ id: "CLOUDFLARE_STORAGE_BATCH_INSERT_FAILED",
708
1395
  domain: error.ErrorDomain.STORAGE,
709
1396
  category: error.ErrorCategory.THIRD_PARTY,
1397
+ text: `Error in batch insert for table ${input.tableName}`,
710
1398
  details: {
711
- tableName
1399
+ tableName: input.tableName
712
1400
  }
713
1401
  },
714
1402
  error$1
715
1403
  );
716
1404
  }
717
1405
  }
718
- async load({ tableName, keys }) {
1406
+ /**
1407
+ * Helper to safely serialize data for KV storage
1408
+ */
1409
+ safeSerialize(data) {
1410
+ return typeof data === "string" ? data : JSON.stringify(data);
1411
+ }
1412
+ async putNamespaceValue({
1413
+ tableName,
1414
+ key,
1415
+ value,
1416
+ metadata
1417
+ }) {
719
1418
  try {
720
- const key = this.getKey(tableName, keys);
721
- const data = await this.getKV(tableName, key);
722
- if (!data) return null;
723
- const processed = {
724
- ...data,
725
- createdAt: this.ensureDate(data.createdAt),
726
- updatedAt: this.ensureDate(data.updatedAt),
727
- metadata: this.ensureMetadata(data.metadata)
1419
+ const serializedValue = this.safeSerialize(value);
1420
+ const serializedMetadata = metadata ? this.safeSerialize(metadata) : "";
1421
+ if (this.bindings) {
1422
+ const binding = this.getBinding(tableName);
1423
+ await binding.put(key, serializedValue, { metadata: serializedMetadata });
1424
+ } else {
1425
+ const namespaceId = await this.getNamespaceId(tableName);
1426
+ await this.client.kv.namespaces.values.update(namespaceId, key, {
1427
+ account_id: this.accountId,
1428
+ value: serializedValue,
1429
+ metadata: serializedMetadata
1430
+ });
1431
+ }
1432
+ } catch (error) {
1433
+ const message = error instanceof Error ? error.message : String(error);
1434
+ this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
1435
+ throw error;
1436
+ }
1437
+ }
1438
+ async putKV({
1439
+ tableName,
1440
+ key,
1441
+ value,
1442
+ metadata
1443
+ }) {
1444
+ try {
1445
+ await this.putNamespaceValue({ tableName, key, value, metadata });
1446
+ } catch (error) {
1447
+ this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
1448
+ throw new Error(`Failed to put KV value: ${error.message}`);
1449
+ }
1450
+ }
1451
+ async createTable({
1452
+ tableName,
1453
+ schema
1454
+ }) {
1455
+ try {
1456
+ const schemaKey = this.getSchemaKey(tableName);
1457
+ const metadata = {
1458
+ type: "table_schema",
1459
+ tableName,
1460
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
728
1461
  };
729
- return processed;
1462
+ await this.putKV({ tableName, key: schemaKey, value: schema, metadata });
730
1463
  } catch (error$1) {
731
- const mastraError = new error.MastraError(
1464
+ throw new error.MastraError(
732
1465
  {
733
- id: "CLOUDFLARE_STORAGE_LOAD_FAILED",
1466
+ id: "CLOUDFLARE_STORAGE_CREATE_TABLE_FAILED",
734
1467
  domain: error.ErrorDomain.STORAGE,
735
1468
  category: error.ErrorCategory.THIRD_PARTY,
736
1469
  details: {
@@ -739,394 +1472,432 @@ var CloudflareStore = class extends storage.MastraStorage {
739
1472
  },
740
1473
  error$1
741
1474
  );
742
- this.logger?.trackException(mastraError);
743
- this.logger?.error(mastraError.toString());
744
- return null;
745
1475
  }
746
1476
  }
747
- async getThreadById({ threadId }) {
748
- const thread = await this.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
749
- if (!thread) return null;
1477
+ async listNamespaceKeys(tableName, options) {
750
1478
  try {
751
- return {
752
- ...thread,
753
- createdAt: this.ensureDate(thread.createdAt),
754
- updatedAt: this.ensureDate(thread.updatedAt),
755
- metadata: this.ensureMetadata(thread.metadata)
756
- };
1479
+ if (this.bindings) {
1480
+ const binding = this.getBinding(tableName);
1481
+ const response = await binding.list({
1482
+ limit: options?.limit || 1e3,
1483
+ prefix: options?.prefix
1484
+ });
1485
+ return response.keys;
1486
+ } else {
1487
+ const namespaceId = await this.getNamespaceId(tableName);
1488
+ const response = await this.client.kv.namespaces.keys.list(namespaceId, {
1489
+ account_id: this.accountId,
1490
+ limit: options?.limit || 1e3,
1491
+ prefix: options?.prefix
1492
+ });
1493
+ return response.result;
1494
+ }
757
1495
  } catch (error$1) {
758
- const mastraError = new error.MastraError(
1496
+ throw new error.MastraError(
759
1497
  {
760
- id: "CLOUDFLARE_STORAGE_GET_THREAD_BY_ID_FAILED",
1498
+ id: "CLOUDFLARE_STORAGE_LIST_NAMESPACE_KEYS_FAILED",
761
1499
  domain: error.ErrorDomain.STORAGE,
762
1500
  category: error.ErrorCategory.THIRD_PARTY,
763
1501
  details: {
764
- threadId
1502
+ tableName
765
1503
  }
766
1504
  },
767
1505
  error$1
768
1506
  );
769
- this.logger?.trackException(mastraError);
770
- this.logger?.error(mastraError.toString());
771
- return null;
772
1507
  }
773
1508
  }
774
- async getThreadsByResourceId({ resourceId }) {
1509
+ async deleteNamespaceValue(tableName, key) {
1510
+ if (this.bindings) {
1511
+ const binding = this.getBinding(tableName);
1512
+ await binding.delete(key);
1513
+ } else {
1514
+ const namespaceId = await this.getNamespaceId(tableName);
1515
+ await this.client.kv.namespaces.values.delete(namespaceId, key, {
1516
+ account_id: this.accountId
1517
+ });
1518
+ }
1519
+ }
1520
+ async deleteKV(tableName, key) {
775
1521
  try {
776
- const keyList = await this.listKV(storage.TABLE_THREADS);
777
- const threads = await Promise.all(
778
- keyList.map(async (keyObj) => {
779
- try {
780
- const data = await this.getKV(storage.TABLE_THREADS, keyObj.name);
781
- if (!data) return null;
782
- const thread = typeof data === "string" ? JSON.parse(data) : data;
783
- if (!thread || !thread.resourceId || thread.resourceId !== resourceId) return null;
784
- return {
785
- ...thread,
786
- createdAt: this.ensureDate(thread.createdAt),
787
- updatedAt: this.ensureDate(thread.updatedAt),
788
- metadata: this.ensureMetadata(thread.metadata)
789
- };
790
- } catch (error$1) {
791
- const mastraError = new error.MastraError(
792
- {
793
- id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
794
- domain: error.ErrorDomain.STORAGE,
795
- category: error.ErrorCategory.THIRD_PARTY,
796
- details: {
797
- resourceId
798
- }
799
- },
800
- error$1
801
- );
802
- this.logger?.trackException(mastraError);
803
- this.logger?.error(mastraError.toString());
804
- return null;
805
- }
806
- })
807
- );
808
- return threads.filter((thread) => thread !== null);
1522
+ await this.deleteNamespaceValue(tableName, key);
1523
+ } catch (error) {
1524
+ this.logger.error(`Failed to delete KV value for ${tableName}:${key}:`, error);
1525
+ throw new Error(`Failed to delete KV value: ${error.message}`);
1526
+ }
1527
+ }
1528
+ async listKV(tableName, options) {
1529
+ try {
1530
+ return await this.listNamespaceKeys(tableName, options);
1531
+ } catch (error) {
1532
+ this.logger.error(`Failed to list KV for ${tableName}:`, error);
1533
+ throw new Error(`Failed to list KV: ${error.message}`);
1534
+ }
1535
+ }
1536
+ };
1537
+ function transformScoreRow(row) {
1538
+ let input = void 0;
1539
+ if (row.input) {
1540
+ try {
1541
+ input = JSON.parse(row.input);
1542
+ } catch {
1543
+ input = row.input;
1544
+ }
1545
+ }
1546
+ return {
1547
+ ...row,
1548
+ input
1549
+ };
1550
+ }
1551
+ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
1552
+ operations;
1553
+ constructor({ operations }) {
1554
+ super();
1555
+ this.operations = operations;
1556
+ }
1557
+ async getScoreById({ id }) {
1558
+ try {
1559
+ const score = await this.operations.getKV(storage.TABLE_SCORERS, id);
1560
+ if (!score) {
1561
+ return null;
1562
+ }
1563
+ return transformScoreRow(score);
809
1564
  } catch (error$1) {
810
1565
  const mastraError = new error.MastraError(
811
1566
  {
812
- id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1567
+ id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORE_BY_ID_FAILED",
813
1568
  domain: error.ErrorDomain.STORAGE,
814
1569
  category: error.ErrorCategory.THIRD_PARTY,
815
- details: {
816
- resourceId
817
- }
1570
+ text: `Failed to get score by id: ${id}`
818
1571
  },
819
1572
  error$1
820
1573
  );
821
- this.logger?.trackException(mastraError);
822
- this.logger?.error(mastraError.toString());
823
- return [];
1574
+ this.logger.trackException(mastraError);
1575
+ this.logger.error(mastraError.toString());
1576
+ return null;
824
1577
  }
825
1578
  }
826
- async saveThread({ thread }) {
1579
+ async saveScore(score) {
827
1580
  try {
828
- await this.insert({ tableName: storage.TABLE_THREADS, record: thread });
829
- return thread;
1581
+ const { input, ...rest } = score;
1582
+ const serializedRecord = {};
1583
+ for (const [key, value] of Object.entries(rest)) {
1584
+ if (value !== null && value !== void 0) {
1585
+ if (typeof value === "object") {
1586
+ serializedRecord[key] = JSON.stringify(value);
1587
+ } else {
1588
+ serializedRecord[key] = value;
1589
+ }
1590
+ } else {
1591
+ serializedRecord[key] = null;
1592
+ }
1593
+ }
1594
+ serializedRecord.input = JSON.stringify(input);
1595
+ serializedRecord.createdAt = (/* @__PURE__ */ new Date()).toISOString();
1596
+ serializedRecord.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1597
+ await this.operations.putKV({
1598
+ tableName: storage.TABLE_SCORERS,
1599
+ key: score.id,
1600
+ value: serializedRecord
1601
+ });
1602
+ const scoreFromDb = await this.getScoreById({ id: score.id });
1603
+ return { score: scoreFromDb };
830
1604
  } catch (error$1) {
831
- throw new error.MastraError(
1605
+ const mastraError = new error.MastraError(
832
1606
  {
833
- id: "CLOUDFLARE_STORAGE_SAVE_THREAD_FAILED",
1607
+ id: "CLOUDFLARE_STORAGE_SCORES_SAVE_SCORE_FAILED",
834
1608
  domain: error.ErrorDomain.STORAGE,
835
1609
  category: error.ErrorCategory.THIRD_PARTY,
836
- details: {
837
- threadId: thread.id
838
- }
1610
+ text: `Failed to save score: ${score.id}`
839
1611
  },
840
1612
  error$1
841
1613
  );
1614
+ this.logger.trackException(mastraError);
1615
+ this.logger.error(mastraError.toString());
1616
+ throw mastraError;
842
1617
  }
843
1618
  }
844
- async updateThread({
845
- id,
846
- title,
847
- metadata
1619
+ async getScoresByScorerId({
1620
+ scorerId,
1621
+ pagination
848
1622
  }) {
849
1623
  try {
850
- const thread = await this.getThreadById({ threadId: id });
851
- if (!thread) {
852
- throw new Error(`Thread ${id} not found`);
1624
+ const keys = await this.operations.listKV(storage.TABLE_SCORERS);
1625
+ const scores = [];
1626
+ for (const { name: key } of keys) {
1627
+ const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
1628
+ if (score && score.scorerId === scorerId) {
1629
+ scores.push(transformScoreRow(score));
1630
+ }
853
1631
  }
854
- const updatedThread = {
855
- ...thread,
856
- title,
857
- metadata: this.ensureMetadata({
858
- ...thread.metadata ?? {},
859
- ...metadata
860
- }),
861
- updatedAt: /* @__PURE__ */ new Date()
1632
+ scores.sort((a, b) => {
1633
+ const dateA = new Date(a.createdAt || 0).getTime();
1634
+ const dateB = new Date(b.createdAt || 0).getTime();
1635
+ return dateB - dateA;
1636
+ });
1637
+ const total = scores.length;
1638
+ const start = pagination.page * pagination.perPage;
1639
+ const end = start + pagination.perPage;
1640
+ const pagedScores = scores.slice(start, end);
1641
+ return {
1642
+ pagination: {
1643
+ total,
1644
+ page: pagination.page,
1645
+ perPage: pagination.perPage,
1646
+ hasMore: end < total
1647
+ },
1648
+ scores: pagedScores
862
1649
  };
863
- await this.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
864
- return updatedThread;
865
1650
  } catch (error$1) {
866
- throw new error.MastraError(
1651
+ const mastraError = new error.MastraError(
867
1652
  {
868
- id: "CLOUDFLARE_STORAGE_UPDATE_THREAD_FAILED",
1653
+ id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_SCORER_ID_FAILED",
869
1654
  domain: error.ErrorDomain.STORAGE,
870
1655
  category: error.ErrorCategory.THIRD_PARTY,
871
- details: {
872
- threadId: id,
873
- title
874
- }
1656
+ text: `Failed to get scores by scorer id: ${scorerId}`
875
1657
  },
876
1658
  error$1
877
1659
  );
1660
+ this.logger?.trackException(mastraError);
1661
+ this.logger?.error(mastraError.toString());
1662
+ return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
878
1663
  }
879
1664
  }
880
- async deleteThread({ threadId }) {
1665
+ async getScoresByRunId({
1666
+ runId,
1667
+ pagination
1668
+ }) {
881
1669
  try {
882
- const thread = await this.getThreadById({ threadId });
883
- if (!thread) {
884
- throw new Error(`Thread ${threadId} not found`);
1670
+ const keys = await this.operations.listKV(storage.TABLE_SCORERS);
1671
+ const scores = [];
1672
+ for (const { name: key } of keys) {
1673
+ const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
1674
+ if (score && score.runId === runId) {
1675
+ scores.push(transformScoreRow(score));
1676
+ }
885
1677
  }
886
- const messageKeys = await this.listKV(storage.TABLE_MESSAGES);
887
- const threadMessageKeys = messageKeys.filter((key) => key.name.includes(`${storage.TABLE_MESSAGES}:${threadId}:`));
888
- await Promise.all([
889
- // Delete message order
890
- this.deleteKV(storage.TABLE_MESSAGES, this.getThreadMessagesKey(threadId)),
891
- // Delete all messages
892
- ...threadMessageKeys.map((key) => this.deleteKV(storage.TABLE_MESSAGES, key.name)),
893
- // Delete thread
894
- this.deleteKV(storage.TABLE_THREADS, this.getKey(storage.TABLE_THREADS, { id: threadId }))
895
- ]);
1678
+ scores.sort((a, b) => {
1679
+ const dateA = new Date(a.createdAt || 0).getTime();
1680
+ const dateB = new Date(b.createdAt || 0).getTime();
1681
+ return dateB - dateA;
1682
+ });
1683
+ const total = scores.length;
1684
+ const start = pagination.page * pagination.perPage;
1685
+ const end = start + pagination.perPage;
1686
+ const pagedScores = scores.slice(start, end);
1687
+ return {
1688
+ pagination: {
1689
+ total,
1690
+ page: pagination.page,
1691
+ perPage: pagination.perPage,
1692
+ hasMore: end < total
1693
+ },
1694
+ scores: pagedScores
1695
+ };
896
1696
  } catch (error$1) {
897
- throw new error.MastraError(
1697
+ const mastraError = new error.MastraError(
898
1698
  {
899
- id: "CLOUDFLARE_STORAGE_DELETE_THREAD_FAILED",
1699
+ id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_RUN_ID_FAILED",
900
1700
  domain: error.ErrorDomain.STORAGE,
901
1701
  category: error.ErrorCategory.THIRD_PARTY,
902
- details: {
903
- threadId
904
- }
1702
+ text: `Failed to get scores by run id: ${runId}`
905
1703
  },
906
1704
  error$1
907
1705
  );
1706
+ this.logger.trackException(mastraError);
1707
+ this.logger.error(mastraError.toString());
1708
+ return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
908
1709
  }
909
1710
  }
910
- getMessageKey(threadId, messageId) {
911
- try {
912
- return this.getKey(storage.TABLE_MESSAGES, { threadId, id: messageId });
913
- } catch (error) {
914
- const message = error instanceof Error ? error.message : String(error);
915
- this.logger.error(`Error getting message key for thread ${threadId} and message ${messageId}:`, { message });
916
- throw error;
917
- }
918
- }
919
- getThreadMessagesKey(threadId) {
1711
+ async getScoresByEntityId({
1712
+ entityId,
1713
+ entityType,
1714
+ pagination
1715
+ }) {
920
1716
  try {
921
- return this.getKey(storage.TABLE_MESSAGES, { threadId, id: "messages" });
922
- } catch (error) {
923
- const message = error instanceof Error ? error.message : String(error);
924
- this.logger.error(`Error getting thread messages key for thread ${threadId}:`, { message });
925
- throw error;
1717
+ const keys = await this.operations.listKV(storage.TABLE_SCORERS);
1718
+ const scores = [];
1719
+ for (const { name: key } of keys) {
1720
+ const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
1721
+ if (score && score.entityId === entityId && score.entityType === entityType) {
1722
+ scores.push(transformScoreRow(score));
1723
+ }
1724
+ }
1725
+ scores.sort((a, b) => {
1726
+ const dateA = new Date(a.createdAt || 0).getTime();
1727
+ const dateB = new Date(b.createdAt || 0).getTime();
1728
+ return dateB - dateA;
1729
+ });
1730
+ const total = scores.length;
1731
+ const start = pagination.page * pagination.perPage;
1732
+ const end = start + pagination.perPage;
1733
+ const pagedScores = scores.slice(start, end);
1734
+ return {
1735
+ pagination: {
1736
+ total,
1737
+ page: pagination.page,
1738
+ perPage: pagination.perPage,
1739
+ hasMore: end < total
1740
+ },
1741
+ scores: pagedScores
1742
+ };
1743
+ } catch (error$1) {
1744
+ const mastraError = new error.MastraError(
1745
+ {
1746
+ id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_ENTITY_ID_FAILED",
1747
+ domain: error.ErrorDomain.STORAGE,
1748
+ category: error.ErrorCategory.THIRD_PARTY,
1749
+ text: `Failed to get scores by entity id: ${entityId}, type: ${entityType}`
1750
+ },
1751
+ error$1
1752
+ );
1753
+ this.logger.trackException(mastraError);
1754
+ this.logger.error(mastraError.toString());
1755
+ return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
926
1756
  }
927
1757
  }
928
- async saveMessages(args) {
929
- const { messages, format = "v1" } = args;
930
- if (!Array.isArray(messages) || messages.length === 0) return [];
1758
+ };
1759
+ var TracesStorageCloudflare = class extends storage.TracesStorage {
1760
+ operations;
1761
+ constructor({ operations }) {
1762
+ super();
1763
+ this.operations = operations;
1764
+ }
1765
+ async getTraces(args) {
1766
+ const paginatedArgs = {
1767
+ name: args.name,
1768
+ scope: args.scope,
1769
+ page: args.page,
1770
+ perPage: args.perPage,
1771
+ attributes: args.attributes,
1772
+ filters: args.filters,
1773
+ dateRange: args.fromDate || args.toDate ? {
1774
+ start: args.fromDate,
1775
+ end: args.toDate
1776
+ } : void 0
1777
+ };
931
1778
  try {
932
- const validatedMessages = messages.map((message, index) => {
933
- const errors = [];
934
- if (!message.id) errors.push("id is required");
935
- if (!message.threadId) errors.push("threadId is required");
936
- if (!message.content) errors.push("content is required");
937
- if (!message.role) errors.push("role is required");
938
- if (!message.createdAt) errors.push("createdAt is required");
939
- if (errors.length > 0) {
940
- throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
941
- }
942
- return {
943
- ...message,
944
- createdAt: this.ensureDate(message.createdAt),
945
- type: message.type || "v2",
946
- _index: index
947
- };
948
- }).filter((m) => !!m);
949
- const messagesByThread = validatedMessages.reduce((acc, message) => {
950
- if (message.threadId && !acc.has(message.threadId)) {
951
- acc.set(message.threadId, []);
952
- }
953
- if (message.threadId) {
954
- acc.get(message.threadId).push(message);
955
- }
956
- return acc;
957
- }, /* @__PURE__ */ new Map());
958
- await Promise.all(
959
- Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
960
- try {
961
- const thread = await this.getThreadById({ threadId });
962
- if (!thread) {
963
- throw new Error(`Thread ${threadId} not found`);
964
- }
965
- await Promise.all(
966
- threadMessages.map(async (message) => {
967
- const key = this.getMessageKey(threadId, message.id);
968
- const { _index, ...cleanMessage } = message;
969
- const serializedMessage = {
970
- ...cleanMessage,
971
- createdAt: this.serializeDate(cleanMessage.createdAt)
972
- };
973
- await this.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
974
- })
975
- );
976
- const orderKey = this.getThreadMessagesKey(threadId);
977
- const entries = await this.updateSorting(threadMessages);
978
- await this.updateSortedMessages(orderKey, entries);
979
- } catch (error$1) {
980
- throw new error.MastraError(
981
- {
982
- id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
983
- domain: error.ErrorDomain.STORAGE,
984
- category: error.ErrorCategory.THIRD_PARTY,
985
- details: {
986
- threadId
987
- }
988
- },
989
- error$1
990
- );
991
- }
992
- })
993
- );
994
- const prepared = validatedMessages.map(
995
- ({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
996
- );
997
- const list = new agent.MessageList().add(prepared, "memory");
998
- if (format === `v2`) return list.get.all.v2();
999
- return list.get.all.v1();
1779
+ const result = await this.getTracesPaginated(paginatedArgs);
1780
+ return result.traces;
1000
1781
  } catch (error$1) {
1001
1782
  throw new error.MastraError(
1002
1783
  {
1003
- id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
1784
+ id: "CLOUDFLARE_STORAGE_GET_TRACES_ERROR",
1004
1785
  domain: error.ErrorDomain.STORAGE,
1005
- category: error.ErrorCategory.THIRD_PARTY
1786
+ category: error.ErrorCategory.THIRD_PARTY,
1787
+ text: `Failed to retrieve traces: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1788
+ details: {
1789
+ name: args.name ?? "",
1790
+ scope: args.scope ?? ""
1791
+ }
1006
1792
  },
1007
1793
  error$1
1008
1794
  );
1009
1795
  }
1010
1796
  }
1011
- async getMessages({
1012
- threadId,
1013
- resourceId,
1014
- selectBy,
1015
- format
1016
- }) {
1017
- if (!threadId) throw new Error("threadId is required");
1018
- const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
1019
- const messageIds = /* @__PURE__ */ new Set();
1020
- if (limit === 0 && !selectBy?.include?.length) return [];
1797
+ async getTracesPaginated(args) {
1021
1798
  try {
1022
- await Promise.all([
1023
- selectBy?.include?.length ? this.getIncludedMessagesWithContext(threadId, selectBy.include, messageIds) : Promise.resolve(),
1024
- limit > 0 && !selectBy?.include?.length ? this.getRecentMessages(threadId, limit, messageIds) : Promise.resolve()
1025
- ]);
1026
- const messages = await this.fetchAndParseMessages(threadId, Array.from(messageIds));
1027
- if (!messages.length) return [];
1028
- try {
1029
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
1030
- const messageOrder = await this.getFullOrder(threadMessagesKey);
1031
- const orderMap = new Map(messageOrder.map((id, index) => [id, index]));
1032
- messages.sort((a, b) => {
1033
- const indexA = orderMap.get(a.id);
1034
- const indexB = orderMap.get(b.id);
1035
- if (indexA !== void 0 && indexB !== void 0) return orderMap.get(a.id) - orderMap.get(b.id);
1036
- return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
1037
- });
1038
- } catch (error$1) {
1039
- const mastraError = new error.MastraError(
1040
- {
1041
- id: "CLOUDFLARE_STORAGE_SORT_MESSAGES_FAILED",
1042
- domain: error.ErrorDomain.STORAGE,
1043
- category: error.ErrorCategory.THIRD_PARTY,
1044
- text: `Error sorting messages for thread ${threadId} falling back to creation time`,
1045
- details: {
1046
- threadId
1799
+ const { name, scope, attributes, filters, page = 0, perPage = 100, dateRange } = args;
1800
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
1801
+ const keyObjs = await this.operations.listKV(storage.TABLE_TRACES, { prefix: `${prefix}${storage.TABLE_TRACES}` });
1802
+ const traces = [];
1803
+ for (const { name: key } of keyObjs) {
1804
+ try {
1805
+ const data = await this.operations.getKV(storage.TABLE_TRACES, key);
1806
+ if (!data) continue;
1807
+ if (name && data.name !== name) continue;
1808
+ if (scope && data.scope !== scope) continue;
1809
+ if (attributes) {
1810
+ const dataAttributes = data.attributes || {};
1811
+ let shouldSkip = false;
1812
+ for (const [key2, value] of Object.entries(attributes)) {
1813
+ if (dataAttributes[key2] !== value) {
1814
+ shouldSkip = true;
1815
+ break;
1816
+ }
1047
1817
  }
1048
- },
1049
- error$1
1050
- );
1051
- this.logger?.trackException(mastraError);
1052
- this.logger?.error(mastraError.toString());
1053
- messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1818
+ if (shouldSkip) continue;
1819
+ }
1820
+ if (dateRange?.start || dateRange?.end) {
1821
+ const traceDate = new Date(data.createdAt || 0);
1822
+ if (dateRange.start && traceDate < dateRange.start) continue;
1823
+ if (dateRange.end && traceDate > dateRange.end) continue;
1824
+ }
1825
+ if (filters) {
1826
+ let shouldSkip = false;
1827
+ for (const [key2, value] of Object.entries(filters)) {
1828
+ if (data[key2] !== value) {
1829
+ shouldSkip = true;
1830
+ break;
1831
+ }
1832
+ }
1833
+ if (shouldSkip) continue;
1834
+ }
1835
+ traces.push(data);
1836
+ } catch (err) {
1837
+ this.logger.error("Failed to parse trace:", { key, error: err });
1838
+ }
1054
1839
  }
1055
- const prepared = messages.map(({ _index, ...message }) => ({
1056
- ...message,
1057
- type: message.type === `v2` ? void 0 : message.type,
1058
- createdAt: this.ensureDate(message.createdAt)
1059
- }));
1060
- const list = new agent.MessageList({ threadId, resourceId }).add(prepared, "memory");
1061
- if (format === `v1`) return list.get.all.v1();
1062
- return list.get.all.v2();
1840
+ traces.sort((a, b) => {
1841
+ const aTime = new Date(a.createdAt || 0).getTime();
1842
+ const bTime = new Date(b.createdAt || 0).getTime();
1843
+ return bTime - aTime;
1844
+ });
1845
+ const total = traces.length;
1846
+ const start = page * perPage;
1847
+ const end = start + perPage;
1848
+ const pagedTraces = traces.slice(start, end);
1849
+ return {
1850
+ traces: pagedTraces,
1851
+ total,
1852
+ page,
1853
+ perPage,
1854
+ hasMore: end < total
1855
+ };
1063
1856
  } catch (error$1) {
1064
1857
  const mastraError = new error.MastraError(
1065
1858
  {
1066
- id: "CLOUDFLARE_STORAGE_GET_MESSAGES_FAILED",
1859
+ id: "CLOUDFLARE_STORAGE_GET_TRACES_PAGINATED_FAILED",
1067
1860
  domain: error.ErrorDomain.STORAGE,
1068
1861
  category: error.ErrorCategory.THIRD_PARTY,
1069
- text: `Error retrieving messages for thread ${threadId}`,
1070
- details: {
1071
- threadId
1072
- }
1862
+ text: "Error getting traces with pagination"
1073
1863
  },
1074
1864
  error$1
1075
1865
  );
1076
- this.logger?.trackException(mastraError);
1077
- this.logger?.error(mastraError.toString());
1078
- return [];
1866
+ this.logger.trackException?.(mastraError);
1867
+ this.logger.error(mastraError.toString());
1868
+ return { traces: [], total: 0, page: 0, perPage: 100, hasMore: false };
1079
1869
  }
1080
1870
  }
1871
+ async batchTraceInsert({ records }) {
1872
+ this.logger.debug("Batch inserting traces", { count: records.length });
1873
+ await this.operations.batchInsert({
1874
+ tableName: storage.TABLE_TRACES,
1875
+ records
1876
+ });
1877
+ }
1878
+ };
1879
+ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
1880
+ operations;
1881
+ constructor({ operations }) {
1882
+ super();
1883
+ this.operations = operations;
1884
+ }
1081
1885
  validateWorkflowParams(params) {
1082
- const { namespace, workflowName, runId } = params;
1083
- if (!namespace || !workflowName || !runId) {
1886
+ const { workflowName, runId } = params;
1887
+ if (!workflowName || !runId) {
1084
1888
  throw new Error("Invalid workflow snapshot parameters");
1085
1889
  }
1086
1890
  }
1087
- validateWorkflowState(state) {
1088
- if (!state?.runId || !state?.value || !state?.context?.input || !state?.activePaths) {
1089
- throw new Error("Invalid workflow state structure");
1090
- }
1091
- }
1092
- normalizeSteps(steps) {
1093
- const normalizedSteps = {};
1094
- for (const [stepId, step] of Object.entries(steps)) {
1095
- normalizedSteps[stepId] = {
1096
- status: step.status,
1097
- payload: step.payload || step.result,
1098
- error: step.error
1099
- };
1100
- }
1101
- return normalizedSteps;
1102
- }
1103
- normalizeWorkflowState(data) {
1104
- return {
1105
- runId: data.runId,
1106
- value: data.value,
1107
- context: data.context,
1108
- serializedStepGraph: data.serializedStepGraph,
1109
- suspendedPaths: data.suspendedPaths || {},
1110
- activePaths: data.activePaths || [],
1111
- timestamp: data.timestamp || Date.now(),
1112
- status: data.status,
1113
- result: data.result,
1114
- error: data.error
1115
- };
1116
- }
1117
1891
  async persistWorkflowSnapshot(params) {
1118
1892
  try {
1119
- this.validateWorkflowParams(params);
1120
- const { namespace, workflowName, runId, snapshot } = params;
1121
- const normalizedState = this.normalizeWorkflowState(snapshot);
1122
- this.validateWorkflowState(normalizedState);
1123
- await this.insert({
1893
+ const { workflowName, runId, snapshot } = params;
1894
+ await this.operations.putKV({
1124
1895
  tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1125
- record: {
1126
- namespace,
1896
+ key: this.operations.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId }),
1897
+ value: {
1127
1898
  workflow_name: workflowName,
1128
1899
  run_id: runId,
1129
- snapshot: normalizedState,
1900
+ snapshot: typeof snapshot === "string" ? snapshot : JSON.stringify(snapshot),
1130
1901
  createdAt: /* @__PURE__ */ new Date(),
1131
1902
  updatedAt: /* @__PURE__ */ new Date()
1132
1903
  }
@@ -1137,9 +1908,8 @@ var CloudflareStore = class extends storage.MastraStorage {
1137
1908
  id: "CLOUDFLARE_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1138
1909
  domain: error.ErrorDomain.STORAGE,
1139
1910
  category: error.ErrorCategory.THIRD_PARTY,
1140
- text: `Error persisting workflow snapshot for namespace ${params.namespace}, workflow ${params.workflowName}, run ${params.runId}`,
1911
+ text: `Error persisting workflow snapshot for workflow ${params.workflowName}, run ${params.runId}`,
1141
1912
  details: {
1142
- namespace: params.namespace,
1143
1913
  workflowName: params.workflowName,
1144
1914
  runId: params.runId
1145
1915
  }
@@ -1151,172 +1921,31 @@ var CloudflareStore = class extends storage.MastraStorage {
1151
1921
  async loadWorkflowSnapshot(params) {
1152
1922
  try {
1153
1923
  this.validateWorkflowParams(params);
1154
- const { namespace, workflowName, runId } = params;
1155
- const key = this.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { namespace, workflow_name: workflowName, run_id: runId });
1156
- const data = await this.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
1924
+ const { workflowName, runId } = params;
1925
+ const key = this.operations.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId });
1926
+ const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
1157
1927
  if (!data) return null;
1158
- const state = this.normalizeWorkflowState(data.snapshot || data);
1159
- this.validateWorkflowState(state);
1160
- return state;
1928
+ const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
1929
+ return snapshotData;
1161
1930
  } catch (error$1) {
1162
1931
  const mastraError = new error.MastraError(
1163
1932
  {
1164
1933
  id: "CLOUDFLARE_STORAGE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1165
1934
  domain: error.ErrorDomain.STORAGE,
1166
1935
  category: error.ErrorCategory.THIRD_PARTY,
1167
- text: `Error loading workflow snapshot for namespace ${params.namespace}, workflow ${params.workflowName}, run ${params.runId}`,
1936
+ text: `Error loading workflow snapshot for workflow ${params.workflowName}, run ${params.runId}`,
1168
1937
  details: {
1169
- namespace: params.namespace,
1170
1938
  workflowName: params.workflowName,
1171
1939
  runId: params.runId
1172
1940
  }
1173
1941
  },
1174
1942
  error$1
1175
1943
  );
1176
- this.logger?.trackException(mastraError);
1177
- this.logger?.error(mastraError.toString());
1944
+ this.logger.trackException?.(mastraError);
1945
+ this.logger.error(mastraError.toString());
1178
1946
  return null;
1179
1947
  }
1180
1948
  }
1181
- async batchInsert(input) {
1182
- if (!input.records || input.records.length === 0) return;
1183
- try {
1184
- await Promise.all(
1185
- input.records.map(async (record) => {
1186
- const key = this.getKey(input.tableName, record);
1187
- const processedRecord = {
1188
- ...record,
1189
- createdAt: record.createdAt ? this.serializeDate(record.createdAt) : void 0,
1190
- updatedAt: record.updatedAt ? this.serializeDate(record.updatedAt) : void 0,
1191
- metadata: record.metadata ? JSON.stringify(record.metadata) : void 0
1192
- };
1193
- await this.putKV({ tableName: input.tableName, key, value: processedRecord });
1194
- })
1195
- );
1196
- } catch (error$1) {
1197
- throw new error.MastraError(
1198
- {
1199
- id: "CLOUDFLARE_STORAGE_BATCH_INSERT_FAILED",
1200
- domain: error.ErrorDomain.STORAGE,
1201
- category: error.ErrorCategory.THIRD_PARTY,
1202
- text: `Error in batch insert for table ${input.tableName}`,
1203
- details: {
1204
- tableName: input.tableName
1205
- }
1206
- },
1207
- error$1
1208
- );
1209
- }
1210
- }
1211
- async getTraces({
1212
- name,
1213
- scope,
1214
- page = 0,
1215
- perPage = 100,
1216
- attributes,
1217
- fromDate,
1218
- toDate
1219
- }) {
1220
- try {
1221
- let keys;
1222
- if (this.bindings) {
1223
- keys = (await this.listKV(storage.TABLE_TRACES))?.map((k) => k.name) || [];
1224
- } else {
1225
- const namespaceId = await this.getNamespaceId(storage.TABLE_TRACES);
1226
- const result = await this.client.kv.namespaces.keys.list(namespaceId, {
1227
- prefix: "",
1228
- limit: 1e3,
1229
- account_id: this.accountId
1230
- });
1231
- keys = result.result?.map((k) => k.name) || [];
1232
- }
1233
- const traceRecords = await Promise.all(
1234
- keys.map(async (key) => {
1235
- const record = await this.getKV(storage.TABLE_TRACES, key);
1236
- if (!record) return null;
1237
- return record;
1238
- })
1239
- );
1240
- let filteredTraces = traceRecords.filter(
1241
- (record) => record !== null && typeof record === "object"
1242
- );
1243
- if (name) {
1244
- filteredTraces = filteredTraces.filter((record) => record.name?.toLowerCase().startsWith(name.toLowerCase()));
1245
- }
1246
- if (scope) {
1247
- filteredTraces = filteredTraces.filter((record) => record.scope === scope);
1248
- }
1249
- if (attributes) {
1250
- filteredTraces = filteredTraces.filter((record) => {
1251
- if (!record.attributes) return false;
1252
- const recordAttrs = this.parseJSON(record.attributes);
1253
- if (!recordAttrs) return false;
1254
- return Object.entries(attributes).every(([key, value]) => recordAttrs[key] === value);
1255
- });
1256
- }
1257
- if (fromDate) {
1258
- filteredTraces = filteredTraces.filter((record) => new Date(record.createdAt).getTime() >= fromDate.getTime());
1259
- }
1260
- if (toDate) {
1261
- filteredTraces = filteredTraces.filter((record) => new Date(record.createdAt).getTime() <= toDate.getTime());
1262
- }
1263
- filteredTraces.sort((a, b) => {
1264
- const dateA = new Date(a.createdAt).getTime();
1265
- const dateB = new Date(b.createdAt).getTime();
1266
- return dateB - dateA;
1267
- });
1268
- const start = page * perPage;
1269
- const end = start + perPage;
1270
- const paginatedTraces = filteredTraces.slice(start, end);
1271
- return paginatedTraces.map((record) => ({
1272
- id: record.id,
1273
- parentSpanId: record.parentSpanId,
1274
- traceId: record.traceId,
1275
- name: record.name,
1276
- scope: record.scope,
1277
- kind: record.kind,
1278
- status: this.parseJSON(record.status),
1279
- events: this.parseJSON(record.events) || [],
1280
- links: this.parseJSON(record.links) || [],
1281
- attributes: this.parseJSON(record?.attributes) || {},
1282
- startTime: record.startTime,
1283
- endTime: record.endTime,
1284
- other: this.parseJSON(record.other) || {},
1285
- createdAt: record.createdAt
1286
- }));
1287
- } catch (error$1) {
1288
- const mastraError = new error.MastraError(
1289
- {
1290
- id: "CLOUDFLARE_STORAGE_GET_TRACES_FAILED",
1291
- domain: error.ErrorDomain.STORAGE,
1292
- category: error.ErrorCategory.THIRD_PARTY,
1293
- text: `Failed to get traces`
1294
- },
1295
- error$1
1296
- );
1297
- this.logger?.trackException(mastraError);
1298
- this.logger?.error(mastraError.toString());
1299
- return [];
1300
- }
1301
- }
1302
- parseJSON(value) {
1303
- if (typeof value === "string") {
1304
- try {
1305
- return JSON.parse(value);
1306
- } catch {
1307
- return value;
1308
- }
1309
- }
1310
- return value;
1311
- }
1312
- getEvalsByAgentName(_agentName, _type) {
1313
- throw new error.MastraError({
1314
- id: "CLOUDFLARE_STORAGE_GET_EVALS_BY_AGENT_NAME_FAILED",
1315
- domain: error.ErrorDomain.STORAGE,
1316
- category: error.ErrorCategory.THIRD_PARTY,
1317
- text: `Failed to get evals by agent name`
1318
- });
1319
- }
1320
1949
  parseWorkflowRun(row) {
1321
1950
  let parsedSnapshot = row.snapshot;
1322
1951
  if (typeof parsedSnapshot === "string") {
@@ -1330,28 +1959,24 @@ var CloudflareStore = class extends storage.MastraStorage {
1330
1959
  workflowName: row.workflow_name,
1331
1960
  runId: row.run_id,
1332
1961
  snapshot: parsedSnapshot,
1333
- createdAt: this.ensureDate(row.createdAt),
1334
- updatedAt: this.ensureDate(row.updatedAt),
1962
+ createdAt: storage.ensureDate(row.createdAt),
1963
+ updatedAt: storage.ensureDate(row.updatedAt),
1335
1964
  resourceId: row.resourceId
1336
1965
  };
1337
1966
  }
1338
1967
  buildWorkflowSnapshotPrefix({
1339
- namespace,
1340
1968
  workflowName,
1341
1969
  runId,
1342
1970
  resourceId
1343
1971
  }) {
1344
- const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
1972
+ const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
1345
1973
  let key = `${prefix}${storage.TABLE_WORKFLOW_SNAPSHOT}`;
1346
- if (namespace) key += `:${namespace}`;
1347
1974
  if (workflowName) key += `:${workflowName}`;
1348
1975
  if (runId) key += `:${runId}`;
1349
1976
  if (resourceId) key += `:${resourceId}`;
1350
- if (!resourceId && (runId || workflowName || namespace)) key += ":";
1351
1977
  return key;
1352
1978
  }
1353
1979
  async getWorkflowRuns({
1354
- namespace,
1355
1980
  workflowName,
1356
1981
  limit = 20,
1357
1982
  offset = 0,
@@ -1360,28 +1985,32 @@ var CloudflareStore = class extends storage.MastraStorage {
1360
1985
  toDate
1361
1986
  } = {}) {
1362
1987
  try {
1363
- const prefix = this.buildWorkflowSnapshotPrefix({ namespace, workflowName });
1364
- const keyObjs = await this.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
1988
+ const prefix = this.buildWorkflowSnapshotPrefix({ workflowName });
1989
+ const keyObjs = await this.operations.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
1365
1990
  const runs = [];
1366
1991
  for (const { name: key } of keyObjs) {
1367
1992
  const parts = key.split(":");
1368
1993
  const idx = parts.indexOf(storage.TABLE_WORKFLOW_SNAPSHOT);
1369
- if (idx === -1 || parts.length < idx + 4) continue;
1370
- const ns = parts[idx + 1];
1371
- const wfName = parts[idx + 2];
1372
- const keyResourceId = parts.length > idx + 4 ? parts[idx + 4] : void 0;
1373
- if (namespace && ns !== namespace || workflowName && wfName !== workflowName) continue;
1374
- if (resourceId && keyResourceId && keyResourceId !== resourceId) continue;
1375
- const data = await this.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
1994
+ if (idx === -1 || parts.length < idx + 3) continue;
1995
+ const wfName = parts[idx + 1];
1996
+ const keyResourceId = parts.length > idx + 3 ? parts[idx + 3] : void 0;
1997
+ if (workflowName && wfName !== workflowName) continue;
1998
+ if (resourceId && keyResourceId !== resourceId) continue;
1999
+ const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
1376
2000
  if (!data) continue;
1377
2001
  try {
1378
- if (resourceId && data.resourceId && data.resourceId !== resourceId) continue;
1379
- const createdAt = this.ensureDate(data.createdAt);
2002
+ if (resourceId && !keyResourceId) continue;
2003
+ const createdAt = storage.ensureDate(data.createdAt);
1380
2004
  if (fromDate && createdAt && createdAt < fromDate) continue;
1381
2005
  if (toDate && createdAt && createdAt > toDate) continue;
1382
- const state = this.normalizeWorkflowState(data.snapshot || data);
1383
- this.validateWorkflowState(state);
1384
- const run = this.parseWorkflowRun({ ...data, snapshot: state });
2006
+ const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
2007
+ const resourceIdToUse = keyResourceId || data.resourceId;
2008
+ const run = this.parseWorkflowRun({
2009
+ ...data,
2010
+ workflow_name: wfName,
2011
+ resourceId: resourceIdToUse,
2012
+ snapshot: snapshotData
2013
+ });
1385
2014
  runs.push(run);
1386
2015
  } catch (err) {
1387
2016
  this.logger.error("Failed to parse workflow snapshot:", { key, error: err });
@@ -1406,29 +2035,35 @@ var CloudflareStore = class extends storage.MastraStorage {
1406
2035
  },
1407
2036
  error$1
1408
2037
  );
1409
- this.logger?.trackException(mastraError);
1410
- this.logger?.error(mastraError.toString());
2038
+ this.logger.trackException?.(mastraError);
2039
+ this.logger.error(mastraError.toString());
1411
2040
  return { runs: [], total: 0 };
1412
2041
  }
1413
2042
  }
1414
2043
  async getWorkflowRunById({
1415
- namespace,
1416
2044
  runId,
1417
2045
  workflowName
1418
2046
  }) {
1419
2047
  try {
1420
- if (!runId || !workflowName || !namespace) {
1421
- throw new Error("runId, workflowName, and namespace are required");
2048
+ if (!runId || !workflowName) {
2049
+ throw new Error("runId, workflowName, are required");
1422
2050
  }
1423
- const prefix = this.buildWorkflowSnapshotPrefix({ namespace, workflowName, runId });
1424
- const keyObjs = await this.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
2051
+ const prefix = this.buildWorkflowSnapshotPrefix({ workflowName, runId });
2052
+ const keyObjs = await this.operations.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
1425
2053
  if (!keyObjs.length) return null;
1426
- const key = keyObjs[0]?.name;
1427
- const data = await this.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
2054
+ const exactKey = keyObjs.find((k) => {
2055
+ const parts = k.name.split(":");
2056
+ const idx = parts.indexOf(storage.TABLE_WORKFLOW_SNAPSHOT);
2057
+ if (idx === -1 || parts.length < idx + 3) return false;
2058
+ const wfName = parts[idx + 1];
2059
+ const rId = parts[idx + 2];
2060
+ return wfName === workflowName && rId === runId;
2061
+ });
2062
+ if (!exactKey) return null;
2063
+ const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, exactKey.name);
1428
2064
  if (!data) return null;
1429
- const state = this.normalizeWorkflowState(data.snapshot || data);
1430
- this.validateWorkflowState(state);
1431
- return this.parseWorkflowRun({ ...data, snapshot: state });
2065
+ const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
2066
+ return this.parseWorkflowRun({ ...data, snapshot: snapshotData });
1432
2067
  } catch (error$1) {
1433
2068
  const mastraError = new error.MastraError(
1434
2069
  {
@@ -1436,47 +2071,282 @@ var CloudflareStore = class extends storage.MastraStorage {
1436
2071
  domain: error.ErrorDomain.STORAGE,
1437
2072
  category: error.ErrorCategory.THIRD_PARTY,
1438
2073
  details: {
1439
- namespace,
1440
2074
  workflowName,
1441
2075
  runId
1442
2076
  }
1443
2077
  },
1444
2078
  error$1
1445
2079
  );
1446
- this.logger?.trackException(mastraError);
1447
- this.logger?.error(mastraError.toString());
2080
+ this.logger.trackException?.(mastraError);
2081
+ this.logger.error(mastraError.toString());
1448
2082
  return null;
1449
2083
  }
1450
2084
  }
1451
- async getTracesPaginated(_args) {
1452
- throw new error.MastraError({
1453
- id: "CLOUDFLARE_STORAGE_GET_TRACES_PAGINATED_FAILED",
1454
- domain: error.ErrorDomain.STORAGE,
1455
- category: error.ErrorCategory.THIRD_PARTY,
1456
- text: "Method not implemented."
1457
- });
2085
+ };
2086
+
2087
+ // src/storage/types.ts
2088
+ function isWorkersConfig(config) {
2089
+ return "bindings" in config;
2090
+ }
2091
+
2092
+ // src/storage/index.ts
2093
+ var CloudflareStore = class extends storage.MastraStorage {
2094
+ stores;
2095
+ client;
2096
+ accountId;
2097
+ namespacePrefix;
2098
+ bindings;
2099
+ validateWorkersConfig(config) {
2100
+ if (!isWorkersConfig(config)) {
2101
+ throw new Error("Invalid Workers API configuration");
2102
+ }
2103
+ if (!config.bindings) {
2104
+ throw new Error("KV bindings are required when using Workers Binding API");
2105
+ }
2106
+ const requiredTables = [
2107
+ storage.TABLE_THREADS,
2108
+ storage.TABLE_MESSAGES,
2109
+ storage.TABLE_WORKFLOW_SNAPSHOT,
2110
+ storage.TABLE_EVALS,
2111
+ storage.TABLE_SCORERS,
2112
+ storage.TABLE_TRACES
2113
+ ];
2114
+ for (const table of requiredTables) {
2115
+ if (!(table in config.bindings)) {
2116
+ throw new Error(`Missing KV binding for table: ${table}`);
2117
+ }
2118
+ }
2119
+ }
2120
+ validateRestConfig(config) {
2121
+ if (isWorkersConfig(config)) {
2122
+ throw new Error("Invalid REST API configuration");
2123
+ }
2124
+ if (!config.accountId?.trim()) {
2125
+ throw new Error("accountId is required for REST API");
2126
+ }
2127
+ if (!config.apiToken?.trim()) {
2128
+ throw new Error("apiToken is required for REST API");
2129
+ }
2130
+ }
2131
+ constructor(config) {
2132
+ super({ name: "Cloudflare" });
2133
+ try {
2134
+ if (isWorkersConfig(config)) {
2135
+ this.validateWorkersConfig(config);
2136
+ this.bindings = config.bindings;
2137
+ this.namespacePrefix = config.keyPrefix?.trim() || "";
2138
+ this.logger.info("Using Cloudflare KV Workers Binding API");
2139
+ } else {
2140
+ this.validateRestConfig(config);
2141
+ this.accountId = config.accountId.trim();
2142
+ this.namespacePrefix = config.namespacePrefix?.trim() || "";
2143
+ this.client = new Cloudflare__default.default({
2144
+ apiToken: config.apiToken.trim()
2145
+ });
2146
+ this.logger.info("Using Cloudflare KV REST API");
2147
+ }
2148
+ const operations = new StoreOperationsCloudflare({
2149
+ accountId: this.accountId,
2150
+ client: this.client,
2151
+ namespacePrefix: this.namespacePrefix,
2152
+ bindings: this.bindings
2153
+ });
2154
+ const legacyEvals = new LegacyEvalsStorageCloudflare({
2155
+ operations
2156
+ });
2157
+ const workflows = new WorkflowsStorageCloudflare({
2158
+ operations
2159
+ });
2160
+ const traces = new TracesStorageCloudflare({
2161
+ operations
2162
+ });
2163
+ const memory = new MemoryStorageCloudflare({
2164
+ operations
2165
+ });
2166
+ const scores = new ScoresStorageCloudflare({
2167
+ operations
2168
+ });
2169
+ this.stores = {
2170
+ operations,
2171
+ legacyEvals,
2172
+ workflows,
2173
+ traces,
2174
+ memory,
2175
+ scores
2176
+ };
2177
+ } catch (error$1) {
2178
+ throw new error.MastraError(
2179
+ {
2180
+ id: "CLOUDFLARE_STORAGE_INIT_FAILED",
2181
+ domain: error.ErrorDomain.STORAGE,
2182
+ category: error.ErrorCategory.THIRD_PARTY
2183
+ },
2184
+ error$1
2185
+ );
2186
+ }
2187
+ }
2188
+ async createTable({
2189
+ tableName,
2190
+ schema
2191
+ }) {
2192
+ return this.stores.operations.createTable({ tableName, schema });
2193
+ }
2194
+ async alterTable(_args) {
2195
+ return this.stores.operations.alterTable(_args);
2196
+ }
2197
+ async clearTable({ tableName }) {
2198
+ return this.stores.operations.clearTable({ tableName });
2199
+ }
2200
+ async dropTable({ tableName }) {
2201
+ return this.stores.operations.dropTable({ tableName });
2202
+ }
2203
+ async insert({
2204
+ tableName,
2205
+ record
2206
+ }) {
2207
+ return this.stores.operations.insert({ tableName, record });
2208
+ }
2209
+ async load({ tableName, keys }) {
2210
+ return this.stores.operations.load({ tableName, keys });
2211
+ }
2212
+ async getThreadById({ threadId }) {
2213
+ return this.stores.memory.getThreadById({ threadId });
2214
+ }
2215
+ async getThreadsByResourceId({ resourceId }) {
2216
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
2217
+ }
2218
+ async saveThread({ thread }) {
2219
+ return this.stores.memory.saveThread({ thread });
2220
+ }
2221
+ async updateThread({
2222
+ id,
2223
+ title,
2224
+ metadata
2225
+ }) {
2226
+ return this.stores.memory.updateThread({ id, title, metadata });
2227
+ }
2228
+ async deleteThread({ threadId }) {
2229
+ return this.stores.memory.deleteThread({ threadId });
2230
+ }
2231
+ async saveMessages(args) {
2232
+ return this.stores.memory.saveMessages(args);
2233
+ }
2234
+ async getMessages({
2235
+ threadId,
2236
+ resourceId,
2237
+ selectBy,
2238
+ format
2239
+ }) {
2240
+ return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format });
2241
+ }
2242
+ async persistWorkflowSnapshot(params) {
2243
+ return this.stores.workflows.persistWorkflowSnapshot(params);
1458
2244
  }
1459
- async getThreadsByResourceIdPaginated(_args) {
1460
- throw new error.MastraError({
1461
- id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1462
- domain: error.ErrorDomain.STORAGE,
1463
- category: error.ErrorCategory.THIRD_PARTY,
1464
- text: "Method not implemented."
2245
+ async loadWorkflowSnapshot(params) {
2246
+ return this.stores.workflows.loadWorkflowSnapshot(params);
2247
+ }
2248
+ async batchInsert(input) {
2249
+ return this.stores.operations.batchInsert(input);
2250
+ }
2251
+ async getTraces({
2252
+ name,
2253
+ scope,
2254
+ page = 0,
2255
+ perPage = 100,
2256
+ attributes,
2257
+ fromDate,
2258
+ toDate
2259
+ }) {
2260
+ return this.stores.traces.getTraces({
2261
+ name,
2262
+ scope,
2263
+ page,
2264
+ perPage,
2265
+ attributes,
2266
+ fromDate,
2267
+ toDate
1465
2268
  });
1466
2269
  }
1467
- async getMessagesPaginated(_args) {
1468
- throw new error.MastraError({
1469
- id: "CLOUDFLARE_STORAGE_GET_MESSAGES_PAGINATED_FAILED",
1470
- domain: error.ErrorDomain.STORAGE,
1471
- category: error.ErrorCategory.THIRD_PARTY,
1472
- text: "Method not implemented."
2270
+ async getEvalsByAgentName(agentName, type) {
2271
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2272
+ }
2273
+ async getEvals(options) {
2274
+ return this.stores.legacyEvals.getEvals(options);
2275
+ }
2276
+ async getWorkflowRuns({
2277
+ workflowName,
2278
+ limit = 20,
2279
+ offset = 0,
2280
+ resourceId,
2281
+ fromDate,
2282
+ toDate
2283
+ } = {}) {
2284
+ return this.stores.workflows.getWorkflowRuns({
2285
+ workflowName,
2286
+ limit,
2287
+ offset,
2288
+ resourceId,
2289
+ fromDate,
2290
+ toDate
1473
2291
  });
1474
2292
  }
1475
- async close() {
2293
+ async getWorkflowRunById({
2294
+ runId,
2295
+ workflowName
2296
+ }) {
2297
+ return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2298
+ }
2299
+ async getTracesPaginated(args) {
2300
+ return this.stores.traces.getTracesPaginated(args);
2301
+ }
2302
+ async getThreadsByResourceIdPaginated(args) {
2303
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
2304
+ }
2305
+ async getMessagesPaginated(args) {
2306
+ return this.stores.memory.getMessagesPaginated(args);
2307
+ }
2308
+ async updateMessages(args) {
2309
+ return this.stores.memory.updateMessages(args);
1476
2310
  }
1477
- async updateMessages(_args) {
1478
- this.logger.error("updateMessages is not yet implemented in CloudflareStore");
1479
- throw new Error("Method not implemented");
2311
+ async getScoreById({ id }) {
2312
+ return this.stores.scores.getScoreById({ id });
2313
+ }
2314
+ async saveScore(score) {
2315
+ return this.stores.scores.saveScore(score);
2316
+ }
2317
+ async getScoresByRunId({
2318
+ runId,
2319
+ pagination
2320
+ }) {
2321
+ return this.stores.scores.getScoresByRunId({ runId, pagination });
2322
+ }
2323
+ async getScoresByEntityId({
2324
+ entityId,
2325
+ entityType,
2326
+ pagination
2327
+ }) {
2328
+ return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2329
+ }
2330
+ async getScoresByScorerId({
2331
+ scorerId,
2332
+ pagination
2333
+ }) {
2334
+ return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
2335
+ }
2336
+ async getResourceById({ resourceId }) {
2337
+ return this.stores.memory.getResourceById({ resourceId });
2338
+ }
2339
+ async saveResource({ resource }) {
2340
+ return this.stores.memory.saveResource({ resource });
2341
+ }
2342
+ async updateResource({
2343
+ resourceId,
2344
+ workingMemory,
2345
+ metadata
2346
+ }) {
2347
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2348
+ }
2349
+ async close() {
1480
2350
  }
1481
2351
  };
1482
2352