@mastra/cloudflare-d1 0.0.0-share-agent-metadata-with-cloud-20250718110128 → 0.0.0-sidebar-window-undefined-fix-20251029233656

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.js CHANGED
@@ -1,8 +1,9 @@
1
- import { MessageList } from '@mastra/core/agent';
2
1
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
- import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_TRACES, TABLE_EVALS } from '@mastra/core/storage';
2
+ import { MastraStorage, StoreOperations, ScoresStorage, TABLE_SCORERS, LegacyEvalsStorage, TABLE_EVALS, serializeDate, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate, MemoryStorage, TABLE_RESOURCES, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, safelyParseJSON } from '@mastra/core/storage';
4
3
  import Cloudflare from 'cloudflare';
5
4
  import { parseSqlIdentifier } from '@mastra/core/utils';
5
+ import { MessageList } from '@mastra/core/agent';
6
+ import { saveScorePayloadSchema } from '@mastra/core/scores';
6
7
 
7
8
  // src/storage/index.ts
8
9
  var SqlBuilder = class {
@@ -235,402 +236,291 @@ function parseSelectIdentifier(column) {
235
236
  return column;
236
237
  }
237
238
 
238
- // src/storage/index.ts
239
+ // src/storage/domains/utils.ts
239
240
  function isArrayOfRecords(value) {
240
241
  return value && Array.isArray(value) && value.length > 0;
241
242
  }
242
- var D1Store = class extends MastraStorage {
243
- client;
244
- binding;
245
- // D1Database binding
246
- tablePrefix;
247
- /**
248
- * Creates a new D1Store instance
249
- * @param config Configuration for D1 access (either REST API or Workers Binding API)
250
- */
251
- constructor(config) {
243
+ function deserializeValue(value, type) {
244
+ if (value === null || value === void 0) return null;
245
+ if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
252
246
  try {
253
- super({ name: "D1" });
254
- if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
255
- throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
256
- }
257
- this.tablePrefix = config.tablePrefix || "";
258
- if ("binding" in config) {
259
- if (!config.binding) {
260
- throw new Error("D1 binding is required when using Workers Binding API");
261
- }
262
- this.binding = config.binding;
263
- this.logger.info("Using D1 Workers Binding API");
264
- } else if ("client" in config) {
265
- if (!config.client) {
266
- throw new Error("D1 client is required when using D1ClientConfig");
267
- }
268
- this.client = config.client;
269
- this.logger.info("Using D1 Client");
270
- } else {
271
- if (!config.accountId || !config.databaseId || !config.apiToken) {
272
- throw new Error("accountId, databaseId, and apiToken are required when using REST API");
273
- }
274
- const cfClient = new Cloudflare({
275
- apiToken: config.apiToken
276
- });
277
- this.client = {
278
- query: ({ sql, params }) => {
279
- return cfClient.d1.database.query(config.databaseId, {
280
- account_id: config.accountId,
281
- sql,
282
- params
283
- });
284
- }
285
- };
286
- this.logger.info("Using D1 REST API");
287
- }
288
- } catch (error) {
289
- throw new MastraError(
290
- {
291
- id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
292
- domain: ErrorDomain.STORAGE,
293
- category: ErrorCategory.SYSTEM,
294
- text: "Error initializing D1Store"
295
- },
296
- error
297
- );
247
+ return JSON.parse(value);
248
+ } catch {
249
+ return value;
298
250
  }
299
251
  }
300
- // Helper method to get the full table name with prefix
301
- getTableName(tableName) {
302
- return `${this.tablePrefix}${tableName}`;
303
- }
304
- formatSqlParams(params) {
305
- return params.map((p) => p === void 0 || p === null ? null : p);
252
+ return value;
253
+ }
254
+
255
+ // src/storage/domains/legacy-evals/index.ts
256
+ var LegacyEvalsStorageD1 = class extends LegacyEvalsStorage {
257
+ operations;
258
+ constructor({ operations }) {
259
+ super();
260
+ this.operations = operations;
306
261
  }
307
- async executeWorkersBindingQuery({
308
- sql,
309
- params = [],
310
- first = false
311
- }) {
312
- if (!this.binding) {
313
- throw new Error("Workers binding is not configured");
262
+ async getEvals(options) {
263
+ const { agentName, type, page = 0, perPage = 40, dateRange } = options || {};
264
+ const fullTableName = this.operations.getTableName(TABLE_EVALS);
265
+ const conditions = [];
266
+ const queryParams = [];
267
+ if (agentName) {
268
+ conditions.push(`agent_name = ?`);
269
+ queryParams.push(agentName);
314
270
  }
315
- try {
316
- const statement = this.binding.prepare(sql);
317
- const formattedParams = this.formatSqlParams(params);
318
- let result;
319
- if (formattedParams.length > 0) {
320
- if (first) {
321
- result = await statement.bind(...formattedParams).first();
322
- if (!result) return null;
323
- return result;
324
- } else {
325
- result = await statement.bind(...formattedParams).all();
326
- const results = result.results || [];
327
- if (result.meta) {
328
- this.logger.debug("Query metadata", { meta: result.meta });
329
- }
330
- return results;
331
- }
332
- } else {
333
- if (first) {
334
- result = await statement.first();
335
- if (!result) return null;
336
- return result;
337
- } else {
338
- result = await statement.all();
339
- const results = result.results || [];
340
- if (result.meta) {
341
- this.logger.debug("Query metadata", { meta: result.meta });
342
- }
343
- return results;
344
- }
345
- }
346
- } catch (workerError) {
347
- this.logger.error("Workers Binding API error", {
348
- message: workerError instanceof Error ? workerError.message : String(workerError),
349
- sql
350
- });
351
- throw new Error(`D1 Workers API error: ${workerError.message}`);
271
+ if (type === "test") {
272
+ conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
273
+ } else if (type === "live") {
274
+ conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
352
275
  }
353
- }
354
- async executeRestQuery({
355
- sql,
356
- params = [],
357
- first = false
358
- }) {
359
- if (!this.client) {
360
- throw new Error("Missing required REST API configuration");
276
+ if (dateRange?.start) {
277
+ conditions.push(`created_at >= ?`);
278
+ queryParams.push(serializeDate(dateRange.start));
361
279
  }
362
- try {
363
- const response = await this.client.query({
364
- sql,
365
- params: this.formatSqlParams(params)
366
- });
367
- const result = response.result || [];
368
- const results = result.flatMap((r) => r.results || []);
369
- if (first) {
370
- const firstResult = isArrayOfRecords(results) && results.length > 0 ? results[0] : null;
371
- if (!firstResult) return null;
372
- return firstResult;
373
- }
374
- return results;
375
- } catch (restError) {
376
- this.logger.error("REST API error", {
377
- message: restError instanceof Error ? restError.message : String(restError),
378
- sql
379
- });
380
- throw new Error(`D1 REST API error: ${restError.message}`);
280
+ if (dateRange?.end) {
281
+ conditions.push(`created_at <= ?`);
282
+ queryParams.push(serializeDate(dateRange.end));
381
283
  }
382
- }
383
- /**
384
- * Execute a SQL query against the D1 database
385
- * @param options Query options including SQL, parameters, and whether to return only the first result
386
- * @returns Query results as an array or a single object if first=true
387
- */
388
- async executeQuery(options) {
389
- const { sql, params = [], first = false } = options;
390
- try {
391
- this.logger.debug("Executing SQL query", { sql, params, first });
392
- if (this.binding) {
393
- return this.executeWorkersBindingQuery({ sql, params, first });
394
- } else if (this.client) {
395
- return this.executeRestQuery({ sql, params, first });
396
- } else {
397
- throw new Error("No valid D1 configuration provided");
398
- }
399
- } catch (error) {
400
- this.logger.error("Error executing SQL query", {
401
- message: error instanceof Error ? error.message : String(error),
402
- sql,
403
- params,
404
- first
405
- });
406
- throw new Error(`D1 query error: ${error.message}`);
284
+ const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
285
+ if (conditions.length > 0) {
286
+ countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
407
287
  }
408
- }
409
- // Helper to get existing table columns
410
- async getTableColumns(tableName) {
288
+ const { sql: countSql, params: countParams } = countQueryBuilder.build();
411
289
  try {
412
- const sql = `PRAGMA table_info(${tableName})`;
413
- const result = await this.executeQuery({ sql, params: [] });
414
- if (!result || !Array.isArray(result)) {
415
- return [];
416
- }
417
- return result.map((row) => ({
418
- name: row.name,
419
- type: row.type
420
- }));
421
- } catch (error) {
422
- this.logger.error(`Error getting table columns for ${tableName}:`, {
423
- message: error instanceof Error ? error.message : String(error)
290
+ const countResult = await this.operations.executeQuery({
291
+ sql: countSql,
292
+ params: countParams,
293
+ first: true
424
294
  });
425
- return [];
426
- }
427
- }
428
- // Helper to serialize objects to JSON strings
429
- serializeValue(value) {
430
- if (value === null || value === void 0) return null;
431
- if (value instanceof Date) {
432
- return this.serializeDate(value);
433
- }
434
- if (typeof value === "object") {
435
- return JSON.stringify(value);
436
- }
437
- return value;
438
- }
439
- // Helper to deserialize JSON strings to objects
440
- deserializeValue(value, type) {
441
- if (value === null || value === void 0) return null;
442
- if (type === "date" && typeof value === "string") {
443
- return new Date(value);
444
- }
445
- if (type === "jsonb" && typeof value === "string") {
446
- try {
447
- return JSON.parse(value);
448
- } catch {
449
- return value;
295
+ const total = Number(countResult?.count || 0);
296
+ const currentOffset = page * perPage;
297
+ if (total === 0) {
298
+ return {
299
+ evals: [],
300
+ total: 0,
301
+ page,
302
+ perPage,
303
+ hasMore: false
304
+ };
450
305
  }
451
- }
452
- if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
453
- try {
454
- return JSON.parse(value);
455
- } catch {
456
- return value;
306
+ const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
307
+ if (conditions.length > 0) {
308
+ dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
457
309
  }
458
- }
459
- return value;
460
- }
461
- getSqlType(type) {
462
- switch (type) {
463
- case "bigint":
464
- return "INTEGER";
465
- // SQLite uses INTEGER for all integer sizes
466
- case "jsonb":
467
- return "TEXT";
468
- // Store JSON as TEXT in SQLite
469
- default:
470
- return super.getSqlType(type);
471
- }
472
- }
473
- async createTable({
474
- tableName,
475
- schema
476
- }) {
477
- const fullTableName = this.getTableName(tableName);
478
- const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
479
- const type = this.getSqlType(colDef.type);
480
- const nullable = colDef.nullable === false ? "NOT NULL" : "";
481
- const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
482
- return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
483
- });
484
- const tableConstraints = [];
485
- if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
486
- tableConstraints.push("UNIQUE (workflow_name, run_id)");
487
- }
488
- try {
489
- const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
490
- const { sql, params } = query.build();
491
- await this.executeQuery({ sql, params });
492
- this.logger.debug(`Created table ${fullTableName}`);
493
- } catch (error) {
494
- this.logger.error(`Error creating table ${fullTableName}:`, {
495
- message: error instanceof Error ? error.message : String(error)
310
+ dataQueryBuilder.orderBy("created_at", "DESC").limit(perPage).offset(currentOffset);
311
+ const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
312
+ const rows = await this.operations.executeQuery({
313
+ sql: dataSql,
314
+ params: dataParams
315
+ });
316
+ const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
317
+ const result = deserializeValue(row.result);
318
+ const testInfo = row.test_info ? deserializeValue(row.test_info) : void 0;
319
+ if (!result || typeof result !== "object" || !("score" in result)) {
320
+ throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
321
+ }
322
+ return {
323
+ input: row.input,
324
+ output: row.output,
325
+ result,
326
+ agentName: row.agent_name,
327
+ metricName: row.metric_name,
328
+ instructions: row.instructions,
329
+ testInfo,
330
+ globalRunId: row.global_run_id,
331
+ runId: row.run_id,
332
+ createdAt: row.created_at
333
+ };
496
334
  });
335
+ const hasMore = currentOffset + evals.length < total;
336
+ return {
337
+ evals,
338
+ total,
339
+ page,
340
+ perPage,
341
+ hasMore
342
+ };
343
+ } catch (error) {
497
344
  throw new MastraError(
498
345
  {
499
- id: "CLOUDFLARE_D1_STORAGE_CREATE_TABLE_ERROR",
346
+ id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
500
347
  domain: ErrorDomain.STORAGE,
501
348
  category: ErrorCategory.THIRD_PARTY,
502
- text: `Failed to create table ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
503
- details: { tableName }
349
+ text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
350
+ details: { agentName: agentName ?? "", type: type ?? "" }
504
351
  },
505
352
  error
506
353
  );
507
354
  }
508
355
  }
509
356
  /**
510
- * Alters table schema to add columns if they don't exist
511
- * @param tableName Name of the table
512
- * @param schema Schema of the table
513
- * @param ifNotExists Array of column names to add if they don't exist
357
+ * @deprecated use getEvals instead
514
358
  */
515
- async alterTable({
516
- tableName,
517
- schema,
518
- ifNotExists
519
- }) {
520
- const fullTableName = this.getTableName(tableName);
359
+ async getEvalsByAgentName(agentName, type) {
360
+ const fullTableName = this.operations.getTableName(TABLE_EVALS);
521
361
  try {
522
- const existingColumns = await this.getTableColumns(fullTableName);
523
- const existingColumnNames = new Set(existingColumns.map((col) => col.name.toLowerCase()));
524
- for (const columnName of ifNotExists) {
525
- if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
526
- const columnDef = schema[columnName];
527
- const sqlType = this.getSqlType(columnDef.type);
528
- const nullable = columnDef.nullable === false ? "NOT NULL" : "";
529
- const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
530
- const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
531
- await this.executeQuery({ sql: alterSql, params: [] });
532
- this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
533
- }
362
+ let query = createSqlBuilder().select("*").from(fullTableName).where("agent_name = ?", agentName);
363
+ if (type === "test") {
364
+ query = query.andWhere("test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL");
365
+ } else if (type === "live") {
366
+ query = query.andWhere("(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)");
534
367
  }
368
+ query.orderBy("created_at", "DESC");
369
+ const { sql, params } = query.build();
370
+ const results = await this.operations.executeQuery({ sql, params });
371
+ return isArrayOfRecords(results) ? results.map((row) => {
372
+ const result = deserializeValue(row.result);
373
+ const testInfo = row.test_info ? deserializeValue(row.test_info) : void 0;
374
+ return {
375
+ input: row.input || "",
376
+ output: row.output || "",
377
+ result,
378
+ agentName: row.agent_name || "",
379
+ metricName: row.metric_name || "",
380
+ instructions: row.instructions || "",
381
+ runId: row.run_id || "",
382
+ globalRunId: row.global_run_id || "",
383
+ createdAt: row.created_at || "",
384
+ testInfo
385
+ };
386
+ }) : [];
535
387
  } catch (error) {
536
- throw new MastraError(
388
+ const mastraError = new MastraError(
537
389
  {
538
- id: "CLOUDFLARE_D1_STORAGE_ALTER_TABLE_ERROR",
390
+ id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
539
391
  domain: ErrorDomain.STORAGE,
540
392
  category: ErrorCategory.THIRD_PARTY,
541
- text: `Failed to alter table ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
542
- details: { tableName }
393
+ text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
394
+ details: { agentName }
543
395
  },
544
396
  error
545
397
  );
398
+ this.logger?.error(mastraError.toString());
399
+ this.logger?.trackException(mastraError);
400
+ return [];
546
401
  }
547
402
  }
548
- async clearTable({ tableName }) {
549
- const fullTableName = this.getTableName(tableName);
403
+ };
404
+ var MemoryStorageD1 = class extends MemoryStorage {
405
+ operations;
406
+ constructor({ operations }) {
407
+ super();
408
+ this.operations = operations;
409
+ }
410
+ async getResourceById({ resourceId }) {
411
+ const resource = await this.operations.load({
412
+ tableName: TABLE_RESOURCES,
413
+ keys: { id: resourceId }
414
+ });
415
+ if (!resource) return null;
550
416
  try {
551
- const query = createSqlBuilder().delete(fullTableName);
552
- const { sql, params } = query.build();
553
- await this.executeQuery({ sql, params });
554
- this.logger.debug(`Cleared table ${fullTableName}`);
417
+ return {
418
+ ...resource,
419
+ createdAt: ensureDate(resource.createdAt),
420
+ updatedAt: ensureDate(resource.updatedAt),
421
+ metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata || "{}") : resource.metadata
422
+ };
555
423
  } catch (error) {
556
- throw new MastraError(
424
+ const mastraError = new MastraError(
557
425
  {
558
- id: "CLOUDFLARE_D1_STORAGE_CLEAR_TABLE_ERROR",
426
+ id: "CLOUDFLARE_D1_STORAGE_GET_RESOURCE_BY_ID_ERROR",
559
427
  domain: ErrorDomain.STORAGE,
560
428
  category: ErrorCategory.THIRD_PARTY,
561
- text: `Failed to clear table ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
562
- details: { tableName }
429
+ text: `Error processing resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
430
+ details: { resourceId }
563
431
  },
564
432
  error
565
433
  );
434
+ this.logger?.error(mastraError.toString());
435
+ this.logger?.trackException(mastraError);
436
+ return null;
566
437
  }
567
438
  }
568
- async processRecord(record) {
569
- const processedRecord = {};
570
- for (const [key, value] of Object.entries(record)) {
571
- processedRecord[key] = this.serializeValue(value);
572
- }
573
- return processedRecord;
574
- }
575
- async insert({ tableName, record }) {
576
- const fullTableName = this.getTableName(tableName);
577
- const processedRecord = await this.processRecord(record);
439
+ async saveResource({ resource }) {
440
+ const fullTableName = this.operations.getTableName(TABLE_RESOURCES);
441
+ const resourceToSave = {
442
+ id: resource.id,
443
+ workingMemory: resource.workingMemory,
444
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : null,
445
+ createdAt: resource.createdAt,
446
+ updatedAt: resource.updatedAt
447
+ };
448
+ const processedRecord = await this.operations.processRecord(resourceToSave);
578
449
  const columns = Object.keys(processedRecord);
579
450
  const values = Object.values(processedRecord);
580
- const query = createSqlBuilder().insert(fullTableName, columns, values);
451
+ const updateMap = {
452
+ workingMemory: "excluded.workingMemory",
453
+ metadata: "excluded.metadata",
454
+ createdAt: "excluded.createdAt",
455
+ updatedAt: "excluded.updatedAt"
456
+ };
457
+ const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
581
458
  const { sql, params } = query.build();
582
459
  try {
583
- await this.executeQuery({ sql, params });
460
+ await this.operations.executeQuery({ sql, params });
461
+ return resource;
584
462
  } catch (error) {
585
463
  throw new MastraError(
586
464
  {
587
- id: "CLOUDFLARE_D1_STORAGE_INSERT_ERROR",
465
+ id: "CLOUDFLARE_D1_STORAGE_SAVE_RESOURCE_ERROR",
588
466
  domain: ErrorDomain.STORAGE,
589
467
  category: ErrorCategory.THIRD_PARTY,
590
- text: `Failed to insert into ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
591
- details: { tableName }
468
+ text: `Failed to save resource to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
469
+ details: { resourceId: resource.id }
592
470
  },
593
471
  error
594
472
  );
595
473
  }
596
474
  }
597
- async load({ tableName, keys }) {
598
- const fullTableName = this.getTableName(tableName);
599
- const query = createSqlBuilder().select("*").from(fullTableName);
600
- let firstKey = true;
601
- for (const [key, value] of Object.entries(keys)) {
602
- if (firstKey) {
603
- query.where(`${key} = ?`, value);
604
- firstKey = false;
605
- } else {
606
- query.andWhere(`${key} = ?`, value);
607
- }
475
+ async updateResource({
476
+ resourceId,
477
+ workingMemory,
478
+ metadata
479
+ }) {
480
+ const existingResource = await this.getResourceById({ resourceId });
481
+ if (!existingResource) {
482
+ const newResource = {
483
+ id: resourceId,
484
+ workingMemory,
485
+ metadata: metadata || {},
486
+ createdAt: /* @__PURE__ */ new Date(),
487
+ updatedAt: /* @__PURE__ */ new Date()
488
+ };
489
+ return this.saveResource({ resource: newResource });
608
490
  }
609
- query.limit(1);
491
+ const updatedAt = /* @__PURE__ */ new Date();
492
+ const updatedResource = {
493
+ ...existingResource,
494
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
495
+ metadata: {
496
+ ...existingResource.metadata,
497
+ ...metadata
498
+ },
499
+ updatedAt
500
+ };
501
+ const fullTableName = this.operations.getTableName(TABLE_RESOURCES);
502
+ const columns = ["workingMemory", "metadata", "updatedAt"];
503
+ const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
504
+ const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
610
505
  const { sql, params } = query.build();
611
506
  try {
612
- const result = await this.executeQuery({ sql, params, first: true });
613
- if (!result) return null;
614
- const processedResult = {};
615
- for (const [key, value] of Object.entries(result)) {
616
- processedResult[key] = this.deserializeValue(value);
617
- }
618
- return processedResult;
507
+ await this.operations.executeQuery({ sql, params });
508
+ return updatedResource;
619
509
  } catch (error) {
620
510
  throw new MastraError(
621
511
  {
622
- id: "CLOUDFLARE_D1_STORAGE_LOAD_ERROR",
512
+ id: "CLOUDFLARE_D1_STORAGE_UPDATE_RESOURCE_ERROR",
623
513
  domain: ErrorDomain.STORAGE,
624
514
  category: ErrorCategory.THIRD_PARTY,
625
- text: `Failed to load from ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
626
- details: { tableName }
515
+ text: `Failed to update resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
516
+ details: { resourceId }
627
517
  },
628
518
  error
629
519
  );
630
520
  }
631
521
  }
632
522
  async getThreadById({ threadId }) {
633
- const thread = await this.load({
523
+ const thread = await this.operations.load({
634
524
  tableName: TABLE_THREADS,
635
525
  keys: { id: threadId }
636
526
  });
@@ -638,8 +528,8 @@ var D1Store = class extends MastraStorage {
638
528
  try {
639
529
  return {
640
530
  ...thread,
641
- createdAt: this.ensureDate(thread.createdAt),
642
- updatedAt: this.ensureDate(thread.updatedAt),
531
+ createdAt: ensureDate(thread.createdAt),
532
+ updatedAt: ensureDate(thread.updatedAt),
643
533
  metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
644
534
  };
645
535
  } catch (error) {
@@ -662,15 +552,15 @@ var D1Store = class extends MastraStorage {
662
552
  * @deprecated use getThreadsByResourceIdPaginated instead
663
553
  */
664
554
  async getThreadsByResourceId({ resourceId }) {
665
- const fullTableName = this.getTableName(TABLE_THREADS);
555
+ const fullTableName = this.operations.getTableName(TABLE_THREADS);
666
556
  try {
667
557
  const query = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId);
668
558
  const { sql, params } = query.build();
669
- const results = await this.executeQuery({ sql, params });
559
+ const results = await this.operations.executeQuery({ sql, params });
670
560
  return (isArrayOfRecords(results) ? results : []).map((thread) => ({
671
561
  ...thread,
672
- createdAt: this.ensureDate(thread.createdAt),
673
- updatedAt: this.ensureDate(thread.updatedAt),
562
+ createdAt: ensureDate(thread.createdAt),
563
+ updatedAt: ensureDate(thread.updatedAt),
674
564
  metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
675
565
  }));
676
566
  } catch (error) {
@@ -691,19 +581,19 @@ var D1Store = class extends MastraStorage {
691
581
  }
692
582
  async getThreadsByResourceIdPaginated(args) {
693
583
  const { resourceId, page, perPage } = args;
694
- const fullTableName = this.getTableName(TABLE_THREADS);
584
+ const fullTableName = this.operations.getTableName(TABLE_THREADS);
695
585
  const mapRowToStorageThreadType = (row) => ({
696
586
  ...row,
697
- createdAt: this.ensureDate(row.createdAt),
698
- updatedAt: this.ensureDate(row.updatedAt),
587
+ createdAt: ensureDate(row.createdAt),
588
+ updatedAt: ensureDate(row.updatedAt),
699
589
  metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
700
590
  });
701
591
  try {
702
592
  const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
703
- const countResult = await this.executeQuery(countQuery.build());
593
+ const countResult = await this.operations.executeQuery(countQuery.build());
704
594
  const total = Number(countResult?.[0]?.count ?? 0);
705
595
  const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
706
- const results = await this.executeQuery(selectQuery.build());
596
+ const results = await this.operations.executeQuery(selectQuery.build());
707
597
  const threads = results.map(mapRowToStorageThreadType);
708
598
  return {
709
599
  threads,
@@ -735,16 +625,16 @@ var D1Store = class extends MastraStorage {
735
625
  }
736
626
  }
737
627
  async saveThread({ thread }) {
738
- const fullTableName = this.getTableName(TABLE_THREADS);
628
+ const fullTableName = this.operations.getTableName(TABLE_THREADS);
739
629
  const threadToSave = {
740
630
  id: thread.id,
741
631
  resourceId: thread.resourceId,
742
632
  title: thread.title,
743
633
  metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
744
- createdAt: thread.createdAt,
745
- updatedAt: thread.updatedAt
634
+ createdAt: thread.createdAt.toISOString(),
635
+ updatedAt: thread.updatedAt.toISOString()
746
636
  };
747
- const processedRecord = await this.processRecord(threadToSave);
637
+ const processedRecord = await this.operations.processRecord(threadToSave);
748
638
  const columns = Object.keys(processedRecord);
749
639
  const values = Object.values(processedRecord);
750
640
  const updateMap = {
@@ -757,7 +647,7 @@ var D1Store = class extends MastraStorage {
757
647
  const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
758
648
  const { sql, params } = query.build();
759
649
  try {
760
- await this.executeQuery({ sql, params });
650
+ await this.operations.executeQuery({ sql, params });
761
651
  return thread;
762
652
  } catch (error) {
763
653
  throw new MastraError(
@@ -782,16 +672,17 @@ var D1Store = class extends MastraStorage {
782
672
  if (!thread) {
783
673
  throw new Error(`Thread ${id} not found`);
784
674
  }
785
- const fullTableName = this.getTableName(TABLE_THREADS);
675
+ const fullTableName = this.operations.getTableName(TABLE_THREADS);
786
676
  const mergedMetadata = {
787
677
  ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
788
678
  ...metadata
789
679
  };
680
+ const updatedAt = /* @__PURE__ */ new Date();
790
681
  const columns = ["title", "metadata", "updatedAt"];
791
- const values = [title, JSON.stringify(mergedMetadata), (/* @__PURE__ */ new Date()).toISOString()];
682
+ const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
792
683
  const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
793
684
  const { sql, params } = query.build();
794
- await this.executeQuery({ sql, params });
685
+ await this.operations.executeQuery({ sql, params });
795
686
  return {
796
687
  ...thread,
797
688
  title,
@@ -799,7 +690,7 @@ var D1Store = class extends MastraStorage {
799
690
  ...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
800
691
  ...metadata
801
692
  },
802
- updatedAt: /* @__PURE__ */ new Date()
693
+ updatedAt
803
694
  };
804
695
  } catch (error) {
805
696
  throw new MastraError(
@@ -815,15 +706,15 @@ var D1Store = class extends MastraStorage {
815
706
  }
816
707
  }
817
708
  async deleteThread({ threadId }) {
818
- const fullTableName = this.getTableName(TABLE_THREADS);
709
+ const fullTableName = this.operations.getTableName(TABLE_THREADS);
819
710
  try {
820
711
  const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
821
712
  const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
822
- await this.executeQuery({ sql: threadSql, params: threadParams });
823
- const messagesTableName = this.getTableName(TABLE_MESSAGES);
713
+ await this.operations.executeQuery({ sql: threadSql, params: threadParams });
714
+ const messagesTableName = this.operations.getTableName(TABLE_MESSAGES);
824
715
  const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
825
716
  const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
826
- await this.executeQuery({ sql: messagesSql, params: messagesParams });
717
+ await this.operations.executeQuery({ sql: messagesSql, params: messagesParams });
827
718
  } catch (error) {
828
719
  throw new MastraError(
829
720
  {
@@ -854,6 +745,9 @@ var D1Store = class extends MastraStorage {
854
745
  if (!message.role) {
855
746
  throw new Error(`Message at index ${i} missing role`);
856
747
  }
748
+ if (!message.resourceId) {
749
+ throw new Error(`Message at index ${i} missing resourceId`);
750
+ }
857
751
  const thread = await this.getThreadById({ threadId: message.threadId });
858
752
  if (!thread) {
859
753
  throw new Error(`Thread ${message.threadId} not found`);
@@ -872,13 +766,13 @@ var D1Store = class extends MastraStorage {
872
766
  };
873
767
  });
874
768
  await Promise.all([
875
- this.batchUpsert({
769
+ this.operations.batchUpsert({
876
770
  tableName: TABLE_MESSAGES,
877
771
  records: messagesToInsert
878
772
  }),
879
773
  // Update thread's updatedAt timestamp
880
- this.executeQuery({
881
- sql: `UPDATE ${this.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
774
+ this.operations.executeQuery({
775
+ sql: `UPDATE ${this.operations.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
882
776
  params: [now.toISOString(), threadId]
883
777
  })
884
778
  ]);
@@ -899,64 +793,78 @@ var D1Store = class extends MastraStorage {
899
793
  }
900
794
  }
901
795
  async _getIncludedMessages(threadId, selectBy) {
796
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
902
797
  const include = selectBy?.include;
903
798
  if (!include) return null;
904
- const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
905
- const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
906
- const includeIds = include.map((i) => i.id);
907
- const sql = `
908
- WITH ordered_messages AS (
909
- SELECT
910
- *,
911
- ROW_NUMBER() OVER (ORDER BY createdAt DESC) AS row_num
912
- FROM ${this.getTableName(TABLE_MESSAGES)}
913
- WHERE thread_id = ?
914
- )
915
- SELECT
916
- m.id,
917
- m.content,
918
- m.role,
919
- m.type,
920
- m.createdAt,
921
- m.thread_id AS threadId
922
- FROM ordered_messages m
923
- WHERE m.id IN (${includeIds.map(() => "?").join(",")})
924
- OR EXISTS (
925
- SELECT 1 FROM ordered_messages target
926
- WHERE target.id IN (${includeIds.map(() => "?").join(",")})
927
- AND (
928
- (m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
929
- OR
930
- (m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
931
- )
932
- )
933
- ORDER BY m.createdAt DESC
934
- `;
935
- const params = [
936
- threadId,
937
- ...includeIds,
938
- // for m.id IN (...)
939
- ...includeIds,
940
- // for target.id IN (...)
941
- prevMax,
942
- nextMax
943
- ];
944
- const messages = await this.executeQuery({ sql, params });
945
- return messages;
799
+ const unionQueries = [];
800
+ const params = [];
801
+ let paramIdx = 1;
802
+ for (const inc of include) {
803
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
804
+ const searchId = inc.threadId || threadId;
805
+ unionQueries.push(`
806
+ SELECT * FROM (
807
+ WITH ordered_messages AS (
808
+ SELECT
809
+ *,
810
+ ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
811
+ FROM ${this.operations.getTableName(TABLE_MESSAGES)}
812
+ WHERE thread_id = ?
813
+ )
814
+ SELECT
815
+ m.id,
816
+ m.content,
817
+ m.role,
818
+ m.type,
819
+ m.createdAt,
820
+ m.thread_id AS threadId,
821
+ m.resourceId
822
+ FROM ordered_messages m
823
+ WHERE m.id = ?
824
+ OR EXISTS (
825
+ SELECT 1 FROM ordered_messages target
826
+ WHERE target.id = ?
827
+ AND (
828
+ (m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
829
+ OR
830
+ (m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
831
+ )
832
+ )
833
+ ) AS query_${paramIdx}
834
+ `);
835
+ params.push(searchId, id, id, withNextMessages, withPreviousMessages);
836
+ paramIdx++;
837
+ }
838
+ const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
839
+ const messages = await this.operations.executeQuery({ sql: finalQuery, params });
840
+ if (!Array.isArray(messages)) {
841
+ return [];
842
+ }
843
+ const processedMessages = messages.map((message) => {
844
+ const processedMsg = {};
845
+ for (const [key, value] of Object.entries(message)) {
846
+ if (key === `type` && value === `v2`) continue;
847
+ processedMsg[key] = deserializeValue(value);
848
+ }
849
+ return processedMsg;
850
+ });
851
+ return processedMessages;
946
852
  }
947
853
  async getMessages({
948
854
  threadId,
855
+ resourceId,
949
856
  selectBy,
950
857
  format
951
858
  }) {
952
- const fullTableName = this.getTableName(TABLE_MESSAGES);
953
- const limit = this.resolveMessageLimit({
954
- last: selectBy?.last,
955
- defaultLimit: 40
956
- });
957
- const include = selectBy?.include || [];
958
- const messages = [];
959
859
  try {
860
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
861
+ const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
862
+ const limit = resolveMessageLimit({
863
+ last: selectBy?.last,
864
+ defaultLimit: 40
865
+ });
866
+ const include = selectBy?.include || [];
867
+ const messages = [];
960
868
  if (include.length) {
961
869
  const includeResult = await this._getIncludedMessages(threadId, selectBy);
962
870
  if (Array.isArray(includeResult)) messages.push(...includeResult);
@@ -968,7 +876,7 @@ var D1Store = class extends MastraStorage {
968
876
  }
969
877
  query.orderBy("createdAt", "DESC").limit(limit);
970
878
  const { sql, params } = query.build();
971
- const result = await this.executeQuery({ sql, params });
879
+ const result = await this.operations.executeQuery({ sql, params });
972
880
  if (Array.isArray(result)) messages.push(...result);
973
881
  messages.sort((a, b) => {
974
882
  const aRecord = a;
@@ -981,7 +889,7 @@ var D1Store = class extends MastraStorage {
981
889
  const processedMsg = {};
982
890
  for (const [key, value] of Object.entries(message)) {
983
891
  if (key === `type` && value === `v2`) continue;
984
- processedMsg[key] = this.deserializeValue(value);
892
+ processedMsg[key] = deserializeValue(value);
985
893
  }
986
894
  return processedMsg;
987
895
  });
@@ -996,7 +904,48 @@ var D1Store = class extends MastraStorage {
996
904
  domain: ErrorDomain.STORAGE,
997
905
  category: ErrorCategory.THIRD_PARTY,
998
906
  text: `Failed to retrieve messages for thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
999
- details: { threadId }
907
+ details: { threadId, resourceId: resourceId ?? "" }
908
+ },
909
+ error
910
+ );
911
+ this.logger?.error(mastraError.toString());
912
+ this.logger?.trackException(mastraError);
913
+ throw mastraError;
914
+ }
915
+ }
916
+ async getMessagesById({
917
+ messageIds,
918
+ format
919
+ }) {
920
+ if (messageIds.length === 0) return [];
921
+ const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
922
+ const messages = [];
923
+ try {
924
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
925
+ query.orderBy("createdAt", "DESC");
926
+ const { sql, params } = query.build();
927
+ const result = await this.operations.executeQuery({ sql, params });
928
+ if (Array.isArray(result)) messages.push(...result);
929
+ const processedMessages = messages.map((message) => {
930
+ const processedMsg = {};
931
+ for (const [key, value] of Object.entries(message)) {
932
+ if (key === `type` && value === `v2`) continue;
933
+ processedMsg[key] = deserializeValue(value);
934
+ }
935
+ return processedMsg;
936
+ });
937
+ this.logger.debug(`Retrieved ${messages.length} messages`);
938
+ const list = new MessageList().add(processedMessages, "memory");
939
+ if (format === `v1`) return list.get.all.v1();
940
+ return list.get.all.v2();
941
+ } catch (error) {
942
+ const mastraError = new MastraError(
943
+ {
944
+ id: "CLOUDFLARE_D1_STORAGE_GET_MESSAGES_BY_ID_ERROR",
945
+ domain: ErrorDomain.STORAGE,
946
+ category: ErrorCategory.THIRD_PARTY,
947
+ text: `Failed to retrieve messages by ID: ${error instanceof Error ? error.message : String(error)}`,
948
+ details: { messageIds: JSON.stringify(messageIds) }
1000
949
  },
1001
950
  error
1002
951
  );
@@ -1007,44 +956,97 @@ var D1Store = class extends MastraStorage {
1007
956
  }
1008
957
  async getMessagesPaginated({
1009
958
  threadId,
959
+ resourceId,
1010
960
  selectBy,
1011
961
  format
1012
962
  }) {
1013
- const { dateRange, page = 0, perPage = 40 } = selectBy?.pagination || {};
963
+ const { dateRange, page = 0, perPage: perPageInput } = selectBy?.pagination || {};
1014
964
  const { start: fromDate, end: toDate } = dateRange || {};
1015
- const fullTableName = this.getTableName(TABLE_MESSAGES);
965
+ const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
966
+ const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
1016
967
  const messages = [];
1017
968
  try {
969
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
1018
970
  if (selectBy?.include?.length) {
1019
971
  const includeResult = await this._getIncludedMessages(threadId, selectBy);
1020
972
  if (Array.isArray(includeResult)) messages.push(...includeResult);
1021
973
  }
1022
974
  const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
1023
975
  if (fromDate) {
1024
- countQuery.andWhere("createdAt >= ?", this.serializeDate(fromDate));
976
+ countQuery.andWhere("createdAt >= ?", serializeDate(fromDate));
1025
977
  }
1026
978
  if (toDate) {
1027
- countQuery.andWhere("createdAt <= ?", this.serializeDate(toDate));
979
+ countQuery.andWhere("createdAt <= ?", serializeDate(toDate));
1028
980
  }
1029
- const countResult = await this.executeQuery(countQuery.build());
981
+ const countResult = await this.operations.executeQuery(countQuery.build());
1030
982
  const total = Number(countResult[0]?.count ?? 0);
1031
- const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
983
+ if (total === 0 && messages.length === 0) {
984
+ return {
985
+ messages: [],
986
+ total: 0,
987
+ page,
988
+ perPage,
989
+ hasMore: false
990
+ };
991
+ }
992
+ const excludeIds = messages.map((m) => m.id);
993
+ const excludeCondition = excludeIds.length > 0 ? `AND id NOT IN (${excludeIds.map(() => "?").join(",")})` : "";
994
+ let query;
995
+ let queryParams = [threadId];
1032
996
  if (fromDate) {
1033
- query.andWhere("createdAt >= ?", this.serializeDate(fromDate));
997
+ queryParams.push(serializeDate(fromDate));
1034
998
  }
1035
999
  if (toDate) {
1036
- query.andWhere("createdAt <= ?", this.serializeDate(toDate));
1000
+ queryParams.push(serializeDate(toDate));
1001
+ }
1002
+ if (excludeIds.length > 0) {
1003
+ queryParams.push(...excludeIds);
1004
+ }
1005
+ if (selectBy?.last && selectBy.last > 0) {
1006
+ query = `
1007
+ SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
1008
+ FROM ${fullTableName}
1009
+ WHERE thread_id = ?
1010
+ ${fromDate ? "AND createdAt >= ?" : ""}
1011
+ ${toDate ? "AND createdAt <= ?" : ""}
1012
+ ${excludeCondition}
1013
+ ORDER BY createdAt DESC
1014
+ LIMIT ?
1015
+ `;
1016
+ queryParams.push(selectBy.last);
1017
+ } else {
1018
+ query = `
1019
+ SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
1020
+ FROM ${fullTableName}
1021
+ WHERE thread_id = ?
1022
+ ${fromDate ? "AND createdAt >= ?" : ""}
1023
+ ${toDate ? "AND createdAt <= ?" : ""}
1024
+ ${excludeCondition}
1025
+ ORDER BY createdAt DESC
1026
+ LIMIT ? OFFSET ?
1027
+ `;
1028
+ queryParams.push(perPage, page * perPage);
1029
+ }
1030
+ const results = await this.operations.executeQuery({ sql: query, params: queryParams });
1031
+ const processedMessages = results.map((message) => {
1032
+ const processedMsg = {};
1033
+ for (const [key, value] of Object.entries(message)) {
1034
+ if (key === `type` && value === `v2`) continue;
1035
+ processedMsg[key] = deserializeValue(value);
1036
+ }
1037
+ return processedMsg;
1038
+ });
1039
+ if (selectBy?.last) {
1040
+ processedMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1037
1041
  }
1038
- query.orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
1039
- const results = await this.executeQuery(query.build());
1040
- const list = new MessageList().add(results, "memory");
1042
+ const list = new MessageList().add(processedMessages, "memory");
1041
1043
  messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
1042
1044
  return {
1043
1045
  messages,
1044
1046
  total,
1045
1047
  page,
1046
1048
  perPage,
1047
- hasMore: page * perPage + messages.length < total
1049
+ hasMore: selectBy?.last ? false : page * perPage + messages.length < total
1048
1050
  };
1049
1051
  } catch (error) {
1050
1052
  const mastraError = new MastraError(
@@ -1053,7 +1055,7 @@ var D1Store = class extends MastraStorage {
1053
1055
  domain: ErrorDomain.STORAGE,
1054
1056
  category: ErrorCategory.THIRD_PARTY,
1055
1057
  text: `Failed to retrieve messages for thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
1056
- details: { threadId }
1058
+ details: { threadId, resourceId: resourceId ?? "" }
1057
1059
  },
1058
1060
  error
1059
1061
  );
@@ -1068,132 +1070,446 @@ var D1Store = class extends MastraStorage {
1068
1070
  };
1069
1071
  }
1070
1072
  }
1071
- async persistWorkflowSnapshot({
1072
- workflowName,
1073
- runId,
1074
- snapshot
1075
- }) {
1076
- const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1077
- const now = (/* @__PURE__ */ new Date()).toISOString();
1078
- const currentSnapshot = await this.load({
1079
- tableName: TABLE_WORKFLOW_SNAPSHOT,
1080
- keys: { workflow_name: workflowName, run_id: runId }
1081
- });
1082
- const persisting = currentSnapshot ? {
1083
- ...currentSnapshot,
1084
- snapshot: JSON.stringify(snapshot),
1085
- updatedAt: now
1086
- } : {
1087
- workflow_name: workflowName,
1088
- run_id: runId,
1089
- snapshot,
1090
- createdAt: now,
1091
- updatedAt: now
1092
- };
1093
- const processedRecord = await this.processRecord(persisting);
1094
- const columns = Object.keys(processedRecord);
1095
- const values = Object.values(processedRecord);
1096
- const updateMap = {
1097
- snapshot: "excluded.snapshot",
1098
- updatedAt: "excluded.updatedAt"
1099
- };
1100
- this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
1101
- const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
1102
- const { sql, params } = query.build();
1073
+ async updateMessages(args) {
1074
+ const { messages } = args;
1075
+ this.logger.debug("Updating messages", { count: messages.length });
1076
+ if (!messages.length) {
1077
+ return [];
1078
+ }
1079
+ const messageIds = messages.map((m) => m.id);
1080
+ const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
1081
+ const threadsTableName = this.operations.getTableName(TABLE_THREADS);
1103
1082
  try {
1104
- await this.executeQuery({ sql, params });
1083
+ const placeholders = messageIds.map(() => "?").join(",");
1084
+ const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
1085
+ const existingMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
1086
+ if (existingMessages.length === 0) {
1087
+ return [];
1088
+ }
1089
+ const parsedExistingMessages = existingMessages.map((msg) => {
1090
+ if (typeof msg.content === "string") {
1091
+ try {
1092
+ msg.content = JSON.parse(msg.content);
1093
+ } catch {
1094
+ }
1095
+ }
1096
+ return msg;
1097
+ });
1098
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
1099
+ const updateQueries = [];
1100
+ for (const existingMessage of parsedExistingMessages) {
1101
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
1102
+ if (!updatePayload) continue;
1103
+ const { id, ...fieldsToUpdate } = updatePayload;
1104
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
1105
+ threadIdsToUpdate.add(existingMessage.threadId);
1106
+ if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
1107
+ threadIdsToUpdate.add(updatePayload.threadId);
1108
+ }
1109
+ const setClauses = [];
1110
+ const values = [];
1111
+ const updatableFields = { ...fieldsToUpdate };
1112
+ if (updatableFields.content) {
1113
+ const existingContent = existingMessage.content || {};
1114
+ const newContent = {
1115
+ ...existingContent,
1116
+ ...updatableFields.content,
1117
+ // Deep merge metadata if it exists on both
1118
+ ...existingContent?.metadata && updatableFields.content.metadata ? {
1119
+ metadata: {
1120
+ ...existingContent.metadata,
1121
+ ...updatableFields.content.metadata
1122
+ }
1123
+ } : {}
1124
+ };
1125
+ setClauses.push(`content = ?`);
1126
+ values.push(JSON.stringify(newContent));
1127
+ delete updatableFields.content;
1128
+ }
1129
+ for (const key in updatableFields) {
1130
+ if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
1131
+ const dbColumn = key === "threadId" ? "thread_id" : key;
1132
+ setClauses.push(`${dbColumn} = ?`);
1133
+ values.push(updatableFields[key]);
1134
+ }
1135
+ }
1136
+ if (setClauses.length > 0) {
1137
+ values.push(id);
1138
+ const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
1139
+ updateQueries.push({ sql: updateQuery, params: values });
1140
+ }
1141
+ }
1142
+ for (const query of updateQueries) {
1143
+ await this.operations.executeQuery(query);
1144
+ }
1145
+ if (threadIdsToUpdate.size > 0) {
1146
+ const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
1147
+ const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
1148
+ const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
1149
+ await this.operations.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
1150
+ }
1151
+ const updatedMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
1152
+ return updatedMessages.map((message) => {
1153
+ if (typeof message.content === "string") {
1154
+ try {
1155
+ message.content = JSON.parse(message.content);
1156
+ } catch {
1157
+ }
1158
+ }
1159
+ return message;
1160
+ });
1105
1161
  } catch (error) {
1106
1162
  throw new MastraError(
1107
1163
  {
1108
- id: "CLOUDFLARE_D1_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_ERROR",
1164
+ id: "CLOUDFLARE_D1_STORAGE_UPDATE_MESSAGES_FAILED",
1109
1165
  domain: ErrorDomain.STORAGE,
1110
1166
  category: ErrorCategory.THIRD_PARTY,
1111
- text: `Failed to persist workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
1112
- details: { workflowName, runId }
1167
+ details: { count: messages.length }
1113
1168
  },
1114
1169
  error
1115
1170
  );
1116
1171
  }
1117
1172
  }
1118
- async loadWorkflowSnapshot(params) {
1119
- const { workflowName, runId } = params;
1120
- this.logger.debug("Loading workflow snapshot", { workflowName, runId });
1173
+ };
1174
+ var StoreOperationsD1 = class extends StoreOperations {
1175
+ client;
1176
+ binding;
1177
+ tablePrefix;
1178
+ constructor(config) {
1179
+ super();
1180
+ this.client = config.client;
1181
+ this.binding = config.binding;
1182
+ this.tablePrefix = config.tablePrefix || "";
1183
+ }
1184
+ async hasColumn(table, column) {
1185
+ const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
1186
+ const sql = `PRAGMA table_info(${fullTableName});`;
1187
+ const result = await this.executeQuery({ sql, params: [] });
1188
+ if (!result || !Array.isArray(result)) return false;
1189
+ return result.some((col) => col.name === column || col.name === column.toLowerCase());
1190
+ }
1191
+ getTableName(tableName) {
1192
+ return `${this.tablePrefix}${tableName}`;
1193
+ }
1194
+ formatSqlParams(params) {
1195
+ return params.map((p) => p === void 0 || p === null ? null : p);
1196
+ }
1197
+ async executeWorkersBindingQuery({
1198
+ sql,
1199
+ params = [],
1200
+ first = false
1201
+ }) {
1202
+ if (!this.binding) {
1203
+ throw new Error("Workers binding is not configured");
1204
+ }
1121
1205
  try {
1122
- const d = await this.load({
1123
- tableName: TABLE_WORKFLOW_SNAPSHOT,
1124
- keys: {
1125
- workflow_name: workflowName,
1126
- run_id: runId
1206
+ const statement = this.binding.prepare(sql);
1207
+ const formattedParams = this.formatSqlParams(params);
1208
+ let result;
1209
+ if (formattedParams.length > 0) {
1210
+ if (first) {
1211
+ result = await statement.bind(...formattedParams).first();
1212
+ if (!result) return null;
1213
+ return result;
1214
+ } else {
1215
+ result = await statement.bind(...formattedParams).all();
1216
+ const results = result.results || [];
1217
+ return results;
1127
1218
  }
1128
- });
1129
- return d ? d.snapshot : null;
1219
+ } else {
1220
+ if (first) {
1221
+ result = await statement.first();
1222
+ if (!result) return null;
1223
+ return result;
1224
+ } else {
1225
+ result = await statement.all();
1226
+ const results = result.results || [];
1227
+ return results;
1228
+ }
1229
+ }
1130
1230
  } catch (error) {
1131
1231
  throw new MastraError(
1132
1232
  {
1133
- id: "CLOUDFLARE_D1_STORAGE_LOAD_WORKFLOW_SNAPSHOT_ERROR",
1233
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_WORKERS_BINDING_QUERY_FAILED",
1134
1234
  domain: ErrorDomain.STORAGE,
1135
1235
  category: ErrorCategory.THIRD_PARTY,
1136
- text: `Failed to load workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
1137
- details: { workflowName, runId }
1236
+ details: { sql }
1237
+ },
1238
+ error
1239
+ );
1240
+ }
1241
+ }
1242
+ async executeRestQuery({
1243
+ sql,
1244
+ params = [],
1245
+ first = false
1246
+ }) {
1247
+ if (!this.client) {
1248
+ throw new Error("D1 client is not configured");
1249
+ }
1250
+ try {
1251
+ const formattedParams = this.formatSqlParams(params);
1252
+ const response = await this.client.query({
1253
+ sql,
1254
+ params: formattedParams
1255
+ });
1256
+ const result = response.result || [];
1257
+ const results = result.flatMap((r) => r.results || []);
1258
+ if (first) {
1259
+ return results[0] || null;
1260
+ }
1261
+ return results;
1262
+ } catch (error) {
1263
+ throw new MastraError(
1264
+ {
1265
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_REST_QUERY_FAILED",
1266
+ domain: ErrorDomain.STORAGE,
1267
+ category: ErrorCategory.THIRD_PARTY,
1268
+ details: { sql }
1269
+ },
1270
+ error
1271
+ );
1272
+ }
1273
+ }
1274
+ async executeQuery(options) {
1275
+ if (this.binding) {
1276
+ return this.executeWorkersBindingQuery(options);
1277
+ } else if (this.client) {
1278
+ return this.executeRestQuery(options);
1279
+ } else {
1280
+ throw new Error("Neither binding nor client is configured");
1281
+ }
1282
+ }
1283
+ async getTableColumns(tableName) {
1284
+ try {
1285
+ const sql = `PRAGMA table_info(${tableName})`;
1286
+ const result = await this.executeQuery({ sql });
1287
+ if (!result || !Array.isArray(result)) {
1288
+ return [];
1289
+ }
1290
+ return result.map((row) => ({
1291
+ name: row.name,
1292
+ type: row.type
1293
+ }));
1294
+ } catch (error) {
1295
+ this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
1296
+ return [];
1297
+ }
1298
+ }
1299
+ serializeValue(value) {
1300
+ if (value === null || value === void 0) {
1301
+ return null;
1302
+ }
1303
+ if (value instanceof Date) {
1304
+ return value.toISOString();
1305
+ }
1306
+ if (typeof value === "object") {
1307
+ return JSON.stringify(value);
1308
+ }
1309
+ return value;
1310
+ }
1311
+ getSqlType(type) {
1312
+ switch (type) {
1313
+ case "bigint":
1314
+ return "INTEGER";
1315
+ // SQLite uses INTEGER for all integer sizes
1316
+ case "jsonb":
1317
+ return "TEXT";
1318
+ // Store JSON as TEXT in SQLite
1319
+ default:
1320
+ return super.getSqlType(type);
1321
+ }
1322
+ }
1323
+ async createTable({
1324
+ tableName,
1325
+ schema
1326
+ }) {
1327
+ try {
1328
+ const fullTableName = this.getTableName(tableName);
1329
+ const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
1330
+ const type = this.getSqlType(colDef.type);
1331
+ const nullable = colDef.nullable === false ? "NOT NULL" : "";
1332
+ const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
1333
+ return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
1334
+ });
1335
+ const tableConstraints = [];
1336
+ if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
1337
+ tableConstraints.push("UNIQUE (workflow_name, run_id)");
1338
+ }
1339
+ const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
1340
+ const { sql, params } = query.build();
1341
+ await this.executeQuery({ sql, params });
1342
+ this.logger.debug(`Created table ${fullTableName}`);
1343
+ } catch (error) {
1344
+ throw new MastraError(
1345
+ {
1346
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_CREATE_TABLE_FAILED",
1347
+ domain: ErrorDomain.STORAGE,
1348
+ category: ErrorCategory.THIRD_PARTY,
1349
+ details: { tableName }
1350
+ },
1351
+ error
1352
+ );
1353
+ }
1354
+ }
1355
+ async clearTable({ tableName }) {
1356
+ try {
1357
+ const fullTableName = this.getTableName(tableName);
1358
+ const query = createSqlBuilder().delete(fullTableName);
1359
+ const { sql, params } = query.build();
1360
+ await this.executeQuery({ sql, params });
1361
+ this.logger.debug(`Cleared table ${fullTableName}`);
1362
+ } catch (error) {
1363
+ throw new MastraError(
1364
+ {
1365
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_CLEAR_TABLE_FAILED",
1366
+ domain: ErrorDomain.STORAGE,
1367
+ category: ErrorCategory.THIRD_PARTY,
1368
+ details: { tableName }
1369
+ },
1370
+ error
1371
+ );
1372
+ }
1373
+ }
1374
+ async dropTable({ tableName }) {
1375
+ try {
1376
+ const fullTableName = this.getTableName(tableName);
1377
+ const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
1378
+ await this.executeQuery({ sql });
1379
+ this.logger.debug(`Dropped table ${fullTableName}`);
1380
+ } catch (error) {
1381
+ throw new MastraError(
1382
+ {
1383
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_DROP_TABLE_FAILED",
1384
+ domain: ErrorDomain.STORAGE,
1385
+ category: ErrorCategory.THIRD_PARTY,
1386
+ details: { tableName }
1387
+ },
1388
+ error
1389
+ );
1390
+ }
1391
+ }
1392
+ async alterTable(args) {
1393
+ try {
1394
+ const fullTableName = this.getTableName(args.tableName);
1395
+ const existingColumns = await this.getTableColumns(fullTableName);
1396
+ const existingColumnNames = new Set(existingColumns.map((col) => col.name));
1397
+ for (const [columnName, column] of Object.entries(args.schema)) {
1398
+ if (!existingColumnNames.has(columnName) && args.ifNotExists.includes(columnName)) {
1399
+ const sqlType = this.getSqlType(column.type);
1400
+ const defaultValue = this.getDefaultValue(column.type);
1401
+ const sql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${defaultValue}`;
1402
+ await this.executeQuery({ sql });
1403
+ this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
1404
+ }
1405
+ }
1406
+ } catch (error) {
1407
+ throw new MastraError(
1408
+ {
1409
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_ALTER_TABLE_FAILED",
1410
+ domain: ErrorDomain.STORAGE,
1411
+ category: ErrorCategory.THIRD_PARTY,
1412
+ details: { tableName: args.tableName }
1413
+ },
1414
+ error
1415
+ );
1416
+ }
1417
+ }
1418
+ async insert({ tableName, record }) {
1419
+ try {
1420
+ const fullTableName = this.getTableName(tableName);
1421
+ const processedRecord = await this.processRecord(record);
1422
+ const columns = Object.keys(processedRecord);
1423
+ const values = Object.values(processedRecord);
1424
+ const query = createSqlBuilder().insert(fullTableName, columns, values);
1425
+ const { sql, params } = query.build();
1426
+ await this.executeQuery({ sql, params });
1427
+ } catch (error) {
1428
+ throw new MastraError(
1429
+ {
1430
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_INSERT_FAILED",
1431
+ domain: ErrorDomain.STORAGE,
1432
+ category: ErrorCategory.THIRD_PARTY,
1433
+ details: { tableName }
1138
1434
  },
1139
1435
  error
1140
1436
  );
1141
1437
  }
1142
1438
  }
1143
- /**
1144
- * Insert multiple records in a batch operation
1145
- * @param tableName The table to insert into
1146
- * @param records The records to insert
1147
- */
1148
1439
  async batchInsert({ tableName, records }) {
1149
- if (records.length === 0) return;
1150
- const fullTableName = this.getTableName(tableName);
1151
1440
  try {
1152
- const batchSize = 50;
1153
- for (let i = 0; i < records.length; i += batchSize) {
1154
- const batch = records.slice(i, i + batchSize);
1155
- const recordsToInsert = batch;
1156
- if (recordsToInsert.length > 0) {
1157
- const firstRecord = recordsToInsert[0];
1158
- const columns = Object.keys(firstRecord || {});
1159
- for (const record of recordsToInsert) {
1160
- const values = columns.map((col) => {
1161
- if (!record) return null;
1162
- const value = typeof col === "string" ? record[col] : null;
1163
- return this.serializeValue(value);
1164
- });
1165
- const query = createSqlBuilder().insert(fullTableName, columns, values);
1166
- const { sql, params } = query.build();
1167
- await this.executeQuery({ sql, params });
1168
- }
1441
+ if (records.length === 0) return;
1442
+ const fullTableName = this.getTableName(tableName);
1443
+ const processedRecords = await Promise.all(records.map((record) => this.processRecord(record)));
1444
+ const columns = Object.keys(processedRecords[0] || {});
1445
+ for (const record of processedRecords) {
1446
+ const values = Object.values(record);
1447
+ const query = createSqlBuilder().insert(fullTableName, columns, values);
1448
+ const { sql, params } = query.build();
1449
+ await this.executeQuery({ sql, params });
1450
+ }
1451
+ } catch (error) {
1452
+ throw new MastraError(
1453
+ {
1454
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_BATCH_INSERT_FAILED",
1455
+ domain: ErrorDomain.STORAGE,
1456
+ category: ErrorCategory.THIRD_PARTY,
1457
+ details: { tableName }
1458
+ },
1459
+ error
1460
+ );
1461
+ }
1462
+ }
1463
+ async load({ tableName, keys }) {
1464
+ try {
1465
+ const fullTableName = this.getTableName(tableName);
1466
+ const query = createSqlBuilder().select("*").from(fullTableName);
1467
+ let firstKey = true;
1468
+ for (const [key, value] of Object.entries(keys)) {
1469
+ if (firstKey) {
1470
+ query.where(`${key} = ?`, value);
1471
+ firstKey = false;
1472
+ } else {
1473
+ query.andWhere(`${key} = ?`, value);
1169
1474
  }
1170
- this.logger.debug(
1171
- `Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
1172
- );
1173
1475
  }
1174
- this.logger.debug(`Successfully batch inserted ${records.length} records into ${tableName}`);
1476
+ query.orderBy("createdAt", "DESC");
1477
+ query.limit(1);
1478
+ const { sql, params } = query.build();
1479
+ const result = await this.executeQuery({ sql, params, first: true });
1480
+ if (!result) {
1481
+ return null;
1482
+ }
1483
+ const deserializedResult = {};
1484
+ for (const [key, value] of Object.entries(result)) {
1485
+ deserializedResult[key] = deserializeValue(value);
1486
+ }
1487
+ return deserializedResult;
1175
1488
  } catch (error) {
1176
1489
  throw new MastraError(
1177
1490
  {
1178
- id: "CLOUDFLARE_D1_STORAGE_BATCH_INSERT_ERROR",
1491
+ id: "CLOUDFLARE_D1_STORE_OPERATIONS_LOAD_FAILED",
1179
1492
  domain: ErrorDomain.STORAGE,
1180
1493
  category: ErrorCategory.THIRD_PARTY,
1181
- text: `Failed to batch insert into ${tableName}: ${error instanceof Error ? error.message : String(error)}`,
1182
1494
  details: { tableName }
1183
1495
  },
1184
1496
  error
1185
1497
  );
1186
1498
  }
1187
1499
  }
1500
+ async processRecord(record) {
1501
+ const processed = {};
1502
+ for (const [key, value] of Object.entries(record)) {
1503
+ processed[key] = this.serializeValue(value);
1504
+ }
1505
+ return processed;
1506
+ }
1188
1507
  /**
1189
1508
  * Upsert multiple records in a batch operation
1190
1509
  * @param tableName The table to insert into
1191
1510
  * @param records The records to insert
1192
1511
  */
1193
- async batchUpsert({
1194
- tableName,
1195
- records
1196
- }) {
1512
+ async batchUpsert({ tableName, records }) {
1197
1513
  if (records.length === 0) return;
1198
1514
  const fullTableName = this.getTableName(tableName);
1199
1515
  try {
@@ -1240,273 +1556,395 @@ var D1Store = class extends MastraStorage {
1240
1556
  );
1241
1557
  }
1242
1558
  }
1243
- /**
1244
- * @deprecated use getTracesPaginated instead
1245
- */
1246
- async getTraces({
1247
- name,
1248
- scope,
1249
- page,
1250
- perPage,
1251
- attributes,
1252
- fromDate,
1253
- toDate
1254
- }) {
1255
- const fullTableName = this.getTableName(TABLE_TRACES);
1559
+ };
1560
+ function transformScoreRow(row) {
1561
+ const deserialized = { ...row };
1562
+ deserialized.input = safelyParseJSON(row.input);
1563
+ deserialized.output = safelyParseJSON(row.output);
1564
+ deserialized.scorer = safelyParseJSON(row.scorer);
1565
+ deserialized.preprocessStepResult = safelyParseJSON(row.preprocessStepResult);
1566
+ deserialized.analyzeStepResult = safelyParseJSON(row.analyzeStepResult);
1567
+ deserialized.metadata = safelyParseJSON(row.metadata);
1568
+ deserialized.additionalContext = safelyParseJSON(row.additionalContext);
1569
+ deserialized.runtimeContext = safelyParseJSON(row.runtimeContext);
1570
+ deserialized.entity = safelyParseJSON(row.entity);
1571
+ deserialized.createdAt = row.createdAtZ || row.createdAt;
1572
+ deserialized.updatedAt = row.updatedAtZ || row.updatedAt;
1573
+ return deserialized;
1574
+ }
1575
+ var ScoresStorageD1 = class extends ScoresStorage {
1576
+ operations;
1577
+ constructor({ operations }) {
1578
+ super();
1579
+ this.operations = operations;
1580
+ }
1581
+ async getScoreById({ id }) {
1256
1582
  try {
1257
- const query = createSqlBuilder().select("*").from(fullTableName).where("1=1");
1258
- if (name) {
1259
- query.andWhere("name LIKE ?", `%${name}%`);
1260
- }
1261
- if (scope) {
1262
- query.andWhere("scope = ?", scope);
1583
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1584
+ const query = createSqlBuilder().select("*").from(fullTableName).where("id = ?", id);
1585
+ const { sql, params } = query.build();
1586
+ const result = await this.operations.executeQuery({ sql, params, first: true });
1587
+ if (!result) {
1588
+ return null;
1263
1589
  }
1264
- if (attributes && Object.keys(attributes).length > 0) {
1265
- for (const [key, value] of Object.entries(attributes)) {
1266
- query.jsonLike("attributes", key, value);
1590
+ return transformScoreRow(result);
1591
+ } catch (error) {
1592
+ throw new MastraError(
1593
+ {
1594
+ id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORE_BY_ID_FAILED",
1595
+ domain: ErrorDomain.STORAGE,
1596
+ category: ErrorCategory.THIRD_PARTY
1597
+ },
1598
+ error
1599
+ );
1600
+ }
1601
+ }
1602
+ async saveScore(score) {
1603
+ let parsedScore;
1604
+ try {
1605
+ parsedScore = saveScorePayloadSchema.parse(score);
1606
+ } catch (error) {
1607
+ throw new MastraError(
1608
+ {
1609
+ id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
1610
+ domain: ErrorDomain.STORAGE,
1611
+ category: ErrorCategory.USER,
1612
+ details: { scoreId: score.id }
1613
+ },
1614
+ error
1615
+ );
1616
+ }
1617
+ try {
1618
+ const id = crypto.randomUUID();
1619
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1620
+ const serializedRecord = {};
1621
+ for (const [key, value] of Object.entries(parsedScore)) {
1622
+ if (value !== null && value !== void 0) {
1623
+ if (typeof value === "object") {
1624
+ serializedRecord[key] = JSON.stringify(value);
1625
+ } else {
1626
+ serializedRecord[key] = value;
1627
+ }
1628
+ } else {
1629
+ serializedRecord[key] = null;
1267
1630
  }
1268
1631
  }
1269
- if (fromDate) {
1270
- query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1271
- }
1272
- if (toDate) {
1273
- query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1274
- }
1275
- query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
1632
+ serializedRecord.id = id;
1633
+ serializedRecord.createdAt = (/* @__PURE__ */ new Date()).toISOString();
1634
+ serializedRecord.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1635
+ const columns = Object.keys(serializedRecord);
1636
+ const values = Object.values(serializedRecord);
1637
+ const query = createSqlBuilder().insert(fullTableName, columns, values);
1276
1638
  const { sql, params } = query.build();
1277
- const results = await this.executeQuery({ sql, params });
1278
- return isArrayOfRecords(results) ? results.map(
1279
- (trace) => ({
1280
- ...trace,
1281
- attributes: this.deserializeValue(trace.attributes, "jsonb"),
1282
- status: this.deserializeValue(trace.status, "jsonb"),
1283
- events: this.deserializeValue(trace.events, "jsonb"),
1284
- links: this.deserializeValue(trace.links, "jsonb"),
1285
- other: this.deserializeValue(trace.other, "jsonb")
1286
- })
1287
- ) : [];
1639
+ await this.operations.executeQuery({ sql, params });
1640
+ const scoreFromDb = await this.getScoreById({ id });
1641
+ return { score: scoreFromDb };
1288
1642
  } catch (error) {
1289
- const mastraError = new MastraError(
1643
+ throw new MastraError(
1290
1644
  {
1291
- id: "CLOUDFLARE_D1_STORAGE_GET_TRACES_ERROR",
1645
+ id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED",
1292
1646
  domain: ErrorDomain.STORAGE,
1293
- category: ErrorCategory.THIRD_PARTY,
1294
- text: `Failed to retrieve traces: ${error instanceof Error ? error.message : String(error)}`,
1295
- details: {
1296
- name: name ?? "",
1297
- scope: scope ?? ""
1298
- }
1647
+ category: ErrorCategory.THIRD_PARTY
1299
1648
  },
1300
1649
  error
1301
1650
  );
1302
- this.logger?.error(mastraError.toString());
1303
- this.logger?.trackException(mastraError);
1304
- return [];
1305
1651
  }
1306
1652
  }
1307
- async getTracesPaginated(args) {
1308
- const { name, scope, page, perPage, attributes, fromDate, toDate } = args;
1309
- const fullTableName = this.getTableName(TABLE_TRACES);
1653
+ async getScoresByScorerId({
1654
+ scorerId,
1655
+ entityId,
1656
+ entityType,
1657
+ source,
1658
+ pagination
1659
+ }) {
1310
1660
  try {
1311
- const dataQuery = createSqlBuilder().select("*").from(fullTableName).where("1=1");
1312
- const countQuery = createSqlBuilder().count().from(fullTableName).where("1=1");
1313
- if (name) {
1314
- dataQuery.andWhere("name LIKE ?", `%${name}%`);
1315
- countQuery.andWhere("name LIKE ?", `%${name}%`);
1661
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1662
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("scorerId = ?", scorerId);
1663
+ if (entityId) {
1664
+ countQuery.andWhere("entityId = ?", entityId);
1316
1665
  }
1317
- if (scope) {
1318
- dataQuery.andWhere("scope = ?", scope);
1319
- countQuery.andWhere("scope = ?", scope);
1666
+ if (entityType) {
1667
+ countQuery.andWhere("entityType = ?", entityType);
1320
1668
  }
1321
- if (attributes && Object.keys(attributes).length > 0) {
1322
- for (const [key, value] of Object.entries(attributes)) {
1323
- dataQuery.jsonLike("attributes", key, value);
1324
- countQuery.jsonLike("attributes", key, value);
1325
- }
1669
+ if (source) {
1670
+ countQuery.andWhere("source = ?", source);
1326
1671
  }
1327
- if (fromDate) {
1328
- const fromDateStr = fromDate instanceof Date ? fromDate.toISOString() : fromDate;
1329
- dataQuery.andWhere("createdAt >= ?", fromDateStr);
1330
- countQuery.andWhere("createdAt >= ?", fromDateStr);
1672
+ const countResult = await this.operations.executeQuery(countQuery.build());
1673
+ const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1674
+ if (total === 0) {
1675
+ return {
1676
+ pagination: {
1677
+ total: 0,
1678
+ page: pagination.page,
1679
+ perPage: pagination.perPage,
1680
+ hasMore: false
1681
+ },
1682
+ scores: []
1683
+ };
1331
1684
  }
1332
- if (toDate) {
1333
- const toDateStr = toDate instanceof Date ? toDate.toISOString() : toDate;
1334
- dataQuery.andWhere("createdAt <= ?", toDateStr);
1335
- countQuery.andWhere("createdAt <= ?", toDateStr);
1685
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("scorerId = ?", scorerId);
1686
+ if (entityId) {
1687
+ selectQuery.andWhere("entityId = ?", entityId);
1336
1688
  }
1337
- const countResult = await this.executeQuery(countQuery.build());
1338
- const total = Number(countResult?.[0]?.count ?? 0);
1339
- dataQuery.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
1340
- const results = await this.executeQuery(dataQuery.build());
1341
- const traces = isArrayOfRecords(results) ? results.map(
1342
- (trace) => ({
1343
- ...trace,
1344
- attributes: this.deserializeValue(trace.attributes, "jsonb"),
1345
- status: this.deserializeValue(trace.status, "jsonb"),
1346
- events: this.deserializeValue(trace.events, "jsonb"),
1347
- links: this.deserializeValue(trace.links, "jsonb"),
1348
- other: this.deserializeValue(trace.other, "jsonb")
1349
- })
1350
- ) : [];
1689
+ if (entityType) {
1690
+ selectQuery.andWhere("entityType = ?", entityType);
1691
+ }
1692
+ if (source) {
1693
+ selectQuery.andWhere("source = ?", source);
1694
+ }
1695
+ selectQuery.limit(pagination.perPage).offset(pagination.page * pagination.perPage);
1696
+ const { sql, params } = selectQuery.build();
1697
+ const results = await this.operations.executeQuery({ sql, params });
1698
+ const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1351
1699
  return {
1352
- traces,
1353
- total,
1354
- page,
1355
- perPage,
1356
- hasMore: page * perPage + traces.length < total
1700
+ pagination: {
1701
+ total,
1702
+ page: pagination.page,
1703
+ perPage: pagination.perPage,
1704
+ hasMore: total > (pagination.page + 1) * pagination.perPage
1705
+ },
1706
+ scores
1357
1707
  };
1358
1708
  } catch (error) {
1359
- const mastraError = new MastraError(
1709
+ throw new MastraError(
1360
1710
  {
1361
- id: "CLOUDFLARE_D1_STORAGE_GET_TRACES_ERROR",
1711
+ id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SCORER_ID_FAILED",
1362
1712
  domain: ErrorDomain.STORAGE,
1363
- category: ErrorCategory.THIRD_PARTY,
1364
- text: `Failed to retrieve traces: ${error instanceof Error ? error.message : String(error)}`,
1365
- details: { name: name ?? "", scope: scope ?? "" }
1713
+ category: ErrorCategory.THIRD_PARTY
1366
1714
  },
1367
1715
  error
1368
1716
  );
1369
- this.logger?.error(mastraError.toString());
1370
- this.logger?.trackException(mastraError);
1371
- return { traces: [], total: 0, page, perPage, hasMore: false };
1372
1717
  }
1373
1718
  }
1374
- /**
1375
- * @deprecated use getEvals instead
1376
- */
1377
- async getEvalsByAgentName(agentName, type) {
1378
- const fullTableName = this.getTableName(TABLE_EVALS);
1719
+ async getScoresByRunId({
1720
+ runId,
1721
+ pagination
1722
+ }) {
1379
1723
  try {
1380
- let query = createSqlBuilder().select("*").from(fullTableName).where("agent_name = ?", agentName);
1381
- if (type === "test") {
1382
- query = query.andWhere("test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL");
1383
- } else if (type === "live") {
1384
- query = query.andWhere("(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)");
1385
- }
1386
- query.orderBy("created_at", "DESC");
1387
- const { sql, params } = query.build();
1388
- const results = await this.executeQuery({ sql, params });
1389
- return isArrayOfRecords(results) ? results.map((row) => {
1390
- const result = this.deserializeValue(row.result);
1391
- const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
1724
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1725
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("runId = ?", runId);
1726
+ const countResult = await this.operations.executeQuery(countQuery.build());
1727
+ const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1728
+ if (total === 0) {
1392
1729
  return {
1393
- input: row.input || "",
1394
- output: row.output || "",
1395
- result,
1396
- agentName: row.agent_name || "",
1397
- metricName: row.metric_name || "",
1398
- instructions: row.instructions || "",
1399
- runId: row.run_id || "",
1400
- globalRunId: row.global_run_id || "",
1401
- createdAt: row.created_at || "",
1402
- testInfo
1730
+ pagination: {
1731
+ total: 0,
1732
+ page: pagination.page,
1733
+ perPage: pagination.perPage,
1734
+ hasMore: false
1735
+ },
1736
+ scores: []
1403
1737
  };
1404
- }) : [];
1738
+ }
1739
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("runId = ?", runId).limit(pagination.perPage).offset(pagination.page * pagination.perPage);
1740
+ const { sql, params } = selectQuery.build();
1741
+ const results = await this.operations.executeQuery({ sql, params });
1742
+ const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1743
+ return {
1744
+ pagination: {
1745
+ total,
1746
+ page: pagination.page,
1747
+ perPage: pagination.perPage,
1748
+ hasMore: total > (pagination.page + 1) * pagination.perPage
1749
+ },
1750
+ scores
1751
+ };
1405
1752
  } catch (error) {
1406
- const mastraError = new MastraError(
1753
+ throw new MastraError(
1407
1754
  {
1408
- id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
1755
+ id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_RUN_ID_FAILED",
1409
1756
  domain: ErrorDomain.STORAGE,
1410
- category: ErrorCategory.THIRD_PARTY,
1411
- text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
1412
- details: { agentName }
1757
+ category: ErrorCategory.THIRD_PARTY
1413
1758
  },
1414
1759
  error
1415
1760
  );
1416
- this.logger?.error(mastraError.toString());
1417
- this.logger?.trackException(mastraError);
1418
- return [];
1419
1761
  }
1420
1762
  }
1421
- async getEvals(options) {
1422
- const { agentName, type, page = 0, perPage = 40, fromDate, toDate } = options || {};
1423
- const fullTableName = this.getTableName(TABLE_EVALS);
1424
- const conditions = [];
1425
- const queryParams = [];
1426
- if (agentName) {
1427
- conditions.push(`agent_name = ?`);
1428
- queryParams.push(agentName);
1429
- }
1430
- if (type === "test") {
1431
- conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
1432
- } else if (type === "live") {
1433
- conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
1434
- }
1435
- if (fromDate) {
1436
- conditions.push(`createdAt >= ?`);
1437
- queryParams.push(this.serializeDate(fromDate));
1438
- }
1439
- if (toDate) {
1440
- conditions.push(`createdAt <= ?`);
1441
- queryParams.push(this.serializeDate(toDate));
1442
- }
1443
- const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
1444
- if (conditions.length > 0) {
1445
- countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1446
- }
1447
- const { sql: countSql, params: countParams } = countQueryBuilder.build();
1763
+ async getScoresByEntityId({
1764
+ entityId,
1765
+ entityType,
1766
+ pagination
1767
+ }) {
1448
1768
  try {
1449
- const countResult = await this.executeQuery({
1450
- sql: countSql,
1451
- params: countParams,
1452
- first: true
1453
- });
1454
- const total = Number(countResult?.count || 0);
1455
- const currentOffset = page * perPage;
1769
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1770
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType);
1771
+ const countResult = await this.operations.executeQuery(countQuery.build());
1772
+ const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1456
1773
  if (total === 0) {
1457
1774
  return {
1458
- evals: [],
1459
- total: 0,
1460
- page,
1461
- perPage,
1462
- hasMore: false
1775
+ pagination: {
1776
+ total: 0,
1777
+ page: pagination.page,
1778
+ perPage: pagination.perPage,
1779
+ hasMore: false
1780
+ },
1781
+ scores: []
1463
1782
  };
1464
1783
  }
1465
- const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
1466
- if (conditions.length > 0) {
1467
- dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1784
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType).limit(pagination.perPage).offset(pagination.page * pagination.perPage);
1785
+ const { sql, params } = selectQuery.build();
1786
+ const results = await this.operations.executeQuery({ sql, params });
1787
+ const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
1788
+ return {
1789
+ pagination: {
1790
+ total,
1791
+ page: pagination.page,
1792
+ perPage: pagination.perPage,
1793
+ hasMore: total > (pagination.page + 1) * pagination.perPage
1794
+ },
1795
+ scores
1796
+ };
1797
+ } catch (error) {
1798
+ throw new MastraError(
1799
+ {
1800
+ id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_ENTITY_ID_FAILED",
1801
+ domain: ErrorDomain.STORAGE,
1802
+ category: ErrorCategory.THIRD_PARTY
1803
+ },
1804
+ error
1805
+ );
1806
+ }
1807
+ }
1808
+ async getScoresBySpan({
1809
+ traceId,
1810
+ spanId,
1811
+ pagination
1812
+ }) {
1813
+ try {
1814
+ const fullTableName = this.operations.getTableName(TABLE_SCORERS);
1815
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId);
1816
+ const countResult = await this.operations.executeQuery(countQuery.build());
1817
+ const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
1818
+ if (total === 0) {
1819
+ return {
1820
+ pagination: {
1821
+ total: 0,
1822
+ page: pagination.page,
1823
+ perPage: pagination.perPage,
1824
+ hasMore: false
1825
+ },
1826
+ scores: []
1827
+ };
1468
1828
  }
1469
- dataQueryBuilder.orderBy("createdAt", "DESC").limit(perPage).offset(currentOffset);
1470
- const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
1471
- const rows = await this.executeQuery({
1472
- sql: dataSql,
1473
- params: dataParams
1474
- });
1475
- const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
1476
- const result = this.deserializeValue(row.result);
1477
- const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
1478
- if (!result || typeof result !== "object" || !("score" in result)) {
1479
- throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
1829
+ const limit = pagination.perPage + 1;
1830
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId).orderBy("createdAt", "DESC").limit(limit).offset(pagination.page * pagination.perPage);
1831
+ const { sql, params } = selectQuery.build();
1832
+ const results = await this.operations.executeQuery({ sql, params });
1833
+ const rows = Array.isArray(results) ? results : [];
1834
+ const scores = rows.slice(0, pagination.perPage).map(transformScoreRow);
1835
+ return {
1836
+ pagination: {
1837
+ total,
1838
+ page: pagination.page,
1839
+ perPage: pagination.perPage,
1840
+ hasMore: rows.length > pagination.perPage
1841
+ },
1842
+ scores
1843
+ };
1844
+ } catch (error) {
1845
+ throw new MastraError(
1846
+ {
1847
+ id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SPAN_FAILED",
1848
+ domain: ErrorDomain.STORAGE,
1849
+ category: ErrorCategory.THIRD_PARTY
1850
+ },
1851
+ error
1852
+ );
1853
+ }
1854
+ }
1855
+ };
1856
+ var WorkflowsStorageD1 = class extends WorkflowsStorage {
1857
+ operations;
1858
+ constructor({ operations }) {
1859
+ super();
1860
+ this.operations = operations;
1861
+ }
1862
+ updateWorkflowResults({
1863
+ // workflowName,
1864
+ // runId,
1865
+ // stepId,
1866
+ // result,
1867
+ // runtimeContext,
1868
+ }) {
1869
+ throw new Error("Method not implemented.");
1870
+ }
1871
+ updateWorkflowState({
1872
+ // workflowName,
1873
+ // runId,
1874
+ // opts,
1875
+ }) {
1876
+ throw new Error("Method not implemented.");
1877
+ }
1878
+ async persistWorkflowSnapshot({
1879
+ workflowName,
1880
+ runId,
1881
+ resourceId,
1882
+ snapshot
1883
+ }) {
1884
+ const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1885
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1886
+ const currentSnapshot = await this.operations.load({
1887
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
1888
+ keys: { workflow_name: workflowName, run_id: runId }
1889
+ });
1890
+ const persisting = currentSnapshot ? {
1891
+ ...currentSnapshot,
1892
+ resourceId,
1893
+ snapshot: JSON.stringify(snapshot),
1894
+ updatedAt: now
1895
+ } : {
1896
+ workflow_name: workflowName,
1897
+ run_id: runId,
1898
+ resourceId,
1899
+ snapshot,
1900
+ createdAt: now,
1901
+ updatedAt: now
1902
+ };
1903
+ const processedRecord = await this.operations.processRecord(persisting);
1904
+ const columns = Object.keys(processedRecord);
1905
+ const values = Object.values(processedRecord);
1906
+ const updateMap = {
1907
+ snapshot: "excluded.snapshot",
1908
+ updatedAt: "excluded.updatedAt"
1909
+ };
1910
+ this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
1911
+ const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
1912
+ const { sql, params } = query.build();
1913
+ try {
1914
+ await this.operations.executeQuery({ sql, params });
1915
+ } catch (error) {
1916
+ throw new MastraError(
1917
+ {
1918
+ id: "CLOUDFLARE_D1_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_ERROR",
1919
+ domain: ErrorDomain.STORAGE,
1920
+ category: ErrorCategory.THIRD_PARTY,
1921
+ text: `Failed to persist workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
1922
+ details: { workflowName, runId }
1923
+ },
1924
+ error
1925
+ );
1926
+ }
1927
+ }
1928
+ async loadWorkflowSnapshot(params) {
1929
+ const { workflowName, runId } = params;
1930
+ this.logger.debug("Loading workflow snapshot", { workflowName, runId });
1931
+ try {
1932
+ const d = await this.operations.load({
1933
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
1934
+ keys: {
1935
+ workflow_name: workflowName,
1936
+ run_id: runId
1480
1937
  }
1481
- return {
1482
- input: row.input,
1483
- output: row.output,
1484
- result,
1485
- agentName: row.agent_name,
1486
- metricName: row.metric_name,
1487
- instructions: row.instructions,
1488
- testInfo,
1489
- globalRunId: row.global_run_id,
1490
- runId: row.run_id,
1491
- createdAt: row.createdAt
1492
- };
1493
1938
  });
1494
- const hasMore = currentOffset + evals.length < total;
1495
- return {
1496
- evals,
1497
- total,
1498
- page,
1499
- perPage,
1500
- hasMore
1501
- };
1939
+ return d ? d.snapshot : null;
1502
1940
  } catch (error) {
1503
1941
  throw new MastraError(
1504
1942
  {
1505
- id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
1943
+ id: "CLOUDFLARE_D1_STORAGE_LOAD_WORKFLOW_SNAPSHOT_ERROR",
1506
1944
  domain: ErrorDomain.STORAGE,
1507
1945
  category: ErrorCategory.THIRD_PARTY,
1508
- text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
1509
- details: { agentName: agentName ?? "", type: type ?? "" }
1946
+ text: `Failed to load workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
1947
+ details: { workflowName, runId }
1510
1948
  },
1511
1949
  error
1512
1950
  );
@@ -1525,17 +1963,11 @@ var D1Store = class extends MastraStorage {
1525
1963
  workflowName: row.workflow_name,
1526
1964
  runId: row.run_id,
1527
1965
  snapshot: parsedSnapshot,
1528
- createdAt: this.ensureDate(row.createdAt),
1529
- updatedAt: this.ensureDate(row.updatedAt),
1966
+ createdAt: ensureDate(row.createdAt),
1967
+ updatedAt: ensureDate(row.updatedAt),
1530
1968
  resourceId: row.resourceId
1531
1969
  };
1532
1970
  }
1533
- async hasColumn(table, column) {
1534
- const sql = `PRAGMA table_info(${table});`;
1535
- const result = await this.executeQuery({ sql, params: [] });
1536
- if (!result || !Array.isArray(result)) return false;
1537
- return result.some((col) => col.name === column || col.name === column.toLowerCase());
1538
- }
1539
1971
  async getWorkflowRuns({
1540
1972
  workflowName,
1541
1973
  fromDate,
@@ -1544,13 +1976,13 @@ var D1Store = class extends MastraStorage {
1544
1976
  offset,
1545
1977
  resourceId
1546
1978
  } = {}) {
1547
- const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1979
+ const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1548
1980
  try {
1549
1981
  const builder = createSqlBuilder().select().from(fullTableName);
1550
1982
  const countBuilder = createSqlBuilder().count().from(fullTableName);
1551
1983
  if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
1552
1984
  if (resourceId) {
1553
- const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
1985
+ const hasResourceId = await this.operations.hasColumn(fullTableName, "resourceId");
1554
1986
  if (hasResourceId) {
1555
1987
  builder.whereAnd("resourceId = ?", resourceId);
1556
1988
  countBuilder.whereAnd("resourceId = ?", resourceId);
@@ -1573,14 +2005,14 @@ var D1Store = class extends MastraStorage {
1573
2005
  let total = 0;
1574
2006
  if (limit !== void 0 && offset !== void 0) {
1575
2007
  const { sql: countSql, params: countParams } = countBuilder.build();
1576
- const countResult = await this.executeQuery({
2008
+ const countResult = await this.operations.executeQuery({
1577
2009
  sql: countSql,
1578
2010
  params: countParams,
1579
2011
  first: true
1580
2012
  });
1581
2013
  total = Number(countResult?.count ?? 0);
1582
2014
  }
1583
- const results = await this.executeQuery({ sql, params });
2015
+ const results = await this.operations.executeQuery({ sql, params });
1584
2016
  const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1585
2017
  return { runs, total: total || runs.length };
1586
2018
  } catch (error) {
@@ -1603,7 +2035,7 @@ var D1Store = class extends MastraStorage {
1603
2035
  runId,
1604
2036
  workflowName
1605
2037
  }) {
1606
- const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
2038
+ const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1607
2039
  try {
1608
2040
  const conditions = [];
1609
2041
  const params = [];
@@ -1617,7 +2049,7 @@ var D1Store = class extends MastraStorage {
1617
2049
  }
1618
2050
  const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1619
2051
  const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1620
- const result = await this.executeQuery({ sql, params, first: true });
2052
+ const result = await this.operations.executeQuery({ sql, params, first: true });
1621
2053
  if (!result) return null;
1622
2054
  return this.parseWorkflowRun(result);
1623
2055
  } catch (error) {
@@ -1633,6 +2065,299 @@ var D1Store = class extends MastraStorage {
1633
2065
  );
1634
2066
  }
1635
2067
  }
2068
+ };
2069
+
2070
+ // src/storage/index.ts
2071
+ var D1Store = class extends MastraStorage {
2072
+ client;
2073
+ binding;
2074
+ // D1Database binding
2075
+ tablePrefix;
2076
+ stores;
2077
+ /**
2078
+ * Creates a new D1Store instance
2079
+ * @param config Configuration for D1 access (either REST API or Workers Binding API)
2080
+ */
2081
+ constructor(config) {
2082
+ try {
2083
+ super({ name: "D1" });
2084
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
2085
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
2086
+ }
2087
+ this.tablePrefix = config.tablePrefix || "";
2088
+ if ("binding" in config) {
2089
+ if (!config.binding) {
2090
+ throw new Error("D1 binding is required when using Workers Binding API");
2091
+ }
2092
+ this.binding = config.binding;
2093
+ this.logger.info("Using D1 Workers Binding API");
2094
+ } else if ("client" in config) {
2095
+ if (!config.client) {
2096
+ throw new Error("D1 client is required when using D1ClientConfig");
2097
+ }
2098
+ this.client = config.client;
2099
+ this.logger.info("Using D1 Client");
2100
+ } else {
2101
+ if (!config.accountId || !config.databaseId || !config.apiToken) {
2102
+ throw new Error("accountId, databaseId, and apiToken are required when using REST API");
2103
+ }
2104
+ const cfClient = new Cloudflare({
2105
+ apiToken: config.apiToken
2106
+ });
2107
+ this.client = {
2108
+ query: ({ sql, params }) => {
2109
+ return cfClient.d1.database.query(config.databaseId, {
2110
+ account_id: config.accountId,
2111
+ sql,
2112
+ params
2113
+ });
2114
+ }
2115
+ };
2116
+ this.logger.info("Using D1 REST API");
2117
+ }
2118
+ } catch (error) {
2119
+ throw new MastraError(
2120
+ {
2121
+ id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
2122
+ domain: ErrorDomain.STORAGE,
2123
+ category: ErrorCategory.SYSTEM,
2124
+ text: "Error initializing D1Store"
2125
+ },
2126
+ error
2127
+ );
2128
+ }
2129
+ const operations = new StoreOperationsD1({
2130
+ client: this.client,
2131
+ binding: this.binding,
2132
+ tablePrefix: this.tablePrefix
2133
+ });
2134
+ const scores = new ScoresStorageD1({
2135
+ operations
2136
+ });
2137
+ const legacyEvals = new LegacyEvalsStorageD1({
2138
+ operations
2139
+ });
2140
+ const workflows = new WorkflowsStorageD1({
2141
+ operations
2142
+ });
2143
+ const memory = new MemoryStorageD1({
2144
+ operations
2145
+ });
2146
+ this.stores = {
2147
+ operations,
2148
+ scores,
2149
+ legacyEvals,
2150
+ workflows,
2151
+ memory
2152
+ };
2153
+ }
2154
+ get supports() {
2155
+ return {
2156
+ selectByIncludeResourceScope: true,
2157
+ resourceWorkingMemory: true,
2158
+ hasColumn: true,
2159
+ createTable: true,
2160
+ deleteMessages: false,
2161
+ getScoresBySpan: true
2162
+ };
2163
+ }
2164
+ async createTable({
2165
+ tableName,
2166
+ schema
2167
+ }) {
2168
+ return this.stores.operations.createTable({ tableName, schema });
2169
+ }
2170
+ /**
2171
+ * Alters table schema to add columns if they don't exist
2172
+ * @param tableName Name of the table
2173
+ * @param schema Schema of the table
2174
+ * @param ifNotExists Array of column names to add if they don't exist
2175
+ */
2176
+ async alterTable({
2177
+ tableName,
2178
+ schema,
2179
+ ifNotExists
2180
+ }) {
2181
+ return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
2182
+ }
2183
+ async clearTable({ tableName }) {
2184
+ return this.stores.operations.clearTable({ tableName });
2185
+ }
2186
+ async dropTable({ tableName }) {
2187
+ return this.stores.operations.dropTable({ tableName });
2188
+ }
2189
+ async hasColumn(table, column) {
2190
+ return this.stores.operations.hasColumn(table, column);
2191
+ }
2192
+ async insert({ tableName, record }) {
2193
+ return this.stores.operations.insert({ tableName, record });
2194
+ }
2195
+ async load({ tableName, keys }) {
2196
+ return this.stores.operations.load({ tableName, keys });
2197
+ }
2198
+ async getThreadById({ threadId }) {
2199
+ return this.stores.memory.getThreadById({ threadId });
2200
+ }
2201
+ /**
2202
+ * @deprecated use getThreadsByResourceIdPaginated instead
2203
+ */
2204
+ async getThreadsByResourceId({ resourceId }) {
2205
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
2206
+ }
2207
+ async getThreadsByResourceIdPaginated(args) {
2208
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
2209
+ }
2210
+ async saveThread({ thread }) {
2211
+ return this.stores.memory.saveThread({ thread });
2212
+ }
2213
+ async updateThread({
2214
+ id,
2215
+ title,
2216
+ metadata
2217
+ }) {
2218
+ return this.stores.memory.updateThread({ id, title, metadata });
2219
+ }
2220
+ async deleteThread({ threadId }) {
2221
+ return this.stores.memory.deleteThread({ threadId });
2222
+ }
2223
+ async saveMessages(args) {
2224
+ return this.stores.memory.saveMessages(args);
2225
+ }
2226
+ async getMessages({
2227
+ threadId,
2228
+ selectBy,
2229
+ format
2230
+ }) {
2231
+ return this.stores.memory.getMessages({ threadId, selectBy, format });
2232
+ }
2233
+ async getMessagesById({
2234
+ messageIds,
2235
+ format
2236
+ }) {
2237
+ return this.stores.memory.getMessagesById({ messageIds, format });
2238
+ }
2239
+ async getMessagesPaginated({
2240
+ threadId,
2241
+ selectBy,
2242
+ format
2243
+ }) {
2244
+ return this.stores.memory.getMessagesPaginated({ threadId, selectBy, format });
2245
+ }
2246
+ async updateWorkflowResults({
2247
+ workflowName,
2248
+ runId,
2249
+ stepId,
2250
+ result,
2251
+ runtimeContext
2252
+ }) {
2253
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
2254
+ }
2255
+ async updateWorkflowState({
2256
+ workflowName,
2257
+ runId,
2258
+ opts
2259
+ }) {
2260
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2261
+ }
2262
+ async persistWorkflowSnapshot({
2263
+ workflowName,
2264
+ runId,
2265
+ resourceId,
2266
+ snapshot
2267
+ }) {
2268
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2269
+ }
2270
+ async loadWorkflowSnapshot(params) {
2271
+ return this.stores.workflows.loadWorkflowSnapshot(params);
2272
+ }
2273
+ async getWorkflowRuns({
2274
+ workflowName,
2275
+ fromDate,
2276
+ toDate,
2277
+ limit,
2278
+ offset,
2279
+ resourceId
2280
+ } = {}) {
2281
+ return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
2282
+ }
2283
+ async getWorkflowRunById({
2284
+ runId,
2285
+ workflowName
2286
+ }) {
2287
+ return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2288
+ }
2289
+ /**
2290
+ * Insert multiple records in a batch operation
2291
+ * @param tableName The table to insert into
2292
+ * @param records The records to insert
2293
+ */
2294
+ async batchInsert({ tableName, records }) {
2295
+ return this.stores.operations.batchInsert({ tableName, records });
2296
+ }
2297
+ /**
2298
+ * @deprecated use getEvals instead
2299
+ */
2300
+ async getEvalsByAgentName(agentName, type) {
2301
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2302
+ }
2303
+ async getEvals(options) {
2304
+ return this.stores.legacyEvals.getEvals(options);
2305
+ }
2306
+ async updateMessages(_args) {
2307
+ return this.stores.memory.updateMessages(_args);
2308
+ }
2309
+ async getResourceById({ resourceId }) {
2310
+ return this.stores.memory.getResourceById({ resourceId });
2311
+ }
2312
+ async saveResource({ resource }) {
2313
+ return this.stores.memory.saveResource({ resource });
2314
+ }
2315
+ async updateResource({
2316
+ resourceId,
2317
+ workingMemory,
2318
+ metadata
2319
+ }) {
2320
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2321
+ }
2322
+ async getScoreById({ id: _id }) {
2323
+ return this.stores.scores.getScoreById({ id: _id });
2324
+ }
2325
+ async saveScore(_score) {
2326
+ return this.stores.scores.saveScore(_score);
2327
+ }
2328
+ async getScoresByRunId({
2329
+ runId: _runId,
2330
+ pagination: _pagination
2331
+ }) {
2332
+ return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
2333
+ }
2334
+ async getScoresByEntityId({
2335
+ entityId: _entityId,
2336
+ entityType: _entityType,
2337
+ pagination: _pagination
2338
+ }) {
2339
+ return this.stores.scores.getScoresByEntityId({
2340
+ entityId: _entityId,
2341
+ entityType: _entityType,
2342
+ pagination: _pagination
2343
+ });
2344
+ }
2345
+ async getScoresByScorerId({
2346
+ scorerId,
2347
+ pagination,
2348
+ entityId,
2349
+ entityType,
2350
+ source
2351
+ }) {
2352
+ return this.stores.scores.getScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
2353
+ }
2354
+ async getScoresBySpan({
2355
+ traceId,
2356
+ spanId,
2357
+ pagination
2358
+ }) {
2359
+ return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination });
2360
+ }
1636
2361
  /**
1637
2362
  * Close the database connection
1638
2363
  * No explicit cleanup needed for D1 in either REST or Workers Binding mode
@@ -1640,10 +2365,8 @@ var D1Store = class extends MastraStorage {
1640
2365
  async close() {
1641
2366
  this.logger.debug("Closing D1 connection");
1642
2367
  }
1643
- async updateMessages(_args) {
1644
- this.logger.error("updateMessages is not yet implemented in CloudflareD1Store");
1645
- throw new Error("Method not implemented");
1646
- }
1647
2368
  };
1648
2369
 
1649
2370
  export { D1Store };
2371
+ //# sourceMappingURL=index.js.map
2372
+ //# sourceMappingURL=index.js.map