@mastra/cloudflare-d1 1.0.0-beta.1 → 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,1127 +259,1201 @@ 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);
688
- }
689
- return processedMsg;
690
- });
691
- return processedMessages;
630
+ return processed;
692
631
  }
693
- async listMessagesById({ messageIds }) {
694
- if (messageIds.length === 0) return { messages: [] };
695
- const fullTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
696
- const messages = [];
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);
697
640
  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);
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
+ }
708
665
  }
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() };
666
+ this.logger.debug(
667
+ `Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
668
+ );
669
+ }
670
+ this.logger.debug(`Successfully batch upserted ${records.length} records into ${tableName}`);
714
671
  } catch (error$1) {
715
- const mastraError = new error.MastraError(
672
+ throw new error.MastraError(
716
673
  {
717
- id: "CLOUDFLARE_D1_STORAGE_LIST_MESSAGES_BY_ID_ERROR",
674
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "BATCH_UPSERT", "FAILED"),
718
675
  domain: error.ErrorDomain.STORAGE,
719
676
  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) }
677
+ text: `Failed to batch upsert into ${tableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
678
+ details: { tableName }
722
679
  },
723
680
  error$1
724
681
  );
725
- this.logger?.error(mastraError.toString());
726
- this.logger?.trackException(mastraError);
727
- throw mastraError;
728
682
  }
729
683
  }
