@mastra/cloudflare-d1 1.0.0-beta.0 → 1.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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,508 +259,600 @@ function parseSelectIdentifier(column) {
242
259
  return column;
243
260
  }
244
261
 
245
- // src/storage/domains/utils.ts
246
- function isArrayOfRecords(value) {
247
- return value && Array.isArray(value) && value.length > 0;
248
- }
249
- function deserializeValue(value, type) {
250
- if (value === null || value === void 0) return null;
251
- if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
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
- return value;
259
- }
260
-
261
- // src/storage/domains/memory/index.ts
262
- var MemoryStorageD1 = class extends storage.MemoryStorage {
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
- async getResourceById({ resourceId }) {
269
- const resource = await this.operations.load({
270
- tableName: storage.TABLE_RESOURCES,
271
- keys: { id: resourceId }
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
- if (!resource) return null;
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
- return {
276
- ...resource,
277
- createdAt: storage.ensureDate(resource.createdAt),
278
- updatedAt: storage.ensureDate(resource.updatedAt),
279
- metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata || "{}") : resource.metadata
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
- const mastraError = new error.MastraError(
350
+ throw new error.MastraError(
283
351
  {
284
- id: "CLOUDFLARE_D1_STORAGE_GET_RESOURCE_BY_ID_ERROR",
352
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "WORKERS_BINDING_QUERY", "FAILED"),
285
353
  domain: error.ErrorDomain.STORAGE,
286
354
  category: error.ErrorCategory.THIRD_PARTY,
287
- text: `Error processing resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
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 saveResource({ resource }) {
298
- const fullTableName = this.operations.getTableName(storage.TABLE_RESOURCES);
299
- const resourceToSave = {
300
- id: resource.id,
301
- workingMemory: resource.workingMemory,
302
- metadata: resource.metadata ? JSON.stringify(resource.metadata) : null,
303
- createdAt: resource.createdAt,
304
- updatedAt: resource.updatedAt
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
- await this.operations.executeQuery({ sql, params });
319
- return resource;
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: "CLOUDFLARE_D1_STORAGE_SAVE_RESOURCE_ERROR",
384
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "REST_QUERY", "FAILED"),
324
385
  domain: error.ErrorDomain.STORAGE,
325
386
  category: error.ErrorCategory.THIRD_PARTY,
326
- text: `Failed to save resource to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
327
- details: { resourceId: resource.id }
387
+ details: { sql }
328
388
  },
329
389
  error$1
330
390
  );
331
391
  }
332
392
  }
333
- async updateResource({
334
- resourceId,
335
- workingMemory,
336
- metadata
337
- }) {
338
- const existingResource = await this.getResourceById({ resourceId });
339
- if (!existingResource) {
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
- const updatedAt = /* @__PURE__ */ new Date();
350
- const updatedResource = {
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
- await this.operations.executeQuery({ sql, params });
366
- return updatedResource;
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: "CLOUDFLARE_D1_STORAGE_UPDATE_RESOURCE_ERROR",
471
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "CREATE_TABLE", "FAILED"),
371
472
  domain: error.ErrorDomain.STORAGE,
372
473
  category: error.ErrorCategory.THIRD_PARTY,
373
- text: `Failed to update resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
374
- details: { resourceId }
474
+ details: { tableName }
375
475
  },
376
476
  error$1
377
477
  );
378
478
  }
379
479
  }
380
- async getThreadById({ threadId }) {
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
- return {
388
- ...thread,
389
- createdAt: storage.ensureDate(thread.createdAt),
390
- updatedAt: storage.ensureDate(thread.updatedAt),
391
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
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
- const mastraError = new error.MastraError(
488
+ throw new error.MastraError(
395
489
  {
396
- id: "CLOUDFLARE_D1_STORAGE_GET_THREAD_BY_ID_ERROR",
490
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "CLEAR_TABLE", "FAILED"),
397
491
  domain: error.ErrorDomain.STORAGE,
398
492
  category: error.ErrorCategory.THIRD_PARTY,
399
- text: `Error processing thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
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 listThreadsByResourceId(args) {
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 countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
434
- const countResult = await this.operations.executeQuery(countQuery.build());
435
- const total = Number(countResult?.[0]?.count ?? 0);
436
- const limitValue = perPageInput === false ? total : perPage;
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
- const mastraError = new error.MastraError(
506
+ throw new error.MastraError(
449
507
  {
450
- id: "CLOUDFLARE_D1_STORAGE_LIST_THREADS_BY_RESOURCE_ID_ERROR",
508
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "DROP_TABLE", "FAILED"),
451
509
  domain: error.ErrorDomain.STORAGE,
452
510
  category: error.ErrorCategory.THIRD_PARTY,
453
- text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
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 saveThread({ thread }) {
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
- await this.operations.executeQuery({ sql, params });
493
- return thread;
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: "CLOUDFLARE_D1_STORAGE_SAVE_THREAD_ERROR",
534
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "ALTER_TABLE", "FAILED"),
498
535
  domain: error.ErrorDomain.STORAGE,
499
536
  category: error.ErrorCategory.THIRD_PARTY,
500
- text: `Failed to save thread to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
501
- details: { threadId: thread.id }
537
+ details: { tableName: args.tableName }
502
538
  },
503
539
  error$1
504
540
  );
505
541
  }
506
542
  }
507
- async updateThread({
508
- id,
509
- title,
510
- metadata
511
- }) {
512
- const thread = await this.getThreadById({ threadId: id });
543
+ async insert({ tableName, record }) {
513
544
  try {
514
- if (!thread) {
515
- throw new Error(`Thread ${id} not found`);
516
- }
517
- const fullTableName = this.operations.getTableName(storage.TABLE_THREADS);
518
- const mergedMetadata = {
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.operations.executeQuery({ sql, params });
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: "CLOUDFLARE_D1_STORAGE_UPDATE_THREAD_ERROR",
555
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "INSERT", "FAILED"),
541
556
  domain: error.ErrorDomain.STORAGE,
542
557
  category: error.ErrorCategory.THIRD_PARTY,
543
- text: `Failed to update thread ${id}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
544
- details: { threadId: id }
558
+ details: { tableName }
545
559
  },
546
560
  error$1
547
561
  );
548
562
  }
549
563
  }
550
- async deleteThread({ threadId }) {
551
- const fullTableName = this.operations.getTableName(storage.TABLE_THREADS);
564
+ async batchInsert({ tableName, records }) {
552
565
  try {
553
- const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
554
- const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
555
- await this.operations.executeQuery({ sql: threadSql, params: threadParams });
556
- const messagesTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
557
- const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
558
- const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
559
- await this.operations.executeQuery({ sql: messagesSql, params: messagesParams });
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: "CLOUDFLARE_D1_STORAGE_DELETE_THREAD_ERROR",
579
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "BATCH_INSERT", "FAILED"),
564
580
  domain: error.ErrorDomain.STORAGE,
565
581
  category: error.ErrorCategory.THIRD_PARTY,
566
- text: `Failed to delete thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
567
- details: { threadId }
582
+ details: { tableName }
568
583
  },
569
584
  error$1
570
585
  );
571
586
  }
572
587
  }
573
- async saveMessages(args) {
574
- const { messages } = args;
575
- if (messages.length === 0) return { messages: [] };
588
+ async load({ tableName, keys }) {
576
589
  try {
577
- const now = /* @__PURE__ */ new Date();
578
- const threadId = messages[0]?.threadId;
579
- for (const [i, message] of messages.entries()) {
580
- if (!message.id) throw new Error(`Message at index ${i} missing id`);
581
- if (!message.threadId) {
582
- throw new Error(`Message at index ${i} missing threadId`);
583
- }
584
- if (!message.content) {
585
- throw new Error(`Message at index ${i} missing content`);
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
- const messagesToInsert = messages.map((message) => {
599
- const createdAt = message.createdAt ? new Date(message.createdAt) : now;
600
- return {
601
- id: message.id,
602
- thread_id: message.threadId,
603
- content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
604
- createdAt: createdAt.toISOString(),
605
- role: message.role,
606
- type: message.type || "v2",
607
- resourceId: message.resourceId
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: "CLOUDFLARE_D1_STORAGE_SAVE_MESSAGES_ERROR",
616
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LOAD", "FAILED"),
628
617
  domain: error.ErrorDomain.STORAGE,
629
618
  category: error.ErrorCategory.THIRD_PARTY,
630
- text: `Failed to save messages: ${error$1 instanceof Error ? error$1.message : String(error$1)}`
619
+ details: { tableName }
631
620
  },
632
621
  error$1
633
622
  );
634
623
  }
635
624
  }
636
- async _getIncludedMessages(threadId, include) {
637
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
638
- if (!include) return null;
639
- const unionQueries = [];
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
- const processedMessages = messages.map((message) => {
684
- const processedMsg = {};
685
- for (const [key, value] of Object.entries(message)) {
686
- if (key === `type` && value === `v2`) continue;
687
- processedMsg[key] = deserializeValue(value);
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
- return processedMsg;
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 listMessagesById({ messageIds }) {
694
- if (messageIds.length === 0) return { messages: [] };
695
- const fullTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
696
- const messages = [];
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
- const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
699
- query.orderBy("createdAt", "DESC");
700
- const { sql, params } = query.build();
701
- const result = await this.operations.executeQuery({ sql, params });
702
- if (Array.isArray(result)) messages.push(...result);
703
- const processedMessages = messages.map((message) => {
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: "CLOUDFLARE_D1_STORAGE_LIST_MESSAGES_BY_ID_ERROR",
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: `Failed to retrieve messages by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
721
- details: { messageIds: JSON.stringify(messageIds) }
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
- throw mastraError;
734
+ return null;
728
735
  }
729
736
  }
730
- async listMessages(args) {
731
- const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
732
- if (!threadId.trim()) {
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) {
761
+ throw new error.MastraError(
762
+ {
763
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_RESOURCE", "FAILED"),
764
+ domain: error.ErrorDomain.STORAGE,
765
+ category: error.ErrorCategory.THIRD_PARTY,
766
+ text: `Failed to save resource to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
767
+ details: { resourceId: resource.id }
768
+ },
769
+ error$1
770
+ );
771
+ }
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) {
733
808
  throw new error.MastraError(
734
809
  {
735
- id: "STORAGE_CLOUDFLARE_D1_LIST_MESSAGES_INVALID_THREAD_ID",
810
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_RESOURCE", "FAILED"),
811
+ domain: error.ErrorDomain.STORAGE,
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 }
815
+ },
816
+ error$1
817
+ );
818
+ }
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;
826
+ try {
827
+ return {
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 || {}
832
+ };
833
+ } catch (error$1) {
834
+ const mastraError = new error.MastraError(
835
+ {
836
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_THREAD_BY_ID", "FAILED"),
736
837
  domain: error.ErrorDomain.STORAGE,
737
838
  category: error.ErrorCategory.THIRD_PARTY,
839
+ text: `Error processing thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
738
840
  details: { threadId }
739
841
  },
740
- new Error("threadId must be a non-empty string")
842
+ error$1
741
843
  );
844
+ this.logger?.error(mastraError.toString());
845
+ this.logger?.trackException(mastraError);
846
+ return null;
742
847
  }
848
+ }
849
+ async listThreadsByResourceId(args) {
850
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
851
+ const perPage = storage.normalizePerPage(perPageInput, 100);
743
852
  if (page < 0) {
744
853
  throw new error.MastraError(
745
854
  {
746
- id: "STORAGE_CLOUDFLARE_D1_LIST_MESSAGES_INVALID_PAGE",
855
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
747
856
  domain: error.ErrorDomain.STORAGE,
748
857
  category: error.ErrorCategory.USER,
749
858
  details: { page }
@@ -751,130 +860,45 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
751
860
  new Error("page must be >= 0")
752
861
  );
753
862
  }
754
- const perPage = storage.normalizePerPage(perPageInput, 40);
755
863
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
864
+ const { field, direction } = this.parseOrderBy(orderBy);
865
+ const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
866
+ const mapRowToStorageThreadType = (row) => ({
867
+ ...row,
868
+ createdAt: storage.ensureDate(row.createdAt),
869
+ updatedAt: storage.ensureDate(row.updatedAt),
870
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
871
+ });
756
872
  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;
873
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
874
+ const countResult = await this.#db.executeQuery(countQuery.build());
875
+ const total = Number(countResult?.[0]?.count ?? 0);
876
+ const limitValue = perPageInput === false ? total : perPage;
877
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy(field, direction).limit(limitValue).offset(offset);
878
+ const results = await this.#db.executeQuery(selectQuery.build());
879
+ const threads = results.map(mapRowToStorageThreadType);
853
880
  return {
854
- messages: finalMessages,
881
+ threads,
855
882
  total,
856
883
  page,
857
884
  perPage: perPageForResponse,
858
- hasMore
885
+ hasMore: perPageInput === false ? false : offset + perPage < total
859
886
  };
860
887
  } catch (error$1) {
861
888
  const mastraError = new error.MastraError(
862
889
  {
863
- id: "CLOUDFLARE_D1_STORAGE_LIST_MESSAGES_ERROR",
890
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
864
891
  domain: error.ErrorDomain.STORAGE,
865
892
  category: error.ErrorCategory.THIRD_PARTY,
866
- text: `Failed to list messages for thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
867
- details: {
868
- threadId,
869
- resourceId: resourceId ?? ""
870
- }
893
+ text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
894
+ details: { resourceId }
871
895
  },
872
896
  error$1
873
897
  );
874
- this.logger?.error?.(mastraError.toString());
875
- this.logger?.trackException?.(mastraError);
898
+ this.logger?.error(mastraError.toString());
899
+ this.logger?.trackException(mastraError);
876
900
  return {
877
- messages: [],
901
+ threads: [],
878
902
  total: 0,
879
903
  page,
880
904
  perPage: perPageForResponse,
@@ -882,487 +906,554 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
882
906
  };
883
907
  }
884
908
  }
885
- async updateMessages(args) {
886
- const { messages } = args;
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);
909
+ async saveThread({ thread }) {
910
+ const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
911
+ const threadToSave = {
912
+ id: thread.id,
913
+ resourceId: thread.resourceId,
914
+ title: thread.title,
915
+ metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
916
+ createdAt: thread.createdAt.toISOString(),
917
+ updatedAt: thread.updatedAt.toISOString()
918
+ };
919
+ const processedRecord = await this.#db.processRecord(threadToSave);
920
+ const columns = Object.keys(processedRecord);
921
+ const values = Object.values(processedRecord);
922
+ const updateMap = {
923
+ resourceId: "excluded.resourceId",
924
+ title: "excluded.title",
925
+ metadata: "excluded.metadata",
926
+ createdAt: "excluded.createdAt",
927
+ updatedAt: "excluded.updatedAt"
928
+ };
929
+ const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
930
+ const { sql, params } = query.build();
894
931
  try {
895
- const placeholders = messageIds.map(() => "?").join(",");
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
- });
932
+ await this.#db.executeQuery({ sql, params });
933
+ return thread;
973
934
  } catch (error$1) {
974
935
  throw new error.MastraError(
975
936
  {
976
- id: "CLOUDFLARE_D1_STORAGE_UPDATE_MESSAGES_FAILED",
937
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_THREAD", "FAILED"),
977
938
  domain: error.ErrorDomain.STORAGE,
978
939
  category: error.ErrorCategory.THIRD_PARTY,
979
- details: { count: messages.length }
940
+ text: `Failed to save thread to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
941
+ details: { threadId: thread.id }
980
942
  },
981
943
  error$1
982
944
  );
983
945
  }
984
946
  }
985
- };
986
- var StoreOperationsD1 = class extends storage.StoreOperations {
987
- client;
988
- binding;
989
- tablePrefix;
990
- constructor(config) {
991
- super();
992
- this.client = config.client;
993
- this.binding = config.binding;
994
- this.tablePrefix = config.tablePrefix || "";
995
- }
996
- async hasColumn(table, column) {
997
- const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
998
- const sql = `PRAGMA table_info(${fullTableName});`;
999
- const result = await this.executeQuery({ sql, params: [] });
1000
- if (!result || !Array.isArray(result)) return false;
1001
- return result.some((col) => col.name === column || col.name === column.toLowerCase());
1002
- }
1003
- getTableName(tableName) {
1004
- return `${this.tablePrefix}${tableName}`;
1005
- }
1006
- formatSqlParams(params) {
1007
- return params.map((p) => p === void 0 || p === null ? null : p);
1008
- }
1009
- async executeWorkersBindingQuery({
1010
- sql,
1011
- params = [],
1012
- first = false
947
+ async updateThread({
948
+ id,
949
+ title,
950
+ metadata
1013
951
  }) {
1014
- if (!this.binding) {
1015
- throw new Error("Workers binding is not configured");
1016
- }
952
+ const thread = await this.getThreadById({ threadId: id });
1017
953
  try {
1018
- const statement = this.binding.prepare(sql);
1019
- const formattedParams = this.formatSqlParams(params);
1020
- let result;
1021
- if (formattedParams.length > 0) {
1022
- if (first) {
1023
- result = await statement.bind(...formattedParams).first();
1024
- if (!result) return null;
1025
- return result;
1026
- } else {
1027
- result = await statement.bind(...formattedParams).all();
1028
- const results = result.results || [];
1029
- return results;
1030
- }
1031
- } else {
1032
- if (first) {
1033
- result = await statement.first();
1034
- if (!result) return null;
1035
- return result;
1036
- } else {
1037
- result = await statement.all();
1038
- const results = result.results || [];
1039
- return results;
1040
- }
954
+ if (!thread) {
955
+ throw new Error(`Thread ${id} not found`);
1041
956
  }
957
+ const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
958
+ const mergedMetadata = {
959
+ ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
960
+ ...metadata
961
+ };
962
+ const updatedAt = /* @__PURE__ */ new Date();
963
+ const columns = ["title", "metadata", "updatedAt"];
964
+ const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
965
+ const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
966
+ const { sql, params } = query.build();
967
+ await this.#db.executeQuery({ sql, params });
968
+ return {
969
+ ...thread,
970
+ title,
971
+ metadata: {
972
+ ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
973
+ ...metadata
974
+ },
975
+ updatedAt
976
+ };
1042
977
  } catch (error$1) {
1043
978
  throw new error.MastraError(
1044
979
  {
1045
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_WORKERS_BINDING_QUERY_FAILED",
980
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_THREAD", "FAILED"),
1046
981
  domain: error.ErrorDomain.STORAGE,
1047
982
  category: error.ErrorCategory.THIRD_PARTY,
1048
- details: { sql }
983
+ text: `Failed to update thread ${id}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
984
+ details: { threadId: id }
1049
985
  },
1050
986
  error$1
1051
987
  );
1052
988
  }
1053
989
  }
1054
- async executeRestQuery({
1055
- sql,
1056
- params = [],
1057
- first = false
1058
- }) {
1059
- if (!this.client) {
1060
- throw new Error("D1 client is not configured");
1061
- }
990
+ async deleteThread({ threadId }) {
991
+ const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
1062
992
  try {
1063
- const formattedParams = this.formatSqlParams(params);
1064
- const response = await this.client.query({
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
+ const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
994
+ const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
995
+ await this.#db.executeQuery({ sql: threadSql, params: threadParams });
996
+ const messagesTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
997
+ const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
998
+ const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
999
+ await this.#db.executeQuery({ sql: messagesSql, params: messagesParams });
1074
1000
  } catch (error$1) {
1075
1001
  throw new error.MastraError(
1076
1002
  {
1077
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_REST_QUERY_FAILED",
1003
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_THREAD", "FAILED"),
1078
1004
  domain: error.ErrorDomain.STORAGE,
1079
1005
  category: error.ErrorCategory.THIRD_PARTY,
1080
- details: { sql }
1006
+ text: `Failed to delete thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1007
+ details: { threadId }
1081
1008
  },
1082
1009
  error$1
1083
1010
  );
1084
1011
  }
1085
1012
  }
1086
- async executeQuery(options) {
1087
- if (this.binding) {
1088
- return this.executeWorkersBindingQuery(options);
1089
- } else if (this.client) {
1090
- return this.executeRestQuery(options);
1091
- } else {
1092
- throw new Error("Neither binding nor client is configured");
1093
- }
1094
- }
1095
- async getTableColumns(tableName) {
1013
+ async saveMessages(args) {
1014
+ const { messages } = args;
1015
+ if (messages.length === 0) return { messages: [] };
1096
1016
  try {
1097
- const sql = `PRAGMA table_info(${tableName})`;
1098
- const result = await this.executeQuery({ sql });
1099
- if (!result || !Array.isArray(result)) {
1100
- return [];
1017
+ const now = /* @__PURE__ */ new Date();
1018
+ const threadId = messages[0]?.threadId;
1019
+ for (const [i, message] of messages.entries()) {
1020
+ if (!message.id) throw new Error(`Message at index ${i} missing id`);
1021
+ if (!message.threadId) {
1022
+ throw new Error(`Message at index ${i} missing threadId`);
1023
+ }
1024
+ if (!message.content) {
1025
+ throw new Error(`Message at index ${i} missing content`);
1026
+ }
1027
+ if (!message.role) {
1028
+ throw new Error(`Message at index ${i} missing role`);
1029
+ }
1030
+ if (!message.resourceId) {
1031
+ throw new Error(`Message at index ${i} missing resourceId`);
1032
+ }
1033
+ const thread = await this.getThreadById({ threadId: message.threadId });
1034
+ if (!thread) {
1035
+ throw new Error(`Thread ${message.threadId} not found`);
1036
+ }
1101
1037
  }
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);
1038
+ const messagesToInsert = messages.map((message) => {
1039
+ const createdAt = message.createdAt ? new Date(message.createdAt) : now;
1040
+ return {
1041
+ id: message.id,
1042
+ thread_id: message.threadId,
1043
+ content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
1044
+ createdAt: createdAt.toISOString(),
1045
+ role: message.role,
1046
+ type: message.type || "v2",
1047
+ resourceId: message.resourceId
1048
+ };
1049
+ });
1050
+ await Promise.all([
1051
+ this.#db.batchUpsert({
1052
+ tableName: storage.TABLE_MESSAGES,
1053
+ records: messagesToInsert
1054
+ }),
1055
+ // Update thread's updatedAt timestamp
1056
+ this.#db.executeQuery({
1057
+ sql: `UPDATE ${this.#db.getTableName(storage.TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
1058
+ params: [now.toISOString(), threadId]
1059
+ })
1060
+ ]);
1061
+ this.logger.debug(`Saved ${messages.length} messages`);
1062
+ const list = new agent.MessageList().add(messages, "memory");
1063
+ return { messages: list.get.all.db() };
1064
+ } catch (error$1) {
1065
+ throw new error.MastraError(
1066
+ {
1067
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_MESSAGES", "FAILED"),
1068
+ domain: error.ErrorDomain.STORAGE,
1069
+ category: error.ErrorCategory.THIRD_PARTY,
1070
+ text: `Failed to save messages: ${error$1 instanceof Error ? error$1.message : String(error$1)}`
1071
+ },
1072
+ error$1
1073
+ );
1120
1074
  }
1121
- return value;
1122
1075
  }
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);
1076
+ async _getIncludedMessages(include) {
1077
+ if (!include || include.length === 0) return null;
1078
+ const unionQueries = [];
1079
+ const params = [];
1080
+ let paramIdx = 1;
1081
+ const tableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1082
+ for (const inc of include) {
1083
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
1084
+ unionQueries.push(`
1085
+ SELECT * FROM (
1086
+ WITH target_thread AS (
1087
+ SELECT thread_id FROM ${tableName} WHERE id = ?
1088
+ ),
1089
+ ordered_messages AS (
1090
+ SELECT
1091
+ *,
1092
+ ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
1093
+ FROM ${tableName}
1094
+ WHERE thread_id = (SELECT thread_id FROM target_thread)
1095
+ )
1096
+ SELECT
1097
+ m.id,
1098
+ m.content,
1099
+ m.role,
1100
+ m.type,
1101
+ m.createdAt,
1102
+ m.thread_id AS threadId,
1103
+ m.resourceId
1104
+ FROM ordered_messages m
1105
+ WHERE m.id = ?
1106
+ OR EXISTS (
1107
+ SELECT 1 FROM ordered_messages target
1108
+ WHERE target.id = ?
1109
+ AND (
1110
+ (m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
1111
+ OR
1112
+ (m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
1113
+ )
1114
+ )
1115
+ ) AS query_${paramIdx}
1116
+ `);
1117
+ params.push(id, id, id, withNextMessages, withPreviousMessages);
1118
+ paramIdx++;
1133
1119
  }
1134
- }
1135
- async createTable({
1136
- tableName,
1137
- schema
1138
- }) {
1139
- try {
1140
- const fullTableName = this.getTableName(tableName);
1141
- const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
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)");
1120
+ const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
1121
+ const messages = await this.#db.executeQuery({ sql: finalQuery, params });
1122
+ if (!Array.isArray(messages)) {
1123
+ return [];
1124
+ }
1125
+ const processedMessages = messages.map((message) => {
1126
+ const processedMsg = {};
1127
+ for (const [key, value] of Object.entries(message)) {
1128
+ if (key === `type` && value === `v2`) continue;
1129
+ processedMsg[key] = deserializeValue(value);
1150
1130
  }
1151
- const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
1131
+ return processedMsg;
1132
+ });
1133
+ return processedMessages;
1134
+ }
1135
+ async listMessagesById({ messageIds }) {
1136
+ if (messageIds.length === 0) return { messages: [] };
1137
+ const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1138
+ const messages = [];
1139
+ try {
1140
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
1141
+ query.orderBy("createdAt", "DESC");
1152
1142
  const { sql, params } = query.build();
1153
- await this.executeQuery({ sql, params });
1154
- this.logger.debug(`Created table ${fullTableName}`);
1143
+ const result = await this.#db.executeQuery({ sql, params });
1144
+ if (Array.isArray(result)) messages.push(...result);
1145
+ const processedMessages = messages.map((message) => {
1146
+ const processedMsg = {};
1147
+ for (const [key, value] of Object.entries(message)) {
1148
+ if (key === `type` && value === `v2`) continue;
1149
+ processedMsg[key] = deserializeValue(value);
1150
+ }
1151
+ return processedMsg;
1152
+ });
1153
+ this.logger.debug(`Retrieved ${messages.length} messages`);
1154
+ const list = new agent.MessageList().add(processedMessages, "memory");
1155
+ return { messages: list.get.all.db() };
1155
1156
  } catch (error$1) {
1156
- throw new error.MastraError(
1157
+ const mastraError = new error.MastraError(
1157
1158
  {
1158
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_CREATE_TABLE_FAILED",
1159
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES_BY_ID", "FAILED"),
1159
1160
  domain: error.ErrorDomain.STORAGE,
1160
1161
  category: error.ErrorCategory.THIRD_PARTY,
1161
- details: { tableName }
1162
+ text: `Failed to retrieve messages by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1163
+ details: { messageIds: JSON.stringify(messageIds) }
1162
1164
  },
1163
1165
  error$1
1164
1166
  );
1167
+ this.logger?.error(mastraError.toString());
1168
+ this.logger?.trackException(mastraError);
1169
+ throw mastraError;
1165
1170
  }
1166
1171
  }
1167
- async clearTable({ tableName }) {
1168
- try {
1169
- const fullTableName = this.getTableName(tableName);
1170
- const query = createSqlBuilder().delete(fullTableName);
1171
- const { sql, params } = query.build();
1172
- await this.executeQuery({ sql, params });
1173
- this.logger.debug(`Cleared table ${fullTableName}`);
1174
- } catch (error$1) {
1172
+ async listMessages(args) {
1173
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
1174
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
1175
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
1175
1176
  throw new error.MastraError(
1176
1177
  {
1177
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_CLEAR_TABLE_FAILED",
1178
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_THREAD_ID"),
1178
1179
  domain: error.ErrorDomain.STORAGE,
1179
1180
  category: error.ErrorCategory.THIRD_PARTY,
1180
- details: { tableName }
1181
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
1181
1182
  },
1182
- error$1
1183
+ new Error("threadId must be a non-empty string or array of non-empty strings")
1183
1184
  );
1184
1185
  }
1185
- }
1186
- async dropTable({ tableName }) {
1187
- try {
1188
- const fullTableName = this.getTableName(tableName);
1189
- const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
1190
- await this.executeQuery({ sql });
1191
- this.logger.debug(`Dropped table ${fullTableName}`);
1192
- } catch (error$1) {
1186
+ if (page < 0) {
1193
1187
  throw new error.MastraError(
1194
1188
  {
1195
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_DROP_TABLE_FAILED",
1189
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_PAGE"),
1196
1190
  domain: error.ErrorDomain.STORAGE,
1197
- category: error.ErrorCategory.THIRD_PARTY,
1198
- details: { tableName }
1191
+ category: error.ErrorCategory.USER,
1192
+ details: { page }
1199
1193
  },
1200
- error$1
1194
+ new Error("page must be >= 0")
1201
1195
  );
1202
1196
  }
1203
- }
1204
- async alterTable(args) {
1197
+ const perPage = storage.normalizePerPage(perPageInput, 40);
1198
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1205
1199
  try {
1206
- const fullTableName = this.getTableName(args.tableName);
1207
- const existingColumns = await this.getTableColumns(fullTableName);
1208
- const existingColumnNames = new Set(existingColumns.map((col) => col.name));
1209
- for (const [columnName, column] of Object.entries(args.schema)) {
1210
- if (!existingColumnNames.has(columnName) && args.ifNotExists.includes(columnName)) {
1211
- const sqlType = this.getSqlType(column.type);
1212
- const defaultValue = this.getDefaultValue(column.type);
1213
- const sql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${defaultValue}`;
1214
- await this.executeQuery({ sql });
1215
- this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
1200
+ const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1201
+ let query = `
1202
+ SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
1203
+ FROM ${fullTableName}
1204
+ WHERE thread_id = ?
1205
+ `;
1206
+ const queryParams = [threadId];
1207
+ if (resourceId) {
1208
+ query += ` AND resourceId = ?`;
1209
+ queryParams.push(resourceId);
1210
+ }
1211
+ const dateRange = filter?.dateRange;
1212
+ if (dateRange?.start) {
1213
+ const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
1214
+ const startOp = dateRange.startExclusive ? ">" : ">=";
1215
+ query += ` AND createdAt ${startOp} ?`;
1216
+ queryParams.push(startDate);
1217
+ }
1218
+ if (dateRange?.end) {
1219
+ const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
1220
+ const endOp = dateRange.endExclusive ? "<" : "<=";
1221
+ query += ` AND createdAt ${endOp} ?`;
1222
+ queryParams.push(endDate);
1223
+ }
1224
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
1225
+ query += ` ORDER BY "${field}" ${direction}`;
1226
+ if (perPage !== Number.MAX_SAFE_INTEGER) {
1227
+ query += ` LIMIT ? OFFSET ?`;
1228
+ queryParams.push(perPage, offset);
1229
+ }
1230
+ const results = await this.#db.executeQuery({ sql: query, params: queryParams });
1231
+ const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
1232
+ const processedMsg = {};
1233
+ for (const [key, value] of Object.entries(message)) {
1234
+ if (key === `type` && value === `v2`) continue;
1235
+ processedMsg[key] = deserializeValue(value);
1236
+ }
1237
+ return processedMsg;
1238
+ });
1239
+ const paginatedCount = paginatedMessages.length;
1240
+ let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
1241
+ const countParams = [threadId];
1242
+ if (resourceId) {
1243
+ countQuery += ` AND resourceId = ?`;
1244
+ countParams.push(resourceId);
1245
+ }
1246
+ if (dateRange?.start) {
1247
+ const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
1248
+ const startOp = dateRange.startExclusive ? ">" : ">=";
1249
+ countQuery += ` AND createdAt ${startOp} ?`;
1250
+ countParams.push(startDate);
1251
+ }
1252
+ if (dateRange?.end) {
1253
+ const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
1254
+ const endOp = dateRange.endExclusive ? "<" : "<=";
1255
+ countQuery += ` AND createdAt ${endOp} ?`;
1256
+ countParams.push(endDate);
1257
+ }
1258
+ const countResult = await this.#db.executeQuery({ sql: countQuery, params: countParams });
1259
+ const total = Number(countResult[0]?.count ?? 0);
1260
+ if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
1261
+ return {
1262
+ messages: [],
1263
+ total: 0,
1264
+ page,
1265
+ perPage: perPageForResponse,
1266
+ hasMore: false
1267
+ };
1268
+ }
1269
+ const messageIds = new Set(paginatedMessages.map((m) => m.id));
1270
+ let includeMessages = [];
1271
+ if (include && include.length > 0) {
1272
+ const includeResult = await this._getIncludedMessages(include);
1273
+ if (Array.isArray(includeResult)) {
1274
+ includeMessages = includeResult;
1275
+ for (const includeMsg of includeMessages) {
1276
+ if (!messageIds.has(includeMsg.id)) {
1277
+ paginatedMessages.push(includeMsg);
1278
+ messageIds.add(includeMsg.id);
1279
+ }
1280
+ }
1216
1281
  }
1217
1282
  }
1283
+ const list = new agent.MessageList().add(paginatedMessages, "memory");
1284
+ let finalMessages = list.get.all.db();
1285
+ finalMessages = finalMessages.sort((a, b) => {
1286
+ const isDateField = field === "createdAt" || field === "updatedAt";
1287
+ const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
1288
+ const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
1289
+ if (aValue === bValue) {
1290
+ return a.id.localeCompare(b.id);
1291
+ }
1292
+ if (typeof aValue === "number" && typeof bValue === "number") {
1293
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
1294
+ }
1295
+ return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
1296
+ });
1297
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
1298
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
1299
+ const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
1300
+ return {
1301
+ messages: finalMessages,
1302
+ total,
1303
+ page,
1304
+ perPage: perPageForResponse,
1305
+ hasMore
1306
+ };
1218
1307
  } catch (error$1) {
1219
- throw new error.MastraError(
1308
+ const mastraError = new error.MastraError(
1220
1309
  {
1221
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_ALTER_TABLE_FAILED",
1310
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "FAILED"),
1222
1311
  domain: error.ErrorDomain.STORAGE,
1223
1312
  category: error.ErrorCategory.THIRD_PARTY,
1224
- details: { tableName: args.tableName }
1313
+ text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1314
+ details: {
1315
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
1316
+ resourceId: resourceId ?? ""
1317
+ }
1225
1318
  },
1226
1319
  error$1
1227
1320
  );
1321
+ this.logger?.error?.(mastraError.toString());
1322
+ this.logger?.trackException?.(mastraError);
1323
+ return {
1324
+ messages: [],
1325
+ total: 0,
1326
+ page,
1327
+ perPage: perPageForResponse,
1328
+ hasMore: false
1329
+ };
1228
1330
  }
1229
1331
  }
1230
- async insert({ tableName, record }) {
1231
- try {
1232
- const fullTableName = this.getTableName(tableName);
1233
- const processedRecord = await this.processRecord(record);
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) {
1240
- throw new error.MastraError(
1241
- {
1242
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_INSERT_FAILED",
1243
- domain: error.ErrorDomain.STORAGE,
1244
- category: error.ErrorCategory.THIRD_PARTY,
1245
- details: { tableName }
1246
- },
1247
- error$1
1248
- );
1332
+ async updateMessages(args) {
1333
+ const { messages } = args;
1334
+ this.logger.debug("Updating messages", { count: messages.length });
1335
+ if (!messages.length) {
1336
+ return [];
1249
1337
  }
1250
- }
1251
- async batchInsert({ tableName, records }) {
1338
+ const messageIds = messages.map((m) => m.id);
1339
+ const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1340
+ const threadsTableName = this.#db.getTableName(storage.TABLE_THREADS);
1252
1341
  try {
1253
- if (records.length === 0) return;
1254
- const fullTableName = this.getTableName(tableName);
1255
- const processedRecords = await Promise.all(records.map((record) => this.processRecord(record)));
1256
- const columns = Object.keys(processedRecords[0] || {});
1257
- for (const record of processedRecords) {
1258
- const values = Object.values(record);
1259
- const query = createSqlBuilder().insert(fullTableName, columns, values);
1260
- const { sql, params } = query.build();
1261
- await this.executeQuery({ sql, params });
1342
+ const placeholders = messageIds.map(() => "?").join(",");
1343
+ const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
1344
+ const existingMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
1345
+ if (existingMessages.length === 0) {
1346
+ return [];
1262
1347
  }
1263
- } catch (error$1) {
1264
- throw new error.MastraError(
1265
- {
1266
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_BATCH_INSERT_FAILED",
1267
- domain: error.ErrorDomain.STORAGE,
1268
- category: error.ErrorCategory.THIRD_PARTY,
1269
- details: { tableName }
1270
- },
1271
- error$1
1272
- );
1273
- }
1274
- }
1275
- async load({ tableName, keys }) {
1276
- try {
1277
- const fullTableName = this.getTableName(tableName);
1278
- const query = createSqlBuilder().select("*").from(fullTableName);
1279
- let firstKey = true;
1280
- for (const [key, value] of Object.entries(keys)) {
1281
- if (firstKey) {
1282
- query.where(`${key} = ?`, value);
1283
- firstKey = false;
1284
- } else {
1285
- query.andWhere(`${key} = ?`, value);
1348
+ const parsedExistingMessages = existingMessages.map((msg) => {
1349
+ if (typeof msg.content === "string") {
1350
+ try {
1351
+ msg.content = JSON.parse(msg.content);
1352
+ } catch {
1353
+ }
1354
+ }
1355
+ return msg;
1356
+ });
1357
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
1358
+ const updateQueries = [];
1359
+ for (const existingMessage of parsedExistingMessages) {
1360
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
1361
+ if (!updatePayload) continue;
1362
+ const { id, ...fieldsToUpdate } = updatePayload;
1363
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
1364
+ threadIdsToUpdate.add(existingMessage.threadId);
1365
+ if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
1366
+ threadIdsToUpdate.add(updatePayload.threadId);
1367
+ }
1368
+ const setClauses = [];
1369
+ const values = [];
1370
+ const updatableFields = { ...fieldsToUpdate };
1371
+ if (updatableFields.content) {
1372
+ const existingContent = existingMessage.content || {};
1373
+ const newContent = {
1374
+ ...existingContent,
1375
+ ...updatableFields.content,
1376
+ // Deep merge metadata if it exists on both
1377
+ ...existingContent?.metadata && updatableFields.content.metadata ? {
1378
+ metadata: {
1379
+ ...existingContent.metadata,
1380
+ ...updatableFields.content.metadata
1381
+ }
1382
+ } : {}
1383
+ };
1384
+ setClauses.push(`content = ?`);
1385
+ values.push(JSON.stringify(newContent));
1386
+ delete updatableFields.content;
1387
+ }
1388
+ for (const key in updatableFields) {
1389
+ if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
1390
+ const dbColumn = key === "threadId" ? "thread_id" : key;
1391
+ setClauses.push(`${dbColumn} = ?`);
1392
+ values.push(updatableFields[key]);
1393
+ }
1394
+ }
1395
+ if (setClauses.length > 0) {
1396
+ values.push(id);
1397
+ const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
1398
+ updateQueries.push({ sql: updateQuery, params: values });
1286
1399
  }
1287
1400
  }
1288
- query.orderBy("createdAt", "DESC");
1289
- query.limit(1);
1290
- const { sql, params } = query.build();
1291
- const result = await this.executeQuery({ sql, params, first: true });
1292
- if (!result) {
1293
- return null;
1401
+ for (const query of updateQueries) {
1402
+ await this.#db.executeQuery(query);
1294
1403
  }
1295
- const deserializedResult = {};
1296
- for (const [key, value] of Object.entries(result)) {
1297
- deserializedResult[key] = deserializeValue(value);
1404
+ if (threadIdsToUpdate.size > 0) {
1405
+ const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
1406
+ const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
1407
+ const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
1408
+ await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
1298
1409
  }
1299
- return deserializedResult;
1410
+ const updatedMessages = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
1411
+ return updatedMessages.map((message) => {
1412
+ if (typeof message.content === "string") {
1413
+ try {
1414
+ message.content = JSON.parse(message.content);
1415
+ } catch {
1416
+ }
1417
+ }
1418
+ return message;
1419
+ });
1300
1420
  } catch (error$1) {
1301
1421
  throw new error.MastraError(
1302
1422
  {
1303
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_LOAD_FAILED",
1423
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_MESSAGES", "FAILED"),
1304
1424
  domain: error.ErrorDomain.STORAGE,
1305
1425
  category: error.ErrorCategory.THIRD_PARTY,
1306
- details: { tableName }
1426
+ details: { count: messages.length }
1307
1427
  },
1308
1428
  error$1
1309
1429
  );
1310
1430
  }
1311
1431
  }
1312
- async processRecord(record) {
1313
- const processed = {};
1314
- for (const [key, value] of Object.entries(record)) {
1315
- processed[key] = this.serializeValue(value);
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);
1432
+ async deleteMessages(messageIds) {
1433
+ if (messageIds.length === 0) return;
1434
+ const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1435
+ const threadsTableName = this.#db.getTableName(storage.TABLE_THREADS);
1327
1436
  try {
1328
- const batchSize = 50;
1329
- for (let i = 0; i < records.length; i += batchSize) {
1330
- const batch = records.slice(i, i + batchSize);
1331
- const recordsToInsert = batch;
1332
- if (recordsToInsert.length > 0) {
1333
- const firstRecord = recordsToInsert[0];
1334
- const columns = Object.keys(firstRecord || {});
1335
- for (const record of recordsToInsert) {
1336
- const values = columns.map((col) => {
1337
- if (!record) return null;
1338
- const value = typeof col === "string" ? record[col] : null;
1339
- return this.serializeValue(value);
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
- );
1437
+ const placeholders = messageIds.map(() => "?").join(",");
1438
+ const selectQuery = `SELECT DISTINCT thread_id FROM ${fullTableName} WHERE id IN (${placeholders})`;
1439
+ const threadResults = await this.#db.executeQuery({ sql: selectQuery, params: messageIds });
1440
+ const threadIds = threadResults.map((r) => r.thread_id).filter(Boolean);
1441
+ const deleteQuery = createSqlBuilder().delete(fullTableName).where(`id IN (${placeholders})`, ...messageIds);
1442
+ const { sql, params } = deleteQuery.build();
1443
+ await this.#db.executeQuery({ sql, params });
1444
+ if (threadIds.length > 0) {
1445
+ const threadPlaceholders = threadIds.map(() => "?").join(",");
1446
+ const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
1447
+ const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...threadIds];
1448
+ await this.#db.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
1356
1449
  }
1357
- this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
1358
1450
  } catch (error$1) {
1359
1451
  throw new error.MastraError(
1360
1452
  {
1361
- id: "CLOUDFLARE_D1_STORAGE_BATCH_UPSERT_ERROR",
1453
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_MESSAGES", "FAILED"),
1362
1454
  domain: error.ErrorDomain.STORAGE,
1363
1455
  category: error.ErrorCategory.THIRD_PARTY,
1364
- text: `Failed to batch upsert into ${tableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1365
- details: { tableName }
1456
+ details: { messageIds: JSON.stringify(messageIds) }
1366
1457
  },
1367
1458
  error$1
1368
1459
  );
@@ -1370,32 +1461,31 @@ var StoreOperationsD1 = class extends storage.StoreOperations {
1370
1461
  }
1371
1462
  };
1372
1463
  function transformScoreRow(row) {
1373
- const deserialized = { ...row };
1374
- deserialized.input = storage.safelyParseJSON(row.input);
1375
- deserialized.output = storage.safelyParseJSON(row.output);
1376
- deserialized.scorer = storage.safelyParseJSON(row.scorer);
1377
- deserialized.preprocessStepResult = storage.safelyParseJSON(row.preprocessStepResult);
1378
- deserialized.analyzeStepResult = storage.safelyParseJSON(row.analyzeStepResult);
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;
1464
+ return storage.transformScoreRow(row, {
1465
+ preferredTimestampFields: {
1466
+ createdAt: "createdAtZ",
1467
+ updatedAt: "updatedAtZ"
1468
+ }
1469
+ });
1386
1470
  }
1387
1471
  var ScoresStorageD1 = class extends storage.ScoresStorage {
1388
- operations;
1389
- constructor({ operations }) {
1472
+ #db;
1473
+ constructor(config) {
1390
1474
  super();
1391
- this.operations = operations;
1475
+ this.#db = new D1DB(resolveD1Config(config));
1476
+ }
1477
+ async init() {
1478
+ await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS] });
1479
+ }
1480
+ async dangerouslyClearAll() {
1481
+ await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
1392
1482
  }
1393
1483
  async getScoreById({ id }) {
1394
1484
  try {
1395
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1485
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1396
1486
  const query = createSqlBuilder().select("*").from(fullTableName).where("id = ?", id);
1397
1487
  const { sql, params } = query.build();
1398
- const result = await this.operations.executeQuery({ sql, params, first: true });
1488
+ const result = await this.#db.executeQuery({ sql, params, first: true });
1399
1489
  if (!result) {
1400
1490
  return null;
1401
1491
  }
@@ -1403,7 +1493,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1403
1493
  } catch (error$1) {
1404
1494
  throw new error.MastraError(
1405
1495
  {
1406
- id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORE_BY_ID_FAILED",
1496
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORE_BY_ID", "FAILED"),
1407
1497
  domain: error.ErrorDomain.STORAGE,
1408
1498
  category: error.ErrorCategory.THIRD_PARTY
1409
1499
  },
@@ -1418,17 +1508,23 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1418
1508
  } catch (error$1) {
1419
1509
  throw new error.MastraError(
1420
1510
  {
1421
- id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
1511
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "VALIDATION_FAILED"),
1422
1512
  domain: error.ErrorDomain.STORAGE,
1423
1513
  category: error.ErrorCategory.USER,
1424
- details: { scoreId: score.id }
1514
+ details: {
1515
+ scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
1516
+ entityId: score.entityId ?? "unknown",
1517
+ entityType: score.entityType ?? "unknown",
1518
+ traceId: score.traceId ?? "",
1519
+ spanId: score.spanId ?? ""
1520
+ }
1425
1521
  },
1426
1522
  error$1
1427
1523
  );
1428
1524
  }
1525
+ const id = crypto.randomUUID();
1429
1526
  try {
1430
- const id = crypto.randomUUID();
1431
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1527
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1432
1528
  const serializedRecord = {};
1433
1529
  for (const [key, value] of Object.entries(parsedScore)) {
1434
1530
  if (value !== null && value !== void 0) {
@@ -1441,22 +1537,23 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1441
1537
  serializedRecord[key] = null;
1442
1538
  }
1443
1539
  }
1540
+ const now = /* @__PURE__ */ new Date();
1444
1541
  serializedRecord.id = id;
1445
- serializedRecord.createdAt = (/* @__PURE__ */ new Date()).toISOString();
1446
- serializedRecord.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1542
+ serializedRecord.createdAt = now.toISOString();
1543
+ serializedRecord.updatedAt = now.toISOString();
1447
1544
  const columns = Object.keys(serializedRecord);
1448
1545
  const values = Object.values(serializedRecord);
1449
1546
  const query = createSqlBuilder().insert(fullTableName, columns, values);
1450
1547
  const { sql, params } = query.build();
1451
- await this.operations.executeQuery({ sql, params });
1452
- const scoreFromDb = await this.getScoreById({ id });
1453
- return { score: scoreFromDb };
1548
+ await this.#db.executeQuery({ sql, params });
1549
+ return { score: { ...parsedScore, id, createdAt: now, updatedAt: now } };
1454
1550
  } catch (error$1) {
1455
1551
  throw new error.MastraError(
1456
1552
  {
1457
- id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED",
1553
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_SCORE", "FAILED"),
1458
1554
  domain: error.ErrorDomain.STORAGE,
1459
- category: error.ErrorCategory.THIRD_PARTY
1555
+ category: error.ErrorCategory.THIRD_PARTY,
1556
+ details: { id }
1460
1557
  },
1461
1558
  error$1
1462
1559
  );
@@ -1473,7 +1570,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1473
1570
  const { page, perPage: perPageInput } = pagination;
1474
1571
  const perPage = storage.normalizePerPage(perPageInput, 100);
1475
1572
  const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1476
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1573
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1477
1574
  const countQuery = createSqlBuilder().count().from(fullTableName).where("scorerId = ?", scorerId);
1478
1575
  if (entityId) {
1479
1576
  countQuery.andWhere("entityId = ?", entityId);
@@ -1484,7 +1581,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1484
1581
  if (source) {
1485
1582
  countQuery.andWhere("source = ?", source);
1486
1583
  }
1487
- const countResult = await this.operations.executeQuery(countQuery.build());
1584
+ const countResult = await this.#db.executeQuery(countQuery.build());
1488
1585
  const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1489
1586
  if (total === 0) {
1490
1587
  return {
@@ -1511,7 +1608,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1511
1608
  }
1512
1609
  selectQuery.limit(limitValue).offset(start);
1513
1610
  const { sql, params } = selectQuery.build();
1514
- const results = await this.operations.executeQuery({ sql, params });
1611
+ const results = await this.#db.executeQuery({ sql, params });
1515
1612
  const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1516
1613
  return {
1517
1614
  pagination: {
@@ -1525,7 +1622,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1525
1622
  } catch (error$1) {
1526
1623
  throw new error.MastraError(
1527
1624
  {
1528
- id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SCORER_ID_FAILED",
1625
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SCORER_ID", "FAILED"),
1529
1626
  domain: error.ErrorDomain.STORAGE,
1530
1627
  category: error.ErrorCategory.THIRD_PARTY
1531
1628
  },
@@ -1541,9 +1638,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1541
1638
  const { page, perPage: perPageInput } = pagination;
1542
1639
  const perPage = storage.normalizePerPage(perPageInput, 100);
1543
1640
  const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1544
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1641
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1545
1642
  const countQuery = createSqlBuilder().count().from(fullTableName).where("runId = ?", runId);
1546
- const countResult = await this.operations.executeQuery(countQuery.build());
1643
+ const countResult = await this.#db.executeQuery(countQuery.build());
1547
1644
  const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1548
1645
  if (total === 0) {
1549
1646
  return {
@@ -1560,7 +1657,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1560
1657
  const limitValue = perPageInput === false ? total : perPage;
1561
1658
  const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("runId = ?", runId).limit(limitValue).offset(start);
1562
1659
  const { sql, params } = selectQuery.build();
1563
- const results = await this.operations.executeQuery({ sql, params });
1660
+ const results = await this.#db.executeQuery({ sql, params });
1564
1661
  const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1565
1662
  return {
1566
1663
  pagination: {
@@ -1574,7 +1671,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1574
1671
  } catch (error$1) {
1575
1672
  throw new error.MastraError(
1576
1673
  {
1577
- id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_RUN_ID_FAILED",
1674
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_RUN_ID", "FAILED"),
1578
1675
  domain: error.ErrorDomain.STORAGE,
1579
1676
  category: error.ErrorCategory.THIRD_PARTY
1580
1677
  },
@@ -1591,9 +1688,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1591
1688
  const { page, perPage: perPageInput } = pagination;
1592
1689
  const perPage = storage.normalizePerPage(perPageInput, 100);
1593
1690
  const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1594
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1691
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1595
1692
  const countQuery = createSqlBuilder().count().from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType);
1596
- const countResult = await this.operations.executeQuery(countQuery.build());
1693
+ const countResult = await this.#db.executeQuery(countQuery.build());
1597
1694
  const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1598
1695
  if (total === 0) {
1599
1696
  return {
@@ -1610,7 +1707,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1610
1707
  const limitValue = perPageInput === false ? total : perPage;
1611
1708
  const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType).limit(limitValue).offset(start);
1612
1709
  const { sql, params } = selectQuery.build();
1613
- const results = await this.operations.executeQuery({ sql, params });
1710
+ const results = await this.#db.executeQuery({ sql, params });
1614
1711
  const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1615
1712
  return {
1616
1713
  pagination: {
@@ -1624,7 +1721,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1624
1721
  } catch (error$1) {
1625
1722
  throw new error.MastraError(
1626
1723
  {
1627
- id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_ENTITY_ID_FAILED",
1724
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_ENTITY_ID", "FAILED"),
1628
1725
  domain: error.ErrorDomain.STORAGE,
1629
1726
  category: error.ErrorCategory.THIRD_PARTY
1630
1727
  },
@@ -1641,9 +1738,9 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1641
1738
  const { page, perPage: perPageInput } = pagination;
1642
1739
  const perPage = storage.normalizePerPage(perPageInput, 100);
1643
1740
  const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1644
- const fullTableName = this.operations.getTableName(storage.TABLE_SCORERS);
1741
+ const fullTableName = this.#db.getTableName(storage.TABLE_SCORERS);
1645
1742
  const countQuery = createSqlBuilder().count().from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId);
1646
- const countResult = await this.operations.executeQuery(countQuery.build());
1743
+ const countResult = await this.#db.executeQuery(countQuery.build());
1647
1744
  const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1648
1745
  if (total === 0) {
1649
1746
  return {
@@ -1660,7 +1757,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1660
1757
  const limitValue = perPageInput === false ? total : perPage;
1661
1758
  const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId).orderBy("createdAt", "DESC").limit(limitValue).offset(start);
1662
1759
  const { sql, params } = selectQuery.build();
1663
- const results = await this.operations.executeQuery({ sql, params });
1760
+ const results = await this.#db.executeQuery({ sql, params });
1664
1761
  const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1665
1762
  return {
1666
1763
  pagination: {
@@ -1674,7 +1771,7 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1674
1771
  } catch (error$1) {
1675
1772
  throw new error.MastraError(
1676
1773
  {
1677
- id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SPAN_FAILED",
1774
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_SCORES_BY_SPAN", "FAILED"),
1678
1775
  domain: error.ErrorDomain.STORAGE,
1679
1776
  category: error.ErrorCategory.THIRD_PARTY
1680
1777
  },
@@ -1684,10 +1781,16 @@ var ScoresStorageD1 = class extends storage.ScoresStorage {
1684
1781
  }
1685
1782
  };
1686
1783
  var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1687
- operations;
1688
- constructor({ operations }) {
1784
+ #db;
1785
+ constructor(config) {
1689
1786
  super();
1690
- this.operations = operations;
1787
+ this.#db = new D1DB(resolveD1Config(config));
1788
+ }
1789
+ async init() {
1790
+ await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT] });
1791
+ }
1792
+ async dangerouslyClearAll() {
1793
+ await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
1691
1794
  }
1692
1795
  updateWorkflowResults({
1693
1796
  // workflowName,
@@ -1709,11 +1812,13 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1709
1812
  workflowName,
1710
1813
  runId,
1711
1814
  resourceId,
1712
- snapshot
1815
+ snapshot,
1816
+ createdAt,
1817
+ updatedAt
1713
1818
  }) {
1714
- const fullTableName = this.operations.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1819
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1715
1820
  const now = (/* @__PURE__ */ new Date()).toISOString();
1716
- const currentSnapshot = await this.operations.load({
1821
+ const currentSnapshot = await this.#db.load({
1717
1822
  tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1718
1823
  keys: { workflow_name: workflowName, run_id: runId }
1719
1824
  });
@@ -1721,16 +1826,16 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1721
1826
  ...currentSnapshot,
1722
1827
  resourceId,
1723
1828
  snapshot: JSON.stringify(snapshot),
1724
- updatedAt: now
1829
+ updatedAt: updatedAt ? updatedAt.toISOString() : now
1725
1830
  } : {
1726
1831
  workflow_name: workflowName,
1727
1832
  run_id: runId,
1728
1833
  resourceId,
1729
1834
  snapshot,
1730
- createdAt: now,
1731
- updatedAt: now
1835
+ createdAt: createdAt ? createdAt.toISOString() : now,
1836
+ updatedAt: updatedAt ? updatedAt.toISOString() : now
1732
1837
  };
1733
- const processedRecord = await this.operations.processRecord(persisting);
1838
+ const processedRecord = await this.#db.processRecord(persisting);
1734
1839
  const columns = Object.keys(processedRecord);
1735
1840
  const values = Object.values(processedRecord);
1736
1841
  const updateMap = {
@@ -1741,11 +1846,11 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1741
1846
  const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
1742
1847
  const { sql, params } = query.build();
1743
1848
  try {
1744
- await this.operations.executeQuery({ sql, params });
1849
+ await this.#db.executeQuery({ sql, params });
1745
1850
  } catch (error$1) {
1746
1851
  throw new error.MastraError(
1747
1852
  {
1748
- id: "CLOUDFLARE_D1_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_ERROR",
1853
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1749
1854
  domain: error.ErrorDomain.STORAGE,
1750
1855
  category: error.ErrorCategory.THIRD_PARTY,
1751
1856
  text: `Failed to persist workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1759,7 +1864,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1759
1864
  const { workflowName, runId } = params;
1760
1865
  this.logger.debug("Loading workflow snapshot", { workflowName, runId });
1761
1866
  try {
1762
- const d = await this.operations.load({
1867
+ const d = await this.#db.load({
1763
1868
  tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1764
1869
  keys: {
1765
1870
  workflow_name: workflowName,
@@ -1770,7 +1875,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1770
1875
  } catch (error$1) {
1771
1876
  throw new error.MastraError(
1772
1877
  {
1773
- id: "CLOUDFLARE_D1_STORAGE_LOAD_WORKFLOW_SNAPSHOT_ERROR",
1878
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1774
1879
  domain: error.ErrorDomain.STORAGE,
1775
1880
  category: error.ErrorCategory.THIRD_PARTY,
1776
1881
  text: `Failed to load workflow snapshot: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1786,7 +1891,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1786
1891
  try {
1787
1892
  parsedSnapshot = JSON.parse(row.snapshot);
1788
1893
  } catch (e) {
1789
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1894
+ this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1790
1895
  }
1791
1896
  }
1792
1897
  return {
@@ -1804,20 +1909,25 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1804
1909
  toDate,
1805
1910
  page,
1806
1911
  perPage,
1807
- resourceId
1912
+ resourceId,
1913
+ status
1808
1914
  } = {}) {
1809
- const fullTableName = this.operations.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1915
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1810
1916
  try {
1811
1917
  const builder = createSqlBuilder().select().from(fullTableName);
1812
1918
  const countBuilder = createSqlBuilder().count().from(fullTableName);
1813
1919
  if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
1920
+ if (status) {
1921
+ builder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
1922
+ countBuilder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
1923
+ }
1814
1924
  if (resourceId) {
1815
- const hasResourceId = await this.operations.hasColumn(fullTableName, "resourceId");
1925
+ const hasResourceId = await this.#db.hasColumn(fullTableName, "resourceId");
1816
1926
  if (hasResourceId) {
1817
1927
  builder.whereAnd("resourceId = ?", resourceId);
1818
1928
  countBuilder.whereAnd("resourceId = ?", resourceId);
1819
1929
  } else {
1820
- console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1930
+ this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1821
1931
  }
1822
1932
  }
1823
1933
  if (fromDate) {
@@ -1838,20 +1948,20 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1838
1948
  let total = 0;
1839
1949
  if (perPage !== void 0 && page !== void 0) {
1840
1950
  const { sql: countSql, params: countParams } = countBuilder.build();
1841
- const countResult = await this.operations.executeQuery({
1951
+ const countResult = await this.#db.executeQuery({
1842
1952
  sql: countSql,
1843
1953
  params: countParams,
1844
1954
  first: true
1845
1955
  });
1846
1956
  total = Number(countResult?.count ?? 0);
1847
1957
  }
1848
- const results = await this.operations.executeQuery({ sql, params });
1958
+ const results = await this.#db.executeQuery({ sql, params });
1849
1959
  const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1850
1960
  return { runs, total: total || runs.length };
1851
1961
  } catch (error$1) {
1852
1962
  throw new error.MastraError(
1853
1963
  {
1854
- id: "CLOUDFLARE_D1_STORAGE_LIST_WORKFLOW_RUNS_ERROR",
1964
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_WORKFLOW_RUNS", "FAILED"),
1855
1965
  domain: error.ErrorDomain.STORAGE,
1856
1966
  category: error.ErrorCategory.THIRD_PARTY,
1857
1967
  text: `Failed to retrieve workflow runs: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1868,7 +1978,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1868
1978
  runId,
1869
1979
  workflowName
1870
1980
  }) {
1871
- const fullTableName = this.operations.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1981
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1872
1982
  try {
1873
1983
  const conditions = [];
1874
1984
  const params = [];
@@ -1882,13 +1992,13 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1882
1992
  }
1883
1993
  const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1884
1994
  const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1885
- const result = await this.operations.executeQuery({ sql, params, first: true });
1995
+ const result = await this.#db.executeQuery({ sql, params, first: true });
1886
1996
  if (!result) return null;
1887
1997
  return this.parseWorkflowRun(result);
1888
1998
  } catch (error$1) {
1889
1999
  throw new error.MastraError(
1890
2000
  {
1891
- id: "CLOUDFLARE_D1_STORAGE_GET_WORKFLOW_RUN_BY_ID_ERROR",
2001
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1892
2002
  domain: error.ErrorDomain.STORAGE,
1893
2003
  category: error.ErrorCategory.THIRD_PARTY,
1894
2004
  text: `Failed to retrieve workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1898,13 +2008,31 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1898
2008
  );
1899
2009
  }
1900
2010
  }
2011
+ async deleteWorkflowRunById({ runId, workflowName }) {
2012
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
2013
+ try {
2014
+ const sql = `DELETE FROM ${fullTableName} WHERE workflow_name = ? AND run_id = ?`;
2015
+ const params = [workflowName, runId];
2016
+ await this.#db.executeQuery({ sql, params });
2017
+ } catch (error$1) {
2018
+ throw new error.MastraError(
2019
+ {
2020
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
2021
+ domain: error.ErrorDomain.STORAGE,
2022
+ category: error.ErrorCategory.THIRD_PARTY,
2023
+ text: `Failed to delete workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
2024
+ details: { runId, workflowName }
2025
+ },
2026
+ error$1
2027
+ );
2028
+ }
2029
+ }
1901
2030
  };
1902
2031
 
1903
2032
  // src/storage/index.ts
1904
2033
  var D1Store = class extends storage.MastraStorage {
1905
2034
  client;
1906
2035
  binding;
1907
- // D1Database binding
1908
2036
  tablePrefix;
1909
2037
  stores;
1910
2038
  /**
@@ -1913,7 +2041,7 @@ var D1Store = class extends storage.MastraStorage {
1913
2041
  */
1914
2042
  constructor(config) {
1915
2043
  try {
1916
- super({ id: config.id, name: "D1" });
2044
+ super({ id: config.id, name: "D1", disableInit: config.disableInit });
1917
2045
  if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
1918
2046
  throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
1919
2047
  }
@@ -1951,7 +2079,7 @@ var D1Store = class extends storage.MastraStorage {
1951
2079
  } catch (error$1) {
1952
2080
  throw new error.MastraError(
1953
2081
  {
1954
- id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
2082
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "INITIALIZATION", "FAILED"),
1955
2083
  domain: error.ErrorDomain.STORAGE,
1956
2084
  category: error.ErrorCategory.SYSTEM,
1957
2085
  text: "Error initializing D1Store"
@@ -1959,196 +2087,26 @@ var D1Store = class extends storage.MastraStorage {
1959
2087
  error$1
1960
2088
  );
1961
2089
  }
1962
- const operations = new StoreOperationsD1({
1963
- client: this.client,
1964
- binding: this.binding,
1965
- tablePrefix: this.tablePrefix
1966
- });
1967
- const scores = new ScoresStorageD1({
1968
- operations
1969
- });
1970
- const workflows = new WorkflowsStorageD1({
1971
- operations
1972
- });
1973
- const memory = new MemoryStorageD1({
1974
- operations
1975
- });
2090
+ let scores;
2091
+ let workflows;
2092
+ let memory;
2093
+ if (this.binding) {
2094
+ const domainConfig = { binding: this.binding, tablePrefix: this.tablePrefix };
2095
+ scores = new ScoresStorageD1(domainConfig);
2096
+ workflows = new WorkflowsStorageD1(domainConfig);
2097
+ memory = new MemoryStorageD1(domainConfig);
2098
+ } else {
2099
+ const domainConfig = { client: this.client, tablePrefix: this.tablePrefix };
2100
+ scores = new ScoresStorageD1(domainConfig);
2101
+ workflows = new WorkflowsStorageD1(domainConfig);
2102
+ memory = new MemoryStorageD1(domainConfig);
2103
+ }
1976
2104
  this.stores = {
1977
- operations,
1978
2105
  scores,
1979
2106
  workflows,
1980
2107
  memory
1981
2108
  };
1982
2109
  }
1983
- get supports() {
1984
- return {
1985
- selectByIncludeResourceScope: true,
1986
- resourceWorkingMemory: true,
1987
- hasColumn: true,
1988
- createTable: true,
1989
- deleteMessages: false,
1990
- listScoresBySpan: true
1991
- };
1992
- }
1993
- async createTable({
1994
- tableName,
1995
- schema
1996
- }) {
1997
- return this.stores.operations.createTable({ tableName, schema });
1998
- }
1999
- /**
2000
- * Alters table schema to add columns if they don't exist
2001
- * @param tableName Name of the table
2002
- * @param schema Schema of the table
2003
- * @param ifNotExists Array of column names to add if they don't exist
2004
- */
2005
- async alterTable({
2006
- tableName,
2007
- schema,
2008
- ifNotExists
2009
- }) {
2010
- return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
2011
- }
2012
- async clearTable({ tableName }) {
2013
- return this.stores.operations.clearTable({ tableName });
2014
- }
2015
- async dropTable({ tableName }) {
2016
- return this.stores.operations.dropTable({ tableName });
2017
- }
2018
- async hasColumn(table, column) {
2019
- return this.stores.operations.hasColumn(table, column);
2020
- }
2021
- async insert({ tableName, record }) {
2022
- return this.stores.operations.insert({ tableName, record });
2023
- }
2024
- async load({ tableName, keys }) {
2025
- return this.stores.operations.load({ tableName, keys });
2026
- }
2027
- async getThreadById({ threadId }) {
2028
- return this.stores.memory.getThreadById({ threadId });
2029
- }
2030
- async saveThread({ thread }) {
2031
- return this.stores.memory.saveThread({ thread });
2032
- }
2033
- async updateThread({
2034
- id,
2035
- title,
2036
- metadata
2037
- }) {
2038
- return this.stores.memory.updateThread({ id, title, metadata });
2039
- }
2040
- async deleteThread({ threadId }) {
2041
- return this.stores.memory.deleteThread({ threadId });
2042
- }
2043
- async saveMessages(args) {
2044
- return this.stores.memory.saveMessages(args);
2045
- }
2046
- async updateWorkflowResults({
2047
- workflowName,
2048
- runId,
2049
- stepId,
2050
- result,
2051
- requestContext
2052
- }) {
2053
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2054
- }
2055
- async updateWorkflowState({
2056
- workflowName,
2057
- runId,
2058
- opts
2059
- }) {
2060
- return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2061
- }
2062
- async persistWorkflowSnapshot({
2063
- workflowName,
2064
- runId,
2065
- resourceId,
2066
- snapshot
2067
- }) {
2068
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2069
- }
2070
- async loadWorkflowSnapshot(params) {
2071
- return this.stores.workflows.loadWorkflowSnapshot(params);
2072
- }
2073
- async listWorkflowRuns({
2074
- workflowName,
2075
- fromDate,
2076
- toDate,
2077
- perPage,
2078
- page,
2079
- resourceId
2080
- } = {}) {
2081
- return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
2082
- }
2083
- async getWorkflowRunById({
2084
- runId,
2085
- workflowName
2086
- }) {
2087
- return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2088
- }
2089
- /**
2090
- * Insert multiple records in a batch operation
2091
- * @param tableName The table to insert into
2092
- * @param records The records to insert
2093
- */
2094
- async batchInsert({ tableName, records }) {
2095
- return this.stores.operations.batchInsert({ tableName, records });
2096
- }
2097
- async updateMessages(_args) {
2098
- return this.stores.memory.updateMessages(_args);
2099
- }
2100
- async getResourceById({ resourceId }) {
2101
- return this.stores.memory.getResourceById({ resourceId });
2102
- }
2103
- async saveResource({ resource }) {
2104
- return this.stores.memory.saveResource({ resource });
2105
- }
2106
- async updateResource({
2107
- resourceId,
2108
- workingMemory,
2109
- metadata
2110
- }) {
2111
- return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2112
- }
2113
- async getScoreById({ id: _id }) {
2114
- return this.stores.scores.getScoreById({ id: _id });
2115
- }
2116
- async saveScore(_score) {
2117
- return this.stores.scores.saveScore(_score);
2118
- }
2119
- async listScoresByRunId({
2120
- runId: _runId,
2121
- pagination: _pagination
2122
- }) {
2123
- return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2124
- }
2125
- async listScoresByEntityId({
2126
- entityId: _entityId,
2127
- entityType: _entityType,
2128
- pagination: _pagination
2129
- }) {
2130
- return this.stores.scores.listScoresByEntityId({
2131
- entityId: _entityId,
2132
- entityType: _entityType,
2133
- pagination: _pagination
2134
- });
2135
- }
2136
- async listScoresByScorerId({
2137
- scorerId,
2138
- pagination,
2139
- entityId,
2140
- entityType,
2141
- source
2142
- }) {
2143
- return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
2144
- }
2145
- async listScoresBySpan({
2146
- traceId,
2147
- spanId,
2148
- pagination
2149
- }) {
2150
- return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2151
- }
2152
2110
  /**
2153
2111
  * Close the database connection
2154
2112
  * No explicit cleanup needed for D1 in either REST or Workers Binding mode
@@ -2159,5 +2117,8 @@ var D1Store = class extends storage.MastraStorage {
2159
2117
  };
2160
2118
 
2161
2119
  exports.D1Store = D1Store;
2120
+ exports.MemoryStorageD1 = MemoryStorageD1;
2121
+ exports.ScoresStorageD1 = ScoresStorageD1;
2122
+ exports.WorkflowsStorageD1 = WorkflowsStorageD1;
2162
2123
  //# sourceMappingURL=index.cjs.map
2163
2124
  //# sourceMappingURL=index.cjs.map