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