730
- async listMessages(args) {
731
- const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
732
- if (!threadId.trim()) {
733
- throw new error.MastraError(
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"]
701
+ });
702
+ }
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;
714
+ try {
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
+ };
721
+ } catch (error$1) {
722
+ const mastraError = new error.MastraError(
734
723
  {
735
- id: "STORAGE_CLOUDFLARE_D1_LIST_MESSAGES_INVALID_THREAD_ID",
724
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_RESOURCE_BY_ID", "FAILED"),
736
725
  domain: error.ErrorDomain.STORAGE,
737
726
  category: error.ErrorCategory.THIRD_PARTY,
738
- details: { threadId }
739
- },
740
- new Error("threadId must be a non-empty string")
741
- );
742
- }
743
- if (page < 0) {
744
- throw new error.MastraError(
745
- {
746
- id: "STORAGE_CLOUDFLARE_D1_LIST_MESSAGES_INVALID_PAGE",
747
- domain: error.ErrorDomain.STORAGE,
748
- category: error.ErrorCategory.USER,
749
- details: { page }
727
+ text: `Error processing resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
728
+ details: { resourceId }
750
729
  },
751
- new Error("page must be >= 0")
730
+ error$1
752
731
  );
732
+ this.logger?.error(mastraError.toString());
733
+ this.logger?.trackException(mastraError);
734
+ return null;
753
735
  }
754
- const perPage = storage.normalizePerPage(perPageInput, 40);
755
- const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
736
+ }
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();
756
757
  try {
757
- const fullTableName = this.operations.getTableName(storage.TABLE_MESSAGES);
758
- let query = `
759
- SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
760
- FROM ${fullTableName}
761
- WHERE thread_id = ?
762
- `;
763
- const queryParams = [threadId];
764
- if (resourceId) {
765
- query += ` AND resourceId = ?`;
766
- queryParams.push(resourceId);
767
- }
768
- const dateRange = filter?.dateRange;
769
- if (dateRange?.start) {
770
- const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
771
- query += ` AND createdAt >= ?`;
772
- queryParams.push(startDate);
773
- }
774
- if (dateRange?.end) {
775
- const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
776
- query += ` AND createdAt <= ?`;
777
- queryParams.push(endDate);
778
- }
779
- const { field, direction } = this.parseOrderBy(orderBy, "ASC");
780
- query += ` ORDER BY "${field}" ${direction}`;
781
- if (perPage !== Number.MAX_SAFE_INTEGER) {
782
- query += ` LIMIT ? OFFSET ?`;
783
- queryParams.push(perPage, offset);
784
- }
785
- const results = await this.operations.executeQuery({ sql: query, params: queryParams });
786
- const paginatedMessages = (isArrayOfRecords(results) ? results : []).map((message) => {
787
- const processedMsg = {};
788
- for (const [key, value] of Object.entries(message)) {
789
- if (key === `type` && value === `v2`) continue;
790
- processedMsg[key] = deserializeValue(value);
791
- }
792
- return processedMsg;
793
- });
794
- const paginatedCount = paginatedMessages.length;
795
- let countQuery = `SELECT count() as count FROM ${fullTableName} WHERE thread_id = ?`;
796
- const countParams = [threadId];
797
- if (resourceId) {
798
- countQuery += ` AND resourceId = ?`;
799
- countParams.push(resourceId);
800
- }
801
- if (dateRange?.start) {
802
- const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
803
- countQuery += ` AND createdAt >= ?`;
804
- countParams.push(startDate);
805
- }
806
- if (dateRange?.end) {
807
- const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
808
- countQuery += ` AND createdAt <= ?`;
809
- countParams.push(endDate);
810
- }
811
- const countResult = await this.operations.executeQuery({ sql: countQuery, params: countParams });
812
- const total = Number(countResult[0]?.count ?? 0);
813
- if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
814
- return {
815
- messages: [],
816
- total: 0,
817
- page,
818
- perPage: perPageForResponse,
819
- hasMore: false
820
- };
821
- }
822
- const messageIds = new Set(paginatedMessages.map((m) => m.id));
823
- let includeMessages = [];
824
- if (include && include.length > 0) {
825
- const includeResult = await this._getIncludedMessages(threadId, include);
826
- if (Array.isArray(includeResult)) {
827
- includeMessages = includeResult;
828
- for (const includeMsg of includeMessages) {
829
- if (!messageIds.has(includeMsg.id)) {
830
- paginatedMessages.push(includeMsg);
831
- messageIds.add(includeMsg.id);
832
- }
833
- }
834
- }
835
- }
836
- const list = new agent.MessageList().add(paginatedMessages, "memory");
837
- let finalMessages = list.get.all.db();
838
- finalMessages = finalMessages.sort((a, b) => {
839
- const isDateField = field === "createdAt" || field === "updatedAt";
840
- const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
841
- const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
842
- if (aValue === bValue) {
843
- return a.id.localeCompare(b.id);
844
- }
845
- if (typeof aValue === "number" && typeof bValue === "number") {
846
- return direction === "ASC" ? aValue - bValue : bValue - aValue;
847
- }
848
- return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
849
- });
850
- const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
851
- const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
852
- const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
853
- return {
854
- messages: finalMessages,
855
- total,
856
- page,
857
- perPage: perPageForResponse,
858
- hasMore
859
- };
758
+ await this.#db.executeQuery({ sql, params });
759
+ return resource;
860
760
  } catch (error$1) {
861
- const mastraError = new error.MastraError(
761
+ throw new error.MastraError(
862
762
  {
863
- id: "CLOUDFLARE_D1_STORAGE_LIST_MESSAGES_ERROR",
763
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_RESOURCE", "FAILED"),
864
764
  domain: error.ErrorDomain.STORAGE,
865
765
  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
- }
766
+ text: `Failed to save resource to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
767
+ details: { resourceId: resource.id }
871
768
  },
872
769
  error$1
873
770
  );
874
- this.logger?.error?.(mastraError.toString());
875
- this.logger?.trackException?.(mastraError);
876
- return {
877
- messages: [],
878
- total: 0,
879
- page,
880
- perPage: perPageForResponse,
881
- hasMore: false
882
- };
883
771
  }
884
772
  }
885
- async updateMessages(args) {
886
- const { messages } = args;
887
- this.logger.debug("Updating messages", { count: messages.length });
888
- if (!messages.length) {
889
- return [];
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 });
890
788
  }
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);
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();
894
804
  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
