@mastra/cloudflare-d1 0.10.1 → 0.10.2-alpha.1

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.
@@ -1,43 +1,19 @@
1
1
  import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
3
3
  import type { MastraMessageV1 } from '@mastra/core/memory';
4
- import type { MastraMessageV2 } from '@mastra/core/memory';
5
- import type { MastraMessageV2 as MastraMessageV2_2 } from '@mastra/core';
4
+ import type { MastraMessageV2 } from '@mastra/core';
6
5
  import { MastraStorage } from '@mastra/core/storage';
6
+ import type { PaginationInfo } from '@mastra/core/storage';
7
7
  import type { StorageColumn } from '@mastra/core/storage';
8
8
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
9
- import type { StorageThreadType } from '@mastra/core/memory';
9
+ import type { StorageThreadType } from '@mastra/core';
10
10
  import type { TABLE_NAMES } from '@mastra/core/storage';
11
+ import type { Trace } from '@mastra/core';
11
12
  import type { WorkflowRun } from '@mastra/core/storage';
12
13
  import type { WorkflowRuns } from '@mastra/core/storage';
13
- import type { WorkflowRunState } from '@mastra/core/workflows';
14
- import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
14
+ import type { WorkflowRunState } from '@mastra/core';
15
15
 
16
- export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
17
-
18
- export declare const createSampleMessage: (threadId: string, parts?: MastraMessageV2_2["content"]["parts"]) => MastraMessageV2_2;
19
-
20
- export declare const createSampleThread: () => {
21
- id: string;
22
- resourceId: string;
23
- title: string;
24
- createdAt: Date;
25
- updatedAt: Date;
26
- metadata: {
27
- key: string;
28
- };
29
- };
30
-
31
- export declare const createSampleThreadWithParams: (threadId: string, resourceId: string, createdAt: Date, updatedAt: Date) => {
32
- id: string;
33
- resourceId: string;
34
- title: string;
35
- createdAt: Date;
36
- updatedAt: Date;
37
- metadata: {
38
- key: string;
39
- };
40
- };
16
+ export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState | string, stepId: string, status: string) => void;
41
17
 
42
18
  export declare const createSampleTrace: (name: string, scope?: string, attributes?: Record<string, string>) => {
43
19
  id: string;
@@ -56,12 +32,6 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
56
32
  createdAt: string;
57
33
  };
58
34
 
59
- export declare const createSampleWorkflowSnapshot: (threadId: string, status: string, createdAt?: Date) => {
60
- snapshot: WorkflowRunState_2;
61
- runId: string;
62
- stepId: string;
63
- };
64
-
65
35
  export declare function createSqlBuilder(): SqlBuilder;
66
36
 
67
37
  /**
@@ -101,15 +71,25 @@ declare class D1Store extends MastraStorage {
101
71
  * @returns Query results as an array or a single object if first=true
102
72
  */
103
73
  private executeQuery;
104
- private getSqlType;
105
- private ensureDate;
106
- private serializeDate;
74
+ private getTableColumns;
107
75
  private serializeValue;
108
76
  private deserializeValue;
77
+ protected getSqlType(type: StorageColumn['type']): string;
109
78
  createTable({ tableName, schema, }: {
110
79
  tableName: TABLE_NAMES;
111
80
  schema: Record<string, StorageColumn>;
112
81
  }): Promise<void>;
82
+ /**
83
+ * Alters table schema to add columns if they don't exist
84
+ * @param tableName Name of the table
85
+ * @param schema Schema of the table
86
+ * @param ifNotExists Array of column names to add if they don't exist
87
+ */
88
+ alterTable({ tableName, schema, ifNotExists, }: {
89
+ tableName: TABLE_NAMES;
90
+ schema: Record<string, StorageColumn>;
91
+ ifNotExists: string[];
92
+ }): Promise<void>;
113
93
  clearTable({ tableName }: {
114
94
  tableName: TABLE_NAMES;
115
95
  }): Promise<void>;
@@ -125,9 +105,19 @@ declare class D1Store extends MastraStorage {
125
105
  getThreadById({ threadId }: {
126
106
  threadId: string;
127
107
  }): Promise<StorageThreadType | null>;
108
+ /**
109
+ * @deprecated use getThreadsByResourceIdPaginated instead
110
+ */
128
111
  getThreadsByResourceId({ resourceId }: {
129
112
  resourceId: string;
130
113
  }): Promise<StorageThreadType[]>;
114
+ getThreadsByResourceIdPaginated(args: {
115
+ resourceId: string;
116
+ page: number;
117
+ perPage: number;
118
+ }): Promise<PaginationInfo & {
119
+ threads: StorageThreadType[];
120
+ }>;
131
121
  saveThread({ thread }: {
132
122
  thread: StorageThreadType;
133
123
  }): Promise<StorageThreadType>;
@@ -147,12 +137,21 @@ declare class D1Store extends MastraStorage {
147
137
  messages: MastraMessageV2[];
148
138
  format: 'v2';
149
139
  }): Promise<MastraMessageV2[]>;
140
+ private _getIncludedMessages;
141
+ /**
142
+ * @deprecated use getMessagesPaginated instead
143
+ */
150
144
  getMessages(args: StorageGetMessagesArg & {
151
145
  format?: 'v1';
152
146
  }): Promise<MastraMessageV1[]>;
153
147
  getMessages(args: StorageGetMessagesArg & {
154
148
  format: 'v2';
155
149
  }): Promise<MastraMessageV2[]>;
150
+ getMessagesPaginated({ threadId, selectBy, format, }: StorageGetMessagesArg & {
151
+ format?: 'v1' | 'v2';
152
+ }): Promise<PaginationInfo & {
153
+ messages: MastraMessageV1[] | MastraMessageV2[];
154
+ }>;
156
155
  persistWorkflowSnapshot({ workflowName, runId, snapshot, }: {
157
156
  workflowName: string;
158
157
  runId: string;
@@ -171,6 +170,9 @@ declare class D1Store extends MastraStorage {
171
170
  tableName: TABLE_NAMES;
172
171
  records: Record<string, any>[];
173
172
  }): Promise<void>;
173
+ /**
174
+ * @deprecated use getTracesPaginated instead
175
+ */
174
176
  getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
175
177
  name?: string;
176
178
  scope?: string;
@@ -179,8 +181,32 @@ declare class D1Store extends MastraStorage {
179
181
  attributes?: Record<string, string>;
180
182
  fromDate?: Date;
181
183
  toDate?: Date;
182
- }): Promise<Record<string, any>[]>;
184
+ }): Promise<Trace[]>;
185
+ getTracesPaginated(args: {
186
+ name?: string;
187
+ scope?: string;
188
+ attributes?: Record<string, string>;
189
+ page: number;
190
+ perPage: number;
191
+ fromDate?: Date;
192
+ toDate?: Date;
193
+ }): Promise<PaginationInfo & {
194
+ traces: Trace[];
195
+ }>;
196
+ /**
197
+ * @deprecated use getEvals instead
198
+ */
183
199
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
200
+ getEvals(options?: {
201
+ agentName?: string;
202
+ type?: 'test' | 'live';
203
+ page?: number;
204
+ perPage?: number;
205
+ fromDate?: Date;
206
+ toDate?: Date;
207
+ }): Promise<PaginationInfo & {
208
+ evals: EvalRow[];
209
+ }>;
184
210
  private parseWorkflowRun;
