@mastra/cloudflare-d1 0.0.0-switch-to-core-20250424015131 → 0.0.0-tool-call-parts-20250630193309

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,15 +1,16 @@
1
1
  'use strict';
2
2
 
3
+ var agent = require('@mastra/core/agent');
4
+ var error = require('@mastra/core/error');
3
5
  var storage = require('@mastra/core/storage');
4
6
  var Cloudflare = require('cloudflare');
7
+ var utils = require('@mastra/core/utils');
5
8
 
6
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
10
 
8
11
  var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
9
12
 
10
13
  // src/storage/index.ts
11
-
12
- // src/storage/sql-builder.ts
13
14
  var SqlBuilder = class {
14
15
  sql = "";
15
16
  params = [];
@@ -19,12 +20,15 @@ var SqlBuilder = class {
19
20
  if (!columns || Array.isArray(columns) && columns.length === 0) {
20
21
  this.sql = "SELECT *";
21
22
  } else {
22
- this.sql = `SELECT ${Array.isArray(columns) ? columns.join(", ") : columns}`;
23
+ const cols = Array.isArray(columns) ? columns : [columns];
24
+ const parsedCols = cols.map((col) => parseSelectIdentifier(col));
25
+ this.sql = `SELECT ${parsedCols.join(", ")}`;
23
26
  }
24
27
  return this;
25
28
  }
26
29
  from(table) {
27
- this.sql += ` FROM ${table}`;
30
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
31
+ this.sql += ` FROM ${parsedTableName}`;
28
32
  return this;
29
33
  }
30
34
  /**
@@ -61,7 +65,11 @@ var SqlBuilder = class {
61
65
  return this;
62
66
  }
63
67
  orderBy(column, direction = "ASC") {
64
- this.sql += ` ORDER BY ${column} ${direction}`;
68
+ const parsedColumn = utils.parseSqlIdentifier(column, "column name");
69
+ if (!["ASC", "DESC"].includes(direction)) {
70
+ throw new Error(`Invalid sort direction: ${direction}`);
71
+ }
72
+ this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
65
73
  return this;
66
74
  }
67
75
  limit(count) {
@@ -74,6 +82,10 @@ var SqlBuilder = class {
74
82
  this.params.push(count);
75
83
  return this;
76
84
  }
85
+ count() {
86
+ this.sql += "SELECT COUNT(*) AS count";
87
+ return this;
88
+ }
77
89
  /**
78
90
  * Insert a row, or update specific columns on conflict (upsert).
79
91
  * @param table Table name
@@ -83,27 +95,33 @@ var SqlBuilder = class {
83
95
  * @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
84
96
  */
85
97
  insert(table, columns, values, conflictColumns, updateMap) {
86
- const placeholders = columns.map(() => "?").join(", ");
98
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
99
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
100
+ const placeholders = parsedColumns.map(() => "?").join(", ");
87
101
  if (conflictColumns && updateMap) {
102
+ const parsedConflictColumns = conflictColumns.map((col) => utils.parseSqlIdentifier(col, "column name"));
88
103
  const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
89
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
104
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
90
105
  this.params.push(...values);
91
106
  return this;
92
107
  }
93
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
108
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
94
109
  this.params.push(...values);
95
110
  return this;
96
111
  }
97
112
  // Update operations
98
113
  update(table, columns, values) {
99
- const setClause = columns.map((col) => `${col} = ?`).join(", ");
100
- this.sql = `UPDATE ${table} SET ${setClause}`;
114
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
115
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
116
+ const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
117
+ this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
101
118
  this.params.push(...values);
102
119
  return this;
103
120
  }
104
121
  // Delete operations
105
122
  delete(table) {
106
- this.sql = `DELETE FROM ${table}`;
123
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
124
+ this.sql = `DELETE FROM ${parsedTableName}`;
107
125
  return this;
108
126
  }
109
127
  /**
@@ -114,9 +132,16 @@ var SqlBuilder = class {
114
132
  * @returns The builder instance
115
133
  */
116
134
  createTable(table, columnDefinitions, tableConstraints) {
117
- const columns = columnDefinitions.join(", ");
135
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
136
+ const parsedColumnDefinitions = columnDefinitions.map((def) => {
137
+ const colName = def.split(/\s+/)[0];
138
+ if (!colName) throw new Error("Empty column name in definition");
139
+ utils.parseSqlIdentifier(colName, "column name");
140
+ return def;
141
+ });
142
+ const columns = parsedColumnDefinitions.join(", ");
118
143
  const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
119
- this.sql = `CREATE TABLE IF NOT EXISTS ${table} (${columns}${constraints})`;
144
+ this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
120
145
  return this;
121
146
  }
122
147
  /**
@@ -139,13 +164,10 @@ var SqlBuilder = class {
139
164
  * @returns The builder instance
140
165
  */
141
166
  createIndex(indexName, tableName, columnName, indexType = "") {
142
- this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${indexName} ON ${tableName}(${columnName})`;
143
- return this;
144
- }
145
- // Raw SQL with params
146
- raw(sql, ...params) {
147
- this.sql = sql;
148
- this.params.push(...params);
167
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
168
+ const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
169
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
170
+ this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
149
171
  return this;
150
172
  }
151
173
  /**
@@ -155,11 +177,12 @@ var SqlBuilder = class {
155
177
  * @param exact If true, will not add % wildcards
156
178
  */
157
179
  like(column, value, exact = false) {
180
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
158
181
  const likeValue = exact ? value : `%${value}%`;
159
182
  if (this.whereAdded) {
160
- this.sql += ` AND ${column} LIKE ?`;
183
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
161
184
  } else {
162
- this.sql += ` WHERE ${column} LIKE ?`;
185
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
163
186
  this.whereAdded = true;
164
187
  }
165
188
  this.params.push(likeValue);
@@ -172,11 +195,13 @@ var SqlBuilder = class {
172
195
  * @param value The value to match
173
196
  */
174
197
  jsonLike(column, key, value) {
175
- const jsonPattern = `%"${key}":"${value}"%`;
198
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
199
+ const parsedKey = utils.parseSqlIdentifier(key, "key name");
200
+ const jsonPattern = `%"${parsedKey}":"${value}"%`;
176
201
  if (this.whereAdded) {
177
- this.sql += ` AND ${column} LIKE ?`;
202
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
178
203
  } else {
179
- this.sql += ` WHERE ${column} LIKE ?`;
204
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
180
205
  this.whereAdded = true;
181
206
  }
182
207
  this.params.push(jsonPattern);
@@ -206,6 +231,15 @@ var SqlBuilder = class {
206
231
  function createSqlBuilder() {
207
232
  return new SqlBuilder();
208
233
  }
234
+ var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
235
+ function parseSelectIdentifier(column) {
236
+ if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
237
+ throw new Error(
238
+ `Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
239
+ );
240
+ }
241
+ return column;
242
+ }
209
243
 
210
244
  // src/storage/index.ts