- });
805
+ await this.#db.executeQuery({ sql, params });
806
+ return updatedResource;
973
807
  } catch (error$1) {
974
808
  throw new error.MastraError(
975
809
  {
976
- id: "CLOUDFLARE_D1_STORAGE_UPDATE_MESSAGES_FAILED",
810
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_RESOURCE", "FAILED"),
977
811
  domain: error.ErrorDomain.STORAGE,
978
812
  category: error.ErrorCategory.THIRD_PARTY,
979
- details: { count: messages.length }
813
+ text: `Failed to update resource ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
814
+ details: { resourceId }
980
815
  },
981
816
  error$1
982
817
  );
983
818
  }
984
819
  }
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
1013
- }) {
1014
- if (!this.binding) {
1015
- throw new Error("Workers binding is not configured");
1016
- }
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;
1017
826
  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
- }
1041
- }
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
+ };
1042
833
  } catch (error$1) {
1043
- throw new error.MastraError(
834
+ const mastraError = new error.MastraError(
1044
835
  {
1045
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_WORKERS_BINDING_QUERY_FAILED",
836
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_THREAD_BY_ID", "FAILED"),
1046
837
  domain: error.ErrorDomain.STORAGE,
1047
838
  category: error.ErrorCategory.THIRD_PARTY,
1048
- details: { sql }
839
+ text: `Error processing thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
840
+ details: { threadId }
1049
841
  },
1050
842
  error$1
1051
843
  );
844
+ this.logger?.error(mastraError.toString());
845
+ this.logger?.trackException(mastraError);
846
+ return null;
1052
847
  }
1053
848
  }
1054
- async executeRestQuery({
1055
- sql,
1056
- params = [],
1057
- first = false
1058
- }) {
1059
- if (!this.client) {
1060
- throw new Error("D1 client is not configured");
849
+ async listThreadsByResourceId(args) {
850
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
851
+ const perPage = storage.normalizePerPage(perPageInput, 100);
852
+ if (page < 0) {
853
+ throw new error.MastraError(
854
+ {
855
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
856
+ domain: error.ErrorDomain.STORAGE,
857
+ category: error.ErrorCategory.USER,
858
+ details: { page }
859
+ },
860
+ new Error("page must be >= 0")
861
+ );
1061
862
  }
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
+ });
1062
872
  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;
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);
880
+ return {
881
+ threads,
882
+ total,
883
+ page,
884
+ perPage: perPageForResponse,
885
+ hasMore: perPageInput === false ? false : offset + perPage < total
886
+ };
1074
887
  } catch (error$1) {
1075
- throw new error.MastraError(
888
+ const mastraError = new error.MastraError(
1076
889
  {
1077
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_REST_QUERY_FAILED",
890
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
1078
891
  domain: error.ErrorDomain.STORAGE,
1079
892
  category: error.ErrorCategory.THIRD_PARTY,
1080
- details: { sql }
893
+ text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
894
+ details: { resourceId }
1081
895
  },
1082
896
  error$1
1083
897
  );
898
+ this.logger?.error(mastraError.toString());
899
+ this.logger?.trackException(mastraError);
900
+ return {
901
+ threads: [],
902
+ total: 0,
903
+ page,
904
+ perPage: perPageForResponse,
905
+ hasMore: false
906
+ };
1084
907
  }
1085
908
  }
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) {
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();
1096
931
  try {
1097
- const sql = `PRAGMA table_info(${tableName})`;
1098
- const result = await this.executeQuery({ sql });
1099
- if (!result || !Array.isArray(result)) {
1100
- return [];
1101
- }
1102
- return result.map((row) => ({
1103
- name: row.name,
1104
- type: row.type
1105
- }));
1106
- } catch (error) {
1107
- this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
1108
- return [];
1109
- }
1110
- }
1111
- serializeValue(value) {
1112
- if (value === null || value === void 0) {
1113
- return null;
1114
- }
1115
- if (value instanceof Date) {
1116
- return value.toISOString();
1117
- }
1118
- if (typeof value === "object") {
1119
- return JSON.stringify(value);
1120
- }
1121
- return value;
1122
- }
1123
- getSqlType(type) {
1124
- switch (type) {
1125
- case "bigint":
1126
- return "INTEGER";
1127
- // SQLite uses INTEGER for all integer sizes
1128
- case "jsonb":
1129
- return "TEXT";
1130
- // Store JSON as TEXT in SQLite
1131
- default:
1132
- return super.getSqlType(type);
932
+ await this.#db.executeQuery({ sql, params });
933
+ return thread;
934
+ } catch (error$1) {
935
+ throw new error.MastraError(
936
+ {
937
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_THREAD", "FAILED"),
938
+ domain: error.ErrorDomain.STORAGE,
939
+ category: error.ErrorCategory.THIRD_PARTY,
940
+ text: `Failed to save thread to ${fullTableName}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
941
+ details: { threadId: thread.id }
942
+ },
943
+ error$1
944
+ );
1133
945
  }
1134
946
  }
1135
- async createTable({
1136
- tableName,
1137
- schema
947
+ async updateThread({
948
+ id,
949
+ title,
950
+ metadata
1138
951
  }) {
952
+ const thread = await this.getThreadById({ threadId: id });
1139
953
  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)");
954
+ if (!thread) {
955
+ throw new Error(`Thread ${id} not found`);
1150
956
  }
1151
- const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
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);
1152
966
  const { sql, params } = query.build();
1153
- await this.executeQuery({ sql, params });
1154
- this.logger.debug(`Created table ${fullTableName}`);
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
+ };
1155
977
  } catch (error$1) {
1156
978
  throw new error.MastraError(
1157
979
  {
1158
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_CREATE_TABLE_FAILED",
980
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "UPDATE_THREAD", "FAILED"),
1159
981
  domain: error.ErrorDomain.STORAGE,
1160
982
  category: error.ErrorCategory.THIRD_PARTY,
1161
- details: { tableName }
983
+ text: `Failed to update thread ${id}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
984
+ details: { threadId: id }
1162
985
  },
1163
986
  error$1
1164
987
  );
1165
988
  }
1166
989
  }