185
211
  private hasColumn;
186
212
  getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId, }?: {
@@ -1,43 +1,19 @@
1
1
  import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
3
3
  import type { MastraMessageV1 } from '@mastra/core/memory';
4
- import type { MastraMessageV2 } from '@mastra/core/memory';
5
- import type { MastraMessageV2 as MastraMessageV2_2 } from '@mastra/core';
4
+ import type { MastraMessageV2 } from '@mastra/core';
6
5
  import { MastraStorage } from '@mastra/core/storage';
6
+ import type { PaginationInfo } from '@mastra/core/storage';
7
7
  import type { StorageColumn } from '@mastra/core/storage';
8
8
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
9
- import type { StorageThreadType } from '@mastra/core/memory';
9
+ import type { StorageThreadType } from '@mastra/core';
10
10
  import type { TABLE_NAMES } from '@mastra/core/storage';
11
+ import type { Trace } from '@mastra/core';
11
12
  import type { WorkflowRun } from '@mastra/core/storage';
12
13
  import type { WorkflowRuns } from '@mastra/core/storage';
13
- import type { WorkflowRunState } from '@mastra/core/workflows';
14
- import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
14
+ import type { WorkflowRunState } from '@mastra/core';
15
15
 
16
- export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
17
-
18
- export declare const createSampleMessage: (threadId: string, parts?: MastraMessageV2_2["content"]["parts"]) => MastraMessageV2_2;
19
-
20
- export declare const createSampleThread: () => {
21
- id: string;
22
- resourceId: string;
23
- title: string;
24
- createdAt: Date;
25
- updatedAt: Date;
26
- metadata: {
27
- key: string;
28
- };
29
- };
30
-
31
- export declare const createSampleThreadWithParams: (threadId: string, resourceId: string, createdAt: Date, updatedAt: Date) => {
32
- id: string;
33
- resourceId: string;
34
- title: string;
35
- createdAt: Date;
36
- updatedAt: Date;
37
- metadata: {
38
- key: string;
39
- };
40
- };
16
+ export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState | string, stepId: string, status: string) => void;
41
17
 
42
18
  export declare const createSampleTrace: (name: string, scope?: string, attributes?: Record<string, string>) => {
43
19
  id: string;
@@ -56,12 +32,6 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
56
32
  createdAt: string;
57
33
  };
58
34
 
59
- export declare const createSampleWorkflowSnapshot: (threadId: string, status: string, createdAt?: Date) => {
60
- snapshot: WorkflowRunState_2;
61
- runId: string;
62
- stepId: string;
63
- };
64
-
65
35
  export declare function createSqlBuilder(): SqlBuilder;
66
36
 
67
37
  /**
@@ -101,15 +71,25 @@ declare class D1Store extends MastraStorage {
101
71
  * @returns Query results as an array or a single object if first=true
102
72
  */
103
73
  private executeQuery;
104
- private getSqlType;
105
- private ensureDate;
106
- private serializeDate;
74
+ private getTableColumns;
107
75
  private serializeValue;
108
76
  private deserializeValue;
77
+ protected getSqlType(type: StorageColumn['type']): string;
109
78
  createTable({ tableName, schema, }: {
110
79
  tableName: TABLE_NAMES;
111
80
  schema: Record<string, StorageColumn>;
112
81
  }): Promise<void>;
82
+ /**
83
+ * Alters table schema to add columns if they don't exist
84
+ * @param tableName Name of the table
85
+ * @param schema Schema of the table
86
+ * @param ifNotExists Array of column names to add if they don't exist
87
+ */
88
+ alterTable({ tableName, schema, ifNotExists, }: {
89
+ tableName: TABLE_NAMES;
90
+ schema: Record<string, StorageColumn>;
91
+ ifNotExists: string[];
92
+ }): Promise<void>;
113
93
  clearTable({ tableName }: {
114
94
  tableName: TABLE_NAMES;
115
95
  }): Promise<void>;
@@ -125,9 +105,19 @@ declare class D1Store extends MastraStorage {
125
105
  getThreadById({ threadId }: {
126
106
  threadId: string;
127
107
  }): Promise<StorageThreadType | null>;
108
+ /**
109
+ * @deprecated use getThreadsByResourceIdPaginated instead
110
+ */
128
111
  getThreadsByResourceId({ resourceId }: {
129
112
  resourceId: string;
130
113
  }): Promise<StorageThreadType[]>;
114
+ getThreadsByResourceIdPaginated(args: {
115
+ resourceId: string;
116
+ page: number;
117
+ perPage: number;
118
+ }): Promise<PaginationInfo & {
119
+ threads: StorageThreadType[];
120
+ }>;
131
121
  saveThread({ thread }: {
132
122
  thread: StorageThreadType;
133
123
  }): Promise<StorageThreadType>;
@@ -147,12 +137,21 @@ declare class D1Store extends MastraStorage {
147
137
  messages: MastraMessageV2[];
148
138
  format: 'v2';
149
139
  }): Promise<MastraMessageV2[]>;
140
+ private _getIncludedMessages;
141
+ /**
142
+ * @deprecated use getMessagesPaginated instead
143
+ */
150
144
  getMessages(args: StorageGetMessagesArg & {
151
145
  format?: 'v1';
152
146
  }): Promise<MastraMessageV1[]>;
153
147
  getMessages(args: StorageGetMessagesArg & {
154
148
  format: 'v2';
155
149
  }): Promise<MastraMessageV2[]>;
