@mastra/cloudflare 0.0.0-vnext-inngest-20250508131921 → 0.0.0-vnext-20251119160359

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