1167
- async clearTable({ tableName }) {
990
+ async deleteThread({ threadId }) {
991
+ const fullTableName = this.#db.getTableName(storage.TABLE_THREADS);
1168
992
  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}`);
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 });
1174
1000
  } catch (error$1) {
1175
1001
  throw new error.MastraError(
1176
1002
  {
1177
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_CLEAR_TABLE_FAILED",
1003
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "DELETE_THREAD", "FAILED"),
1178
1004
  domain: error.ErrorDomain.STORAGE,
1179
1005
  category: error.ErrorCategory.THIRD_PARTY,
1180
- details: { tableName }
1006
+ text: `Failed to delete thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
1007
+ details: { threadId }
1181
1008
  },
1182
1009
  error$1
1183
1010
  );
1184
1011
  }
1185
1012
  }
1186
- async dropTable({ tableName }) {
1013
+ async saveMessages(args) {
1014
+ const { messages } = args;
1015
+ if (messages.length === 0) return { messages: [] };
1187
1016
  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}`);
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
+ }
1037
+ }
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() };
1192
1064
  } catch (error$1) {
1193
1065
  throw new error.MastraError(
1194
1066
  {
1195
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_DROP_TABLE_FAILED",
1067
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "SAVE_MESSAGES", "FAILED"),
1196
1068
  domain: error.ErrorDomain.STORAGE,
1197
1069
  category: error.ErrorCategory.THIRD_PARTY,
1198
- details: { tableName }
1070
+ text: `Failed to save messages: ${error$1 instanceof Error ? error$1.message : String(error$1)}`
1199
1071
  },
1200
1072
  error$1
1201
1073
  );
1202
1074
  }
1203
1075
  }
1204
- async alterTable(args) {
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++;
1119
+ }
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);
1130
+ }
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 = [];
1205
1139
  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}`);
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");
1142
+ const { sql, params } = query.build();
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);
1216
1150
  }
1217
- }
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() };
1218
1156
  } catch (error$1) {
1219
- throw new error.MastraError(
1157
+ const mastraError = new error.MastraError(
1220
1158
  {
1221
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_ALTER_TABLE_FAILED",
1159
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES_BY_ID", "FAILED"),
1222
1160
  domain: error.ErrorDomain.STORAGE,
1223
1161
  category: error.ErrorCategory.THIRD_PARTY,
1224
- details: { tableName: args.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) }
1225
1164
  },
1226
1165
  error$1
1227
1166
  );
1167
+ this.logger?.error(mastraError.toString());
1168
+ this.logger?.trackException(mastraError);
1169
+ throw mastraError;
1228
1170
  }
1229
1171
  }
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) {
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())) {
1240
1176
  throw new error.MastraError(
1241
1177
  {
1242
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_INSERT_FAILED",
1178
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_THREAD_ID"),
1243
1179
  domain: error.ErrorDomain.STORAGE,
1244
1180
  category: error.ErrorCategory.THIRD_PARTY,
1245
- details: { tableName }
1181
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
1246
1182
  },
1247
- error$1
1183
+ new Error("threadId must be a non-empty string or array of non-empty strings")
1248
1184
  );
1249
1185
  }