150
+ getMessagesPaginated({ threadId, selectBy, format, }: StorageGetMessagesArg & {
151
+ format?: 'v1' | 'v2';
152
+ }): Promise<PaginationInfo & {
153
+ messages: MastraMessageV1[] | MastraMessageV2[];
154
+ }>;
156
155
  persistWorkflowSnapshot({ workflowName, runId, snapshot, }: {
157
156
  workflowName: string;
158
157
  runId: string;
@@ -171,6 +170,9 @@ declare class D1Store extends MastraStorage {
171
170
  tableName: TABLE_NAMES;
172
171
  records: Record<string, any>[];
173
172
  }): Promise<void>;
173
+ /**
174
+ * @deprecated use getTracesPaginated instead
175
+ */
174
176
  getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
175
177
  name?: string;
176
178
  scope?: string;
@@ -179,8 +181,32 @@ declare class D1Store extends MastraStorage {
179
181
  attributes?: Record<string, string>;
180
182
  fromDate?: Date;
181
183
  toDate?: Date;
182
- }): Promise<Record<string, any>[]>;
184
+ }): Promise<Trace[]>;
185
+ getTracesPaginated(args: {
186
+ name?: string;
187
+ scope?: string;
188
+ attributes?: Record<string, string>;
189
+ page: number;
190
+ perPage: number;
191
+ fromDate?: Date;
192
+ toDate?: Date;
193
+ }): Promise<PaginationInfo & {
194
+ traces: Trace[];
195
+ }>;
196
+ /**
197
+ * @deprecated use getEvals instead
198
+ */
183
199
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
200
+ getEvals(options?: {
201
+ agentName?: string;
202
+ type?: 'test' | 'live';
203
+ page?: number;
204
+ perPage?: number;
205
+ fromDate?: Date;
206
+ toDate?: Date;
207
+ }): Promise<PaginationInfo & {
208
+ evals: EvalRow[];
209
+ }>;
184
210
  private parseWorkflowRun;
185
211
  private hasColumn;
186
212
  getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId, }?: {
package/dist/index.cjs CHANGED
@@ -389,34 +389,25 @@ var D1Store = class extends storage.MastraStorage {
389
389
  throw new Error(`D1 query error: ${error.message}`);
390
390
  }
391
391
  }
