@mastra/cloudflare 0.0.0-trigger-playground-ui-package-20250506151043 → 0.0.0-unified-sidebar-20251010130811

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