1250
- }
1251
- async batchInsert({ tableName, records }) {
1186
+ if (page < 0) {
1187
+ throw new error.MastraError(
1188
+ {
1189
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "INVALID_PAGE"),
1190
+ domain: error.ErrorDomain.STORAGE,
1191
+ category: error.ErrorCategory.USER,
1192
+ details: { page }
1193
+ },
1194
+ new Error("page must be >= 0")
1195
+ );
1196
+ }
1197
+ const perPage = storage.normalizePerPage(perPageInput, 40);
1198
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1252
1199
  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 });
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
+ }
1281
+ }
1262
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
+ };
1263
1307
  } catch (error$1) {
1264
- throw new error.MastraError(
1308
+ const mastraError = new error.MastraError(
1265
1309
  {
1266
- id: "CLOUDFLARE_D1_STORE_OPERATIONS_BATCH_INSERT_FAILED",
1310
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_MESSAGES", "FAILED"),
1267
1311
  domain: error.ErrorDomain.STORAGE,
1268
1312
  category: error.ErrorCategory.THIRD_PARTY,
1269
- details: { 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
+ }
1270
1318
  },
1271
1319
  error$1
1272
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
+ };
1273
1330
  }
1274
1331
  }
1275
- async load({ tableName, keys }) {
1332
+ async updateMessages(args) {
1333
+ const { messages } = args;
1334
+ this.logger.debug("Updating messages", { count: messages.length });
1335
+ if (!messages.length) {
1336
+ return [];
1337
+ }
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);
1276
1341
  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);
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 [];
1347
+ }
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 {
@@ -1807,7 +1912,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1807
1912
  resourceId,
1808
1913
  status
1809
1914
  } = {}) {
1810
- const fullTableName = this.operations.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1915
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1811
1916
  try {
1812
1917
  const builder = createSqlBuilder().select().from(fullTableName);
1813
1918
  const countBuilder = createSqlBuilder().count().from(fullTableName);
@@ -1817,12 +1922,12 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1817
1922
  countBuilder.whereAnd("json_extract(snapshot, '$.status') = ?", status);
1818
1923
  }
1819
1924
  if (resourceId) {
1820
- const hasResourceId = await this.operations.hasColumn(fullTableName, "resourceId");
1925
+ const hasResourceId = await this.#db.hasColumn(fullTableName, "resourceId");
1821
1926
  if (hasResourceId) {
1822
1927
  builder.whereAnd("resourceId = ?", resourceId);
1823
1928
  countBuilder.whereAnd("resourceId = ?", resourceId);
1824
1929
  } else {
1825
- console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1930
+ this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1826
1931
  }
1827
1932
  }
1828
1933
  if (fromDate) {
@@ -1843,20 +1948,20 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1843
1948
  let total = 0;
1844
1949
  if (perPage !== void 0 && page !== void 0) {
1845
1950
  const { sql: countSql, params: countParams } = countBuilder.build();
1846
- const countResult = await this.operations.executeQuery({
1951
+ const countResult = await this.#db.executeQuery({
1847
1952
  sql: countSql,
1848
1953
  params: countParams,
1849
1954
  first: true
1850
1955
  });
1851
1956
  total = Number(countResult?.count ?? 0);
1852
1957
  }
1853
- const results = await this.operations.executeQuery({ sql, params });
1958
+ const results = await this.#db.executeQuery({ sql, params });
1854
1959
  const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1855
1960
  return { runs, total: total || runs.length };
1856
1961
  } catch (error$1) {
1857
1962
  throw new error.MastraError(
1858
1963
  {
1859
- id: "CLOUDFLARE_D1_STORAGE_LIST_WORKFLOW_RUNS_ERROR",
1964
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_WORKFLOW_RUNS", "FAILED"),
1860
1965
  domain: error.ErrorDomain.STORAGE,
1861
1966
  category: error.ErrorCategory.THIRD_PARTY,
1862
1967
  text: `Failed to retrieve workflow runs: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1873,7 +1978,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1873
1978
  runId,
1874
1979
  workflowName
1875
1980
  }) {
1876
- const fullTableName = this.operations.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1981
+ const fullTableName = this.#db.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1877
1982
  try {
1878
1983
  const conditions = [];
1879
1984
  const params = [];
@@ -1887,13 +1992,13 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1887
1992
  }
1888
1993
  const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1889
1994
  const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1890
- const result = await this.operations.executeQuery({ sql, params, first: true });
1995
+ const result = await this.#db.executeQuery({ sql, params, first: true });
1891
1996
  if (!result) return null;
1892
1997
  return this.parseWorkflowRun(result);
1893
1998
  } catch (error$1) {
1894
1999
  throw new error.MastraError(
1895
2000
  {
1896
- id: "CLOUDFLARE_D1_STORAGE_GET_WORKFLOW_RUN_BY_ID_ERROR",
2001
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1897
2002
  domain: error.ErrorDomain.STORAGE,
1898
2003
  category: error.ErrorCategory.THIRD_PARTY,
1899
2004
  text: `Failed to retrieve workflow run by ID: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
@@ -1903,13 +2008,31 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1903
2008
  );
1904
2009
  }
1905
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
+ }
1906
2030
  };