392
- // Helper to convert storage type to SQL type
393
- getSqlType(type) {
394
- switch (type) {
395
- case "text":
396
- return "TEXT";
397
- case "timestamp":
398
- return "TIMESTAMP";
399
- case "integer":
400
- return "INTEGER";
401
- case "bigint":
402
- return "INTEGER";
403
- // SQLite doesn't have a separate BIGINT type
404
- case "jsonb":
405
- return "TEXT";
406
- // Store JSON as TEXT in SQLite
407
- default:
408
- return "TEXT";
392
+ // Helper to get existing table columns
393
+ async getTableColumns(tableName) {
394
+ try {
395
+ const sql = `PRAGMA table_info(${tableName})`;
396
+ const result = await this.executeQuery({ sql, params: [] });
397
+ if (!result || !Array.isArray(result)) {
398
+ return [];
399
+ }
400
+ return result.map((row) => ({
401
+ name: row.name,
402
+ type: row.type
403
+ }));
404
+ } catch (error) {
405
+ this.logger.error(`Error getting table columns for ${tableName}:`, {
406
+ message: error instanceof Error ? error.message : String(error)
407
+ });
408
+ return [];
409
409
  }
410
410
  }
411
- ensureDate(date) {
412
- if (!date) return void 0;
413
- return date instanceof Date ? date : new Date(date);
414
- }
415
- serializeDate(date) {
416
- if (!date) return void 0;
417
- const dateObj = this.ensureDate(date);
418
- return dateObj?.toISOString();
419
- }
420
411
  // Helper to serialize objects to JSON strings
421
412
  serializeValue(value) {
422
413
  if (value === null || value === void 0) return null;
@@ -450,6 +441,18 @@ var D1Store = class extends storage.MastraStorage {
450
441
  }
451
442
  return value;
452
443
  }
444
+ getSqlType(type) {
445
+ switch (type) {
446
+ case "bigint":
447
+ return "INTEGER";
448
+ // SQLite uses INTEGER for all integer sizes
449
+ case "jsonb":
450
+ return "TEXT";
451
+ // Store JSON as TEXT in SQLite
452
+ default:
453
+ return super.getSqlType(type);
454
+ }
455
+ }
453
456
  async createTable({
454
457
  tableName,
455
458
  schema
@@ -477,6 +480,39 @@ var D1Store = class extends storage.MastraStorage {
477
480
  throw new Error(`Failed to create table ${fullTableName}: ${error}`);
478
481
  }
479
482
  }
483
+ /**
484
+ * Alters table schema to add columns if they don't exist
485
+ * @param tableName Name of the table
486
+ * @param schema Schema of the table
487
+ * @param ifNotExists Array of column names to add if they don't exist
488
+ */
489
+ async alterTable({
490
+ tableName,
491
+ schema,
492
+ ifNotExists
493
+ }) {
494
+ const fullTableName = this.getTableName(tableName);
495
+ try {
496
+ const existingColumns = await this.getTableColumns(fullTableName);
497
+ const existingColumnNames = new Set(existingColumns.map((col) => col.name.toLowerCase()));
498
+ for (const columnName of ifNotExists) {
499
+ if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
500
+ const columnDef = schema[columnName];
501
+ const sqlType = this.getSqlType(columnDef.type);
502
+ const nullable = columnDef.nullable === false ? "NOT NULL" : "";
503
+ const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
504
+ const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
505
+ await this.executeQuery({ sql: alterSql, params: [] });
506
+ this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
507
+ }
508
+ }
509
+ } catch (error) {
510
+ this.logger.error(`Error altering table ${fullTableName}:`, {
511
+ message: error instanceof Error ? error.message : String(error)
512
+ });
513
+ throw new Error(`Failed to alter table ${fullTableName}: ${error}`);
514
+ }
515
+ }
480
516
  async clearTable({ tableName }) {
481
517
  const fullTableName = this.getTableName(tableName);
482
518
  try {
@@ -562,6 +598,9 @@ var D1Store = class extends storage.MastraStorage {
562
598
  return null;
563
599
  }
564
600
  }
601
+ /**
602
+ * @deprecated use getThreadsByResourceIdPaginated instead
603
+ */
565
604
  async getThreadsByResourceId({ resourceId }) {
566
605
  const fullTableName = this.getTableName(storage.TABLE_THREADS);
567
606
  try {
@@ -581,6 +620,29 @@ var D1Store = class extends storage.MastraStorage {
581
620
  return [];
582
621
  }
583
622
  }
623
+ async getThreadsByResourceIdPaginated(args) {
624
+ const { resourceId, page, perPage } = args;
625
+ const fullTableName = this.getTableName(storage.TABLE_THREADS);
626
+ const mapRowToStorageThreadType = (row) => ({
627
+ ...row,
628
+ createdAt: this.ensureDate(row.createdAt),
629
+ updatedAt: this.ensureDate(row.updatedAt),
630
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
631
+ });
632
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
633
+ const countResult = await this.executeQuery(countQuery.build());
634
+ const total = Number(countResult?.[0]?.count ?? 0);
635
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
636
+ const results = await this.executeQuery(selectQuery.build());
637
+ const threads = results.map(mapRowToStorageThreadType);
638
+ return {
639
+ threads,
640
+ total,
641
+ page,
642
+ perPage,
643
+ hasMore: page * perPage + threads.length < total
644
+ };
645
+ }
584
646
  async saveThread({ thread }) {
585
647
  const fullTableName = this.getTableName(storage.TABLE_THREADS);
586
648
  const threadToSave = {
@@ -687,7 +749,8 @@ var D1Store = class extends storage.MastraStorage {
687
749
  content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
688
750
  createdAt: createdAt.toISOString(),
689
751
  role: message.role,
690
- type: message.type || "v2"
752
+ type: message.type || "v2",
753
+ resourceId: message.resourceId
691
754
  };
692
755
  });
693
756
  await this.batchInsert({
@@ -703,26 +766,18 @@ var D1Store = class extends storage.MastraStorage {
703
766
  throw error;
704
767
  }
705
768
  }
706
- async getMessages({
707
- threadId,
708
- selectBy,
709
- format
710
- }) {
711
- const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
712
- const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
713
- const include = selectBy?.include || [];
714
- const messages = [];
715
- try {
716
- if (include.length) {
717
- const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
718
- const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
719
- const includeIds = include.map((i) => i.id);
720
- const sql2 = `
769
+ async _getIncludedMessages(threadId, selectBy) {
770
+ const include = selectBy?.include;
771
+ if (!include) return null;
772
+ const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
773
+ const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
774
+ const includeIds = include.map((i) => i.id);
775
+ const sql = `
721
776
  WITH ordered_messages AS (
722
777
  SELECT
723
778
  *,
724
779
  ROW_NUMBER() OVER (ORDER BY createdAt DESC) AS row_num
725
- FROM ${fullTableName}
780
+ FROM ${this.getTableName(storage.TABLE_MESSAGES)}
726
781
  WHERE thread_id = ?
727
782
  )
728
783
  SELECT
@@ -745,20 +800,38 @@ var D1Store = class extends storage.MastraStorage {
745
800
  )
746
801
  ORDER BY m.createdAt DESC
747
802
  `;
748
- const params2 = [
749
- threadId,
750
- ...includeIds,
751
- // for m.id IN (...)
752
- ...includeIds,
753
- // for target.id IN (...)
754
- prevMax,
755
- nextMax
756
- ];
757
- const includeResult = await this.executeQuery({ sql: sql2, params: params2 });
803
+ const params = [
804
+ threadId,
805
+ ...includeIds,
806
+ // for m.id IN (...)
807
+ ...includeIds,
808
+ // for target.id IN (...)
809
+ prevMax,
810
+ nextMax
811
+ ];
812
+ const messages = await this.executeQuery({ sql, params });
813
+ return messages;
814
+ }
815
+ async getMessages({
816
+ threadId,
817
+ selectBy,
818
+ format
819
+ }) {
820
+ const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
821
+ const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
822
+ const include = selectBy?.include || [];
823
+ const messages = [];
824
+ try {
825
+ if (include.length) {
826
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
758
827
  if (Array.isArray(includeResult)) messages.push(...includeResult);
759
828
  }
760
829
  const excludeIds = messages.map((m) => m.id);
761
- let query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId).andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds).orderBy("createdAt", "DESC").limit(limit);
830
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
831
+ if (excludeIds.length > 0) {
832
+ query.andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds);
833
+ }
834
+ query.orderBy("createdAt", "DESC").limit(limit);
762
835
  const { sql, params } = query.build();
763
836
  const result = await this.executeQuery({ sql, params });
764
837
  if (Array.isArray(result)) messages.push(...result);
@@ -789,6 +862,47 @@ var D1Store = class extends storage.MastraStorage {
789
862
  return [];
790
863
  }
791
864
  }
865
+ async getMessagesPaginated({
866
+ threadId,
867
+ selectBy,
868
+ format
869
+ }) {
870
+ const { dateRange, page = 0, perPage = 40 } = selectBy?.pagination || {};
871
+ const { start: fromDate, end: toDate } = dateRange || {};
872
+ const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
873
+ const messages = [];
874
+ if (selectBy?.include?.length) {
875
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
876
+ if (Array.isArray(includeResult)) messages.push(...includeResult);
877
+ }
878
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
879
+ if (fromDate) {
880
+ countQuery.andWhere("createdAt >= ?", this.serializeDate(fromDate));
881
+ }
882
+ if (toDate) {
883
+ countQuery.andWhere("createdAt <= ?", this.serializeDate(toDate));
884
+ }
885
+ const countResult = await this.executeQuery(countQuery.build());
886
+ const total = Number(countResult[0]?.count ?? 0);
887
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
888
+ if (fromDate) {
889
+ query.andWhere("createdAt >= ?", this.serializeDate(fromDate));
890
+ }
891
+ if (toDate) {
892
+ query.andWhere("createdAt <= ?", this.serializeDate(toDate));
893
+ }
894
+ query.orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
895
+ const results = await this.executeQuery(query.build());
896
+ const list = new agent.MessageList().add(results, "memory");
897
+ messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
898
+ return {
899
+ messages,
900
+ total,
901
+ page,
902
+ perPage,
903
+ hasMore: page * perPage + messages.length < total
904
+ };
905
+ }
792
906
  async persistWorkflowSnapshot({
793
907
  workflowName,
794
908
  runId,
@@ -881,6 +995,9 @@ var D1Store = class extends storage.MastraStorage {
881
995
  throw new Error(`Failed to batch insert into ${tableName}: ${error}`);
882
996
  }
883
997
  }
998
+ /**
999
+ * @deprecated use getTracesPaginated instead
1000
+ */
884
1001
  async getTraces({
885
1002
  name,
886
1003
  scope,
@@ -910,22 +1027,83 @@ var D1Store = class extends storage.MastraStorage {
910
1027
  if (toDate) {
911
1028
  query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
912
1029
  }
913
- query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
1030
+ query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
914
1031
  const { sql, params } = query.build();
915
1032
  const results = await this.executeQuery({ sql, params });
916
- return isArrayOfRecords(results) ? results.map((trace) => ({
917
- ...trace,
918
- attributes: this.deserializeValue(trace.attributes, "jsonb"),
919
- status: this.deserializeValue(trace.status, "jsonb"),
920
- events: this.deserializeValue(trace.events, "jsonb"),
921
- links: this.deserializeValue(trace.links, "jsonb"),
922
- other: this.deserializeValue(trace.other, "jsonb")
923
- })) : [];
1033
+ return isArrayOfRecords(results) ? results.map(
1034
+ (trace) => ({
1035
+ ...trace,
1036
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1037
+ status: this.deserializeValue(trace.status, "jsonb"),
1038
+ events: this.deserializeValue(trace.events, "jsonb"),
1039
+ links: this.deserializeValue(trace.links, "jsonb"),
1040
+ other: this.deserializeValue(trace.other, "jsonb")
1041
+ })
1042
+ ) : [];
924
1043
  } catch (error) {
925
1044
  this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
926
1045
  return [];
927
1046
  }
928
1047
  }
1048
+ async getTracesPaginated(args) {
1049
+ const { name, scope, page, perPage, attributes, fromDate, toDate } = args;
1050
+ const fullTableName = this.getTableName(storage.TABLE_TRACES);
1051
+ try {
1052
+ const dataQuery = createSqlBuilder().select("*").from(fullTableName).where("1=1");
1053
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("1=1");
1054
+ if (name) {
1055
+ dataQuery.andWhere("name LIKE ?", `%${name}%`);
1056
+ countQuery.andWhere("name LIKE ?", `%${name}%`);
1057
+ }
1058
+ if (scope) {
1059
+ dataQuery.andWhere("scope = ?", scope);
1060
+ countQuery.andWhere("scope = ?", scope);
1061
+ }
1062
+ if (attributes && Object.keys(attributes).length > 0) {
1063
+ for (const [key, value] of Object.entries(attributes)) {
1064
+ dataQuery.jsonLike("attributes", key, value);
1065
+ countQuery.jsonLike("attributes", key, value);
1066
+ }
1067
+ }
1068
+ if (fromDate) {
1069
+ const fromDateStr = fromDate instanceof Date ? fromDate.toISOString() : fromDate;
1070
+ dataQuery.andWhere("createdAt >= ?", fromDateStr);
1071
+ countQuery.andWhere("createdAt >= ?", fromDateStr);
1072
+ }
1073
+ if (toDate) {
1074
+ const toDateStr = toDate instanceof Date ? toDate.toISOString() : toDate;
1075
+ dataQuery.andWhere("createdAt <= ?", toDateStr);
1076
+ countQuery.andWhere("createdAt <= ?", toDateStr);
1077
+ }
1078
+ const countResult = await this.executeQuery(countQuery.build());
1079
+ const total = Number(countResult?.[0]?.count ?? 0);
1080
+ dataQuery.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
1081
+ const results = await this.executeQuery(dataQuery.build());
1082
+ const traces = isArrayOfRecords(results) ? results.map(
1083
+ (trace) => ({
1084
+ ...trace,
1085
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1086
+ status: this.deserializeValue(trace.status, "jsonb"),
1087
+ events: this.deserializeValue(trace.events, "jsonb"),
1088
+ links: this.deserializeValue(trace.links, "jsonb"),
1089
+ other: this.deserializeValue(trace.other, "jsonb")
1090
+ })
1091
+ ) : [];
1092
+ return {
1093
+ traces,
1094
+ total,
1095
+ page,
1096
+ perPage,
1097
+ hasMore: page * perPage + traces.length < total
1098
+ };
1099
+ } catch (error) {
1100
+ this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
1101
+ return { traces: [], total: 0, page, perPage, hasMore: false };
1102
+ }
1103
+ }
1104
+ /**
1105
+ * @deprecated use getEvals instead
1106
+ */
929
1107
  async getEvalsByAgentName(agentName, type) {
930
1108
  const fullTableName = this.getTableName(storage.TABLE_EVALS);
931
1109
  try {
@@ -961,6 +1139,80 @@ var D1Store = class extends storage.MastraStorage {
961
1139
  return [];
962
1140
  }
963
1141
  }
1142
+ async getEvals(options) {
1143
+ const { agentName, type, page = 0, perPage = 40, fromDate, toDate } = options || {};
1144
+ const fullTableName = this.getTableName(storage.TABLE_EVALS);
1145
+ const conditions = [];
1146
+ const queryParams = [];
1147
+ if (agentName) {
1148
+ conditions.push(`agent_name = ?`);
1149
+ queryParams.push(agentName);
1150
+ }
1151
+ if (type === "test") {
1152
+ conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
1153
+ } else if (type === "live") {
1154
+ conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
1155
+ }
1156
+ if (fromDate) {
1157
+ conditions.push(`createdAt >= ?`);
1158
+ queryParams.push(this.serializeDate(fromDate));
1159
+ }
1160
+ if (toDate) {
1161
+ conditions.push(`createdAt <= ?`);
1162
+ queryParams.push(this.serializeDate(toDate));
1163
+ }
1164
+ const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
1165
+ if (conditions.length > 0) {
1166
+ countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1167
+ }
1168
+ const { sql: countSql, params: countParams } = countQueryBuilder.build();
1169
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1170
+ const total = Number(countResult?.count || 0);
1171
+ const currentOffset = page * perPage;
1172
+ if (total === 0) {
1173
+ return {
1174
+ evals: [],
1175
+ total: 0,
1176
+ page,
1177
+ perPage,
1178
+ hasMore: false
1179
+ };
1180
+ }
1181
+ const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
1182
+ if (conditions.length > 0) {
1183
+ dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1184
+ }
1185
+ dataQueryBuilder.orderBy("createdAt", "DESC").limit(perPage).offset(currentOffset);
1186
+ const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
1187
+ const rows = await this.executeQuery({ sql: dataSql, params: dataParams });
1188
+ const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
1189
+ const result = this.deserializeValue(row.result);
1190
+ const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
1191
+ if (!result || typeof result !== "object" || !("score" in result)) {
1192
+ throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
1193
+ }
1194
+ return {
1195
+ input: row.input,
1196
+ output: row.output,
1197
+ result,
1198
+ agentName: row.agent_name,
1199
+ metricName: row.metric_name,
1200
+ instructions: row.instructions,
1201
+ testInfo,
1202
+ globalRunId: row.global_run_id,
1203
+ runId: row.run_id,
1204
+ createdAt: row.createdAt
1205
+ };
1206
+ });
1207
+ const hasMore = currentOffset + evals.length < total;
1208
+ return {
1209
+ evals,
1210
+ total,
1211
+ page,
1212
+ perPage,
1213
+ hasMore
1214
+ };
1215
+ }
964
1216
  parseWorkflowRun(row) {
965
1217
  let parsedSnapshot = row.snapshot;
966
1218
  if (typeof parsedSnapshot === "string") {
package/dist/index.js CHANGED
@@ -383,34 +383,25 @@ var D1Store = class extends MastraStorage {
383
383
  throw new Error(`D1 query error: ${error.message}`);
384
384
  }
385
385
  }
386
- // Helper to convert storage type to SQL type
387
- getSqlType(type) {
388
- switch (type) {
389
- case "text":
390
- return "TEXT";
391
- case "timestamp":
392
- return "TIMESTAMP";
393
- case "integer":
394
- return "INTEGER";
395
- case "bigint":
396
- return "INTEGER";
397
- // SQLite doesn't have a separate BIGINT type
398
- case "jsonb":
399
- return "TEXT";
400
- // Store JSON as TEXT in SQLite
401
- default:
402
- return "TEXT";
386
+ // Helper to get existing table columns
387
+ async getTableColumns(tableName) {
388
+ try {
389
+ const sql = `PRAGMA table_info(${tableName})`;
390
+ const result = await this.executeQuery({ sql, params: [] });
391
+ if (!result || !Array.isArray(result)) {
392
+ return [];
393
+ }
394
+ return result.map((row) => ({
395
+ name: row.name,
396
+ type: row.type
397
+ }));
398
+ } catch (error) {
399
+ this.logger.error(`Error getting table columns for ${tableName}:`, {
400
+ message: error instanceof Error ? error.message : String(error)
401
+ });
402
+ return [];
403
403
  }
404
404
  }
405
- ensureDate(date) {
406
- if (!date) return void 0;
407
- return date instanceof Date ? date : new Date(date);
408
- }
409
- serializeDate(date) {
410
- if (!date) return void 0;
411
- const dateObj = this.ensureDate(date);
412
- return dateObj?.toISOString();
413
- }
414
405
  // Helper to serialize objects to JSON strings
415
406
  serializeValue(value) {
416
407
  if (value === null || value === void 0) return null;
@@ -444,6 +435,18 @@ var D1Store = class extends MastraStorage {
444
435
  }
445
436
  return value;
446
437
  }
438
+ getSqlType(type) {
439
+ switch (type) {
440
+ case "bigint":
441
+ return "INTEGER";
442
+ // SQLite uses INTEGER for all integer sizes
443
+ case "jsonb":
444
+ return "TEXT";
445
+ // Store JSON as TEXT in SQLite
446
+ default:
447
+ return super.getSqlType(type);
448
+ }
449
+ }
447
450
  async createTable({
448
451
  tableName,
449
452
  schema
@@ -471,6 +474,39 @@ var D1Store = class extends MastraStorage {
471
474
  throw new Error(`Failed to create table ${fullTableName}: ${error}`);
472
475
  }
473
476
  }
477
+ /**
478
+ * Alters table schema to add columns if they don't exist
479
+ * @param tableName Name of the table
480
+ * @param schema Schema of the table
481
+ * @param ifNotExists Array of column names to add if they don't exist
482
+ */
483
+ async alterTable({
484
+ tableName,
485
+ schema,
486
+ ifNotExists
487
+ }) {
488
+ const fullTableName = this.getTableName(tableName);
489
+ try {
490
+ const existingColumns = await this.getTableColumns(fullTableName);
491
+ const existingColumnNames = new Set(existingColumns.map((col) => col.name.toLowerCase()));
492
+ for (const columnName of ifNotExists) {
493
+ if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
494
+ const columnDef = schema[columnName];
495
+ const sqlType = this.getSqlType(columnDef.type);
496
+ const nullable = columnDef.nullable === false ? "NOT NULL" : "";
497
+ const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
498
+ const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
499
+ await this.executeQuery({ sql: alterSql, params: [] });
500
+ this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
501
+ }
502
+ }
503
+ } catch (error) {
504
+ this.logger.error(`Error altering table ${fullTableName}:`, {
505
+ message: error instanceof Error ? error.message : String(error)
506
+ });
507
+ throw new Error(`Failed to alter table ${fullTableName}: ${error}`);
508
+ }
509
+ }
474
510
  async clearTable({ tableName }) {
475
511
  const fullTableName = this.getTableName(tableName);
476
512
  try {
@@ -556,6 +592,9 @@ var D1Store = class extends MastraStorage {
556
592
  return null;
557
593
  }
558
594
  }
595
+ /**
596
+ * @deprecated use getThreadsByResourceIdPaginated instead
597
+ */
559
598
  async getThreadsByResourceId({ resourceId }) {
560
599
  const fullTableName = this.getTableName(TABLE_THREADS);
561
600
  try {
@@ -575,6 +614,29 @@ var D1Store = class extends MastraStorage {
575
614
  return [];
576
615
  }
577
616
  }
617
+ async getThreadsByResourceIdPaginated(args) {
618
+ const { resourceId, page, perPage } = args;
619
+ const fullTableName = this.getTableName(TABLE_THREADS);
620
+ const mapRowToStorageThreadType = (row) => ({
621
+ ...row,
622
+ createdAt: this.ensureDate(row.createdAt),
623
+ updatedAt: this.ensureDate(row.updatedAt),
624
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
625
+ });
626
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
627
+ const countResult = await this.executeQuery(countQuery.build());
628
+ const total = Number(countResult?.[0]?.count ?? 0);
629
+ const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
630
+ const results = await this.executeQuery(selectQuery.build());
631
+ const threads = results.map(mapRowToStorageThreadType);
632
+ return {
633
+ threads,
634
+ total,
635
+ page,
636
+ perPage,
637
+ hasMore: page * perPage + threads.length < total
638
+ };
639
+ }
578
640
  async saveThread({ thread }) {
579
641
  const fullTableName = this.getTableName(TABLE_THREADS);
580
642
  const threadToSave = {
@@ -681,7 +743,8 @@ var D1Store = class extends MastraStorage {
681
743
  content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
682
744
  createdAt: createdAt.toISOString(),
683
745
  role: message.role,
684
- type: message.type || "v2"
746
+ type: message.type || "v2",
747
+ resourceId: message.resourceId
685
748
  };
686
749
  });
687
750
  await this.batchInsert({
@@ -697,26 +760,18 @@ var D1Store = class extends MastraStorage {
697
760
  throw error;
698
761
  }
699
762
  }
700
- async getMessages({
701
- threadId,
702
- selectBy,
703
- format
704
- }) {
705
- const fullTableName = this.getTableName(TABLE_MESSAGES);
706
- const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
707
- const include = selectBy?.include || [];
708
- const messages = [];
709
- try {
710
- if (include.length) {
711
- const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
712
- const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
713
- const includeIds = include.map((i) => i.id);
714
- const sql2 = `
763
+ async _getIncludedMessages(threadId, selectBy) {
764
+ const include = selectBy?.include;
765
+ if (!include) return null;
766
+ const prevMax = Math.max(...include.map((i) => i.withPreviousMessages || 0));
767
+ const nextMax = Math.max(...include.map((i) => i.withNextMessages || 0));
768
+ const includeIds = include.map((i) => i.id);
769
+ const sql = `
715
770
  WITH ordered_messages AS (
716
771
  SELECT
717
772
  *,
718
773
  ROW_NUMBER() OVER (ORDER BY createdAt DESC) AS row_num
719
- FROM ${fullTableName}
774
+ FROM ${this.getTableName(TABLE_MESSAGES)}
720
775
  WHERE thread_id = ?
721
776
  )
722
777
  SELECT
@@ -739,20 +794,38 @@ var D1Store = class extends MastraStorage {
739
794
  )
740
795
  ORDER BY m.createdAt DESC
741
796
  `;
742
- const params2 = [
743
- threadId,
744
- ...includeIds,
745
- // for m.id IN (...)
746
- ...includeIds,
747
- // for target.id IN (...)
748
- prevMax,
749
- nextMax
750
- ];
751
- const includeResult = await this.executeQuery({ sql: sql2, params: params2 });
797
+ const params = [
798
+ threadId,
799
+ ...includeIds,
800
+ // for m.id IN (...)
801
+ ...includeIds,
802
+ // for target.id IN (...)
803
+ prevMax,
804
+ nextMax
805
+ ];
806
+ const messages = await this.executeQuery({ sql, params });
807
+ return messages;
808
+ }
809
+ async getMessages({
810
+ threadId,
811
+ selectBy,
812
+ format
813
+ }) {
814
+ const fullTableName = this.getTableName(TABLE_MESSAGES);
815
+ const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
816
+ const include = selectBy?.include || [];
817
+ const messages = [];
818
+ try {
819
+ if (include.length) {
820
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
752
821
  if (Array.isArray(includeResult)) messages.push(...includeResult);
753
822
  }
754
823
  const excludeIds = messages.map((m) => m.id);
755
- let query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId).andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds).orderBy("createdAt", "DESC").limit(limit);
824
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
825
+ if (excludeIds.length > 0) {
826
+ query.andWhere(`id NOT IN (${excludeIds.map(() => "?").join(",")})`, ...excludeIds);
827
+ }
828
+ query.orderBy("createdAt", "DESC").limit(limit);
756
829
  const { sql, params } = query.build();
757
830
  const result = await this.executeQuery({ sql, params });
758
831
  if (Array.isArray(result)) messages.push(...result);
@@ -783,6 +856,47 @@ var D1Store = class extends MastraStorage {
783
856
  return [];
784
857
  }
785
858
  }
859
+ async getMessagesPaginated({
860
+ threadId,
861
+ selectBy,
862
+ format
863
+ }) {
864
+ const { dateRange, page = 0, perPage = 40 } = selectBy?.pagination || {};
865
+ const { start: fromDate, end: toDate } = dateRange || {};
866
+ const fullTableName = this.getTableName(TABLE_MESSAGES);
867
+ const messages = [];
868
+ if (selectBy?.include?.length) {
869
+ const includeResult = await this._getIncludedMessages(threadId, selectBy);
870
+ if (Array.isArray(includeResult)) messages.push(...includeResult);
871
+ }
872
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
873
+ if (fromDate) {
874
+ countQuery.andWhere("createdAt >= ?", this.serializeDate(fromDate));
875
+ }
876
+ if (toDate) {
877
+ countQuery.andWhere("createdAt <= ?", this.serializeDate(toDate));
878
+ }
879
+ const countResult = await this.executeQuery(countQuery.build());
880
+ const total = Number(countResult[0]?.count ?? 0);
881
+ const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId"]).from(fullTableName).where("thread_id = ?", threadId);
882
+ if (fromDate) {
883
+ query.andWhere("createdAt >= ?", this.serializeDate(fromDate));
884
+ }
885
+ if (toDate) {
886
+ query.andWhere("createdAt <= ?", this.serializeDate(toDate));
887
+ }
888
+ query.orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
889
+ const results = await this.executeQuery(query.build());
890
+ const list = new MessageList().add(results, "memory");
891
+ messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
892
+ return {
893
+ messages,
894
+ total,
895
+ page,
896
+ perPage,
897
+ hasMore: page * perPage + messages.length < total
898
+ };
899
+ }
786
900
  async persistWorkflowSnapshot({
787
901
  workflowName,
788
902
  runId,
@@ -875,6 +989,9 @@ var D1Store = class extends MastraStorage {
875
989
  throw new Error(`Failed to batch insert into ${tableName}: ${error}`);
876
990
  }
877
991
  }
992
+ /**
993
+ * @deprecated use getTracesPaginated instead
994
+ */
878
995
  async getTraces({
879
996
  name,
880
997
  scope,
@@ -904,22 +1021,83 @@ var D1Store = class extends MastraStorage {
904
1021
  if (toDate) {
905
1022
  query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
906
1023
  }
907
- query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
1024
+ query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
908
1025
  const { sql, params } = query.build();
909
1026
  const results = await this.executeQuery({ sql, params });
910
- return isArrayOfRecords(results) ? results.map((trace) => ({
911
- ...trace,
912
- attributes: this.deserializeValue(trace.attributes, "jsonb"),
913
- status: this.deserializeValue(trace.status, "jsonb"),
914
- events: this.deserializeValue(trace.events, "jsonb"),
915
- links: this.deserializeValue(trace.links, "jsonb"),
916
- other: this.deserializeValue(trace.other, "jsonb")
917
- })) : [];
1027
+ return isArrayOfRecords(results) ? results.map(
1028
+ (trace) => ({
1029
+ ...trace,
1030
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1031
+ status: this.deserializeValue(trace.status, "jsonb"),
1032
+ events: this.deserializeValue(trace.events, "jsonb"),
1033
+ links: this.deserializeValue(trace.links, "jsonb"),
1034
+ other: this.deserializeValue(trace.other, "jsonb")
1035
+ })
1036
+ ) : [];
918
1037
  } catch (error) {
919
1038
  this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
920
1039
  return [];
921
1040
  }
922
1041
  }
1042
+ async getTracesPaginated(args) {
1043
+ const { name, scope, page, perPage, attributes, fromDate, toDate } = args;
1044
+ const fullTableName = this.getTableName(TABLE_TRACES);
1045
+ try {
1046
+ const dataQuery = createSqlBuilder().select("*").from(fullTableName).where("1=1");
1047
+ const countQuery = createSqlBuilder().count().from(fullTableName).where("1=1");
1048
+ if (name) {
1049
+ dataQuery.andWhere("name LIKE ?", `%${name}%`);
1050
+ countQuery.andWhere("name LIKE ?", `%${name}%`);
1051
+ }
1052
+ if (scope) {
1053
+ dataQuery.andWhere("scope = ?", scope);
1054
+ countQuery.andWhere("scope = ?", scope);
1055
+ }
1056
+ if (attributes && Object.keys(attributes).length > 0) {
1057
+ for (const [key, value] of Object.entries(attributes)) {
1058
+ dataQuery.jsonLike("attributes", key, value);
1059
+ countQuery.jsonLike("attributes", key, value);
1060
+ }
1061
+ }
1062
+ if (fromDate) {
1063
+ const fromDateStr = fromDate instanceof Date ? fromDate.toISOString() : fromDate;
1064
+ dataQuery.andWhere("createdAt >= ?", fromDateStr);
1065
+ countQuery.andWhere("createdAt >= ?", fromDateStr);
1066
+ }
1067
+ if (toDate) {
1068
+ const toDateStr = toDate instanceof Date ? toDate.toISOString() : toDate;
1069
+ dataQuery.andWhere("createdAt <= ?", toDateStr);
1070
+ countQuery.andWhere("createdAt <= ?", toDateStr);
1071
+ }
1072
+ const countResult = await this.executeQuery(countQuery.build());
1073
+ const total = Number(countResult?.[0]?.count ?? 0);
1074
+ dataQuery.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
1075
+ const results = await this.executeQuery(dataQuery.build());
1076
+ const traces = isArrayOfRecords(results) ? results.map(
1077
+ (trace) => ({
1078
+ ...trace,
1079
+ attributes: this.deserializeValue(trace.attributes, "jsonb"),
1080
+ status: this.deserializeValue(trace.status, "jsonb"),
1081
+ events: this.deserializeValue(trace.events, "jsonb"),
1082
+ links: this.deserializeValue(trace.links, "jsonb"),
1083
+ other: this.deserializeValue(trace.other, "jsonb")
1084
+ })
1085
+ ) : [];
1086
+ return {
1087
+ traces,
1088
+ total,
1089
+ page,
1090
+ perPage,
1091
+ hasMore: page * perPage + traces.length < total
1092
+ };
1093
+ } catch (error) {
1094
+ this.logger.error("Error getting traces:", { message: error instanceof Error ? error.message : String(error) });
1095
+ return { traces: [], total: 0, page, perPage, hasMore: false };
1096
+ }
1097
+ }
1098
+ /**
1099
+ * @deprecated use getEvals instead
1100
+ */
923
1101
  async getEvalsByAgentName(agentName, type) {
924
1102
  const fullTableName = this.getTableName(TABLE_EVALS);
925
1103
  try {
@@ -955,6 +1133,80 @@ var D1Store = class extends MastraStorage {
955
1133
  return [];
956
1134
  }
957
1135
  }
1136
+ async getEvals(options) {
1137
+ const { agentName, type, page = 0, perPage = 40, fromDate, toDate } = options || {};
1138
+ const fullTableName = this.getTableName(TABLE_EVALS);
1139
+ const conditions = [];
1140
+ const queryParams = [];
1141
+ if (agentName) {
1142
+ conditions.push(`agent_name = ?`);
1143
+ queryParams.push(agentName);
1144
+ }
1145
+ if (type === "test") {
1146
+ conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
1147
+ } else if (type === "live") {
1148
+ conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
1149
+ }
1150
+ if (fromDate) {
1151
+ conditions.push(`createdAt >= ?`);
1152
+ queryParams.push(this.serializeDate(fromDate));
1153
+ }
1154
+ if (toDate) {
1155
+ conditions.push(`createdAt <= ?`);
1156
+ queryParams.push(this.serializeDate(toDate));
1157
+ }
1158
+ const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
1159
+ if (conditions.length > 0) {
1160
+ countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1161
+ }
1162
+ const { sql: countSql, params: countParams } = countQueryBuilder.build();
1163
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1164
+ const total = Number(countResult?.count || 0);
1165
+ const currentOffset = page * perPage;
1166
+ if (total === 0) {
1167
+ return {
1168
+ evals: [],
1169
+ total: 0,
1170
+ page,
1171
+ perPage,
1172
+ hasMore: false
1173
+ };
1174
+ }
1175
+ const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
1176
+ if (conditions.length > 0) {
1177
+ dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
1178
+ }
1179
+ dataQueryBuilder.orderBy("createdAt", "DESC").limit(perPage).offset(currentOffset);
1180
+ const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
1181
+ const rows = await this.executeQuery({ sql: dataSql, params: dataParams });
1182
+ const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
1183
+ const result = this.deserializeValue(row.result);
1184
+ const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
1185
+ if (!result || typeof result !== "object" || !("score" in result)) {
1186
+ throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
1187
+ }
1188
+ return {
1189
+ input: row.input,
1190
+ output: row.output,
1191
+ result,
1192
+ agentName: row.agent_name,
1193
+ metricName: row.metric_name,
1194
+ instructions: row.instructions,
1195
+ testInfo,
1196
+ globalRunId: row.global_run_id,
1197
+ runId: row.run_id,
1198
+ createdAt: row.createdAt
1199
+ };
1200
+ });
1201
+ const hasMore = currentOffset + evals.length < total;
1202
+ return {
1203
+ evals,
1204
+ total,
1205
+ page,
1206
+ perPage,
1207
+ hasMore
1208
+ };
1209
+ }
958
1210
  parseWorkflowRun(row) {
959
1211
  let parsedSnapshot = row.snapshot;
960
1212
  if (typeof parsedSnapshot === "string") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/cloudflare-d1",
3
- "version": "0.10.1",
3
+ "version": "0.10.2-alpha.1",
4
4
  "description": "D1 provider for Mastra - includes db storage capabilities",
5
5
  "type": "module",
6
6
  "files": [
@@ -22,20 +22,21 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "dependencies": {
25
- "cloudflare": "^4.1.0"
25
+ "cloudflare": "^4.3.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@cloudflare/workers-types": "^4.20250417.0",
29
- "@microsoft/api-extractor": "^7.52.5",
30
- "@types/node": "^20.17.27",
31
- "dotenv": "^16.4.7",
32
- "eslint": "^9.23.0",
33
- "miniflare": "^4.20250410.1",
34
- "tsup": "^8.4.0",
28
+ "@cloudflare/workers-types": "^4.20250607.0",
29
+ "@microsoft/api-extractor": "^7.52.8",
30
+ "@types/node": "^20.17.57",
31
+ "dotenv": "^16.5.0",
32
+ "eslint": "^9.28.0",
33
+ "miniflare": "^4.20250525.1",
34
+ "tsup": "^8.5.0",
35
35
  "typescript": "^5.8.2",
36
- "vitest": "^3.1.2",
37
- "@internal/lint": "0.0.8",
38
- "@mastra/core": "0.10.2"
36
+ "vitest": "^3.2.2",
37
+ "@internal/lint": "0.0.10",
38
+ "@mastra/core": "0.10.4-alpha.1",
39
+ "@internal/storage-test-utils": "0.0.6"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "@mastra/core": "^0.10.2-alpha.0"