211
245
  function isArrayOfRecords(value) {
@@ -223,24 +257,39 @@ var D1Store = class extends storage.MastraStorage {
223
257
  * @param config Configuration for D1 access (either REST API or Workers Binding API)
224
258
  */
225
259
  constructor(config) {
226
- super({ name: "D1" });
227
- this.tablePrefix = config.tablePrefix || "";
228
- if ("binding" in config) {
229
- if (!config.binding) {
230
- throw new Error("D1 binding is required when using Workers Binding API");
231
- }
232
- this.binding = config.binding;
233
- this.logger.info("Using D1 Workers Binding API");
234
- } else {
235
- if (!config.accountId || !config.databaseId || !config.apiToken) {
236
- throw new Error("accountId, databaseId, and apiToken are required when using REST API");
260
+ try {
261
+ super({ name: "D1" });
262
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
263
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
237
264
  }
238
- this.accountId = config.accountId;
239
- this.databaseId = config.databaseId;
240
- this.client = new Cloudflare__default.default({
241
- apiToken: config.apiToken
242
- });
243
- this.logger.info("Using D1 REST API");
265
+ this.tablePrefix = config.tablePrefix || "";
266
+ if ("binding" in config) {
267
+ if (!config.binding) {
268
+ throw new Error("D1 binding is required when using Workers Binding API");
269
+ }
270
+ this.binding = config.binding;
271
+ this.logger.info("Using D1 Workers Binding API");
272
+ } else {
273
+ if (!config.accountId || !config.databaseId || !config.apiToken) {
274
+ throw new Error("accountId, databaseId, and apiToken are required when using REST API");
275
+ }
276
+ this.accountId = config.accountId;
277
+ this.databaseId = config.databaseId;
278
+ this.client = new Cloudflare__default.default({
279
+ apiToken: config.apiToken
280
+ });
281
+ this.logger.info("Using D1 REST API");
282
+ }
283
+ } catch (error$1) {
284
+ throw new error.MastraError(
285
+ {
286
+ id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
287
+ domain: error.ErrorDomain.STORAGE,
288
+ category: error.ErrorCategory.SYSTEM,
289
+ text: "Error initializing D1Store"
290
+ },
291
+ error$1
292
+ );
244
293
  }
245
294
  }
246
295
  // Helper method to get the full table name with prefix
@@ -250,30 +299,6 @@ var D1Store = class extends storage.MastraStorage {
250
299
  formatSqlParams(params) {
251
300
  return params.map((p) => p === void 0 || p === null ? null : p);
252
301
  }
253
- // Helper method to create SQL indexes for better query performance
254
- async createIndexIfNotExists(tableName, columnName, indexType = "") {
255
- const fullTableName = this.getTableName(tableName);
256
- const indexName = `idx_${tableName}_${columnName}`;
257
- try {
258
- const checkQuery = createSqlBuilder().checkIndexExists(indexName, fullTableName);
259
- const { sql: checkSql, params: checkParams } = checkQuery.build();
260
- const indexExists = await this.executeQuery({
261
- sql: checkSql,
262
- params: checkParams,
263
- first: true
264
- });
265
- if (!indexExists) {
266
- const createQuery = createSqlBuilder().createIndex(indexName, fullTableName, columnName, indexType);
267
- const { sql: createSql, params: createParams } = createQuery.build();
268
- await this.executeQuery({ sql: createSql, params: createParams });
269
- this.logger.debug(`Created index ${indexName} on ${fullTableName}(${columnName})`);
270
- }
271
- } catch (error) {
272
- this.logger.error(`Error creating index on ${fullTableName}(${columnName}):`, {
273
- message: error instanceof Error ? error.message : String(error)
274
- });
275
- }
276
- }
277
302
  async executeWorkersBindingQuery({
278
303
  sql,
279
304
  params = [],
@@ -377,34 +402,25 @@ var D1Store = class extends storage.MastraStorage {
377
402
  throw new Error(`D1 query error: ${error.message}`);
378
403
  }
379
404
  }
380
- // Helper to convert storage type to SQL type
381
- getSqlType(type) {
382
- switch (type) {
383
- case "text":
384
- return "TEXT";
385
- case "timestamp":
386
- return "TIMESTAMP";
387
- case "integer":
388
- return "INTEGER";
389
- case "bigint":
390
- return "INTEGER";
391
- // SQLite doesn't have a separate BIGINT type
392
- case "jsonb":
393
- return "TEXT";
394
- // Store JSON as TEXT in SQLite
395
- default:
396
- return "TEXT";
405
+ // Helper to get existing table columns
406
+ async getTableColumns(tableName) {
407
+ try {
408
+ const sql = `PRAGMA table_info(${tableName})`;
409
+ const result = await this.executeQuery({ sql, params: [] });
410
+ if (!result || !Array.isArray(result)) {
411
+ return [];
412
+ }
413
+ return result.map((row) => ({
414
+ name: row.name,
415
+ type: row.type
416
+ }));
417
+ } catch (error) {
418
+ this.logger.error(`Error getting table columns for ${tableName}:`, {
419
+ message: error instanceof Error ? error.message : String(error)
420
+ });
421
+ return [];
397
422
  }
398
423
  }
399
- ensureDate(date) {
400
- if (!date) return void 0;
401
- return date instanceof Date ? date : new Date(date);
402
- }
403
- serializeDate(date) {
404
- if (!date) return void 0;
405
- const dateObj = this.ensureDate(date);
406
- return dateObj?.toISOString();
407
- }
408
424
  // Helper to serialize objects to JSON strings
409
425
  serializeValue(value) {
410
426
  if (value === null || value === void 0) return null;
@@ -438,6 +454,18 @@ var D1Store = class extends storage.MastraStorage {
438
454
  }
439
455
  return value;
440
456
  }
457
+ getSqlType(type) {
458
+ switch (type) {
459
+ case "bigint":
460
+ return "INTEGER";
461
+ // SQLite uses INTEGER for all integer sizes
462
+ case "jsonb":
463
+ return "TEXT";
464
+ // Store JSON as TEXT in SQLite
465
+ default:
466
+ return super.getSqlType(type);
467
+ }
468
+ }
441
469
  async createTable({
442
470
  tableName,
443
471
  schema
@@ -453,16 +481,64 @@ var D1Store = class extends storage.MastraStorage {
453
481
  if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
454
482
  tableConstraints.push("UNIQUE (workflow_name, run_id)");
455
483
  }
456
- const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
457
- const { sql, params } = query.build();
458
484
  try {
485
+ const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
486
+ const { sql, params } = query.build();
459
487
  await this.executeQuery({ sql, params });
460
488
  this.logger.debug(`Created table ${fullTableName}`);
461
- } catch (error) {
489
+ } catch (error$1) {
462
490
  this.logger.error(`Error creating table ${fullTableName}:`, {
463
- message: error instanceof Error ? error.message : String(error)
491
+ message: error$1 instanceof Error ? error$1.message : String(error$1)
464
492
  });
465
- throw new Error(`Failed to create table ${fullTableName}: ${error}`);
493
+ throw new error.MastraError(
494
+ {
495
+ id: "CLOUDFLARE_D1_STORAGE_CREATE_TABLE_ERROR",
496
+ domain: error.ErrorDomain.STORAGE,
497
+ category: error.ErrorCategory.THIRD_PARTY,
498
+ text: `Failed to create table ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
499
+ details: { tableName }
500
+ },
501
+ error$1
502
+ );
503
+ }
504
+ }
505
+ /**
506
+ * Alters table schema to add columns if they don't exist
507
+ * @param tableName Name of the table
508
+ * @param schema Schema of the table
509
+ * @param ifNotExists Array of column names to add if they don't exist
510
+ */
511
+ async alterTable({
512
+ tableName,
513
+ schema,
514
+ ifNotExists
515
+ }) {
516
+ const fullTableName = this.getTableName(tableName);
517
+ try {
518
+ const existingColumns = await this.getTableColumns(fullTableName);
519
+ const existingColumnNames = new Set(existingColumns.map((col) => col.name.toLowerCase()));
520
+ for (const columnName of ifNotExists) {
521
+ if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
522
+ const columnDef = schema[columnName];
523
+ const sqlType = this.getSqlType(columnDef.type);
524
+ const nullable = columnDef.nullable === false ? "NOT NULL" : "";
525
+ const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
526
+ const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
527
+ await this.executeQuery({ sql: alterSql, params: [] });
528
+ this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
529
+ }
530
+ }
531
+ } catch (error$1) {
532
+ throw new error.MastraError(
533
+ {
534
+ id: "CLOUDFLARE_D1_STORAGE_ALTER_TABLE_ERROR",
535
+ domain: error.ErrorDomain.STORAGE,
536
+ category: error.ErrorCategory.THIRD_PARTY,
537
+ text: `Failed to alter table ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
538
+ details: { tableName }
539
+ },
540
+ error$1
541
+ );
466
542
  }
467
543
  }
468
544
  async clearTable({ tableName }) {
@@ -472,11 +548,17 @@ var D1Store = class extends storage.MastraStorage {
472
548
  const { sql, params } = query.build();
473
549
  await this.executeQuery({ sql, params });
474
550
  this.logger.debug(`Cleared table ${fullTableName}`);
475
- } catch (error) {
476
- this.logger.error(`Error clearing table ${fullTableName}:`, {
477
- message: error instanceof Error ? error.message : String(error)
478
- });
479
- throw new Error(`Failed to clear table ${fullTableName}: ${error}`);
551
+ } catch (error$1) {
552
+ throw new error.MastraError(
553
+ {
554
+ id: "CLOUDFLARE_D1_STORAGE_CLEAR_TABLE_ERROR",
555
+ domain: error.ErrorDomain.STORAGE,
556
+ category: error.ErrorCategory.THIRD_PARTY,
557
+ text: `Failed to clear table ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
558
+ details: { tableName }
559
+ },
560
+ error$1
561
+ );
480
562
  }
481
563
  }
482
564
  async processRecord(record) {
@@ -495,9 +577,17 @@ var D1Store = class extends storage.MastraStorage {
495
577
  const { sql, params } = query.build();
496
578
  try {
497
579
  await this.executeQuery({ sql, params });
498
- } catch (error) {
499
- this.logger.error(`Error inserting into ${fullTableName}:`, { error });
500
- throw new Error(`Failed to insert into ${fullTableName}: ${error}`);
580
+ } catch (error$1) {
581
+ throw new error.MastraError(
582
+ {
583
+ id: "CLOUDFLARE_D1_STORAGE_INSERT_ERROR",
584
+ domain: error.ErrorDomain.STORAGE,
585
+ category: error.ErrorCategory.THIRD_PARTY,
586
+ text: `Failed to insert into ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
587
+ details: { tableName }
588
+ },
589
+ error$1
590
+ );
501
591
  }
502
592
  }
503
593
  async load({ tableName, keys }) {
@@ -522,11 +612,17 @@ var D1Store = class extends storage.MastraStorage {
522
612
  processedResult[key] = this.deserializeValue(value);
523
613
  }
524
614
  return processedResult;
525
- } catch (error) {
526
- this.logger.error(`Error loading from ${fullTableName}:`, {
527
- message: error instanceof Error ? error.message : String(error)
528
- });
529
- return null;
615
+ } catch (error$1) {
616
+ throw new error.MastraError(
617
+ {
618
+ id: "CLOUDFLARE_D1_STORAGE_LOAD_ERROR",
619
+ domain: error.ErrorDomain.STORAGE,
620
+ category: error.ErrorCategory.THIRD_PARTY,
621
+ text: `Failed to load from ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
622
+ details: { tableName }
623
+ },
624
+ error$1
625
+ );
530
626
  }
531
627
  }
532
628
  async getThreadById({ threadId }) {
@@ -542,13 +638,25 @@ var D1Store = class extends storage.MastraStorage {
542
638
  updatedAt: this.ensureDate(thread.updatedAt),
543
639
  metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
544
640
  };
545
- } catch (error) {
546
- this.logger.error(`Error processing thread ${threadId}:`, {
547
- message: error instanceof Error ? error.message : String(error)
548
- });
641
+ } catch (error$1) {
642
+ const mastraError = new error.MastraError(
643
+ {
644
+ id: "CLOUDFLARE_D1_STORAGE_GET_THREAD_BY_ID_ERROR",
645
+ domain: error.ErrorDomain.STORAGE,
646
+ category: error.ErrorCategory.THIRD_PARTY,
647
+ text: `Error processing thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
648
+ details: { threadId }
649
+ },
650
+ error$1
651
+ );
652
+ this.logger?.error(mastraError.toString());
653
+ this.logger?.trackException(mastraError);
549
654
  return null;
550
655
  }
551
656
  }
657
+ /**
658
+ * @deprecated use getThreadsByResourceIdPaginated instead
659
+ */
552
660
  async getThreadsByResourceId({ resourceId }) {
553
661
  const fullTableName = this.getTableName(storage.TABLE_THREADS);
554
662
  try {
@@ -561,13 +669,67 @@ var D1Store = class extends storage.MastraStorage {
561
669
  updatedAt: this.ensureDate(thread.updatedAt),
562
670
  metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
563
671
  }));
564
- } catch (error) {
565
- this.logger.error(`Error getting threads by resourceId ${resourceId}:`, {
566
- message: error instanceof Error ? error.message : String(error)
567
- });
672
+ } catch (error$1) {
673
+ const mastraError = new error.MastraError(
674
+ {
675
+ id: "CLOUDFLARE_D1_STORAGE_GET_THREADS_BY_RESOURCE_ID_ERROR",
676
+ domain: error.ErrorDomain.STORAGE,
677
+ category: error.ErrorCategory.THIRD_PARTY,
678
+ text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
679
+ details: { resourceId }
680
+ },
681
+ error$1
682
+ );
683
+ this.logger?.error(mastraError.toString());
684
+ this.logger?.trackException(mastraError);
568
685
  return [];
569
686
  }
570
687
  }
688
+ async getThreadsByResourceIdPaginated(args) {
689
+ const { resourceId, page, perPage } = args;
690
+ const fullTableName = this.getTableName(storage.TABLE_THREADS);
691
+ const mapRowToStorageThreadType = (row) => ({
692
+ ...row,
693
+ createdAt: this.ensureDate(row.createdAt),
694
+ updatedAt: this.ensureDate(row.updatedAt),
695
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
696
+ });
697
+ try {
698
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
699
+ const countResult = await this.executeQuery(countQuery.build());
700
+ const total = Number(countResult?.[0]?.count ?? 0);
701
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
702
+ const results = await this.executeQuery(selectQuery.build());
703
+ const threads = results.map(mapRowToStorageThreadType);
704
+ return {
705
+ threads,
706
+ total,
707
+ page,
708
+ perPage,
709
+ hasMore: page * perPage + threads.length < total
710
+ };
711
+ } catch (error$1) {
712
+ const mastraError = new error.MastraError(
713
+ {
714
+ id: "CLOUDFLARE_D1_STORAGE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_ERROR",
715
+ domain: error.ErrorDomain.STORAGE,
716
+ category: error.ErrorCategory.THIRD_PARTY,
717
+ text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
718
+ details: { resourceId }
719
+ },
720
+ error$1
721
+ );
722
+ this.logger?.error(mastraError.toString());
723
+ this.logger?.trackException(mastraError);
724
+ return {
725
+ threads: [],
726
+ total: 0,
727
+ page,
728
+ perPage,
729
+ hasMore: false
730
+ };
731
+ }
732
+ }
571
733
  async saveThread({ thread }) {
572
734
  const fullTableName = this.getTableName(storage.TABLE_THREADS);
573
735
  const threadToSave = {
@@ -593,9 +755,17 @@ var D1Store = class extends storage.MastraStorage {
593
755
  try {
594
756
  await this.executeQuery({ sql, params });
595
757
  return thread;
596
- } catch (error) {
597
- this.logger.error(`Error saving thread to ${fullTableName}:`, { error });
598
- throw error;
758
+ } catch (error$1) {
759
+ throw new error.MastraError(
760
+ {
761
+ id: "CLOUDFLARE_D1_STORAGE_SAVE_THREAD_ERROR",
762
+ domain: error.ErrorDomain.STORAGE,
763
+ category: error.ErrorCategory.THIRD_PARTY,
764
+ text: `Failed to save thread to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
765
+ details: { threadId: thread.id }
766
+ },
767
+ error$1
768
+ );
599
769
  }
600
770
  }
601
771
  async updateThread({
@@ -604,19 +774,19 @@ var D1Store = class extends storage.MastraStorage {
604
774
  metadata
605
775
  }) {
606
776
  const thread = await this.getThreadById({ threadId: id });
607
- if (!thread) {
608
- throw new Error(`Thread ${id} not found`);
609
- }
610
- const fullTableName = this.getTableName(storage.TABLE_THREADS);
611
- const mergedMetadata = {
612
- ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
613
- ...metadata
614
- };
615
- const columns = ["title", "metadata", "updatedAt"];
616
- const values = [title, JSON.stringify(mergedMetadata), (/* @__PURE__ */ new Date()).toISOString()];
617
- const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
618
- const { sql, params } = query.build();
619
777
  try {
778
+ if (!thread) {
779
+ throw new Error(`Thread ${id} not found`);
780
+ }
781
+ const fullTableName = this.getTableName(storage.TABLE_THREADS);
782
+ const mergedMetadata = {
783
+ ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
784
+ ...metadata
785
+ };
786
+ const columns = ["title", "metadata", "updatedAt"];
787
+ const values = [title, JSON.stringify(mergedMetadata), (/* @__PURE__ */ new Date()).toISOString()];
788
+ const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
789
+ const { sql, params } = query.build();
620
790
  await this.executeQuery({ sql, params });
621
791
  return {
622
792
  ...thread,
@@ -627,9 +797,17 @@ var D1Store = class extends storage.MastraStorage {
627
797
  },
628
798
  updatedAt: /* @__PURE__ */ new Date()
629
799
  };
630
- } catch (error) {
631
- this.logger.error("Error updating thread:", { error });
632
- throw error;
800
+ } catch (error$1) {
801
+ throw new error.MastraError(
802
+ {
803
+ id: "CLOUDFLARE_D1_STORAGE_UPDATE_THREAD_ERROR",
804
+ domain: error.ErrorDomain.STORAGE,
805
+ category: error.ErrorCategory.THIRD_PARTY,
806
+ text: `Failed to update thread ${id}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
807
+ details: { threadId: id }
808
+ },
809
+ error$1
810
+ );
633
811
  }
634
812
  }
635
813
  async deleteThread({ threadId }) {
@@ -642,18 +820,25 @@ var D1Store = class extends storage.MastraStorage {
642
820
  const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
643
821
  const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
644
822
  await this.executeQuery({ sql: messagesSql, params: messagesParams });
645
- } catch (error) {
646
- this.logger.error(`Error deleting thread ${threadId}:`, {
647
- message: error instanceof Error ? error.message : String(error)
648
- });
649
- throw new Error(`Failed to delete thread ${threadId}: ${error}`);
823
+ } catch (error$1) {
824
+ throw new error.MastraError(
825
+ {
826
+ id: "CLOUDFLARE_D1_STORAGE_DELETE_THREAD_ERROR",
827
+ domain: error.ErrorDomain.STORAGE,
828
+ category: error.ErrorCategory.THIRD_PARTY,
829
+ text: `Failed to delete thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
830
+ details: { threadId }
831
+ },
832
+ error$1
833
+ );
650
834
  }
651
835
  }
652
- // Thread and message management methods
653
- async saveMessages({ messages }) {
836
+ async saveMessages(args) {
837
+ const { messages, format = "v1" } = args;
654
838
  if (messages.length === 0) return [];
655
839
  try {
656
840
  const now = /* @__PURE__ */ new Date();
841
+ const threadId = messages[0]?.threadId;
657
842
  for (const [i, message] of messages.entries()) {
658
843
  if (!message.id) throw new Error(`Message at index ${i} missing id`);
659
844
  if (!message.threadId) throw new Error(`Message at index ${i} missing threadId`);
@@ -672,36 +857,49 @@ var D1Store = class extends storage.MastraStorage {
672
857
  content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
673
858
  createdAt: createdAt.toISOString(),
674
859
  role: message.role,
675
- type: message.type
860
+ type: message.type || "v2",
861
+ resourceId: message.resourceId
676
862
  };
677
863
  });
678
- await this.batchInsert({
679
- tableName: storage.TABLE_MESSAGES,
680
- records: messagesToInsert
681
- });
864
+ await Promise.all([
865
+ this.batchUpsert({
866
+ tableName: storage.TABLE_MESSAGES,
867
+ records: messagesToInsert
868
+ }),
869
+ // Update thread's updatedAt timestamp
870
+ this.executeQuery({
871
+ sql: `UPDATE ${this.getTableName(storage.TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
872
+ params: [now.toISOString(), threadId]
873
+ })
874
+ ]);
682
875
  this.logger.debug(`Saved ${messages.length} messages`);
683
- return messages;
684
- } catch (error) {
685
- this.logger.error("Error saving messages:", { message: error instanceof Error ? error.message : String(error) });
686
- throw error;
876
+ const list = new agent.MessageList().add(messages, "memory");
877
+ if (format === `v2`) return list.get.all.v2();
878
+ return list.get.all.v1();
879
+ } catch (error$1) {
880
+ throw new error.MastraError(
881
+ {
882
+ id: "CLOUDFLARE_D1_STORAGE_SAVE_MESSAGES_ERROR",
883
+ domain: error.ErrorDomain.STORAGE,
884
+ category: error.ErrorCategory.THIRD_PARTY,
885
+ text: `Failed to save messages: ${error$1 instanceof Error ? error$1.message : String(error$1)}`
886
+ },
887
+ error$1
888
+ );
687
889
  }
688
890
  }
689
- async getMessages({ threadId, selectBy }) {
690
- const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
691
- const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
692
- const include = selectBy?.include || [];
693
- const messages = [];
694
- try {
695
- if (include.length) {
696
- const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
697
- const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
698
- const includeIds = include.map((i) => i.id);
699
- const sql2 = `
891
+ async _getIncludedMessages(threadId, selectBy) {
892
+ const include = selectBy?.include;
893
+ if (!include) return null;
894
+ const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
895
+ const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
896
+ const includeIds = include.map((i) => i.id);
897
+ const sql = `
700
898
  WITH ordered_messages AS (
701
899
  SELECT
702
900
  *,
703
901
  ROW_NUMBER() OVER (ORDER BY createdAt DESC) AS row_num
704
- FROM ${fullTableName}
902
+ FROM ${this.getTableName(storage.TABLE_MESSAGES)}
705
903
  WHERE thread_id = ?
706
904
  )
707
905
  SELECT
@@ -710,7 +908,7 @@ var D1Store = class extends storage.MastraStorage {
710
908
  m.role,
711
909
  m.type,
712
910
  m.createdAt,
713
- m.thread_id AS "threadId"
911
+ m.thread_id AS threadId
714
912
  FROM ordered_messages m
715
913
  WHERE m.id IN (${includeIds.map(() => "?").join(",")})
716
914
  OR EXISTS (
@@ -724,20 +922,38 @@ var D1Store = class extends storage.MastraStorage {
724
922
  )
725
923
  ORDER BY m.createdAt DESC
726
924
  `;
727
- const params2 = [
728
- threadId,
729
- ...includeIds,
730
- // for m.id IN (...)
731
- ...includeIds,
732
- // for target.id IN (...)
733
- prevMax,
734
- nextMax
735
- ];
736
- const includeResult = await this.executeQuery({ sql: sql2, params: params2 });
925
+ const params = [
926
+ threadId,
927
+ ...includeIds,
928
+ // for m.id IN (...)
929
+ ...includeIds,
930
+ // for target.id IN (...)
931
+ prevMax,
932
+ nextMax
933
+ ];
934
+ const messages = await this.executeQuery({ sql, params });
935
+ return messages;
936
+ }
937
+ async getMessages({
938
+ threadId,
939
+ selectBy,
940
+ format
941
+ }) {
942
+ const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
943
+ const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
944
+ const include = selectBy?.include || [];
945
+ const messages = [];
946
+ try {
947
+ if (include.length) {
948
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
737
949
  if (Array.isArray(includeResult)) messages.push(...includeResult);
738
950
  }
739
951
  const excludeIds = messages.map((m) => m.id);
740
- let query = createSqlBuilder().select(["id", "content", "role", "type", '"createdAt"', 'thread_id AS "threadId"']).from(fullTableName).where("thread_id = ?", threadId).andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds).orderBy("createdAt", "DESC").limit(limit);
952
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
953
+ if (excludeIds.length > 0) {
954
+ query.andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds);
955
+ }
956
+ query.orderBy("createdAt", "DESC").limit(limit);
741
957
  const { sql, params } = query.build();
742
958
  const result = await this.executeQuery({ sql, params });
743
959
  if (Array.isArray(result)) messages.push(...result);
@@ -751,18 +967,92 @@ var D1Store = class extends storage.MastraStorage {
751
967
  const processedMessages = messages.map((message) => {
752
968
  const processedMsg = {};
753
969
  for (const [key, value] of Object.entries(message)) {
970
+ if (key === `type` && value === `v2`) continue;
754
971
  processedMsg[key] = this.deserializeValue(value);
755
972
  }
756
973
  return processedMsg;
757
974
  });
758
975
  this.logger.debug(`Retrieved ${messages.length} messages for thread ${threadId}`);
759
- return processedMessages;
760
- } catch (error) {
761
- this.logger.error("Error retrieving messages for thread", {
762
- threadId,
763
- message: error instanceof Error ? error.message : String(error)
764
- });
765
- return [];
976
+ const list = new agent.MessageList().add(processedMessages, "memory");
977
+ if (format === `v2`) return list.get.all.v2();
978
+ return list.get.all.v1();
979
+ } catch (error$1) {
980
+ const mastraError = new error.MastraError(
981
+ {
982
+ id: "CLOUDFLARE_D1_STORAGE_GET_MESSAGES_ERROR",
983
+ domain: error.ErrorDomain.STORAGE,
984
+ category: error.ErrorCategory.THIRD_PARTY,
985
+ text: `Failed to retrieve messages for thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
986
+ details: { threadId }
987
+ },
988
+ error$1
989
+ );
990
+ this.logger?.error(mastraError.toString());
991
+ this.logger?.trackException(mastraError);
992
+ throw mastraError;
993
+ }
994
+ }
995
+ async getMessagesPaginated({
996
+ threadId,
997
+ selectBy,
998
+ format
999
+ }) {
1000
+ const { dateRange, page = 0, perPage = 40 } = selectBy?.pagination || {};
1001
+ const { start: fromDate, end: toDate } = dateRange || {};
1002
+ const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
1003
+ const messages = [];
1004
+ try {
1005
+ if (selectBy?.include?.length) {
1006
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
1007
+ if (Array.isArray(includeResult)) messages.push(...includeResult);
1008
+ }
1009
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
1010
+ if (fromDate) {
1011
+ countQuery.andWhere("createdAt >= ?", this.serializeDate(fromDate));
1012
+ }
1013
+ if (toDate) {
1014
+ countQuery.andWhere("createdAt <= ?", this.serializeDate(toDate));
1015
+ }
1016
+ const countResult = await this.executeQuery(countQuery.build());
1017
+ const total = Number(countResult[0]?.count ?? 0);
1018
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
1019
+ if (fromDate) {
1020
+ query.andWhere("createdAt >= ?", this.serializeDate(fromDate));
1021
+ }
1022
+ if (toDate) {
1023
+ query.andWhere("createdAt <= ?", this.serializeDate(toDate));
1024
+ }
1025
+ query.orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
1026
+ const results = await this.executeQuery(query.build());
1027
+ const list = new agent.MessageList().add(results, "memory");
1028
+ messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
1029
+ return {
1030
+ messages,
1031
+ total,
1032
+ page,
1033
+ perPage,
1034
+ hasMore: page * perPage + messages.length < total
1035
+ };
1036
+ } catch (error$1) {
1037
+ const mastraError = new error.MastraError(
1038
+ {
1039
+ id: "CLOUDFLARE_D1_STORAGE_GET_MESSAGES_PAGINATED_ERROR",
1040
+ domain: error.ErrorDomain.STORAGE,
1041
+ category: error.ErrorCategory.THIRD_PARTY,
1042
+ text: `Failed to retrieve messages for thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1043
+ details: { threadId }
1044
+ },
1045
+ error$1
1046
+ );
1047
+ this.logger?.error(mastraError.toString());
1048
+ this.logger?.trackException(mastraError);
1049
+ return {
1050
+ messages: [],
1051
+ total: 0,
1052
+ page,
1053
+ perPage,
1054
+ hasMore: false
1055
+ };
766
1056
  }
767
1057
  }
768
1058
  async persistWorkflowSnapshot({
@@ -799,24 +1089,43 @@ var D1Store = class extends storage.MastraStorage {
799
1089
  const { sql, params } = query.build();
800
1090
  try {
801
1091
  await this.executeQuery({ sql, params });
802
- } catch (error) {
803
- this.logger.error("Error persisting workflow snapshot:", {
804
- message: error instanceof Error ? error.message : String(error)
805
- });
806
- throw error;
1092
+ } catch (error$1) {
1093
+ throw new error.MastraError(
1094
+ {
1095
+ id: "CLOUDFLARE_D1_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_ERROR",
1096
+ domain: error.ErrorDomain.STORAGE,
1097
+ category: error.ErrorCategory.THIRD_PARTY,
1098
+ text: `Failed to persist workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1099
+ details: { workflowName, runId }
1100
+ },
1101
+ error$1
1102
+ );
807
1103
  }
808
1104
  }
809
1105
  async loadWorkflowSnapshot(params) {
810
1106
  const { workflowName, runId } = params;
811
1107
  this.logger.debug("Loading workflow snapshot", { workflowName, runId });
812
- const d = await this.load({
813
- tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
814
- keys: {
815
- workflow_name: workflowName,
816
- run_id: runId
817
- }
818
- });
819
- return d ? d.snapshot : null;
1108
+ try {
1109
+ const d = await this.load({
1110
+ tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1111
+ keys: {
1112
+ workflow_name: workflowName,
1113
+ run_id: runId
1114
+ }
1115
+ });
1116
+ return d ? d.snapshot : null;
1117
+ } catch (error$1) {
1118
+ throw new error.MastraError(
1119
+ {
1120
+ id: "CLOUDFLARE_D1_STORAGE_LOAD_WORKFLOW_SNAPSHOT_ERROR",
1121
+ domain: error.ErrorDomain.STORAGE,
1122
+ category: error.ErrorCategory.THIRD_PARTY,
1123
+ text: `Failed to load workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1124
+ details: { workflowName, runId }
1125
+ },
1126
+ error$1
1127
+ );
1128
+ }
820
1129
  }
821
1130
  /**
822
1131
  * Insert multiple records in a batch operation
@@ -850,19 +1159,85 @@ var D1Store = class extends storage.MastraStorage {
850
1159
  );
851
1160
  }
852
1161
  this.logger.debug(`Successfully batch inserted ${records.length} records into ${tableName}`);
853
- } catch (error) {
854
- this.logger.error(`Error batch inserting into ${tableName}:`, {
855
- message: error instanceof Error ? error.message : String(error)
856
- });
857
- throw new Error(`Failed to batch insert into ${tableName}: ${error}`);
1162
+ } catch (error$1) {
1163
+ throw new error.MastraError(
1164
+ {
1165
+ id: "CLOUDFLARE_D1_STORAGE_BATCH_INSERT_ERROR",
1166
+ domain: error.ErrorDomain.STORAGE,
1167
+ category: error.ErrorCategory.THIRD_PARTY,
1168
+ text: `Failed to batch insert into ${tableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1169
+ details: { tableName }
1170
+ },
1171
+ error$1
1172
+ );
858
1173
  }
859
1174
  }
1175
+ /**
1176
+ * Upsert multiple records in a batch operation
1177
+ * @param tableName The table to insert into
1178
+ * @param records The records to insert
1179
+ */
1180
+ async batchUpsert({
1181
+ tableName,
1182
+ records
1183
+ }) {
1184
+ if (records.length === 0) return;
1185
+ const fullTableName = this.getTableName(tableName);
1186
+ try {
1187
+ const batchSize = 50;
1188
+ for (let i = 0; i < records.length; i += batchSize) {
1189
+ const batch = records.slice(i, i + batchSize);
1190
+ const recordsToInsert = batch;
1191
+ if (recordsToInsert.length > 0) {
1192
+ const firstRecord = recordsToInsert[0];
1193
+ const columns = Object.keys(firstRecord || {});
1194
+ for (const record of recordsToInsert) {
1195
+ const values = columns.map((col) => {
1196
+ if (!record) return null;
1197
+ const value = typeof col === "string" ? record[col] : null;
1198
+ return this.serializeValue(value);
1199
+ });
1200
+ const recordToUpsert = columns.reduce(
1201
+ (acc, col) => {
1202
+ if (col !== "createdAt") acc[col] = `excluded.${col}`;
1203
+ return acc;
1204
+ },
1205
+ {}
1206
+ );
1207
+ const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], recordToUpsert);
1208
+ const { sql, params } = query.build();
1209
+ await this.executeQuery({ sql, params });
1210
+ }
1211
+ }
1212
+ this.logger.debug(
1213
+ `Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
1214
+ );
1215
+ }
1216
+ this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
1217
+ } catch (error$1) {
1218
+ throw new error.MastraError(
1219
+ {
1220
+ id: "CLOUDFLARE_D1_STORAGE_BATCH_UPSERT_ERROR",
1221
+ domain: error.ErrorDomain.STORAGE,
1222
+ category: error.ErrorCategory.THIRD_PARTY,
1223
+ text: `Failed to batch upsert into ${tableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1224
+ details: { tableName }
1225
+ },
1226
+ error$1
1227
+ );
1228
+ }
1229
+ }
1230
+ /**
1231
+ * @deprecated use getTracesPaginated instead
1232
+ */
860
1233
  async getTraces({
861
1234
  name,
862
1235
  scope,
863
1236
  page,
864
1237
  perPage,
865
- attributes
1238
+ attributes,
1239
+ fromDate,
1240
+ toDate
866
1241
  }) {
867
1242
  const fullTableName = this.getTableName(storage.TABLE_TRACES);
868
1243
  try {
@@ -878,22 +1253,114 @@ var D1Store = class extends storage.MastraStorage {
878
1253
  query.jsonLike("attributes", key, value);
879
1254
  }
880
1255
  }
881
- query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
1256
+ if (fromDate) {
1257
+ query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1258
+ }
1259
+ if (toDate) {
1260
+ query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1261
+ }
1262
+ query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
882
1263
  const { sql, params } = query.build();
883
1264
  const results = await this.executeQuery({ sql, params });
884
- return isArrayOfRecords(results) ? results.map((trace) => ({
885
- ...trace,
886
- attributes: this.deserializeValue(trace.attributes, "jsonb"),
887
- status: this.deserializeValue(trace.status, "jsonb"),
888
- events: this.deserializeValue(trace.events, "jsonb"),
889
- links: this.deserializeValue(trace.links, "jsonb"),
890
- other: this.deserializeValue(trace.other, "jsonb")
891
- })) : [];
892
- } catch (error) {
893
- this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
1265
+ return isArrayOfRecords(results) ? results.map(
1266
+ (trace) => ({
1267
+ ...trace,
1268
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1269
+ status: this.deserializeValue(trace.status, "jsonb"),
1270
+ events: this.deserializeValue(trace.events, "jsonb"),
1271
+ links: this.deserializeValue(trace.links, "jsonb"),
1272
+ other: this.deserializeValue(trace.other, "jsonb")
1273
+ })
1274
+ ) : [];
1275
+ } catch (error$1) {
1276
+ const mastraError = new error.MastraError(
1277
+ {
1278
+ id: "CLOUDFLARE_D1_STORAGE_GET_TRACES_ERROR",
1279
+ domain: error.ErrorDomain.STORAGE,
1280
+ category: error.ErrorCategory.THIRD_PARTY,
1281
+ text: `Failed to retrieve traces: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1282
+ details: {
1283
+ name: name ?? "",
1284
+ scope: scope ?? ""
1285
+ }
1286
+ },
1287
+ error$1
1288
+ );
1289
+ this.logger?.error(mastraError.toString());
1290
+ this.logger?.trackException(mastraError);
894
1291
  return [];
895
1292
  }
896
1293
  }
1294
+ async getTracesPaginated(args) {
1295
+ const { name, scope, page, perPage, attributes, fromDate, toDate } = args;
1296
+ const fullTableName = this.getTableName(storage.TABLE_TRACES);
1297
+ try {
1298
+ const dataQuery = createSqlBuilder().select("*").from(fullTableName).where("1=1");
1299
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("1=1");
1300
+ if (name) {
1301
+ dataQuery.andWhere("name LIKE ?", `%${name}%`);
1302
+ countQuery.andWhere("name LIKE ?", `%${name}%`);
1303
+ }
1304
+ if (scope) {
1305
+ dataQuery.andWhere("scope = ?", scope);
1306
+ countQuery.andWhere("scope = ?", scope);
1307
+ }
1308
+ if (attributes && Object.keys(attributes).length > 0) {
1309
+ for (const [key, value] of Object.entries(attributes)) {
1310
+ dataQuery.jsonLike("attributes", key, value);
1311
+ countQuery.jsonLike("attributes", key, value);
1312
+ }
1313
+ }
1314
+ if (fromDate) {
1315
+ const fromDateStr = fromDate instanceof Date ? fromDate.toISOString() : fromDate;
1316
+ dataQuery.andWhere("createdAt >= ?", fromDateStr);
1317
+ countQuery.andWhere("createdAt >= ?", fromDateStr);
1318
+ }
1319
+ if (toDate) {
1320
+ const toDateStr = toDate instanceof Date ? toDate.toISOString() : toDate;
1321
+ dataQuery.andWhere("createdAt <= ?", toDateStr);
1322
+ countQuery.andWhere("createdAt <= ?", toDateStr);
1323
+ }
1324
+ const countResult = await this.executeQuery(countQuery.build());
1325
+ const total = Number(countResult?.[0]?.count ?? 0);
1326
+ dataQuery.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
1327
+ const results = await this.executeQuery(dataQuery.build());
1328
+ const traces = isArrayOfRecords(results) ? results.map(
1329
+ (trace) => ({
1330
+ ...trace,
1331
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1332
+ status: this.deserializeValue(trace.status, "jsonb"),
1333
+ events: this.deserializeValue(trace.events, "jsonb"),
1334
+ links: this.deserializeValue(trace.links, "jsonb"),
1335
+ other: this.deserializeValue(trace.other, "jsonb")
1336
+ })
1337
+ ) : [];
1338
+ return {
1339
+ traces,
1340
+ total,
1341
+ page,
1342
+ perPage,
1343
+ hasMore: page * perPage + traces.length < total
1344
+ };
1345
+ } catch (error$1) {
1346
+ const mastraError = new error.MastraError(
1347
+ {
1348
+ id: "CLOUDFLARE_D1_STORAGE_GET_TRACES_ERROR",
1349
+ domain: error.ErrorDomain.STORAGE,
1350
+ category: error.ErrorCategory.THIRD_PARTY,
1351
+ text: `Failed to retrieve traces: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1352
+ details: { name: name ?? "", scope: scope ?? "" }
1353
+ },
1354
+ error$1
1355
+ );
1356
+ this.logger?.error(mastraError.toString());
1357
+ this.logger?.trackException(mastraError);
1358
+ return { traces: [], total: 0, page, perPage, hasMore: false };
1359
+ }
1360
+ }
1361
+ /**
1362
+ * @deprecated use getEvals instead
1363
+ */
897
1364
  async getEvalsByAgentName(agentName, type) {
898
1365
  const fullTableName = this.getTableName(storage.TABLE_EVALS);
899
1366
  try {
@@ -922,15 +1389,222 @@ var D1Store = class extends storage.MastraStorage {
922
1389
  testInfo
923
1390
  };
924
1391
  }) : [];
925
- } catch (error) {
926
- this.logger.error(`Error getting evals for agent ${agentName}:`, {
927
- message: error instanceof Error ? error.message : String(error)
928
- });
1392
+ } catch (error$1) {
1393
+ const mastraError = new error.MastraError(
1394
+ {
1395
+ id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
1396
+ domain: error.ErrorDomain.STORAGE,
1397
+ category: error.ErrorCategory.THIRD_PARTY,
1398
+ text: `Failed to retrieve evals for agent ${agentName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1399
+ details: { agentName }
1400
+ },
1401
+ error$1
1402
+ );
1403
+ this.logger?.error(mastraError.toString());
1404
+ this.logger?.trackException(mastraError);
929
1405
  return [];
930
1406
  }
931
1407
  }
932
- getWorkflowRuns(_args) {
933
- throw new Error("Method not implemented.");
1408
+ async getEvals(options) {
1409
+ const { agentName, type, page = 0, perPage = 40, fromDate, toDate } = options || {};
1410
+ const fullTableName = this.getTableName(storage.TABLE_EVALS);
1411
+ const conditions = [];
1412
+ const queryParams = [];
1413
+ if (agentName) {
1414
+ conditions.push(`agent_name = ?`);
1415
+ queryParams.push(agentName);
1416
+ }
1417
+ if (type === "test") {
1418
+ conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
1419
+ } else if (type === "live") {
1420
+ conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
1421
+ }
1422
+ if (fromDate) {
1423
+ conditions.push(`createdAt >= ?`);
1424
+ queryParams.push(this.serializeDate(fromDate));
1425
+ }
1426
+ if (toDate) {
1427
+ conditions.push(`createdAt <= ?`);
1428
+ queryParams.push(this.serializeDate(toDate));
1429
+ }
1430
+ const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
1431
+ if (conditions.length > 0) {
1432
+ countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1433
+ }
1434
+ const { sql: countSql, params: countParams } = countQueryBuilder.build();
1435
+ try {
1436
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1437
+ const total = Number(countResult?.count || 0);
1438
+ const currentOffset = page * perPage;
1439
+ if (total === 0) {
1440
+ return {
1441
+ evals: [],
1442
+ total: 0,
1443
+ page,
1444
+ perPage,
1445
+ hasMore: false
1446
+ };
1447
+ }
1448
+ const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
1449
+ if (conditions.length > 0) {
1450
+ dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1451
+ }
1452
+ dataQueryBuilder.orderBy("createdAt", "DESC").limit(perPage).offset(currentOffset);
1453
+ const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
1454
+ const rows = await this.executeQuery({ sql: dataSql, params: dataParams });
1455
+ const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
1456
+ const result = this.deserializeValue(row.result);
1457
+ const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
1458
+ if (!result || typeof result !== "object" || !("score" in result)) {
1459
+ throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
1460
+ }
1461
+ return {
1462
+ input: row.input,
1463
+ output: row.output,
1464
+ result,
1465
+ agentName: row.agent_name,
1466
+ metricName: row.metric_name,
1467
+ instructions: row.instructions,
1468
+ testInfo,
1469
+ globalRunId: row.global_run_id,
1470
+ runId: row.run_id,
1471
+ createdAt: row.createdAt
1472
+ };
1473
+ });
1474
+ const hasMore = currentOffset + evals.length < total;
1475
+ return {
1476
+ evals,
1477
+ total,
1478
+ page,
1479
+ perPage,
1480
+ hasMore
1481
+ };
1482
+ } catch (error$1) {
1483
+ throw new error.MastraError(
1484
+ {
1485
+ id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
1486
+ domain: error.ErrorDomain.STORAGE,
1487
+ category: error.ErrorCategory.THIRD_PARTY,
1488
+ text: `Failed to retrieve evals for agent ${agentName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1489
+ details: { agentName: agentName ?? "", type: type ?? "" }
1490
+ },
1491
+ error$1
1492
+ );
1493
+ }
1494
+ }
1495
+ parseWorkflowRun(row) {
1496
+ let parsedSnapshot = row.snapshot;
1497
+ if (typeof parsedSnapshot === "string") {
1498
+ try {
1499
+ parsedSnapshot = JSON.parse(row.snapshot);
1500
+ } catch (e) {
1501
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1502
+ }
1503
+ }
1504
+ return {
1505
+ workflowName: row.workflow_name,
1506
+ runId: row.run_id,
1507
+ snapshot: parsedSnapshot,
1508
+ createdAt: this.ensureDate(row.createdAt),
1509
+ updatedAt: this.ensureDate(row.updatedAt),
1510
+ resourceId: row.resourceId
1511
+ };
1512
+ }
1513
+ async hasColumn(table, column) {
1514
+ const sql = `PRAGMA table_info(${table});`;
1515
+ const result = await this.executeQuery({ sql, params: [] });
1516
+ if (!result || !Array.isArray(result)) return false;
1517
+ return result.some((col) => col.name === column || col.name === column.toLowerCase());
1518
+ }
1519
+ async getWorkflowRuns({
1520
+ workflowName,
1521
+ fromDate,
1522
+ toDate,
1523
+ limit,
1524
+ offset,
1525
+ resourceId
1526
+ } = {}) {
1527
+ const fullTableName = this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1528
+ try {
1529
+ const builder = createSqlBuilder().select().from(fullTableName);
1530
+ const countBuilder = createSqlBuilder().count().from(fullTableName);
1531
+ if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
1532
+ if (resourceId) {
1533
+ const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
1534
+ if (hasResourceId) {
1535
+ builder.whereAnd("resourceId = ?", resourceId);
1536
+ countBuilder.whereAnd("resourceId = ?", resourceId);
1537
+ } else {
1538
+ console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1539
+ }
1540
+ }
1541
+ if (fromDate) {
1542
+ builder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1543
+ countBuilder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1544
+ }
1545
+ if (toDate) {
1546
+ builder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1547
+ countBuilder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1548
+ }
1549
+ builder.orderBy("createdAt", "DESC");
1550
+ if (typeof limit === "number") builder.limit(limit);
1551
+ if (typeof offset === "number") builder.offset(offset);
1552
+ const { sql, params } = builder.build();
1553
+ let total = 0;
1554
+ if (limit !== void 0 && offset !== void 0) {
1555
+ const { sql: countSql, params: countParams } = countBuilder.build();
1556
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1557
+ total = Number(countResult?.count ?? 0);
1558
+ }
1559
+ const results = await this.executeQuery({ sql, params });
1560
+ const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1561
+ return { runs, total: total || runs.length };
1562
+ } catch (error$1) {
1563
+ throw new error.MastraError(
1564
+ {
1565
+ id: "CLOUDFLARE_D1_STORAGE_GET_WORKFLOW_RUNS_ERROR",
1566
+ domain: error.ErrorDomain.STORAGE,
1567
+ category: error.ErrorCategory.THIRD_PARTY,
1568
+ text: `Failed to retrieve workflow runs: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1569
+ details: { workflowName: workflowName ?? "", resourceId: resourceId ?? "" }
1570
+ },
1571
+ error$1
1572
+ );
1573
+ }
1574
+ }
1575
+ async getWorkflowRunById({
1576
+ runId,
1577
+ workflowName
1578
+ }) {
1579
+ const fullTableName = this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1580
+ try {
1581
+ const conditions = [];
1582
+ const params = [];
1583
+ if (runId) {
1584
+ conditions.push("run_id = ?");
1585
+ params.push(runId);
1586
+ }
1587
+ if (workflowName) {
1588
+ conditions.push("workflow_name = ?");
1589
+ params.push(workflowName);
1590
+ }
1591
+ const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1592
+ const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1593
+ const result = await this.executeQuery({ sql, params, first: true });
1594
+ if (!result) return null;
1595
+ return this.parseWorkflowRun(result);
1596
+ } catch (error$1) {
1597
+ throw new error.MastraError(
1598
+ {
1599
+ id: "CLOUDFLARE_D1_STORAGE_GET_WORKFLOW_RUN_BY_ID_ERROR",
1600
+ domain: error.ErrorDomain.STORAGE,
1601
+ category: error.ErrorCategory.THIRD_PARTY,
1602
+ text: `Failed to retrieve workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1603
+ details: { runId, workflowName: workflowName ?? "" }
1604
+ },
1605
+ error$1
1606
+ );
1607
+ }
934
1608
  }
935
1609
  /**
936
1610
  * Close the database connection
@@ -939,6 +1613,10 @@ var D1Store = class extends storage.MastraStorage {
939
1613
  async close() {
940
1614
  this.logger.debug("Closing D1 connection");
941
1615
  }
1616
+ async updateMessages(_args) {
1617
+ this.logger.error("updateMessages is not yet implemented in CloudflareD1Store");
1618
+ throw new Error("Method not implemented");
1619
+ }
942
1620
  };
943
1621
 
944
1622
  exports.D1Store = D1Store;