1907
2031
 
1908
2032
  // src/storage/index.ts
1909
2033
  var D1Store = class extends storage.MastraStorage {
1910
2034
  client;
1911
2035
  binding;
1912
- // D1Database binding
1913
2036
  tablePrefix;
1914
2037
  stores;
1915
2038
  /**
@@ -1918,7 +2041,7 @@ var D1Store = class extends storage.MastraStorage {
1918
2041
  */
1919
2042
  constructor(config) {
1920
2043
  try {
1921
- super({ id: config.id, name: "D1" });
2044
+ super({ id: config.id, name: "D1", disableInit: config.disableInit });
1922
2045
  if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
1923
2046
  throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
1924
2047
  }
@@ -1956,7 +2079,7 @@ var D1Store = class extends storage.MastraStorage {
1956
2079
  } catch (error$1) {
1957
2080
  throw new error.MastraError(
1958
2081
  {
1959
- id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
2082
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "INITIALIZATION", "FAILED"),
1960
2083
  domain: error.ErrorDomain.STORAGE,
1961
2084
  category: error.ErrorCategory.SYSTEM,
1962
2085
  text: "Error initializing D1Store"
@@ -1964,189 +2087,26 @@ var D1Store = class extends storage.MastraStorage {
1964
2087
  error$1
1965
2088
  );
1966
2089
  }
1967
- const operations = new StoreOperationsD1({
1968
- client: this.client,
1969
- binding: this.binding,
1970
- tablePrefix: this.tablePrefix
1971
- });
1972
- const scores = new ScoresStorageD1({
1973
- operations
1974
- });
1975
- const workflows = new WorkflowsStorageD1({
1976
- operations
1977
- });
1978
- const memory = new MemoryStorageD1({
1979
- operations
1980
- });
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
+ }
1981
2104
  this.stores = {
1982
- operations,
1983
2105
  scores,
1984
2106
  workflows,
1985
2107
  memory
1986
2108
  };
1987
2109
  }
1988
- get supports() {
1989
- return {
1990
- selectByIncludeResourceScope: true,
1991
- resourceWorkingMemory: true,
1992
- hasColumn: true,
1993
- createTable: true,
1994
- deleteMessages: false,
1995
- listScoresBySpan: true
1996
- };
1997
- }
1998
- async createTable({
1999
- tableName,
2000
- schema
2001
- }) {
2002
- return this.stores.operations.createTable({ tableName, schema });
2003
- }
2004
- /**
2005
- * Alters table schema to add columns if they don't exist
2006
- * @param tableName Name of the table
2007
- * @param schema Schema of the table
2008
- * @param ifNotExists Array of column names to add if they don't exist
2009
- */
2010
- async alterTable({
2011
- tableName,
2012
- schema,
2013
- ifNotExists
2014
- }) {
2015
- return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
2016
- }
2017
- async clearTable({ tableName }) {
2018
- return this.stores.operations.clearTable({ tableName });
2019
- }
2020
- async dropTable({ tableName }) {
2021
- return this.stores.operations.dropTable({ tableName });
2022
- }
2023
- async hasColumn(table, column) {
2024
- return this.stores.operations.hasColumn(table, column);
2025
- }
2026
- async insert({ tableName, record }) {
2027
- return this.stores.operations.insert({ tableName, record });
2028
- }
2029
- async load({ tableName, keys }) {
2030
- return this.stores.operations.load({ tableName, keys });
2031
- }
2032
- async getThreadById({ threadId }) {
2033
- return this.stores.memory.getThreadById({ threadId });
2034
- }
2035
- async saveThread({ thread }) {
2036
- return this.stores.memory.saveThread({ thread });
2037
- }
2038
- async updateThread({
2039
- id,
2040
- title,
2041
- metadata
2042
- }) {
2043
- return this.stores.memory.updateThread({ id, title, metadata });
2044
- }
2045
- async deleteThread({ threadId }) {
2046
- return this.stores.memory.deleteThread({ threadId });
2047
- }
2048
- async saveMessages(args) {
2049
- return this.stores.memory.saveMessages(args);
2050
- }
2051
- async updateWorkflowResults({
2052
- workflowName,
2053
- runId,
2054
- stepId,
2055
- result,
2056
- requestContext
2057
- }) {
2058
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2059
- }
2060
- async updateWorkflowState({
2061
- workflowName,
2062
- runId,
2063
- opts
2064
- }) {
2065
- return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2066
- }
2067
- async persistWorkflowSnapshot({
2068
- workflowName,
2069
- runId,
2070
- resourceId,
2071
- snapshot
2072
- }) {
2073
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2074
- }
2075
- async loadWorkflowSnapshot(params) {
2076
- return this.stores.workflows.loadWorkflowSnapshot(params);
2077
- }
2078
- async listWorkflowRuns(args = {}) {
2079
- return this.stores.workflows.listWorkflowRuns(args);
2080
- }
2081
- async getWorkflowRunById({
2082
- runId,
2083
- workflowName
2084
- }) {
2085
- return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2086
- }
2087
- /**
2088
- * Insert multiple records in a batch operation
2089
- * @param tableName The table to insert into
2090
- * @param records The records to insert
2091
- */
2092
- async batchInsert({ tableName, records }) {
2093
- return this.stores.operations.batchInsert({ tableName, records });
2094
- }
2095
- async updateMessages(_args) {
2096
- return this.stores.memory.updateMessages(_args);
2097
- }
2098
- async getResourceById({ resourceId }) {
2099
- return this.stores.memory.getResourceById({ resourceId });
2100
- }
2101
- async saveResource({ resource }) {
2102
- return this.stores.memory.saveResource({ resource });
2103
- }
2104
- async updateResource({
2105
- resourceId,
2106
- workingMemory,
2107
- metadata
2108
- }) {
2109
- return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2110
- }
2111
- async getScoreById({ id: _id }) {
2112
- return this.stores.scores.getScoreById({ id: _id });
2113
- }
2114
- async saveScore(_score) {
2115
- return this.stores.scores.saveScore(_score);
2116
- }
2117
- async listScoresByRunId({
2118
- runId: _runId,
2119
- pagination: _pagination
2120
- }) {
2121
- return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2122
- }
2123
- async listScoresByEntityId({
2124
- entityId: _entityId,
2125
- entityType: _entityType,
2126
- pagination: _pagination
2127
- }) {
2128
- return this.stores.scores.listScoresByEntityId({
2129
- entityId: _entityId,
2130
- entityType: _entityType,
2131
- pagination: _pagination
2132
- });
2133
- }
2134
- async listScoresByScorerId({
2135
- scorerId,
2136
- pagination,
2137
- entityId,
2138
- entityType,
2139
- source
2140
- }) {
2141
- return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
2142
- }
2143
- async listScoresBySpan({
2144
- traceId,
2145
- spanId,
2146
- pagination
2147
- }) {
2148
- return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2149
- }
2150
2110
  /**
2151
2111
  * Close the database connection
2152
2112
  * No explicit cleanup needed for D1 in either REST or Workers Binding mode
@@ -2157,5 +2117,8 @@ var D1Store = class extends storage.MastraStorage {
2157
2117
  };
2158
2118
 
2159
2119
  exports.D1Store = D1Store;
2120
+ exports.MemoryStorageD1 = MemoryStorageD1;
2121
+ exports.ScoresStorageD1 = ScoresStorageD1;
2122
+ exports.WorkflowsStorageD1 = WorkflowsStorageD1;
2160
2123
  //# sourceMappingURL=index.cjs.map
2161
2124
  //# sourceMappingURL=index.cjs.map