@mastra/cloudflare 1.6.0-alpha.0 → 1.6.0

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