@mastra/cloudflare-d1 1.0.0-beta.1 → 1.0.0-beta.11
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/CHANGELOG.md +524 -0
- package/dist/docs/README.md +31 -0
- package/dist/docs/SKILL.md +32 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/storage/01-reference.md +110 -0
- package/dist/index.cjs +1134 -1110
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1134 -1113
- package/dist/index.js.map +1 -1
- package/dist/storage/{domains/operations → db}/index.d.ts +42 -6
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +8 -7
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +12 -34
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +14 -14
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +55 -177
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var error = require('@mastra/core/error');
|
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
5
|
var Cloudflare = require('cloudflare');
|
|
6
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
7
8
|
var utils = require('@mastra/core/utils');
|
|
8
9
|
var evals = require('@mastra/core/evals');
|
|
9
10
|
|
|
@@ -12,6 +13,22 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
12
13
|
var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
|
|
13
14
|
|
|
14
15
|
// src/storage/index.ts
|
|
16
|
+
|
|
17
|
+
// src/storage/domains/utils.ts
|
|
18
|
+
function isArrayOfRecords(value) {
|
|
19
|
+
return value && Array.isArray(value) && value.length > 0;
|
|
20
|
+
}
|
|
21
|
+
function deserializeValue(value, type) {
|
|
22
|
+
if (value === null || value === void 0) return null;
|
|
23
|
+
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(value);
|
|
26
|
+
} catch {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
15
32
|
var SqlBuilder = class {
|
|
16
33
|
sql = "";
|
|
17
34
|
params = [];
|
|
@@ -242,1127 +259,1262 @@ function parseSelectIdentifier(column) {
|
|
|
242
259
|
return column;
|
|
243
260
|
}
|
|
244
261
|
|
|
245
|
-
// src/storage/
|
|
246
|
-
function
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
return JSON.parse(value);
|
|
254
|
-
} catch {
|
|
255
|
-
return value;
|
|
256
|
-
}
|
|
262
|
+
// src/storage/db/index.ts
|
|
263
|
+
function resolveD1Config(config) {
|
|
264
|
+
if ("client" in config) {
|
|
265
|
+
return {
|
|
266
|
+
client: config.client,
|
|
267
|
+
tablePrefix: config.tablePrefix
|
|
268
|
+
};
|
|
257
269
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
operations;
|
|
264
|
-
constructor({ operations }) {
|
|
265
|
-
super();
|
|
266
|
-
this.operations = operations;
|
|
270
|
+
if ("binding" in config) {
|
|
271
|
+
return {
|
|
272
|
+
binding: config.binding,
|
|
273
|
+
tablePrefix: config.tablePrefix
|
|
274
|
+
};
|
|
267
275
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
const cfClient = new Cloudflare__default.default({ apiToken: config.apiToken });
|
|
277
|
+
return {
|
|
278
|
+
client: {
|
|
279
|
+
query: ({ sql, params }) => {
|
|
280
|
+
return cfClient.d1.database.query(config.databaseId, {
|
|
281
|
+
account_id: config.accountId,
|
|
282
|
+
sql,
|
|
283
|
+
params
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
tablePrefix: config.tablePrefix
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
var D1DB = class extends base.MastraBase {
|
|
291
|
+
client;
|
|
292
|
+
binding;
|
|
293
|
+
tablePrefix;
|
|
294
|
+
constructor(config) {
|
|
295
|
+
super({
|
|
296
|
+
component: "STORAGE",
|
|
297
|
+
name: "D1_DB"
|
|
272
298
|
});
|
|
273
|
-
|
|
299
|
+
this.client = config.client;
|
|
300
|
+
this.binding = config.binding;
|
|
301
|
+
this.tablePrefix = config.tablePrefix || "";
|
|
302
|
+
}
|
|
303
|
+
async hasColumn(table, column) {
|
|
304
|
+
const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
|
|
305
|
+
const sql = `PRAGMA table_info(${fullTableName});`;
|
|
306
|
+
const result = await this.executeQuery({ sql, params: [] });
|
|
307
|
+
if (!result || !Array.isArray(result)) return false;
|
|
308
|
+
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
309
|
+
}
|
|
310
|
+
getTableName(tableName) {
|
|
311
|
+
return `${this.tablePrefix}${tableName}`;
|
|
312
|
+
}
|
|
313
|
+
formatSqlParams(params) {
|
|
314
|
+
return params.map((p) => p === void 0 || p === null ? null : p);
|
|
315
|
+
}
|
|
316
|
+
async executeWorkersBindingQuery({
|
|
317
|
+
sql,
|
|
318
|
+
params = [],
|
|
319
|
+
first = false
|
|
320
|
+
}) {
|
|
321
|
+
if (!this.binding) {
|
|
322
|
+
throw new Error("Workers binding is not configured");
|
|
323
|
+
}
|
|
274
324
|
try {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
325
|
+
const statement = this.binding.prepare(sql);
|
|
326
|
+
const formattedParams = this.formatSqlParams(params);
|
|
327
|
+
let result;
|
|
328
|
+
if (formattedParams.length > 0) {
|
|
329
|
+
if (first) {
|
|
330
|
+
result = await statement.bind(...formattedParams).first();
|
|
331
|
+
if (!result) return null;
|
|
332
|
+
return result;
|
|
333
|
+
} else {
|
|
334
|
+
result = await statement.bind(...formattedParams).all();
|
|
335
|
+
const results = result.results || [];
|
|
336
|
+
return results;
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
if (first) {
|
|
340
|
+
result = await statement.first();
|
|
341
|
+
if (!result) return null;
|
|
342
|
+
return result;
|
|
343
|
+
} else {
|
|
344
|
+
result = await statement.all();
|
|
345
|
+
const results = result.results || [];
|
|
346
|
+
return results;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
281
349
|
} catch (error$1) {
|
|
282
|
-
|
|
350
|
+
throw new error.MastraError(
|
|
283
351
|
{
|
|
284
|
-
id: "
|
|
352
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "WORKERS_BINDING_QUERY", "FAILED"),
|
|
285
353
|
domain: error.ErrorDomain.STORAGE,
|
|
286
354
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
287
|
-
|
|
288
|
-
details: { resourceId }
|
|
355
|
+
details: { sql }
|
|
289
356
|
},
|
|
290
357
|
error$1
|
|
291
358
|
);
|
|
292
|
-
this.logger?.error(mastraError.toString());
|
|
293
|
-
this.logger?.trackException(mastraError);
|
|
294
|
-
return null;
|
|
295
359
|
}
|
|
296
360
|
}
|
|
297
|
-
async
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
};
|
|
306
|
-
const processedRecord = await this.operations.processRecord(resourceToSave);
|
|
307
|
-
const columns = Object.keys(processedRecord);
|
|
308
|
-
const values = Object.values(processedRecord);
|
|
309
|
-
const updateMap = {
|
|
310
|
-
workingMemory: "excluded.workingMemory",
|
|
311
|
-
metadata: "excluded.metadata",
|
|
312
|
-
createdAt: "excluded.createdAt",
|
|
313
|
-
updatedAt: "excluded.updatedAt"
|
|
314
|
-
};
|
|
315
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
316
|
-
const { sql, params } = query.build();
|
|
361
|
+
async executeRestQuery({
|
|
362
|
+
sql,
|
|
363
|
+
params = [],
|
|
364
|
+
first = false
|
|
365
|
+
}) {
|
|
366
|
+
if (!this.client) {
|
|
367
|
+
throw new Error("D1 client is not configured");
|
|
368
|
+
}
|
|
317
369
|
try {
|
|
318
|
-
|
|
319
|
-
|
|
370
|
+
const formattedParams = this.formatSqlParams(params);
|
|
371
|
+
const response = await this.client.query({
|
|
372
|
+
sql,
|
|
373
|
+
params: formattedParams
|
|
374
|
+
});
|
|
375
|
+
const result = response.result || [];
|
|
376
|
+
const results = result.flatMap((r) => r.results || []);
|
|
377
|
+
if (first) {
|
|
378
|
+
return results[0] || null;
|
|
379
|
+
}
|
|
380
|
+
return results;
|
|
320
381
|
} catch (error$1) {
|
|
321
382
|
throw new error.MastraError(
|
|
322
383
|
{
|
|
323
|
-
id: "
|
|
384
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "REST_QUERY", "FAILED"),
|
|
324
385
|
domain: error.ErrorDomain.STORAGE,
|
|
325
386
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
326
|
-
|
|
327
|
-
details: { resourceId: resource.id }
|
|
387
|
+
details: { sql }
|
|
328
388
|
},
|
|
329
389
|
error$1
|
|
330
390
|
);
|
|
331
391
|
}
|
|
332
392
|
}
|
|
333
|
-
async
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const newResource = {
|
|
341
|
-
id: resourceId,
|
|
342
|
-
workingMemory,
|
|
343
|
-
metadata: metadata || {},
|
|
344
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
345
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
346
|
-
};
|
|
347
|
-
return this.saveResource({ resource: newResource });
|
|
393
|
+
async executeQuery(options) {
|
|
394
|
+
if (this.binding) {
|
|
395
|
+
return this.executeWorkersBindingQuery(options);
|
|
396
|
+
} else if (this.client) {
|
|
397
|
+
return this.executeRestQuery(options);
|
|
398
|
+
} else {
|
|
399
|
+
throw new Error("Neither binding nor client is configured");
|
|
348
400
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
...existingResource,
|
|
352
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
353
|
-
metadata: {
|
|
354
|
-
...existingResource.metadata,
|
|
355
|
-
...metadata
|
|
356
|
-
},
|
|
357
|
-
updatedAt
|
|
358
|
-
};
|
|
359
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_RESOURCES);
|
|
360
|
-
const columns = ["workingMemory", "metadata", "updatedAt"];
|
|
361
|
-
const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
|
|
362
|
-
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
|
|
363
|
-
const { sql, params } = query.build();
|
|
401
|
+
}
|
|
402
|
+
async getTableColumns(tableName) {
|
|
364
403
|
try {
|
|
365
|
-
|
|
366
|
-
|
|
404
|
+
const sql = `PRAGMA table_info(${tableName})`;
|
|
405
|
+
const result = await this.executeQuery({ sql });
|
|
406
|
+
if (!result || !Array.isArray(result)) {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
return result.map((row) => ({
|
|
410
|
+
name: row.name,
|
|
411
|
+
type: row.type
|
|
412
|
+
}));
|
|
413
|
+
} catch (error) {
|
|
414
|
+
this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
|
|
415
|
+
return [];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
serializeValue(value) {
|
|
419
|
+
if (value === null || value === void 0) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
if (value instanceof Date) {
|
|
423
|
+
return value.toISOString();
|
|
424
|
+
}
|
|
425
|
+
if (typeof value === "object") {
|
|
426
|
+
return JSON.stringify(value);
|
|
427
|
+
}
|
|
428
|
+
return value;
|
|
429
|
+
}
|
|
430
|
+
getSqlType(type) {
|
|
431
|
+
switch (type) {
|
|
432
|
+
case "bigint":
|
|
433
|
+
return "INTEGER";
|
|
434
|
+
// SQLite uses INTEGER for all integer sizes
|
|
435
|
+
case "jsonb":
|
|
436
|
+
return "TEXT";
|
|
437
|
+
// Store JSON as TEXT in SQLite
|
|
438
|
+
case "boolean":
|
|
439
|
+
return "INTEGER";
|
|
440
|
+
// SQLite uses 0/1 for booleans
|
|
441
|
+
default:
|
|
442
|
+
return storage.getSqlType(type);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
getDefaultValue(type) {
|
|
446
|
+
return storage.getDefaultValue(type);
|
|
447
|
+
}
|
|
448
|
+
async createTable({
|
|
449
|
+
tableName,
|
|
450
|
+
schema
|
|
451
|
+
}) {
|
|
452
|
+
try {
|
|
453
|
+
const fullTableName = this.getTableName(tableName);
|
|
454
|
+
const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
|
|
455
|
+
const type = this.getSqlType(colDef.type);
|
|
456
|
+
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
457
|
+
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
458
|
+
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
459
|
+
});
|
|
460
|
+
const tableConstraints = [];
|
|
461
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
462
|
+
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
463
|
+
}
|
|
464
|
+
const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
|
|
465
|
+
const { sql, params } = query.build();
|
|
466
|
+
await this.executeQuery({ sql, params });
|
|
467
|
+
this.logger.debug(`Created table ${fullTableName}`);
|
|
367
468
|
} catch (error$1) {
|
|
368
469
|
throw new error.MastraError(
|
|
369
470
|
{
|
|
370
|
-
id: "
|
|
471
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "CREATE_TABLE", "FAILED"),
|
|
371
472
|
domain: error.ErrorDomain.STORAGE,
|
|
372
473
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
373
|
-
|
|
374
|
-
details: { resourceId }
|
|
474
|
+
details: { tableName }
|
|
375
475
|
},
|
|
376
476
|
error$1
|
|
377
477
|
);
|
|
378
478
|
}
|
|
379
479
|
}
|
|
380
|
-
async
|
|
381
|
-
const thread = await this.operations.load({
|
|
382
|
-
tableName: storage.TABLE_THREADS,
|
|
383
|
-
keys: { id: threadId }
|
|
384
|
-
});
|
|
385
|
-
if (!thread) return null;
|
|
480
|
+
async clearTable({ tableName }) {
|
|
386
481
|
try {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
};
|
|
482
|
+
const fullTableName = this.getTableName(tableName);
|
|
483
|
+
const query = createSqlBuilder().delete(fullTableName);
|
|
484
|
+
const { sql, params } = query.build();
|
|
485
|
+
await this.executeQuery({ sql, params });
|
|
486
|
+
this.logger.debug(`Cleared table ${fullTableName}`);
|
|
393
487
|
} catch (error$1) {
|
|
394
|
-
|
|
488
|
+
throw new error.MastraError(
|
|
395
489
|
{
|
|
396
|
-
id: "
|
|
490
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "CLEAR_TABLE", "FAILED"),
|
|
397
491
|
domain: error.ErrorDomain.STORAGE,
|
|
398
492
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
399
|
-
|
|
400
|
-
details: { threadId }
|
|
493
|
+
details: { tableName }
|
|
401
494
|
},
|
|
402
495
|
error$1
|
|
403
496
|
);
|
|
404
|
-
this.logger?.error(mastraError.toString());
|
|
405
|
-
this.logger?.trackException(mastraError);
|
|
406
|
-
return null;
|
|
407
497
|
}
|
|
408
498
|
}
|
|
409
|
-
async
|
|
410
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
411
|
-
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
412
|
-
if (page < 0) {
|
|
413
|
-
throw new error.MastraError(
|
|
414
|
-
{
|
|
415
|
-
id: "STORAGE_CLOUDFLARE_D1_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
416
|
-
domain: error.ErrorDomain.STORAGE,
|
|
417
|
-
category: error.ErrorCategory.USER,
|
|
418
|
-
details: { page }
|
|
419
|
-
},
|
|
420
|
-
new Error("page must be >= 0")
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
424
|
-
const { field, direction } = this.parseOrderBy(orderBy);
|
|
425
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_THREADS);
|
|
426
|
-
const mapRowToStorageThreadType = (row) => ({
|
|
427
|
-
...row,
|
|
428
|
-
createdAt: storage.ensureDate(row.createdAt),
|
|
429
|
-
updatedAt: storage.ensureDate(row.updatedAt),
|
|
430
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
431
|
-
});
|
|
499
|
+
async dropTable({ tableName }) {
|
|
432
500
|
try {
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy(field, direction).limit(limitValue).offset(offset);
|
|
438
|
-
const results = await this.operations.executeQuery(selectQuery.build());
|
|
439
|
-
const threads = results.map(mapRowToStorageThreadType);
|
|
440
|
-
return {
|
|
441
|
-
threads,
|
|
442
|
-
total,
|
|
443
|
-
page,
|
|
444
|
-
perPage: perPageForResponse,
|
|
445
|
-
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
446
|
-
};
|
|
501
|
+
const fullTableName = this.getTableName(tableName);
|
|
502
|
+
const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
|
|
503
|
+
await this.executeQuery({ sql });
|
|
504
|
+
this.logger.debug(`Dropped table ${fullTableName}`);
|
|
447
505
|
} catch (error$1) {
|
|
448
|
-
|
|
506
|
+
throw new error.MastraError(
|
|
449
507
|
{
|
|
450
|
-
id: "
|
|
508
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "DROP_TABLE", "FAILED"),
|
|
451
509
|
domain: error.ErrorDomain.STORAGE,
|
|
452
510
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
453
|
-
|
|
454
|
-
details: { resourceId }
|
|
511
|
+
details: { tableName }
|
|
455
512
|
},
|
|
456
513
|
error$1
|
|
457
514
|
);
|
|
458
|
-
this.logger?.error(mastraError.toString());
|
|
459
|
-
this.logger?.trackException(mastraError);
|
|
460
|
-
return {
|
|
461
|
-
threads: [],
|
|
462
|
-
total: 0,
|
|
463
|
-
page,
|
|
464
|
-
perPage: perPageForResponse,
|
|
465
|
-
hasMore: false
|
|
466
|
-
};
|
|
467
515
|
}
|
|
468
516
|
}
|
|
469
|
-
async
|
|
470
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_THREADS);
|
|
471
|
-
const threadToSave = {
|
|
472
|
-
id: thread.id,
|
|
473
|
-
resourceId: thread.resourceId,
|
|
474
|
-
title: thread.title,
|
|
475
|
-
metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
476
|
-
createdAt: thread.createdAt.toISOString(),
|
|
477
|
-
updatedAt: thread.updatedAt.toISOString()
|
|
478
|
-
};
|
|
479
|
-
const processedRecord = await this.operations.processRecord(threadToSave);
|
|
480
|
-
const columns = Object.keys(processedRecord);
|
|
481
|
-
const values = Object.values(processedRecord);
|
|
482
|
-
const updateMap = {
|
|
483
|
-
resourceId: "excluded.resourceId",
|
|
484
|
-
title: "excluded.title",
|
|
485
|
-
metadata: "excluded.metadata",
|
|
486
|
-
createdAt: "excluded.createdAt",
|
|
487
|
-
updatedAt: "excluded.updatedAt"
|
|
488
|
-
};
|
|
489
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
490
|
-
const { sql, params } = query.build();
|
|
517
|
+
async alterTable(args) {
|
|
491
518
|
try {
|
|
492
|
-
|
|
493
|
-
|
|
519
|
+
const fullTableName = this.getTableName(args.tableName);
|
|
520
|
+
const existingColumns = await this.getTableColumns(fullTableName);
|
|
521
|
+
const existingColumnNames = new Set(existingColumns.map((col) => col.name));
|
|
522
|
+
for (const [columnName, column] of Object.entries(args.schema)) {
|
|
523
|
+
if (!existingColumnNames.has(columnName) && args.ifNotExists.includes(columnName)) {
|
|
524
|
+
const sqlType = this.getSqlType(column.type);
|
|
525
|
+
const defaultValue = this.getDefaultValue(column.type);
|
|
526
|
+
const sql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${defaultValue}`;
|
|
527
|
+
await this.executeQuery({ sql });
|
|
528
|
+
this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
494
531
|
} catch (error$1) {
|
|
495
532
|
throw new error.MastraError(
|
|
496
533
|
{
|
|
497
|
-
id: "
|
|
534
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "ALTER_TABLE", "FAILED"),
|
|
498
535
|
domain: error.ErrorDomain.STORAGE,
|
|
499
536
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
500
|
-
|
|
501
|
-
details: { threadId: thread.id }
|
|
537
|
+
details: { tableName: args.tableName }
|
|
502
538
|
},
|
|
503
539
|
error$1
|
|
504
540
|
);
|
|
505
541
|
}
|
|
506
542
|
}
|
|
507
|
-
async
|
|
508
|
-
id,
|
|
509
|
-
title,
|
|
510
|
-
metadata
|
|
511
|
-
}) {
|
|
512
|
-
const thread = await this.getThreadById({ threadId: id });
|
|
543
|
+
async insert({ tableName, record }) {
|
|
513
544
|
try {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
520
|
-
...metadata
|
|
521
|
-
};
|
|
522
|
-
const updatedAt = /* @__PURE__ */ new Date();
|
|
523
|
-
const columns = ["title", "metadata", "updatedAt"];
|
|
524
|
-
const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
|
|
525
|
-
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
|
|
545
|
+
const fullTableName = this.getTableName(tableName);
|
|
546
|
+
const processedRecord = await this.processRecord(record);
|
|
547
|
+
const columns = Object.keys(processedRecord);
|
|
548
|
+
const values = Object.values(processedRecord);
|
|
549
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
526
550
|
const { sql, params } = query.build();
|
|
527
|
-
await this.
|
|
528
|
-
return {
|
|
529
|
-
...thread,
|
|
530
|
-
title,
|
|
531
|
-
metadata: {
|
|
532
|
-
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
533
|
-
...metadata
|
|
534
|
-
},
|
|
535
|
-
updatedAt
|
|
536
|
-
};
|
|
551
|
+
await this.executeQuery({ sql, params });
|
|
537
552
|
} catch (error$1) {
|
|
538
553
|
throw new error.MastraError(
|
|
539
554
|
{
|
|
540
|
-
id: "
|
|
555
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "INSERT", "FAILED"),
|
|
541
556
|
domain: error.ErrorDomain.STORAGE,
|
|
542
557
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
543
|
-
|
|
544
|
-
details: { threadId: id }
|
|
558
|
+
details: { tableName }
|
|
545
559
|
},
|
|
546
560
|
error$1
|
|
547
561
|
);
|
|
548
562
|
}
|
|
549
563
|
}
|
|
550
|
-
async
|
|
551
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_THREADS);
|
|
564
|
+
async batchInsert({ tableName, records }) {
|
|
552
565
|
try {
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
await
|
|
556
|
-
const
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
566
|
+
if (records.length === 0) return;
|
|
567
|
+
const fullTableName = this.getTableName(tableName);
|
|
568
|
+
const processedRecords = await Promise.all(records.map((record) => this.processRecord(record)));
|
|
569
|
+
const columns = Object.keys(processedRecords[0] || {});
|
|
570
|
+
for (const record of processedRecords) {
|
|
571
|
+
const values = Object.values(record);
|
|
572
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
573
|
+
const { sql, params } = query.build();
|
|
574
|
+
await this.executeQuery({ sql, params });
|
|
575
|
+
}
|
|
560
576
|
} catch (error$1) {
|
|
561
577
|
throw new error.MastraError(
|
|
562
578
|
{
|
|
563
|
-
id: "
|
|
579
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "BATCH_INSERT", "FAILED"),
|
|
564
580
|
domain: error.ErrorDomain.STORAGE,
|
|
565
581
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
566
|
-
|
|
567
|
-
details: { threadId }
|
|
582
|
+
details: { tableName }
|
|
568
583
|
},
|
|
569
584
|
error$1
|
|
570
585
|
);
|
|
571
586
|
}
|
|
572
587
|
}
|
|
573
|
-
async
|
|
574
|
-
const { messages } = args;
|
|
575
|
-
if (messages.length === 0) return { messages: [] };
|
|
588
|
+
async load({ tableName, keys }) {
|
|
576
589
|
try {
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
if (
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
if (!message.role) {
|
|
588
|
-
throw new Error(`Message at index ${i} missing role`);
|
|
589
|
-
}
|
|
590
|
-
if (!message.resourceId) {
|
|
591
|
-
throw new Error(`Message at index ${i} missing resourceId`);
|
|
592
|
-
}
|
|
593
|
-
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
594
|
-
if (!thread) {
|
|
595
|
-
throw new Error(`Thread ${message.threadId} not found`);
|
|
590
|
+
const fullTableName = this.getTableName(tableName);
|
|
591
|
+
const query = createSqlBuilder().select("*").from(fullTableName);
|
|
592
|
+
let firstKey = true;
|
|
593
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
594
|
+
if (firstKey) {
|
|
595
|
+
query.where(`${key} = ?`, value);
|
|
596
|
+
firstKey = false;
|
|
597
|
+
} else {
|
|
598
|
+
query.andWhere(`${key} = ?`, value);
|
|
596
599
|
}
|
|
597
600
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
await Promise.all([
|
|
611
|
-
this.operations.batchUpsert({
|
|
612
|
-
tableName: storage.TABLE_MESSAGES,
|
|
613
|
-
records: messagesToInsert
|
|
614
|
-
}),
|
|
615
|
-
// Update thread's updatedAt timestamp
|
|
616
|
-
this.operations.executeQuery({
|
|
617
|
-
sql: `UPDATE ${this.operations.getTableName(storage.TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
618
|
-
params: [now.toISOString(), threadId]
|
|
619
|
-
})
|
|
620
|
-
]);
|
|
621
|
-
this.logger.debug(`Saved ${messages.length} messages`);
|
|
622
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
623
|
-
return { messages: list.get.all.db() };
|
|
601
|
+
query.orderBy("createdAt", "DESC");
|
|
602
|
+
query.limit(1);
|
|
603
|
+
const { sql, params } = query.build();
|
|
604
|
+
const result = await this.executeQuery({ sql, params, first: true });
|
|
605
|
+
if (!result) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
const deserializedResult = {};
|
|
609
|
+
for (const [key, value] of Object.entries(result)) {
|
|
610
|
+
deserializedResult[key] = deserializeValue(value);
|
|
611
|
+
}
|
|
612
|
+
return deserializedResult;
|
|
624
613
|
} catch (error$1) {
|
|
625
614
|
throw new error.MastraError(
|
|
626
615
|
{
|
|
627
|
-
id: "
|
|
616
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LOAD", "FAILED"),
|
|
628
617
|
domain: error.ErrorDomain.STORAGE,
|
|
629
618
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
630
|
-
|
|
619
|
+
details: { tableName }
|
|
631
620
|
},
|
|
632
621
|
error$1
|
|
633
622
|
);
|
|
634
623
|
}
|
|
635
624
|
}
|
|
636
|
-
async
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const params = [];
|
|
641
|
-
let paramIdx = 1;
|
|
642
|
-
for (const inc of include) {
|
|
643
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
644
|
-
const searchId = inc.threadId || threadId;
|
|
645
|
-
unionQueries.push(`
|
|
646
|
-
SELECT * FROM (
|
|
647
|
-
WITH ordered_messages AS (
|
|
648
|
-
SELECT
|
|
649
|
-
*,
|
|
650
|
-
ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
|
|
651
|
-
FROM ${this.operations.getTableName(storage.TABLE_MESSAGES)}
|
|
652
|
-
WHERE thread_id = ?
|
|
653
|
-
)
|
|
654
|
-
SELECT
|
|
655
|
-
m.id,
|
|
656
|
-
m.content,
|
|
657
|
-
m.role,
|
|
658
|
-
m.type,
|
|
659
|
-
m.createdAt,
|
|
660
|
-
m.thread_id AS threadId,
|
|
661
|
-
m.resourceId
|
|
662
|
-
FROM ordered_messages m
|
|
663
|
-
WHERE m.id = ?
|
|
664
|
-
OR EXISTS (
|
|
665
|
-
SELECT 1 FROM ordered_messages target
|
|
666
|
-
WHERE target.id = ?
|
|
667
|
-
AND (
|
|
668
|
-
(m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
|
|
669
|
-
OR
|
|
670
|
-
(m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
|
|
671
|
-
)
|
|
672
|
-
)
|
|
673
|
-
) AS query_${paramIdx}
|
|
674
|
-
`);
|
|
675
|
-
params.push(searchId, id, id, withNextMessages, withPreviousMessages);
|
|
676
|
-
paramIdx++;
|
|
677
|
-
}
|
|
678
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
|
|
679
|
-
const messages = await this.operations.executeQuery({ sql: finalQuery, params });
|
|
680
|
-
if (!Array.isArray(messages)) {
|
|
681
|
-
return [];
|
|
625
|
+
async processRecord(record) {
|
|
626
|
+
const processed = {};
|
|
627
|
+
for (const [key, value] of Object.entries(record)) {
|
|
628
|
+
processed[key] = this.serializeValue(value);
|
|
682
629
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
630
|
+
return processed;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Upsert multiple records in a batch operation
|
|
634
|
+
* @param tableName The table to insert into
|
|
635
|
+
* @param records The records to insert
|
|
636
|
+
*/
|
|
637
|
+
async batchUpsert({ tableName, records }) {
|
|
638
|
+
if (records.length === 0) return;
|
|
639
|
+
const fullTableName = this.getTableName(tableName);
|
|
640
|
+
try {
|
|
641
|
+
const batchSize = 50;
|
|
642
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
643
|
+
const batch = records.slice(i, i + batchSize);
|
|
644
|
+
const recordsToInsert = batch;
|
|
645
|
+
if (recordsToInsert.length > 0) {
|
|
646
|
+
const firstRecord = recordsToInsert[0];
|
|
647
|
+
const columns = Object.keys(firstRecord || {});
|
|
648
|
+
for (const record of recordsToInsert) {
|
|
649
|
+
const values = columns.map((col) => {
|
|
650
|
+
if (!record) return null;
|
|
651
|
+
const value = typeof col === "string" ? record[col] : null;
|
|
652
|
+
return this.serializeValue(value);
|
|
653
|
+
});
|
|
654
|
+
const recordToUpsert = columns.reduce(
|
|
655
|
+
(acc, col) => {
|
|
656
|
+
if (col !== "createdAt") acc[col] = `excluded.${col}`;
|
|
657
|
+
return acc;
|
|
658
|
+
},
|
|
659
|
+
{}
|
|
660
|
+
);
|
|
661
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], recordToUpsert);
|
|
662
|
+
const { sql, params } = query.build();
|
|
663
|
+
await this.executeQuery({ sql, params });
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
this.logger.debug(
|
|
667
|
+
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
668
|
+
);
|
|
688
669
|
}
|
|
689
|
-
|
|
670
|
+
this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
|
|
671
|
+
} catch (error$1) {
|
|
672
|
+
throw new error.MastraError(
|
|
673
|
+
{
|
|
674
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "BATCH_UPSERT", "FAILED"),
|
|
675
|
+
domain: error.ErrorDomain.STORAGE,
|
|
676
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
677
|
+
text: `Failed to batch upsert into ${tableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
678
|
+
details: { tableName }
|
|
679
|
+
},
|
|
680
|
+
error$1
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// src/storage/domains/memory/index.ts
|
|
687
|
+
var MemoryStorageD1 = class extends storage.MemoryStorage {
|
|
688
|
+
#db;
|
|
689
|
+
constructor(config) {
|
|
690
|
+
super();
|
|
691
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
692
|
+
}
|
|
693
|
+
async init() {
|
|
694
|
+
await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
695
|
+
await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
696
|
+
await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
697
|
+
await this.#db.alterTable({
|
|
698
|
+
tableName: storage.TABLE_MESSAGES,
|
|
699
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
|
|
700
|
+
ifNotExists: ["resourceId"]
|
|
690
701
|
});
|
|
691
|
-
return processedMessages;
|
|
692
702
|
}
|
|
693
|
-
async
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
703
|
+
async dangerouslyClearAll() {
|
|
704
|
+
await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
705
|
+
await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
706
|
+
await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
707
|
+
}
|
|
708
|
+
async getResourceById({ resourceId }) {
|
|
709
|
+
const resource = await this.#db.load({
|
|
710
|
+
tableName: storage.TABLE_RESOURCES,
|
|
711
|
+
keys: { id: resourceId }
|
|
712
|
+
});
|
|
713
|
+
if (!resource) return null;
|
|
697
714
|
try {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
const processedMsg = {};
|
|
705
|
-
for (const [key, value] of Object.entries(message)) {
|
|
706
|
-
if (key === `type` && value === `v2`) continue;
|
|
707
|
-
processedMsg[key] = deserializeValue(value);
|
|
708
|
-
}
|
|
709
|
-
return processedMsg;
|
|
710
|
-
});
|
|
711
|
-
this.logger.debug(`Retrieved ${messages.length} messages`);
|
|
712
|
-
const list = new agent.MessageList().add(processedMessages, "memory");
|
|
713
|
-
return { messages: list.get.all.db() };
|
|
715
|
+
return {
|
|
716
|
+
...resource,
|
|
717
|
+
createdAt: storage.ensureDate(resource.createdAt),
|
|
718
|
+
updatedAt: storage.ensureDate(resource.updatedAt),
|
|
719
|
+
metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata || "{}") : resource.metadata
|
|
720
|
+
};
|
|
714
721
|
} catch (error$1) {
|
|
715
722
|
const mastraError = new error.MastraError(
|
|
716
723
|
{
|
|
717
|
-
id: "
|
|
724
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
718
725
|
domain: error.ErrorDomain.STORAGE,
|
|
719
726
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
720
|
-
text: `
|
|
721
|
-
details: {
|
|
727
|
+
text: `Error processing resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
728
|
+
details: { resourceId }
|
|
722
729
|
},
|
|
723
730
|
error$1
|
|
724
731
|
);
|
|
725
732
|
this.logger?.error(mastraError.toString());
|
|
726
733
|
this.logger?.trackException(mastraError);
|
|
727
|
-
|
|
734
|
+
return null;
|
|
728
735
|
}
|
|
729
736
|
}
|
|
730
|
-
async
|
|
731
|
-
const
|
|
732
|
-
|
|
737
|
+
async saveResource({ resource }) {
|
|
738
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_RESOURCES);
|
|
739
|
+
const resourceToSave = {
|
|
740
|
+
id: resource.id,
|
|
741
|
+
workingMemory: resource.workingMemory,
|
|
742
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : null,
|
|
743
|
+
createdAt: resource.createdAt,
|
|
744
|
+
updatedAt: resource.updatedAt
|
|
745
|
+
};
|
|
746
|
+
const processedRecord = await this.#db.processRecord(resourceToSave);
|
|
747
|
+
const columns = Object.keys(processedRecord);
|
|
748
|
+
const values = Object.values(processedRecord);
|
|
749
|
+
const updateMap = {
|
|
750
|
+
workingMemory: "excluded.workingMemory",
|
|
751
|
+
metadata: "excluded.metadata",
|
|
752
|
+
createdAt: "excluded.createdAt",
|
|
753
|
+
updatedAt: "excluded.updatedAt"
|
|
754
|
+
};
|
|
755
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
756
|
+
const { sql, params } = query.build();
|
|
757
|
+
try {
|
|
758
|
+
await this.#db.executeQuery({ sql, params });
|
|
759
|
+
return resource;
|
|
760
|
+
} catch (error$1) {
|
|
733
761
|
throw new error.MastraError(
|
|
734
762
|
{
|
|
735
|
-
id: "
|
|
763
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_RESOURCE", "FAILED"),
|
|
736
764
|
domain: error.ErrorDomain.STORAGE,
|
|
737
765
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
738
|
-
|
|
766
|
+
text: `Failed to save resource to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
767
|
+
details: { resourceId: resource.id }
|
|
739
768
|
},
|
|
740
|
-
|
|
769
|
+
error$1
|
|
741
770
|
);
|
|
742
771
|
}
|
|
743
|
-
|
|
772
|
+
}
|
|
773
|
+
async updateResource({
|
|
774
|
+
resourceId,
|
|
775
|
+
workingMemory,
|
|
776
|
+
metadata
|
|
777
|
+
}) {
|
|
778
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
779
|
+
if (!existingResource) {
|
|
780
|
+
const newResource = {
|
|
781
|
+
id: resourceId,
|
|
782
|
+
workingMemory,
|
|
783
|
+
metadata: metadata || {},
|
|
784
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
785
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
786
|
+
};
|
|
787
|
+
return this.saveResource({ resource: newResource });
|
|
788
|
+
}
|
|
789
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
790
|
+
const updatedResource = {
|
|
791
|
+
...existingResource,
|
|
792
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
793
|
+
metadata: {
|
|
794
|
+
...existingResource.metadata,
|
|
795
|
+
...metadata
|
|
796
|
+
},
|
|
797
|
+
updatedAt
|
|
798
|
+
};
|
|
799
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_RESOURCES);
|
|
800
|
+
const columns = ["workingMemory", "metadata", "updatedAt"];
|
|
801
|
+
const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
|
|
802
|
+
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
|
|
803
|
+
const { sql, params } = query.build();
|
|
804
|
+
try {
|
|
805
|
+
await this.#db.executeQuery({ sql, params });
|
|
806
|
+
return updatedResource;
|
|
807
|
+
} catch (error$1) {
|
|
744
808
|
throw new error.MastraError(
|
|
745
809
|
{
|
|
746
|
-
id: "
|
|
810
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_RESOURCE", "FAILED"),
|
|
747
811
|
domain: error.ErrorDomain.STORAGE,
|
|
748
|
-
category: error.ErrorCategory.
|
|
749
|
-
|
|
812
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
813
|
+
text: `Failed to update resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
814
|
+
details: { resourceId }
|
|
750
815
|
},
|
|
751
|
-
|
|
816
|
+
error$1
|
|
752
817
|
);
|
|
753
818
|
}
|
|
754
|
-
|
|
755
|
-
|
|
819
|
+
}
|
|
820
|
+
async getThreadById({ threadId }) {
|
|
821
|
+
const thread = await this.#db.load({
|
|
822
|
+
tableName: storage.TABLE_THREADS,
|
|
823
|
+
keys: { id: threadId }
|
|
824
|
+
});
|
|
825
|
+
if (!thread) return null;
|
|
756
826
|
try {
|
|
757
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
|
|
758
|
-
let query = `
|
|
759
|
-
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
760
|
-
FROM ${fullTableName}
|
|
761
|
-
WHERE thread_id = ?
|
|
762
|
-
`;
|
|
763
|
-
const queryParams = [threadId];
|
|
764
|
-
if (resourceId) {
|
|
765
|
-
query += ` AND resourceId = ?`;
|
|
766
|
-
queryParams.push(resourceId);
|
|
767
|
-
}
|
|
768
|
-
const dateRange = filter?.dateRange;
|
|
769
|
-
if (dateRange?.start) {
|
|
770
|
-
const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
|
|
771
|
-
query += ` AND createdAt >= ?`;
|
|
772
|
-
queryParams.push(startDate);
|
|
773
|
-
}
|
|
774
|
-
if (dateRange?.end) {
|
|
775
|
-
const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
|
|
776
|
-
query += ` AND createdAt <= ?`;
|
|
777
|
-
queryParams.push(endDate);
|
|
778
|
-
}
|
|
779
|
-
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
780
|
-
query += ` ORDER BY "${field}" ${direction}`;
|
|
781
|
-
if (perPage !== Number.MAX_SAFE_INTEGER) {
|
|
782
|
-
query += ` LIMIT ? OFFSET ?`;
|
|
783
|
-
queryParams.push(perPage, offset);
|
|
784
|
-
}
|
|
785
|
-
const results = await this.operations.executeQuery({ sql: query, params: queryParams });
|
|
786
|
-
const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
|
|
787
|
-
const processedMsg = {};
|
|
788
|
-
for (const [key, value] of Object.entries(message)) {
|
|
789
|
-
if (key === `type` && value === `v2`) continue;
|
|
790
|
-
processedMsg[key] = deserializeValue(value);
|
|
791
|
-
}
|
|
792
|
-
return processedMsg;
|
|
793
|
-
});
|
|
794
|
-
const paginatedCount = paginatedMessages.length;
|
|
795
|
-
let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
|
|
796
|
-
const countParams = [threadId];
|
|
797
|
-
if (resourceId) {
|
|
798
|
-
countQuery += ` AND resourceId = ?`;
|
|
799
|
-
countParams.push(resourceId);
|
|
800
|
-
}
|
|
801
|
-
if (dateRange?.start) {
|
|
802
|
-
const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
|
|
803
|
-
countQuery += ` AND createdAt >= ?`;
|
|
804
|
-
countParams.push(startDate);
|
|
805
|
-
}
|
|
806
|
-
if (dateRange?.end) {
|
|
807
|
-
const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
|
|
808
|
-
countQuery += ` AND createdAt <= ?`;
|
|
809
|
-
countParams.push(endDate);
|
|
810
|
-
}
|
|
811
|
-
const countResult = await this.operations.executeQuery({ sql: countQuery, params: countParams });
|
|
812
|
-
const total = Number(countResult[0]?.count ?? 0);
|
|
813
|
-
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
814
|
-
return {
|
|
815
|
-
messages: [],
|
|
816
|
-
total: 0,
|
|
817
|
-
page,
|
|
818
|
-
perPage: perPageForResponse,
|
|
819
|
-
hasMore: false
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
823
|
-
let includeMessages = [];
|
|
824
|
-
if (include && include.length > 0) {
|
|
825
|
-
const includeResult = await this._getIncludedMessages(threadId, include);
|
|
826
|
-
if (Array.isArray(includeResult)) {
|
|
827
|
-
includeMessages = includeResult;
|
|
828
|
-
for (const includeMsg of includeMessages) {
|
|
829
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
830
|
-
paginatedMessages.push(includeMsg);
|
|
831
|
-
messageIds.add(includeMsg.id);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
const list = new agent.MessageList().add(paginatedMessages, "memory");
|
|
837
|
-
let finalMessages = list.get.all.db();
|
|
838
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
839
|
-
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
840
|
-
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
841
|
-
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
842
|
-
if (aValue === bValue) {
|
|
843
|
-
return a.id.localeCompare(b.id);
|
|
844
|
-
}
|
|
845
|
-
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
846
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
847
|
-
}
|
|
848
|
-
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
849
|
-
});
|
|
850
|
-
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
851
|
-
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
852
|
-
const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
853
827
|
return {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
hasMore
|
|
828
|
+
...thread,
|
|
829
|
+
createdAt: storage.ensureDate(thread.createdAt),
|
|
830
|
+
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
831
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
|
|
859
832
|
};
|
|
860
833
|
} catch (error$1) {
|
|
861
834
|
const mastraError = new error.MastraError(
|
|
862
835
|
{
|
|
863
|
-
id: "
|
|
836
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_THREAD_BY_ID", "FAILED"),
|
|
864
837
|
domain: error.ErrorDomain.STORAGE,
|
|
865
838
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
866
|
-
text: `
|
|
867
|
-
details: {
|
|
868
|
-
threadId,
|
|
869
|
-
resourceId: resourceId ?? ""
|
|
870
|
-
}
|
|
839
|
+
text: `Error processing thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
840
|
+
details: { threadId }
|
|
871
841
|
},
|
|
872
842
|
error$1
|
|
873
843
|
);
|
|
874
|
-
this.logger?.error
|
|
875
|
-
this.logger?.trackException
|
|
876
|
-
return
|
|
877
|
-
messages: [],
|
|
878
|
-
total: 0,
|
|
879
|
-
page,
|
|
880
|
-
perPage: perPageForResponse,
|
|
881
|
-
hasMore: false
|
|
882
|
-
};
|
|
844
|
+
this.logger?.error(mastraError.toString());
|
|
845
|
+
this.logger?.trackException(mastraError);
|
|
846
|
+
return null;
|
|
883
847
|
}
|
|
884
848
|
}
|
|
885
|
-
async
|
|
886
|
-
const {
|
|
887
|
-
this.logger.debug("Updating messages", { count: messages.length });
|
|
888
|
-
if (!messages.length) {
|
|
889
|
-
return [];
|
|
890
|
-
}
|
|
891
|
-
const messageIds = messages.map((m) => m.id);
|
|
892
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
|
|
893
|
-
const threadsTableName = this.operations.getTableName(storage.TABLE_THREADS);
|
|
849
|
+
async listThreads(args) {
|
|
850
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
894
851
|
try {
|
|
895
|
-
|
|
896
|
-
const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
897
|
-
const existingMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
898
|
-
if (existingMessages.length === 0) {
|
|
899
|
-
return [];
|
|
900
|
-
}
|
|
901
|
-
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
902
|
-
if (typeof msg.content === "string") {
|
|
903
|
-
try {
|
|
904
|
-
msg.content = JSON.parse(msg.content);
|
|
905
|
-
} catch {
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
return msg;
|
|
909
|
-
});
|
|
910
|
-
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
911
|
-
const updateQueries = [];
|
|
912
|
-
for (const existingMessage of parsedExistingMessages) {
|
|
913
|
-
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
914
|
-
if (!updatePayload) continue;
|
|
915
|
-
const { id, ...fieldsToUpdate } = updatePayload;
|
|
916
|
-
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
917
|
-
threadIdsToUpdate.add(existingMessage.threadId);
|
|
918
|
-
if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
919
|
-
threadIdsToUpdate.add(updatePayload.threadId);
|
|
920
|
-
}
|
|
921
|
-
const setClauses = [];
|
|
922
|
-
const values = [];
|
|
923
|
-
const updatableFields = { ...fieldsToUpdate };
|
|
924
|
-
if (updatableFields.content) {
|
|
925
|
-
const existingContent = existingMessage.content || {};
|
|
926
|
-
const newContent = {
|
|
927
|
-
...existingContent,
|
|
928
|
-
...updatableFields.content,
|
|
929
|
-
// Deep merge metadata if it exists on both
|
|
930
|
-
...existingContent?.metadata && updatableFields.content.metadata ? {
|
|
931
|
-
metadata: {
|
|
932
|
-
...existingContent.metadata,
|
|
933
|
-
...updatableFields.content.metadata
|
|
934
|
-
}
|
|
935
|
-
} : {}
|
|
936
|
-
};
|
|
937
|
-
setClauses.push(`content = ?`);
|
|
938
|
-
values.push(JSON.stringify(newContent));
|
|
939
|
-
delete updatableFields.content;
|
|
940
|
-
}
|
|
941
|
-
for (const key in updatableFields) {
|
|
942
|
-
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
943
|
-
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
944
|
-
setClauses.push(`${dbColumn} = ?`);
|
|
945
|
-
values.push(updatableFields[key]);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
if (setClauses.length > 0) {
|
|
949
|
-
values.push(id);
|
|
950
|
-
const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
951
|
-
updateQueries.push({ sql: updateQuery, params: values });
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
for (const query of updateQueries) {
|
|
955
|
-
await this.operations.executeQuery(query);
|
|
956
|
-
}
|
|
957
|
-
if (threadIdsToUpdate.size > 0) {
|
|
958
|
-
const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
|
|
959
|
-
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
960
|
-
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
|
|
961
|
-
await this.operations.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
962
|
-
}
|
|
963
|
-
const updatedMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
964
|
-
return updatedMessages.map((message) => {
|
|
965
|
-
if (typeof message.content === "string") {
|
|
966
|
-
try {
|
|
967
|
-
message.content = JSON.parse(message.content);
|
|
968
|
-
} catch {
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
return message;
|
|
972
|
-
});
|
|
852
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
973
853
|
} catch (error$1) {
|
|
974
854
|
throw new error.MastraError(
|
|
975
855
|
{
|
|
976
|
-
id: "
|
|
856
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_PAGE"),
|
|
977
857
|
domain: error.ErrorDomain.STORAGE,
|
|
978
|
-
category: error.ErrorCategory.
|
|
979
|
-
details: {
|
|
858
|
+
category: error.ErrorCategory.USER,
|
|
859
|
+
details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
|
|
980
860
|
},
|
|
981
|
-
error$1
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
const
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
const results = result.results || [];
|
|
1039
|
-
return results;
|
|
861
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid pagination parameters")
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
865
|
+
try {
|
|
866
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
867
|
+
} catch (error$1) {
|
|
868
|
+
throw new error.MastraError(
|
|
869
|
+
{
|
|
870
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
871
|
+
domain: error.ErrorDomain.STORAGE,
|
|
872
|
+
category: error.ErrorCategory.USER,
|
|
873
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
874
|
+
},
|
|
875
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid metadata key")
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
879
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
880
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
881
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
882
|
+
...row,
|
|
883
|
+
createdAt: storage.ensureDate(row.createdAt),
|
|
884
|
+
updatedAt: storage.ensureDate(row.updatedAt),
|
|
885
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
886
|
+
});
|
|
887
|
+
try {
|
|
888
|
+
let countQuery = createSqlBuilder().count().from(fullTableName);
|
|
889
|
+
let selectQuery = createSqlBuilder().select("*").from(fullTableName);
|
|
890
|
+
if (filter?.resourceId) {
|
|
891
|
+
countQuery = countQuery.whereAnd("resourceId = ?", filter.resourceId);
|
|
892
|
+
selectQuery = selectQuery.whereAnd("resourceId = ?", filter.resourceId);
|
|
893
|
+
}
|
|
894
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
895
|
+
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
896
|
+
if (value !== null && typeof value === "object") {
|
|
897
|
+
throw new error.MastraError(
|
|
898
|
+
{
|
|
899
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_METADATA_VALUE"),
|
|
900
|
+
domain: error.ErrorDomain.STORAGE,
|
|
901
|
+
category: error.ErrorCategory.USER,
|
|
902
|
+
text: `Metadata filter value for key "${key}" must be a scalar type (string, number, boolean, or null), got ${Array.isArray(value) ? "array" : "object"}`,
|
|
903
|
+
details: { key, valueType: Array.isArray(value) ? "array" : "object" }
|
|
904
|
+
},
|
|
905
|
+
new Error("Invalid metadata filter value type")
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
if (value === null) {
|
|
909
|
+
const condition = `json_extract(metadata, '$.${key}') IS NULL`;
|
|
910
|
+
countQuery = countQuery.whereAnd(condition);
|
|
911
|
+
selectQuery = selectQuery.whereAnd(condition);
|
|
912
|
+
} else {
|
|
913
|
+
const condition = `json_extract(metadata, '$.${key}') = ?`;
|
|
914
|
+
const filterValue = value;
|
|
915
|
+
countQuery = countQuery.whereAnd(condition, filterValue);
|
|
916
|
+
selectQuery = selectQuery.whereAnd(condition, filterValue);
|
|
917
|
+
}
|
|
1040
918
|
}
|
|
1041
919
|
}
|
|
920
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
921
|
+
const total = Number(countResult?.[0]?.count ?? 0);
|
|
922
|
+
if (total === 0) {
|
|
923
|
+
return {
|
|
924
|
+
threads: [],
|
|
925
|
+
total: 0,
|
|
926
|
+
page,
|
|
927
|
+
perPage: perPageForResponse,
|
|
928
|
+
hasMore: false
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
932
|
+
selectQuery = selectQuery.orderBy(field, direction).limit(limitValue).offset(offset);
|
|
933
|
+
const results = await this.#db.executeQuery(selectQuery.build());
|
|
934
|
+
const threads = results.map(mapRowToStorageThreadType);
|
|
935
|
+
return {
|
|
936
|
+
threads,
|
|
937
|
+
total,
|
|
938
|
+
page,
|
|
939
|
+
perPage: perPageForResponse,
|
|
940
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
941
|
+
};
|
|
1042
942
|
} catch (error$1) {
|
|
1043
|
-
|
|
943
|
+
if (error$1 instanceof error.MastraError && error$1.category === error.ErrorCategory.USER) {
|
|
944
|
+
throw error$1;
|
|
945
|
+
}
|
|
946
|
+
const mastraError = new error.MastraError(
|
|
1044
947
|
{
|
|
1045
|
-
id: "
|
|
948
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "FAILED"),
|
|
1046
949
|
domain: error.ErrorDomain.STORAGE,
|
|
1047
950
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1048
|
-
|
|
951
|
+
text: `Error listing threads: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
952
|
+
details: {
|
|
953
|
+
...filter?.resourceId && { resourceId: filter.resourceId },
|
|
954
|
+
hasMetadataFilter: !!filter?.metadata
|
|
955
|
+
}
|
|
1049
956
|
},
|
|
1050
957
|
error$1
|
|
1051
958
|
);
|
|
959
|
+
this.logger?.error(mastraError.toString());
|
|
960
|
+
this.logger?.trackException(mastraError);
|
|
961
|
+
return {
|
|
962
|
+
threads: [],
|
|
963
|
+
total: 0,
|
|
964
|
+
page,
|
|
965
|
+
perPage: perPageForResponse,
|
|
966
|
+
hasMore: false
|
|
967
|
+
};
|
|
1052
968
|
}
|
|
1053
969
|
}
|
|
1054
|
-
async
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
970
|
+
async saveThread({ thread }) {
|
|
971
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
972
|
+
const threadToSave = {
|
|
973
|
+
id: thread.id,
|
|
974
|
+
resourceId: thread.resourceId,
|
|
975
|
+
title: thread.title,
|
|
976
|
+
metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
977
|
+
createdAt: thread.createdAt.toISOString(),
|
|
978
|
+
updatedAt: thread.updatedAt.toISOString()
|
|
979
|
+
};
|
|
980
|
+
const processedRecord = await this.#db.processRecord(threadToSave);
|
|
981
|
+
const columns = Object.keys(processedRecord);
|
|
982
|
+
const values = Object.values(processedRecord);
|
|
983
|
+
const updateMap = {
|
|
984
|
+
resourceId: "excluded.resourceId",
|
|
985
|
+
title: "excluded.title",
|
|
986
|
+
metadata: "excluded.metadata",
|
|
987
|
+
createdAt: "excluded.createdAt",
|
|
988
|
+
updatedAt: "excluded.updatedAt"
|
|
989
|
+
};
|
|
990
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
991
|
+
const { sql, params } = query.build();
|
|
1062
992
|
try {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
sql,
|
|
1066
|
-
params: formattedParams
|
|
1067
|
-
});
|
|
1068
|
-
const result = response.result || [];
|
|
1069
|
-
const results = result.flatMap((r) => r.results || []);
|
|
1070
|
-
if (first) {
|
|
1071
|
-
return results[0] || null;
|
|
1072
|
-
}
|
|
1073
|
-
return results;
|
|
993
|
+
await this.#db.executeQuery({ sql, params });
|
|
994
|
+
return thread;
|
|
1074
995
|
} catch (error$1) {
|
|
1075
996
|
throw new error.MastraError(
|
|
1076
997
|
{
|
|
1077
|
-
id: "
|
|
998
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_THREAD", "FAILED"),
|
|
1078
999
|
domain: error.ErrorDomain.STORAGE,
|
|
1079
1000
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1080
|
-
|
|
1001
|
+
text: `Failed to save thread to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1002
|
+
details: { threadId: thread.id }
|
|
1081
1003
|
},
|
|
1082
1004
|
error$1
|
|
1083
1005
|
);
|
|
1084
1006
|
}
|
|
1085
1007
|
}
|
|
1086
|
-
async
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
return this.executeRestQuery(options);
|
|
1091
|
-
} else {
|
|
1092
|
-
throw new Error("Neither binding nor client is configured");
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
async getTableColumns(tableName) {
|
|
1096
|
-
try {
|
|
1097
|
-
const sql = `PRAGMA table_info(${tableName})`;
|
|
1098
|
-
const result = await this.executeQuery({ sql });
|
|
1099
|
-
if (!result || !Array.isArray(result)) {
|
|
1100
|
-
return [];
|
|
1101
|
-
}
|
|
1102
|
-
return result.map((row) => ({
|
|
1103
|
-
name: row.name,
|
|
1104
|
-
type: row.type
|
|
1105
|
-
}));
|
|
1106
|
-
} catch (error) {
|
|
1107
|
-
this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
|
|
1108
|
-
return [];
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
serializeValue(value) {
|
|
1112
|
-
if (value === null || value === void 0) {
|
|
1113
|
-
return null;
|
|
1114
|
-
}
|
|
1115
|
-
if (value instanceof Date) {
|
|
1116
|
-
return value.toISOString();
|
|
1117
|
-
}
|
|
1118
|
-
if (typeof value === "object") {
|
|
1119
|
-
return JSON.stringify(value);
|
|
1120
|
-
}
|
|
1121
|
-
return value;
|
|
1122
|
-
}
|
|
1123
|
-
getSqlType(type) {
|
|
1124
|
-
switch (type) {
|
|
1125
|
-
case "bigint":
|
|
1126
|
-
return "INTEGER";
|
|
1127
|
-
// SQLite uses INTEGER for all integer sizes
|
|
1128
|
-
case "jsonb":
|
|
1129
|
-
return "TEXT";
|
|
1130
|
-
// Store JSON as TEXT in SQLite
|
|
1131
|
-
default:
|
|
1132
|
-
return super.getSqlType(type);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
async createTable({
|
|
1136
|
-
tableName,
|
|
1137
|
-
schema
|
|
1008
|
+
async updateThread({
|
|
1009
|
+
id,
|
|
1010
|
+
title,
|
|
1011
|
+
metadata
|
|
1138
1012
|
}) {
|
|
1013
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
1139
1014
|
try {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
const type = this.getSqlType(colDef.type);
|
|
1143
|
-
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
1144
|
-
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
1145
|
-
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
1146
|
-
});
|
|
1147
|
-
const tableConstraints = [];
|
|
1148
|
-
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1149
|
-
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
1015
|
+
if (!thread) {
|
|
1016
|
+
throw new Error(`Thread ${id} not found`);
|
|
1150
1017
|
}
|
|
1151
|
-
const
|
|
1018
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
1019
|
+
const mergedMetadata = {
|
|
1020
|
+
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1021
|
+
...metadata
|
|
1022
|
+
};
|
|
1023
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
1024
|
+
const columns = ["title", "metadata", "updatedAt"];
|
|
1025
|
+
const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
|
|
1026
|
+
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
|
|
1152
1027
|
const { sql, params } = query.build();
|
|
1153
|
-
await this.executeQuery({ sql, params });
|
|
1154
|
-
|
|
1028
|
+
await this.#db.executeQuery({ sql, params });
|
|
1029
|
+
return {
|
|
1030
|
+
...thread,
|
|
1031
|
+
title,
|
|
1032
|
+
metadata: {
|
|
1033
|
+
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1034
|
+
...metadata
|
|
1035
|
+
},
|
|
1036
|
+
updatedAt
|
|
1037
|
+
};
|
|
1155
1038
|
} catch (error$1) {
|
|
1156
1039
|
throw new error.MastraError(
|
|
1157
1040
|
{
|
|
1158
|
-
id: "
|
|
1041
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_THREAD", "FAILED"),
|
|
1159
1042
|
domain: error.ErrorDomain.STORAGE,
|
|
1160
1043
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1161
|
-
|
|
1044
|
+
text: `Failed to update thread ${id}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1045
|
+
details: { threadId: id }
|
|
1162
1046
|
},
|
|
1163
1047
|
error$1
|
|
1164
1048
|
);
|
|
1165
1049
|
}
|
|
1166
1050
|
}
|
|
1167
|
-
async
|
|
1051
|
+
async deleteThread({ threadId }) {
|
|
1052
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
1168
1053
|
try {
|
|
1169
|
-
const
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1054
|
+
const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
|
|
1055
|
+
const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
|
|
1056
|
+
await this.#db.executeQuery({ sql: threadSql, params: threadParams });
|
|
1057
|
+
const messagesTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1058
|
+
const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
|
|
1059
|
+
const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
|
|
1060
|
+
await this.#db.executeQuery({ sql: messagesSql, params: messagesParams });
|
|
1174
1061
|
} catch (error$1) {
|
|
1175
1062
|
throw new error.MastraError(
|
|
1176
1063
|
{
|
|
1177
|
-
id: "
|
|
1064
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_THREAD", "FAILED"),
|
|
1178
1065
|
domain: error.ErrorDomain.STORAGE,
|
|
1179
1066
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1180
|
-
|
|
1067
|
+
text: `Failed to delete thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1068
|
+
details: { threadId }
|
|
1181
1069
|
},
|
|
1182
1070
|
error$1
|
|
1183
1071
|
);
|
|
1184
1072
|
}
|
|
1185
1073
|
}
|
|
1186
|
-
async
|
|
1074
|
+
async saveMessages(args) {
|
|
1075
|
+
const { messages } = args;
|
|
1076
|
+
if (messages.length === 0) return { messages: [] };
|
|
1187
1077
|
try {
|
|
1188
|
-
const
|
|
1189
|
-
const
|
|
1190
|
-
|
|
1191
|
-
|
|
1078
|
+
const now = /* @__PURE__ */ new Date();
|
|
1079
|
+
const threadId = messages[0]?.threadId;
|
|
1080
|
+
for (const [i, message] of messages.entries()) {
|
|
1081
|
+
if (!message.id) throw new Error(`Message at index ${i} missing id`);
|
|
1082
|
+
if (!message.threadId) {
|
|
1083
|
+
throw new Error(`Message at index ${i} missing threadId`);
|
|
1084
|
+
}
|
|
1085
|
+
if (!message.content) {
|
|
1086
|
+
throw new Error(`Message at index ${i} missing content`);
|
|
1087
|
+
}
|
|
1088
|
+
if (!message.role) {
|
|
1089
|
+
throw new Error(`Message at index ${i} missing role`);
|
|
1090
|
+
}
|
|
1091
|
+
if (!message.resourceId) {
|
|
1092
|
+
throw new Error(`Message at index ${i} missing resourceId`);
|
|
1093
|
+
}
|
|
1094
|
+
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
1095
|
+
if (!thread) {
|
|
1096
|
+
throw new Error(`Thread ${message.threadId} not found`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
const messagesToInsert = messages.map((message) => {
|
|
1100
|
+
const createdAt = message.createdAt ? new Date(message.createdAt) : now;
|
|
1101
|
+
return {
|
|
1102
|
+
id: message.id,
|
|
1103
|
+
thread_id: message.threadId,
|
|
1104
|
+
content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
1105
|
+
createdAt: createdAt.toISOString(),
|
|
1106
|
+
role: message.role,
|
|
1107
|
+
type: message.type || "v2",
|
|
1108
|
+
resourceId: message.resourceId
|
|
1109
|
+
};
|
|
1110
|
+
});
|
|
1111
|
+
await Promise.all([
|
|
1112
|
+
this.#db.batchUpsert({
|
|
1113
|
+
tableName: storage.TABLE_MESSAGES,
|
|
1114
|
+
records: messagesToInsert
|
|
1115
|
+
}),
|
|
1116
|
+
// Update thread's updatedAt timestamp
|
|
1117
|
+
this.#db.executeQuery({
|
|
1118
|
+
sql: `UPDATE ${this.#db.getTableName(storage.TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
1119
|
+
params: [now.toISOString(), threadId]
|
|
1120
|
+
})
|
|
1121
|
+
]);
|
|
1122
|
+
this.logger.debug(`Saved ${messages.length} messages`);
|
|
1123
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
1124
|
+
return { messages: list.get.all.db() };
|
|
1192
1125
|
} catch (error$1) {
|
|
1193
1126
|
throw new error.MastraError(
|
|
1194
1127
|
{
|
|
1195
|
-
id: "
|
|
1128
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_MESSAGES", "FAILED"),
|
|
1196
1129
|
domain: error.ErrorDomain.STORAGE,
|
|
1197
1130
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1198
|
-
|
|
1131
|
+
text: `Failed to save messages: ${error$1 instanceof Error ? error$1.message : String(error$1)}`
|
|
1199
1132
|
},
|
|
1200
1133
|
error$1
|
|
1201
1134
|
);
|
|
1202
1135
|
}
|
|
1203
1136
|
}
|
|
1204
|
-
async
|
|
1137
|
+
async _getIncludedMessages(include) {
|
|
1138
|
+
if (!include || include.length === 0) return null;
|
|
1139
|
+
const unionQueries = [];
|
|
1140
|
+
const params = [];
|
|
1141
|
+
let paramIdx = 1;
|
|
1142
|
+
const tableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1143
|
+
for (const inc of include) {
|
|
1144
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1145
|
+
unionQueries.push(`
|
|
1146
|
+
SELECT * FROM (
|
|
1147
|
+
WITH target_thread AS (
|
|
1148
|
+
SELECT thread_id FROM ${tableName} WHERE id = ?
|
|
1149
|
+
),
|
|
1150
|
+
ordered_messages AS (
|
|
1151
|
+
SELECT
|
|
1152
|
+
*,
|
|
1153
|
+
ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
|
|
1154
|
+
FROM ${tableName}
|
|
1155
|
+
WHERE thread_id = (SELECT thread_id FROM target_thread)
|
|
1156
|
+
)
|
|
1157
|
+
SELECT
|
|
1158
|
+
m.id,
|
|
1159
|
+
m.content,
|
|
1160
|
+
m.role,
|
|
1161
|
+
m.type,
|
|
1162
|
+
m.createdAt,
|
|
1163
|
+
m.thread_id AS threadId,
|
|
1164
|
+
m.resourceId
|
|
1165
|
+
FROM ordered_messages m
|
|
1166
|
+
WHERE m.id = ?
|
|
1167
|
+
OR EXISTS (
|
|
1168
|
+
SELECT 1 FROM ordered_messages target
|
|
1169
|
+
WHERE target.id = ?
|
|
1170
|
+
AND (
|
|
1171
|
+
(m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
|
|
1172
|
+
OR
|
|
1173
|
+
(m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
|
|
1174
|
+
)
|
|
1175
|
+
)
|
|
1176
|
+
) AS query_${paramIdx}
|
|
1177
|
+
`);
|
|
1178
|
+
params.push(id, id, id, withNextMessages, withPreviousMessages);
|
|
1179
|
+
paramIdx++;
|
|
1180
|
+
}
|
|
1181
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
|
|
1182
|
+
const messages = await this.#db.executeQuery({ sql: finalQuery, params });
|
|
1183
|
+
if (!Array.isArray(messages)) {
|
|
1184
|
+
return [];
|
|
1185
|
+
}
|
|
1186
|
+
const processedMessages = messages.map((message) => {
|
|
1187
|
+
const processedMsg = {};
|
|
1188
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1189
|
+
if (key === `type` && value === `v2`) continue;
|
|
1190
|
+
processedMsg[key] = deserializeValue(value);
|
|
1191
|
+
}
|
|
1192
|
+
return processedMsg;
|
|
1193
|
+
});
|
|
1194
|
+
return processedMessages;
|
|
1195
|
+
}
|
|
1196
|
+
async listMessagesById({ messageIds }) {
|
|
1197
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1198
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1199
|
+
const messages = [];
|
|
1205
1200
|
try {
|
|
1206
|
-
const
|
|
1207
|
-
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1201
|
+
const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
|
|
1202
|
+
query.orderBy("createdAt", "DESC");
|
|
1203
|
+
const { sql, params } = query.build();
|
|
1204
|
+
const result = await this.#db.executeQuery({ sql, params });
|
|
1205
|
+
if (Array.isArray(result)) messages.push(...result);
|
|
1206
|
+
const processedMessages = messages.map((message) => {
|
|
1207
|
+
const processedMsg = {};
|
|
1208
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1209
|
+
if (key === `type` && value === `v2`) continue;
|
|
1210
|
+
processedMsg[key] = deserializeValue(value);
|
|
1216
1211
|
}
|
|
1217
|
-
|
|
1212
|
+
return processedMsg;
|
|
1213
|
+
});
|
|
1214
|
+
this.logger.debug(`Retrieved ${messages.length} messages`);
|
|
1215
|
+
const list = new agent.MessageList().add(processedMessages, "memory");
|
|
1216
|
+
return { messages: list.get.all.db() };
|
|
1218
1217
|
} catch (error$1) {
|
|
1219
|
-
|
|
1218
|
+
const mastraError = new error.MastraError(
|
|
1220
1219
|
{
|
|
1221
|
-
id: "
|
|
1220
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1222
1221
|
domain: error.ErrorDomain.STORAGE,
|
|
1223
1222
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1224
|
-
|
|
1223
|
+
text: `Failed to retrieve messages by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1224
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1225
1225
|
},
|
|
1226
1226
|
error$1
|
|
1227
1227
|
);
|
|
1228
|
+
this.logger?.error(mastraError.toString());
|
|
1229
|
+
this.logger?.trackException(mastraError);
|
|
1230
|
+
throw mastraError;
|
|
1228
1231
|
}
|
|
1229
1232
|
}
|
|
1230
|
-
async
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
const columns = Object.keys(processedRecord);
|
|
1235
|
-
const values = Object.values(processedRecord);
|
|
1236
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1237
|
-
const { sql, params } = query.build();
|
|
1238
|
-
await this.executeQuery({ sql, params });
|
|
1239
|
-
} catch (error$1) {
|
|
1233
|
+
async listMessages(args) {
|
|
1234
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1235
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
1236
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1240
1237
|
throw new error.MastraError(
|
|
1241
1238
|
{
|
|
1242
|
-
id: "
|
|
1239
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1243
1240
|
domain: error.ErrorDomain.STORAGE,
|
|
1244
1241
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1245
|
-
details: {
|
|
1242
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1246
1243
|
},
|
|
1247
|
-
|
|
1244
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1248
1245
|
);
|
|
1249
1246
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1247
|
+
if (page < 0) {
|
|
1248
|
+
throw new error.MastraError(
|
|
1249
|
+
{
|
|
1250
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1251
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1252
|
+
category: error.ErrorCategory.USER,
|
|
1253
|
+
details: { page }
|
|
1254
|
+
},
|
|
1255
|
+
new Error("page must be >= 0")
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
1259
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1252
1260
|
try {
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1261
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1262
|
+
let query = `
|
|
1263
|
+
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
1264
|
+
FROM ${fullTableName}
|
|
1265
|
+
WHERE thread_id = ?
|
|
1266
|
+
`;
|
|
1267
|
+
const queryParams = [threadId];
|
|
1268
|
+
if (resourceId) {
|
|
1269
|
+
query += ` AND resourceId = ?`;
|
|
1270
|
+
queryParams.push(resourceId);
|
|
1271
|
+
}
|
|
1272
|
+
const dateRange = filter?.dateRange;
|
|
1273
|
+
if (dateRange?.start) {
|
|
1274
|
+
const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
|
|
1275
|
+
const startOp = dateRange.startExclusive ? ">" : ">=";
|
|
1276
|
+
query += ` AND createdAt ${startOp} ?`;
|
|
1277
|
+
queryParams.push(startDate);
|
|
1278
|
+
}
|
|
1279
|
+
if (dateRange?.end) {
|
|
1280
|
+
const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
|
|
1281
|
+
const endOp = dateRange.endExclusive ? "<" : "<=";
|
|
1282
|
+
query += ` AND createdAt ${endOp} ?`;
|
|
1283
|
+
queryParams.push(endDate);
|
|
1284
|
+
}
|
|
1285
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1286
|
+
query += ` ORDER BY "${field}" ${direction}`;
|
|
1287
|
+
if (perPage !== Number.MAX_SAFE_INTEGER) {
|
|
1288
|
+
query += ` LIMIT ? OFFSET ?`;
|
|
1289
|
+
queryParams.push(perPage, offset);
|
|
1290
|
+
}
|
|
1291
|
+
const results = await this.#db.executeQuery({ sql: query, params: queryParams });
|
|
1292
|
+
const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
|
|
1293
|
+
const processedMsg = {};
|
|
1294
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1295
|
+
if (key === `type` && value === `v2`) continue;
|
|
1296
|
+
processedMsg[key] = deserializeValue(value);
|
|
1297
|
+
}
|
|
1298
|
+
return processedMsg;
|
|
1299
|
+
});
|
|
1300
|
+
const paginatedCount = paginatedMessages.length;
|
|
1301
|
+
let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
|
|
1302
|
+
const countParams = [threadId];
|
|
1303
|
+
if (resourceId) {
|
|
1304
|
+
countQuery += ` AND resourceId = ?`;
|
|
1305
|
+
countParams.push(resourceId);
|
|
1306
|
+
}
|
|
1307
|
+
if (dateRange?.start) {
|
|
1308
|
+
const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
|
|
1309
|
+
const startOp = dateRange.startExclusive ? ">" : ">=";
|
|
1310
|
+
countQuery += ` AND createdAt ${startOp} ?`;
|
|
1311
|
+
countParams.push(startDate);
|
|
1312
|
+
}
|
|
1313
|
+
if (dateRange?.end) {
|
|
1314
|
+
const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
|
|
1315
|
+
const endOp = dateRange.endExclusive ? "<" : "<=";
|
|
1316
|
+
countQuery += ` AND createdAt ${endOp} ?`;
|
|
1317
|
+
countParams.push(endDate);
|
|
1318
|
+
}
|
|
1319
|
+
const countResult = await this.#db.executeQuery({ sql: countQuery, params: countParams });
|
|
1320
|
+
const total = Number(countResult[0]?.count ?? 0);
|
|
1321
|
+
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
1322
|
+
return {
|
|
1323
|
+
messages: [],
|
|
1324
|
+
total: 0,
|
|
1325
|
+
page,
|
|
1326
|
+
perPage: perPageForResponse,
|
|
1327
|
+
hasMore: false
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
1331
|
+
let includeMessages = [];
|
|
1332
|
+
if (include && include.length > 0) {
|
|
1333
|
+
const includeResult = await this._getIncludedMessages(include);
|
|
1334
|
+
if (Array.isArray(includeResult)) {
|
|
1335
|
+
includeMessages = includeResult;
|
|
1336
|
+
for (const includeMsg of includeMessages) {
|
|
1337
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
1338
|
+
paginatedMessages.push(includeMsg);
|
|
1339
|
+
messageIds.add(includeMsg.id);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1262
1343
|
}
|
|
1344
|
+
const list = new agent.MessageList().add(paginatedMessages, "memory");
|
|
1345
|
+
let finalMessages = list.get.all.db();
|
|
1346
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
1347
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
1348
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
1349
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
1350
|
+
if (aValue === bValue) {
|
|
1351
|
+
return a.id.localeCompare(b.id);
|
|
1352
|
+
}
|
|
1353
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
1354
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1355
|
+
}
|
|
1356
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
1357
|
+
});
|
|
1358
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
1359
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
1360
|
+
const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
1361
|
+
return {
|
|
1362
|
+
messages: finalMessages,
|
|
1363
|
+
total,
|
|
1364
|
+
page,
|
|
1365
|
+
perPage: perPageForResponse,
|
|
1366
|
+
hasMore
|
|
1367
|
+
};
|
|
1263
1368
|
} catch (error$1) {
|
|
1264
|
-
|
|
1369
|
+
const mastraError = new error.MastraError(
|
|
1265
1370
|
{
|
|
1266
|
-
id: "
|
|
1371
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "FAILED"),
|
|
1267
1372
|
domain: error.ErrorDomain.STORAGE,
|
|
1268
1373
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1269
|
-
|
|
1374
|
+
text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1375
|
+
details: {
|
|
1376
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1377
|
+
resourceId: resourceId ?? ""
|
|
1378
|
+
}
|
|
1270
1379
|
},
|
|
1271
1380
|
error$1
|
|
1272
1381
|
);
|
|
1382
|
+
this.logger?.error?.(mastraError.toString());
|
|
1383
|
+
this.logger?.trackException?.(mastraError);
|
|
1384
|
+
return {
|
|
1385
|
+
messages: [],
|
|
1386
|
+
total: 0,
|
|
1387
|
+
page,
|
|
1388
|
+
perPage: perPageForResponse,
|
|
1389
|
+
hasMore: false
|
|
1390
|
+
};
|
|
1273
1391
|
}
|
|
1274
1392
|
}
|
|
1275
|
-
async
|
|
1393
|
+
async updateMessages(args) {
|
|
1394
|
+
const { messages } = args;
|
|
1395
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1396
|
+
if (!messages.length) {
|
|
1397
|
+
return [];
|
|
1398
|
+
}
|
|
1399
|
+
const messageIds = messages.map((m) => m.id);
|
|
1400
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1401
|
+
const threadsTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
1276
1402
|
try {
|
|
1277
|
-
const
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1403
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1404
|
+
const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
1405
|
+
const existingMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1406
|
+
if (existingMessages.length === 0) {
|
|
1407
|
+
return [];
|
|
1408
|
+
}
|
|
1409
|
+
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
1410
|
+
if (typeof msg.content === "string") {
|
|
1411
|
+
try {
|
|
1412
|
+
msg.content = JSON.parse(msg.content);
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return msg;
|
|
1417
|
+
});
|
|
1418
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1419
|
+
const updateQueries = [];
|
|
1420
|
+
for (const existingMessage of parsedExistingMessages) {
|
|
1421
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1422
|
+
if (!updatePayload) continue;
|
|
1423
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1424
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1425
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1426
|
+
if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1427
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1428
|
+
}
|
|
1429
|
+
const setClauses = [];
|
|
1430
|
+
const values = [];
|
|
1431
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1432
|
+
if (updatableFields.content) {
|
|
1433
|
+
const existingContent = existingMessage.content || {};
|
|
1434
|
+
const newContent = {
|
|
1435
|
+
...existingContent,
|
|
1436
|
+
...updatableFields.content,
|
|
1437
|
+
// Deep merge metadata if it exists on both
|
|
1438
|
+
...existingContent?.metadata && updatableFields.content.metadata ? {
|
|
1439
|
+
metadata: {
|
|
1440
|
+
...existingContent.metadata,
|
|
1441
|
+
...updatableFields.content.metadata
|
|
1442
|
+
}
|
|
1443
|
+
} : {}
|
|
1444
|
+
};
|
|
1445
|
+
setClauses.push(`content = ?`);
|
|
1446
|
+
values.push(JSON.stringify(newContent));
|
|
1447
|
+
delete updatableFields.content;
|
|
1448
|
+
}
|
|
1449
|
+
for (const key in updatableFields) {
|
|
1450
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1451
|
+
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
1452
|
+
setClauses.push(`${dbColumn} = ?`);
|
|
1453
|
+
values.push(updatableFields[key]);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
if (setClauses.length > 0) {
|
|
1457
|
+
values.push(id);
|
|
1458
|
+
const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1459
|
+
updateQueries.push({ sql: updateQuery, params: values });
|
|
1286
1460
|
}
|
|
1287
1461
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
const { sql, params } = query.build();
|
|
1291
|
-
const result = await this.executeQuery({ sql, params, first: true });
|
|
1292
|
-
if (!result) {
|
|
1293
|
-
return null;
|
|
1462
|
+
for (const query of updateQueries) {
|
|
1463
|
+
await this.#db.executeQuery(query);
|
|
1294
1464
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1465
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1466
|
+
const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
|
|
1467
|
+
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
1468
|
+
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
|
|
1469
|
+
await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
1298
1470
|
}
|
|
1299
|
-
|
|
1471
|
+
const updatedMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1472
|
+
return updatedMessages.map((message) => {
|
|
1473
|
+
if (typeof message.content === "string") {
|
|
1474
|
+
try {
|
|
1475
|
+
message.content = JSON.parse(message.content);
|
|
1476
|
+
} catch {
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
return message;
|
|
1480
|
+
});
|
|
1300
1481
|
} catch (error$1) {
|
|
1301
1482
|
throw new error.MastraError(
|
|
1302
1483
|
{
|
|
1303
|
-
id: "
|
|
1484
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_MESSAGES", "FAILED"),
|
|
1304
1485
|
domain: error.ErrorDomain.STORAGE,
|
|
1305
1486
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1306
|
-
details: {
|
|
1487
|
+
details: { count: messages.length }
|
|
1307
1488
|
},
|
|
1308
1489
|
error$1
|
|
1309
1490
|
);
|
|
1310
1491
|
}
|
|
1311
1492
|
}
|
|
1312
|
-
async
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
}
|
|
1317
|
-
return processed;
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* Upsert multiple records in a batch operation
|
|
1321
|
-
* @param tableName The table to insert into
|
|
1322
|
-
* @param records The records to insert
|
|
1323
|
-
*/
|
|
1324
|
-
async batchUpsert({ tableName, records }) {
|
|
1325
|
-
if (records.length === 0) return;
|
|
1326
|
-
const fullTableName = this.getTableName(tableName);
|
|
1493
|
+
async deleteMessages(messageIds) {
|
|
1494
|
+
if (messageIds.length === 0) return;
|
|
1495
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
|
|
1496
|
+
const threadsTableName = this.#db.getTableName(storage.TABLE_THREADS);
|
|
1327
1497
|
try {
|
|
1328
|
-
const
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
});
|
|
1341
|
-
const recordToUpsert = columns.reduce(
|
|
1342
|
-
(acc, col) => {
|
|
1343
|
-
if (col !== "createdAt") acc[col] = `excluded.${col}`;
|
|
1344
|
-
return acc;
|
|
1345
|
-
},
|
|
1346
|
-
{}
|
|
1347
|
-
);
|
|
1348
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], recordToUpsert);
|
|
1349
|
-
const { sql, params } = query.build();
|
|
1350
|
-
await this.executeQuery({ sql, params });
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
this.logger.debug(
|
|
1354
|
-
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
1355
|
-
);
|
|
1498
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1499
|
+
const selectQuery = `SELECT DISTINCT thread_id FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
1500
|
+
const threadResults = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1501
|
+
const threadIds = threadResults.map((r) => r.thread_id).filter(Boolean);
|
|
1502
|
+
const deleteQuery = createSqlBuilder().delete(fullTableName).where(`id IN (${placeholders})`, ...messageIds);
|
|
1503
|
+
const { sql, params } = deleteQuery.build();
|
|
1504
|
+
await this.#db.executeQuery({ sql, params });
|
|
1505
|
+
if (threadIds.length > 0) {
|
|
1506
|
+
const threadPlaceholders = threadIds.map(() => "?").join(",");
|
|
1507
|
+
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
1508
|
+
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...threadIds];
|
|
1509
|
+
await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
1356
1510
|
}
|
|
1357
|
-
this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
|
|
1358
1511
|
} catch (error$1) {
|
|
1359
1512
|
throw new error.MastraError(
|
|
1360
1513
|
{
|
|
1361
|
-
id: "
|
|
1514
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_MESSAGES", "FAILED"),
|
|
1362
1515
|
domain: error.ErrorDomain.STORAGE,
|
|
1363
1516
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1364
|
-
|
|
1365
|
-
details: { tableName }
|
|
1517
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1366
1518
|
},
|
|
1367
1519
|
error$1
|
|
1368
1520
|
);
|
|
@@ -1370,32 +1522,31 @@ var StoreOperationsD1 = class extends storage.StoreOperations {
|
|
|
1370
1522
|
}
|
|
1371
1523
|
};
|
|
1372
1524
|
function transformScoreRow(row) {
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
deserialized.metadata = storage.safelyParseJSON(row.metadata);
|
|
1380
|
-
deserialized.additionalContext = storage.safelyParseJSON(row.additionalContext);
|
|
1381
|
-
deserialized.requestContext = storage.safelyParseJSON(row.requestContext);
|
|
1382
|
-
deserialized.entity = storage.safelyParseJSON(row.entity);
|
|
1383
|
-
deserialized.createdAt = row.createdAtZ || row.createdAt;
|
|
1384
|
-
deserialized.updatedAt = row.updatedAtZ || row.updatedAt;
|
|
1385
|
-
return deserialized;
|
|
1525
|
+
return storage.transformScoreRow(row, {
|
|
1526
|
+
preferredTimestampFields: {
|
|
1527
|
+
createdAt: "createdAtZ",
|
|
1528
|
+
updatedAt: "updatedAtZ"
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1386
1531
|
}
|
|
1387
1532
|
var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
1388
|
-
|
|
1389
|
-
constructor(
|
|
1533
|
+
#db;
|
|
1534
|
+
constructor(config) {
|
|
1390
1535
|
super();
|
|
1391
|
-
this
|
|
1536
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
1537
|
+
}
|
|
1538
|
+
async init() {
|
|
1539
|
+
await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS] });
|
|
1540
|
+
}
|
|
1541
|
+
async dangerouslyClearAll() {
|
|
1542
|
+
await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1392
1543
|
}
|
|
1393
1544
|
async getScoreById({ id }) {
|
|
1394
1545
|
try {
|
|
1395
|
-
const fullTableName = this.
|
|
1546
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1396
1547
|
const query = createSqlBuilder().select("*").from(fullTableName).where("id = ?", id);
|
|
1397
1548
|
const { sql, params } = query.build();
|
|
1398
|
-
const result = await this.
|
|
1549
|
+
const result = await this.#db.executeQuery({ sql, params, first: true });
|
|
1399
1550
|
if (!result) {
|
|
1400
1551
|
return null;
|
|
1401
1552
|
}
|
|
@@ -1403,7 +1554,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1403
1554
|
} catch (error$1) {
|
|
1404
1555
|
throw new error.MastraError(
|
|
1405
1556
|
{
|
|
1406
|
-
id: "
|
|
1557
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORE_BY_ID", "FAILED"),
|
|
1407
1558
|
domain: error.ErrorDomain.STORAGE,
|
|
1408
1559
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1409
1560
|
},
|
|
@@ -1418,17 +1569,23 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1418
1569
|
} catch (error$1) {
|
|
1419
1570
|
throw new error.MastraError(
|
|
1420
1571
|
{
|
|
1421
|
-
id: "
|
|
1572
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
1422
1573
|
domain: error.ErrorDomain.STORAGE,
|
|
1423
1574
|
category: error.ErrorCategory.USER,
|
|
1424
|
-
details: {
|
|
1575
|
+
details: {
|
|
1576
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1577
|
+
entityId: score.entityId ?? "unknown",
|
|
1578
|
+
entityType: score.entityType ?? "unknown",
|
|
1579
|
+
traceId: score.traceId ?? "",
|
|
1580
|
+
spanId: score.spanId ?? ""
|
|
1581
|
+
}
|
|
1425
1582
|
},
|
|
1426
1583
|
error$1
|
|
1427
1584
|
);
|
|
1428
1585
|
}
|
|
1586
|
+
const id = crypto.randomUUID();
|
|
1429
1587
|
try {
|
|
1430
|
-
const
|
|
1431
|
-
const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
|
|
1588
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1432
1589
|
const serializedRecord = {};
|
|
1433
1590
|
for (const [key, value] of Object.entries(parsedScore)) {
|
|
1434
1591
|
if (value !== null && value !== void 0) {
|
|
@@ -1441,22 +1598,23 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1441
1598
|
serializedRecord[key] = null;
|
|
1442
1599
|
}
|
|
1443
1600
|
}
|
|
1601
|
+
const now = /* @__PURE__ */ new Date();
|
|
1444
1602
|
serializedRecord.id = id;
|
|
1445
|
-
serializedRecord.createdAt =
|
|
1446
|
-
serializedRecord.updatedAt =
|
|
1603
|
+
serializedRecord.createdAt = now.toISOString();
|
|
1604
|
+
serializedRecord.updatedAt = now.toISOString();
|
|
1447
1605
|
const columns = Object.keys(serializedRecord);
|
|
1448
1606
|
const values = Object.values(serializedRecord);
|
|
1449
1607
|
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1450
1608
|
const { sql, params } = query.build();
|
|
1451
|
-
await this.
|
|
1452
|
-
|
|
1453
|
-
return { score: scoreFromDb };
|
|
1609
|
+
await this.#db.executeQuery({ sql, params });
|
|
1610
|
+
return { score: { ...parsedScore, id, createdAt: now, updatedAt: now } };
|
|
1454
1611
|
} catch (error$1) {
|
|
1455
1612
|
throw new error.MastraError(
|
|
1456
1613
|
{
|
|
1457
|
-
id: "
|
|
1614
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "FAILED"),
|
|
1458
1615
|
domain: error.ErrorDomain.STORAGE,
|
|
1459
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1616
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1617
|
+
details: { id }
|
|
1460
1618
|
},
|
|
1461
1619
|
error$1
|
|
1462
1620
|
);
|
|
@@ -1473,7 +1631,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1473
1631
|
const { page, perPage: perPageInput } = pagination;
|
|
1474
1632
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1475
1633
|
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1476
|
-
const fullTableName = this.
|
|
1634
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1477
1635
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("scorerId = ?", scorerId);
|
|
1478
1636
|
if (entityId) {
|
|
1479
1637
|
countQuery.andWhere("entityId = ?", entityId);
|
|
@@ -1484,7 +1642,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1484
1642
|
if (source) {
|
|
1485
1643
|
countQuery.andWhere("source = ?", source);
|
|
1486
1644
|
}
|
|
1487
|
-
const countResult = await this.
|
|
1645
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1488
1646
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1489
1647
|
if (total === 0) {
|
|
1490
1648
|
return {
|
|
@@ -1511,7 +1669,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1511
1669
|
}
|
|
1512
1670
|
selectQuery.limit(limitValue).offset(start);
|
|
1513
1671
|
const { sql, params } = selectQuery.build();
|
|
1514
|
-
const results = await this.
|
|
1672
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1515
1673
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1516
1674
|
return {
|
|
1517
1675
|
pagination: {
|
|
@@ -1525,7 +1683,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1525
1683
|
} catch (error$1) {
|
|
1526
1684
|
throw new error.MastraError(
|
|
1527
1685
|
{
|
|
1528
|
-
id: "
|
|
1686
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1529
1687
|
domain: error.ErrorDomain.STORAGE,
|
|
1530
1688
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1531
1689
|
},
|
|
@@ -1541,9 +1699,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1541
1699
|
const { page, perPage: perPageInput } = pagination;
|
|
1542
1700
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1543
1701
|
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1544
|
-
const fullTableName = this.
|
|
1702
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1545
1703
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("runId = ?", runId);
|
|
1546
|
-
const countResult = await this.
|
|
1704
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1547
1705
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1548
1706
|
if (total === 0) {
|
|
1549
1707
|
return {
|
|
@@ -1560,7 +1718,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1560
1718
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1561
1719
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("runId = ?", runId).limit(limitValue).offset(start);
|
|
1562
1720
|
const { sql, params } = selectQuery.build();
|
|
1563
|
-
const results = await this.
|
|
1721
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1564
1722
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1565
1723
|
return {
|
|
1566
1724
|
pagination: {
|
|
@@ -1574,7 +1732,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1574
1732
|
} catch (error$1) {
|
|
1575
1733
|
throw new error.MastraError(
|
|
1576
1734
|
{
|
|
1577
|
-
id: "
|
|
1735
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_RUN_ID", "FAILED"),
|
|
1578
1736
|
domain: error.ErrorDomain.STORAGE,
|
|
1579
1737
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1580
1738
|
},
|
|
@@ -1591,9 +1749,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1591
1749
|
const { page, perPage: perPageInput } = pagination;
|
|
1592
1750
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1593
1751
|
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1594
|
-
const fullTableName = this.
|
|
1752
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1595
1753
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType);
|
|
1596
|
-
const countResult = await this.
|
|
1754
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1597
1755
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1598
1756
|
if (total === 0) {
|
|
1599
1757
|
return {
|
|
@@ -1610,7 +1768,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1610
1768
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1611
1769
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType).limit(limitValue).offset(start);
|
|
1612
1770
|
const { sql, params } = selectQuery.build();
|
|
1613
|
-
const results = await this.
|
|
1771
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1614
1772
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1615
1773
|
return {
|
|
1616
1774
|
pagination: {
|
|
@@ -1624,7 +1782,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1624
1782
|
} catch (error$1) {
|
|
1625
1783
|
throw new error.MastraError(
|
|
1626
1784
|
{
|
|
1627
|
-
id: "
|
|
1785
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1628
1786
|
domain: error.ErrorDomain.STORAGE,
|
|
1629
1787
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1630
1788
|
},
|
|
@@ -1641,9 +1799,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1641
1799
|
const { page, perPage: perPageInput } = pagination;
|
|
1642
1800
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1643
1801
|
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1644
|
-
const fullTableName = this.
|
|
1802
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
|
|
1645
1803
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId);
|
|
1646
|
-
const countResult = await this.
|
|
1804
|
+
const countResult = await this.#db.executeQuery(countQuery.build());
|
|
1647
1805
|
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1648
1806
|
if (total === 0) {
|
|
1649
1807
|
return {
|
|
@@ -1660,7 +1818,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1660
1818
|
const limitValue = perPageInput === false ? total : perPage;
|
|
1661
1819
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId).orderBy("createdAt", "DESC").limit(limitValue).offset(start);
|
|
1662
1820
|
const { sql, params } = selectQuery.build();
|
|
1663
|
-
const results = await this.
|
|
1821
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1664
1822
|
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1665
1823
|
return {
|
|
1666
1824
|
pagination: {
|
|
@@ -1674,7 +1832,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1674
1832
|
} catch (error$1) {
|
|
1675
1833
|
throw new error.MastraError(
|
|
1676
1834
|
{
|
|
1677
|
-
id: "
|
|
1835
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SPAN", "FAILED"),
|
|
1678
1836
|
domain: error.ErrorDomain.STORAGE,
|
|
1679
1837
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1680
1838
|
},
|
|
@@ -1684,10 +1842,16 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
|
|
|
1684
1842
|
}
|
|
1685
1843
|
};
|
|
1686
1844
|
var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
1687
|
-
|
|
1688
|
-
constructor(
|
|
1845
|
+
#db;
|
|
1846
|
+
constructor(config) {
|
|
1689
1847
|
super();
|
|
1690
|
-
this
|
|
1848
|
+
this.#db = new D1DB(resolveD1Config(config));
|
|
1849
|
+
}
|
|
1850
|
+
async init() {
|
|
1851
|
+
await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT] });
|
|
1852
|
+
}
|
|
1853
|
+
async dangerouslyClearAll() {
|
|
1854
|
+
await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1691
1855
|
}
|
|
1692
1856
|
updateWorkflowResults({
|
|
1693
1857
|
// workflowName,
|
|
@@ -1709,11 +1873,13 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1709
1873
|
workflowName,
|
|
1710
1874
|
runId,
|
|
1711
1875
|
resourceId,
|
|
1712
|
-
snapshot
|
|
1876
|
+
snapshot,
|
|
1877
|
+
createdAt,
|
|
1878
|
+
updatedAt
|
|
1713
1879
|
}) {
|
|
1714
|
-
const fullTableName = this.
|
|
1880
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1715
1881
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1716
|
-
const currentSnapshot = await this.
|
|
1882
|
+
const currentSnapshot = await this.#db.load({
|
|
1717
1883
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1718
1884
|
keys: { workflow_name: workflowName, run_id: runId }
|
|
1719
1885
|
});
|
|
@@ -1721,16 +1887,16 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1721
1887
|
...currentSnapshot,
|
|
1722
1888
|
resourceId,
|
|
1723
1889
|
snapshot: JSON.stringify(snapshot),
|
|
1724
|
-
updatedAt: now
|
|
1890
|
+
updatedAt: updatedAt ? updatedAt.toISOString() : now
|
|
1725
1891
|
} : {
|
|
1726
1892
|
workflow_name: workflowName,
|
|
1727
1893
|
run_id: runId,
|
|
1728
1894
|
resourceId,
|
|
1729
1895
|
snapshot,
|
|
1730
|
-
createdAt: now,
|
|
1731
|
-
updatedAt: now
|
|
1896
|
+
createdAt: createdAt ? createdAt.toISOString() : now,
|
|
1897
|
+
updatedAt: updatedAt ? updatedAt.toISOString() : now
|
|
1732
1898
|
};
|
|
1733
|
-
const processedRecord = await this.
|
|
1899
|
+
const processedRecord = await this.#db.processRecord(persisting);
|
|
1734
1900
|
const columns = Object.keys(processedRecord);
|
|
1735
1901
|
const values = Object.values(processedRecord);
|
|
1736
1902
|
const updateMap = {
|
|
@@ -1741,11 +1907,11 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1741
1907
|
const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
|
|
1742
1908
|
const { sql, params } = query.build();
|
|
1743
1909
|
try {
|
|
1744
|
-
await this.
|
|
1910
|
+
await this.#db.executeQuery({ sql, params });
|
|
1745
1911
|
} catch (error$1) {
|
|
1746
1912
|
throw new error.MastraError(
|
|
1747
1913
|
{
|
|
1748
|
-
id: "
|
|
1914
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1749
1915
|
domain: error.ErrorDomain.STORAGE,
|
|
1750
1916
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1751
1917
|
text: `Failed to persist workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
@@ -1759,7 +1925,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1759
1925
|
const { workflowName, runId } = params;
|
|
1760
1926
|
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
1761
1927
|
try {
|
|
1762
|
-
const d = await this.
|
|
1928
|
+
const d = await this.#db.load({
|
|
1763
1929
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1764
1930
|
keys: {
|
|
1765
1931
|
workflow_name: workflowName,
|
|
@@ -1770,7 +1936,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1770
1936
|
} catch (error$1) {
|
|
1771
1937
|
throw new error.MastraError(
|
|
1772
1938
|
{
|
|
1773
|
-
id: "
|
|
1939
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1774
1940
|
domain: error.ErrorDomain.STORAGE,
|
|
1775
1941
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1776
1942
|
text: `Failed to load workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
@@ -1786,7 +1952,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1786
1952
|
try {
|
|
1787
1953
|
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1788
1954
|
} catch (e) {
|
|
1789
|
-
|
|
1955
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1790
1956
|
}
|
|
1791
1957
|
}
|
|
1792
1958
|
return {
|
|
@@ -1807,7 +1973,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1807
1973
|
resourceId,
|
|
1808
1974
|
status
|
|
1809
1975
|
} = {}) {
|
|
1810
|
-
const fullTableName = this.
|
|
1976
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1811
1977
|
try {
|
|
1812
1978
|
const builder = createSqlBuilder().select().from(fullTableName);
|
|
1813
1979
|
const countBuilder = createSqlBuilder().count().from(fullTableName);
|
|
@@ -1817,12 +1983,12 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1817
1983
|
countBuilder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
|
|
1818
1984
|
}
|
|
1819
1985
|
if (resourceId) {
|
|
1820
|
-
const hasResourceId = await this.
|
|
1986
|
+
const hasResourceId = await this.#db.hasColumn(fullTableName, "resourceId");
|
|
1821
1987
|
if (hasResourceId) {
|
|
1822
1988
|
builder.whereAnd("resourceId = ?", resourceId);
|
|
1823
1989
|
countBuilder.whereAnd("resourceId = ?", resourceId);
|
|
1824
1990
|
} else {
|
|
1825
|
-
|
|
1991
|
+
this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
|
|
1826
1992
|
}
|
|
1827
1993
|
}
|
|
1828
1994
|
if (fromDate) {
|
|
@@ -1843,20 +2009,20 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1843
2009
|
let total = 0;
|
|
1844
2010
|
if (perPage !== void 0 && page !== void 0) {
|
|
1845
2011
|
const { sql: countSql, params: countParams } = countBuilder.build();
|
|
1846
|
-
const countResult = await this.
|
|
2012
|
+
const countResult = await this.#db.executeQuery({
|
|
1847
2013
|
sql: countSql,
|
|
1848
2014
|
params: countParams,
|
|
1849
2015
|
first: true
|
|
1850
2016
|
});
|
|
1851
2017
|
total = Number(countResult?.count ?? 0);
|
|
1852
2018
|
}
|
|
1853
|
-
const results = await this.
|
|
2019
|
+
const results = await this.#db.executeQuery({ sql, params });
|
|
1854
2020
|
const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
|
|
1855
2021
|
return { runs, total: total || runs.length };
|
|
1856
2022
|
} catch (error$1) {
|
|
1857
2023
|
throw new error.MastraError(
|
|
1858
2024
|
{
|
|
1859
|
-
id: "
|
|
2025
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1860
2026
|
domain: error.ErrorDomain.STORAGE,
|
|
1861
2027
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1862
2028
|
text: `Failed to retrieve workflow runs: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
@@ -1873,7 +2039,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1873
2039
|
runId,
|
|
1874
2040
|
workflowName
|
|
1875
2041
|
}) {
|
|
1876
|
-
const fullTableName = this.
|
|
2042
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1877
2043
|
try {
|
|
1878
2044
|
const conditions = [];
|
|
1879
2045
|
const params = [];
|
|
@@ -1887,13 +2053,13 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1887
2053
|
}
|
|
1888
2054
|
const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
|
|
1889
2055
|
const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
|
|
1890
|
-
const result = await this.
|
|
2056
|
+
const result = await this.#db.executeQuery({ sql, params, first: true });
|
|
1891
2057
|
if (!result) return null;
|
|
1892
2058
|
return this.parseWorkflowRun(result);
|
|
1893
2059
|
} catch (error$1) {
|
|
1894
2060
|
throw new error.MastraError(
|
|
1895
2061
|
{
|
|
1896
|
-
id: "
|
|
2062
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1897
2063
|
domain: error.ErrorDomain.STORAGE,
|
|
1898
2064
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1899
2065
|
text: `Failed to retrieve workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
@@ -1903,13 +2069,31 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
|
|
|
1903
2069
|
);
|
|
1904
2070
|
}
|
|
1905
2071
|
}
|
|
2072
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2073
|
+
const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
2074
|
+
try {
|
|
2075
|
+
const sql = `DELETE FROM ${fullTableName} WHERE workflow_name = ? AND run_id = ?`;
|
|
2076
|
+
const params = [workflowName, runId];
|
|
2077
|
+
await this.#db.executeQuery({ sql, params });
|
|
2078
|
+
} catch (error$1) {
|
|
2079
|
+
throw new error.MastraError(
|
|
2080
|
+
{
|
|
2081
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
2082
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2083
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2084
|
+
text: `Failed to delete workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
2085
|
+
details: { runId, workflowName }
|
|
2086
|
+
},
|
|
2087
|
+
error$1
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
1906
2091
|
};
|
|
1907
2092
|
|
|
1908
2093
|
// src/storage/index.ts
|
|
1909
2094
|
var D1Store = class extends storage.MastraStorage {
|
|
1910
2095
|
client;
|
|
1911
2096
|
binding;
|
|
1912
|
-
// D1Database binding
|
|
1913
2097
|
tablePrefix;
|
|
1914
2098
|
stores;
|
|
1915
2099
|
/**
|
|
@@ -1918,7 +2102,7 @@ var D1Store = class extends storage.MastraStorage {
|
|
|
1918
2102
|
*/
|
|
1919
2103
|
constructor(config) {
|
|
1920
2104
|
try {
|
|
1921
|
-
super({ id: config.id, name: "D1" });
|
|
2105
|
+
super({ id: config.id, name: "D1", disableInit: config.disableInit });
|
|
1922
2106
|
if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
|
|
1923
2107
|
throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
|
|
1924
2108
|
}
|
|
@@ -1956,7 +2140,7 @@ var D1Store = class extends storage.MastraStorage {
|
|
|
1956
2140
|
} catch (error$1) {
|
|
1957
2141
|
throw new error.MastraError(
|
|
1958
2142
|
{
|
|
1959
|
-
id: "
|
|
2143
|
+
id: storage.createStorageErrorId("CLOUDFLARE_D1", "INITIALIZATION", "FAILED"),
|
|
1960
2144
|
domain: error.ErrorDomain.STORAGE,
|
|
1961
2145
|
category: error.ErrorCategory.SYSTEM,
|
|
1962
2146
|
text: "Error initializing D1Store"
|
|
@@ -1964,189 +2148,26 @@ var D1Store = class extends storage.MastraStorage {
|
|
|
1964
2148
|
error$1
|
|
1965
2149
|
);
|
|
1966
2150
|
}
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
}
|
|
2151
|
+
let scores;
|
|
2152
|
+
let workflows;
|
|
2153
|
+
let memory;
|
|
2154
|
+
if (this.binding) {
|
|
2155
|
+
const domainConfig = { binding: this.binding, tablePrefix: this.tablePrefix };
|
|
2156
|
+
scores = new ScoresStorageD1(domainConfig);
|
|
2157
|
+
workflows = new WorkflowsStorageD1(domainConfig);
|
|
2158
|
+
memory = new MemoryStorageD1(domainConfig);
|
|
2159
|
+
} else {
|
|
2160
|
+
const domainConfig = { client: this.client, tablePrefix: this.tablePrefix };
|
|
2161
|
+
scores = new ScoresStorageD1(domainConfig);
|
|
2162
|
+
workflows = new WorkflowsStorageD1(domainConfig);
|
|
2163
|
+
memory = new MemoryStorageD1(domainConfig);
|
|
2164
|
+
}
|
|
1981
2165
|
this.stores = {
|
|
1982
|
-
operations,
|
|
1983
2166
|
scores,
|
|
1984
2167
|
workflows,
|
|
1985
2168
|
memory
|
|
1986
2169
|
};
|
|
1987
2170
|
}
|
|
1988
|
-
get supports() {
|
|
1989
|
-
return {
|
|
1990
|
-
selectByIncludeResourceScope: true,
|
|
1991
|
-
resourceWorkingMemory: true,
|
|
1992
|
-
hasColumn: true,
|
|
1993
|
-
createTable: true,
|
|
1994
|
-
deleteMessages: false,
|
|
1995
|
-
listScoresBySpan: true
|
|
1996
|
-
};
|
|
1997
|
-
}
|
|
1998
|
-
async createTable({
|
|
1999
|
-
tableName,
|
|
2000
|
-
schema
|
|
2001
|
-
}) {
|
|
2002
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
2003
|
-
}
|
|
2004
|
-
/**
|
|
2005
|
-
* Alters table schema to add columns if they don't exist
|
|
2006
|
-
* @param tableName Name of the table
|
|
2007
|
-
* @param schema Schema of the table
|
|
2008
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
2009
|
-
*/
|
|
2010
|
-
async alterTable({
|
|
2011
|
-
tableName,
|
|
2012
|
-
schema,
|
|
2013
|
-
ifNotExists
|
|
2014
|
-
}) {
|
|
2015
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2016
|
-
}
|
|
2017
|
-
async clearTable({ tableName }) {
|
|
2018
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2019
|
-
}
|
|
2020
|
-
async dropTable({ tableName }) {
|
|
2021
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2022
|
-
}
|
|
2023
|
-
async hasColumn(table, column) {
|
|
2024
|
-
return this.stores.operations.hasColumn(table, column);
|
|
2025
|
-
}
|
|
2026
|
-
async insert({ tableName, record }) {
|
|
2027
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2028
|
-
}
|
|
2029
|
-
async load({ tableName, keys }) {
|
|
2030
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2031
|
-
}
|
|
2032
|
-
async getThreadById({ threadId }) {
|
|
2033
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2034
|
-
}
|
|
2035
|
-
async saveThread({ thread }) {
|
|
2036
|
-
return this.stores.memory.saveThread({ thread });
|
|
2037
|
-
}
|
|
2038
|
-
async updateThread({
|
|
2039
|
-
id,
|
|
2040
|
-
title,
|
|
2041
|
-
metadata
|
|
2042
|
-
}) {
|
|
2043
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2044
|
-
}
|
|
2045
|
-
async deleteThread({ threadId }) {
|
|
2046
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2047
|
-
}
|
|
2048
|
-
async saveMessages(args) {
|
|
2049
|
-
return this.stores.memory.saveMessages(args);
|
|
2050
|
-
}
|
|
2051
|
-
async updateWorkflowResults({
|
|
2052
|
-
workflowName,
|
|
2053
|
-
runId,
|
|
2054
|
-
stepId,
|
|
2055
|
-
result,
|
|
2056
|
-
requestContext
|
|
2057
|
-
}) {
|
|
2058
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2059
|
-
}
|
|
2060
|
-
async updateWorkflowState({
|
|
2061
|
-
workflowName,
|
|
2062
|
-
runId,
|
|
2063
|
-
opts
|
|
2064
|
-
}) {
|
|
2065
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2066
|
-
}
|
|
2067
|
-
async persistWorkflowSnapshot({
|
|
2068
|
-
workflowName,
|
|
2069
|
-
runId,
|
|
2070
|
-
resourceId,
|
|
2071
|
-
snapshot
|
|
2072
|
-
}) {
|
|
2073
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2074
|
-
}
|
|
2075
|
-
async loadWorkflowSnapshot(params) {
|
|
2076
|
-
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2077
|
-
}
|
|
2078
|
-
async listWorkflowRuns(args = {}) {
|
|
2079
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
2080
|
-
}
|
|
2081
|
-
async getWorkflowRunById({
|
|
2082
|
-
runId,
|
|
2083
|
-
workflowName
|
|
2084
|
-
}) {
|
|
2085
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2086
|
-
}
|
|
2087
|
-
/**
|
|
2088
|
-
* Insert multiple records in a batch operation
|
|
2089
|
-
* @param tableName The table to insert into
|
|
2090
|
-
* @param records The records to insert
|
|
2091
|
-
*/
|
|
2092
|
-
async batchInsert({ tableName, records }) {
|
|
2093
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2094
|
-
}
|
|
2095
|
-
async updateMessages(_args) {
|
|
2096
|
-
return this.stores.memory.updateMessages(_args);
|
|
2097
|
-
}
|
|
2098
|
-
async getResourceById({ resourceId }) {
|
|
2099
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2100
|
-
}
|
|
2101
|
-
async saveResource({ resource }) {
|
|
2102
|
-
return this.stores.memory.saveResource({ resource });
|
|
2103
|
-
}
|
|
2104
|
-
async updateResource({
|
|
2105
|
-
resourceId,
|
|
2106
|
-
workingMemory,
|
|
2107
|
-
metadata
|
|
2108
|
-
}) {
|
|
2109
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2110
|
-
}
|
|
2111
|
-
async getScoreById({ id: _id }) {
|
|
2112
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2113
|
-
}
|
|
2114
|
-
async saveScore(_score) {
|
|
2115
|
-
return this.stores.scores.saveScore(_score);
|
|
2116
|
-
}
|
|
2117
|
-
async listScoresByRunId({
|
|
2118
|
-
runId: _runId,
|
|
2119
|
-
pagination: _pagination
|
|
2120
|
-
}) {
|
|
2121
|
-
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2122
|
-
}
|
|
2123
|
-
async listScoresByEntityId({
|
|
2124
|
-
entityId: _entityId,
|
|
2125
|
-
entityType: _entityType,
|
|
2126
|
-
pagination: _pagination
|
|
2127
|
-
}) {
|
|
2128
|
-
return this.stores.scores.listScoresByEntityId({
|
|
2129
|
-
entityId: _entityId,
|
|
2130
|
-
entityType: _entityType,
|
|
2131
|
-
pagination: _pagination
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
async listScoresByScorerId({
|
|
2135
|
-
scorerId,
|
|
2136
|
-
pagination,
|
|
2137
|
-
entityId,
|
|
2138
|
-
entityType,
|
|
2139
|
-
source
|
|
2140
|
-
}) {
|
|
2141
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2142
|
-
}
|
|
2143
|
-
async listScoresBySpan({
|
|
2144
|
-
traceId,
|
|
2145
|
-
spanId,
|
|
2146
|
-
pagination
|
|
2147
|
-
}) {
|
|
2148
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2149
|
-
}
|
|
2150
2171
|
/**
|
|
2151
2172
|
* Close the database connection
|
|
2152
2173
|
* No explicit cleanup needed for D1 in either REST or Workers Binding mode
|
|
@@ -2157,5 +2178,8 @@ var D1Store = class extends storage.MastraStorage {
|
|
|
2157
2178
|
};
|
|
2158
2179
|
|
|
2159
2180
|
exports.D1Store = D1Store;
|
|
2181
|
+
exports.MemoryStorageD1 = MemoryStorageD1;
|
|
2182
|
+
exports.ScoresStorageD1 = ScoresStorageD1;
|
|
2183
|
+
exports.WorkflowsStorageD1 = WorkflowsStorageD1;
|
|
2160
2184
|
//# sourceMappingURL=index.cjs.map
|
|
2161
2185
|
//# sourceMappingURL=index.cjs.map
|