@mastra/cloudflare-d1 0.0.0-switch-to-core-20250424015131 → 0.0.0-vector-query-sources-20250516172905

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.
@@ -2,15 +2,19 @@ import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
3
3
  import { MastraStorage } from '@mastra/core/storage';
4
4
  import type { MessageType } from '@mastra/core/memory';
5
+ import type { MessageType as MessageType_2 } from '@mastra/core';
5
6
  import type { StorageColumn } from '@mastra/core/storage';
6
7
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
7
8
  import type { StorageThreadType } from '@mastra/core/memory';
8
9
  import type { TABLE_NAMES } from '@mastra/core/storage';
10
+ import type { WorkflowRun } from '@mastra/core/storage';
9
11
  import type { WorkflowRuns } from '@mastra/core/storage';
10
12
  import type { WorkflowRunState } from '@mastra/core/workflows';
11
13
  import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
12
14
 
13
- export declare const createSampleMessage: (threadId: string) => any;
15
+ export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
16
+
17
+ export declare const createSampleMessage: (threadId: string) => MessageType_2;
14
18
 
15
19
  export declare const createSampleThread: () => {
16
20
  id: string;
@@ -51,7 +55,11 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
51
55
  createdAt: string;
52
56
  };
53
57
 
54
- export declare const createSampleWorkflowSnapshot: (threadId: string) => WorkflowRunState_2;
58
+ export declare const createSampleWorkflowSnapshot: (threadId: string, status: string, createdAt?: Date) => {
59
+ snapshot: WorkflowRunState_2;
60
+ runId: string;
61
+ stepId: string;
62
+ };
55
63
 
56
64
  export declare function createSqlBuilder(): SqlBuilder;
57
65
 
@@ -153,21 +161,30 @@ declare class D1Store extends MastraStorage {
153
161
  tableName: TABLE_NAMES;
154
162
  records: Record<string, any>[];
155
163
  }): Promise<void>;
156
- getTraces({ name, scope, page, perPage, attributes, }: {
164
+ getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
157
165
  name?: string;
158
166
  scope?: string;
159
167
  page: number;
160
168
  perPage: number;
161
169
  attributes?: Record<string, string>;
170
+ fromDate?: Date;
171
+ toDate?: Date;
162
172
  }): Promise<Record<string, any>[]>;
163
173
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
164
- getWorkflowRuns(_args?: {
174
+ private parseWorkflowRun;
175
+ private hasColumn;
176
+ getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId, }?: {
165
177
  workflowName?: string;
166
178
  fromDate?: Date;
167
179
  toDate?: Date;
168
180
  limit?: number;
169
181
  offset?: number;
182
+ resourceId?: string;
170
183
  }): Promise<WorkflowRuns>;
184
+ getWorkflowRunById({ runId, workflowName, }: {
185
+ runId: string;
186
+ workflowName?: string;
187
+ }): Promise<WorkflowRun | null>;
171
188
  /**
172
189
  * Close the database connection
173
190
  * No explicit cleanup needed for D1 in either REST or Workers Binding mode
@@ -196,9 +213,30 @@ declare interface D1WorkersConfig {
196
213
  export { D1WorkersConfig }
197
214
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
198
215
 
216
+ /**
217
+ * Parses and returns a valid SQL SELECT column identifier.
218
+ * Allows a single identifier (letters, numbers, underscores), or '*', optionally with 'AS alias'.
219
+ *
220
+ * @param column - The column identifier string to parse.
221
+ * @returns The validated column identifier as a branded type.
222
+ * @throws {Error} If invalid.
223
+ *
224
+ * @example
225
+ * const col = parseSelectIdentifier('user_id'); // Ok
226
+ * parseSelectIdentifier('user_id AS uid'); // Ok
227
+ * parseSelectIdentifier('*'); // Ok
228
+ * parseSelectIdentifier('user id'); // Throws error
229
+ */
230
+ export declare function parseSelectIdentifier(column: string): SelectIdentifier;
231
+
199
232
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
200
233
  interval?: number) => Promise<T>;
201
234
 
235
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
236
+ declare type SelectIdentifier = string & {
237
+ __brand: 'SelectIdentifier';
238
+ };
239
+
202
240
  /**
203
241
  * SQL Builder class for constructing type-safe SQL queries
204
242
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -226,6 +264,7 @@ export declare class SqlBuilder {
226
264
  orderBy(column: string, direction?: 'ASC' | 'DESC'): SqlBuilder;
227
265
  limit(count: number): SqlBuilder;
228
266
  offset(count: number): SqlBuilder;
267
+ count(): SqlBuilder;
229
268
  /**
230
269
  * Insert a row, or update specific columns on conflict (upsert).
231
270
  * @param table Table name
@@ -261,7 +300,6 @@ export declare class SqlBuilder {
261
300
  * @returns The builder instance
262
301
  */
263
302
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
264
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
265
303
  /**
266
304
  * Add a LIKE condition to the query
267
305
  * @param column The column to check
@@ -299,7 +337,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
299
337
  /**
300
338
  * Interface for SQL query options with generic type support
301
339
  */
302
- declare interface SqlQueryOptions {
340
+ export declare interface SqlQueryOptions {
303
341
  /** SQL query to execute */
304
342
  sql: string;
305
343
  /** Parameters to bind to the query */
@@ -307,7 +345,5 @@ declare interface SqlQueryOptions {
307
345
  /** Whether to return only the first result */
308
346
  first?: boolean;
309
347
  }
310
- export { SqlQueryOptions }
311
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
312
348
 
313
349
  export { }
@@ -2,15 +2,19 @@ import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
3
3
  import { MastraStorage } from '@mastra/core/storage';
4
4
  import type { MessageType } from '@mastra/core/memory';
5
+ import type { MessageType as MessageType_2 } from '@mastra/core';
5
6
  import type { StorageColumn } from '@mastra/core/storage';
6
7
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
7
8
  import type { StorageThreadType } from '@mastra/core/memory';
8
9
  import type { TABLE_NAMES } from '@mastra/core/storage';
10
+ import type { WorkflowRun } from '@mastra/core/storage';
9
11
  import type { WorkflowRuns } from '@mastra/core/storage';
10
12
  import type { WorkflowRunState } from '@mastra/core/workflows';
11
13
  import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
12
14
 
13
- export declare const createSampleMessage: (threadId: string) => any;
15
+ export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
16
+
17
+ export declare const createSampleMessage: (threadId: string) => MessageType_2;
14
18
 
15
19
  export declare const createSampleThread: () => {
16
20
  id: string;
@@ -51,7 +55,11 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
51
55
  createdAt: string;
52
56
  };
53
57
 
54
- export declare const createSampleWorkflowSnapshot: (threadId: string) => WorkflowRunState_2;
58
+ export declare const createSampleWorkflowSnapshot: (threadId: string, status: string, createdAt?: Date) => {
59
+ snapshot: WorkflowRunState_2;
60
+ runId: string;
61
+ stepId: string;
62
+ };
55
63
 
56
64
  export declare function createSqlBuilder(): SqlBuilder;
57
65
 
@@ -153,21 +161,30 @@ declare class D1Store extends MastraStorage {
153
161
  tableName: TABLE_NAMES;
154
162
  records: Record<string, any>[];
155
163
  }): Promise<void>;
156
- getTraces({ name, scope, page, perPage, attributes, }: {
164
+ getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
157
165
  name?: string;
158
166
  scope?: string;
159
167
  page: number;
160
168
  perPage: number;
161
169
  attributes?: Record<string, string>;
170
+ fromDate?: Date;
171
+ toDate?: Date;
162
172
  }): Promise<Record<string, any>[]>;
163
173
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
164
- getWorkflowRuns(_args?: {
174
+ private parseWorkflowRun;
175
+ private hasColumn;
176
+ getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId, }?: {
165
177
  workflowName?: string;
166
178
  fromDate?: Date;
167
179
  toDate?: Date;
168
180
  limit?: number;
169
181
  offset?: number;
182
+ resourceId?: string;
170
183
  }): Promise<WorkflowRuns>;
184
+ getWorkflowRunById({ runId, workflowName, }: {
185
+ runId: string;
186
+ workflowName?: string;
187
+ }): Promise<WorkflowRun | null>;
171
188
  /**
172
189
  * Close the database connection
173
190
  * No explicit cleanup needed for D1 in either REST or Workers Binding mode
@@ -196,9 +213,30 @@ declare interface D1WorkersConfig {
196
213
  export { D1WorkersConfig }
197
214
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
198
215
 
216
+ /**
217
+ * Parses and returns a valid SQL SELECT column identifier.
218
+ * Allows a single identifier (letters, numbers, underscores), or '*', optionally with 'AS alias'.
219
+ *
220
+ * @param column - The column identifier string to parse.
221
+ * @returns The validated column identifier as a branded type.
222
+ * @throws {Error} If invalid.
223
+ *
224
+ * @example
225
+ * const col = parseSelectIdentifier('user_id'); // Ok
226
+ * parseSelectIdentifier('user_id AS uid'); // Ok
227
+ * parseSelectIdentifier('*'); // Ok
228
+ * parseSelectIdentifier('user id'); // Throws error
229
+ */
230
+ export declare function parseSelectIdentifier(column: string): SelectIdentifier;
231
+
199
232
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
200
233
  interval?: number) => Promise<T>;
201
234
 
235
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
236
+ declare type SelectIdentifier = string & {
237
+ __brand: 'SelectIdentifier';
238
+ };
239
+
202
240
  /**
203
241
  * SQL Builder class for constructing type-safe SQL queries
204
242
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -226,6 +264,7 @@ export declare class SqlBuilder {
226
264
  orderBy(column: string, direction?: 'ASC' | 'DESC'): SqlBuilder;
227
265
  limit(count: number): SqlBuilder;
228
266
  offset(count: number): SqlBuilder;
267
+ count(): SqlBuilder;
229
268
  /**
230
269
  * Insert a row, or update specific columns on conflict (upsert).
231
270
  * @param table Table name
@@ -261,7 +300,6 @@ export declare class SqlBuilder {
261
300
  * @returns The builder instance
262
301
  */
263
302
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
264
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
265
303
  /**
266
304
  * Add a LIKE condition to the query
267
305
  * @param column The column to check
@@ -299,7 +337,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
299
337
  /**
300
338
  * Interface for SQL query options with generic type support
301
339
  */
302
- declare interface SqlQueryOptions {
340
+ export declare interface SqlQueryOptions {
303
341
  /** SQL query to execute */
304
342
  sql: string;
305
343
  /** Parameters to bind to the query */
@@ -307,7 +345,5 @@ declare interface SqlQueryOptions {
307
345
  /** Whether to return only the first result */
308
346
  first?: boolean;
309
347
  }
310
- export { SqlQueryOptions }
311
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
312
348
 
313
349
  export { }
package/dist/index.cjs CHANGED
@@ -2,14 +2,13 @@
2
2
 
3
3
  var storage = require('@mastra/core/storage');
4
4
  var Cloudflare = require('cloudflare');
5
+ var utils = require('@mastra/core/utils');
5
6
 
6
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
8
 
8
9
  var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
9
10
 
10
11
  // src/storage/index.ts
11
-
12
- // src/storage/sql-builder.ts
13
12
  var SqlBuilder = class {
14
13
  sql = "";
15
14
  params = [];
@@ -19,12 +18,15 @@ var SqlBuilder = class {
19
18
  if (!columns || Array.isArray(columns) && columns.length === 0) {
20
19
  this.sql = "SELECT *";
21
20
  } else {
22
- this.sql = `SELECT ${Array.isArray(columns) ? columns.join(", ") : columns}`;
21
+ const cols = Array.isArray(columns) ? columns : [columns];
22
+ const parsedCols = cols.map((col) => parseSelectIdentifier(col));
23
+ this.sql = `SELECT ${parsedCols.join(", ")}`;
23
24
  }
24
25
  return this;
25
26
  }
26
27
  from(table) {
27
- this.sql += ` FROM ${table}`;
28
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
29
+ this.sql += ` FROM ${parsedTableName}`;
28
30
  return this;
29
31
  }
30
32
  /**
@@ -61,7 +63,11 @@ var SqlBuilder = class {
61
63
  return this;
62
64
  }
63
65
  orderBy(column, direction = "ASC") {
64
- this.sql += ` ORDER BY ${column} ${direction}`;
66
+ const parsedColumn = utils.parseSqlIdentifier(column, "column name");
67
+ if (!["ASC", "DESC"].includes(direction)) {
68
+ throw new Error(`Invalid sort direction: ${direction}`);
69
+ }
70
+ this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
65
71
  return this;
66
72
  }
67
73
  limit(count) {
@@ -74,6 +80,10 @@ var SqlBuilder = class {
74
80
  this.params.push(count);
75
81
  return this;
76
82
  }
83
+ count() {
84
+ this.sql += "SELECT COUNT(*) AS count";
85
+ return this;
86
+ }
77
87
  /**
78
88
  * Insert a row, or update specific columns on conflict (upsert).
79
89
  * @param table Table name
@@ -83,27 +93,33 @@ var SqlBuilder = class {
83
93
  * @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
84
94
  */
85
95
  insert(table, columns, values, conflictColumns, updateMap) {
86
- const placeholders = columns.map(() => "?").join(", ");
96
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
97
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
98
+ const placeholders = parsedColumns.map(() => "?").join(", ");
87
99
  if (conflictColumns && updateMap) {
100
+ const parsedConflictColumns = conflictColumns.map((col) => utils.parseSqlIdentifier(col, "column name"));
88
101
  const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
89
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
102
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
90
103
  this.params.push(...values);
91
104
  return this;
92
105
  }
93
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
106
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
94
107
  this.params.push(...values);
95
108
  return this;
96
109
  }
97
110
  // Update operations
98
111
  update(table, columns, values) {
99
- const setClause = columns.map((col) => `${col} = ?`).join(", ");
100
- this.sql = `UPDATE ${table} SET ${setClause}`;
112
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
113
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
114
+ const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
115
+ this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
101
116
  this.params.push(...values);
102
117
  return this;
103
118
  }
104
119
  // Delete operations
105
120
  delete(table) {
106
- this.sql = `DELETE FROM ${table}`;
121
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
122
+ this.sql = `DELETE FROM ${parsedTableName}`;
107
123
  return this;
108
124
  }
109
125
  /**
@@ -114,9 +130,16 @@ var SqlBuilder = class {
114
130
  * @returns The builder instance
115
131
  */
116
132
  createTable(table, columnDefinitions, tableConstraints) {
117
- const columns = columnDefinitions.join(", ");
133
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
134
+ const parsedColumnDefinitions = columnDefinitions.map((def) => {
135
+ const colName = def.split(/\s+/)[0];
136
+ if (!colName) throw new Error("Empty column name in definition");
137
+ utils.parseSqlIdentifier(colName, "column name");
138
+ return def;
139
+ });
140
+ const columns = parsedColumnDefinitions.join(", ");
118
141
  const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
119
- this.sql = `CREATE TABLE IF NOT EXISTS ${table} (${columns}${constraints})`;
142
+ this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
120
143
  return this;
121
144
  }
122
145
  /**
@@ -139,13 +162,10 @@ var SqlBuilder = class {
139
162
  * @returns The builder instance
140
163
  */
141
164
  createIndex(indexName, tableName, columnName, indexType = "") {
142
- this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${indexName} ON ${tableName}(${columnName})`;
143
- return this;
144
- }
145
- // Raw SQL with params
146
- raw(sql, ...params) {
147
- this.sql = sql;
148
- this.params.push(...params);
165
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
166
+ const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
167
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
168
+ this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
149
169
  return this;
150
170
  }
151
171
  /**
@@ -155,11 +175,12 @@ var SqlBuilder = class {
155
175
  * @param exact If true, will not add % wildcards
156
176
  */
157
177
  like(column, value, exact = false) {
178
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
158
179
  const likeValue = exact ? value : `%${value}%`;
159
180
  if (this.whereAdded) {
160
- this.sql += ` AND ${column} LIKE ?`;
181
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
161
182
  } else {
162
- this.sql += ` WHERE ${column} LIKE ?`;
183
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
163
184
  this.whereAdded = true;
164
185
  }
165
186
  this.params.push(likeValue);
@@ -172,11 +193,13 @@ var SqlBuilder = class {
172
193
  * @param value The value to match
173
194
  */
174
195
  jsonLike(column, key, value) {
175
- const jsonPattern = `%"${key}":"${value}"%`;
196
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
197
+ const parsedKey = utils.parseSqlIdentifier(key, "key name");
198
+ const jsonPattern = `%"${parsedKey}":"${value}"%`;
176
199
  if (this.whereAdded) {
177
- this.sql += ` AND ${column} LIKE ?`;
200
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
178
201
  } else {
179
- this.sql += ` WHERE ${column} LIKE ?`;
202
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
180
203
  this.whereAdded = true;
181
204
  }
182
205
  this.params.push(jsonPattern);
@@ -206,6 +229,15 @@ var SqlBuilder = class {
206
229
  function createSqlBuilder() {
207
230
  return new SqlBuilder();
208
231
  }
232
+ var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
233
+ function parseSelectIdentifier(column) {
234
+ if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
235
+ throw new Error(
236
+ `Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
237
+ );
238
+ }
239
+ return column;
240
+ }
209
241
 
210
242
  // src/storage/index.ts
211
243
  function isArrayOfRecords(value) {
@@ -224,6 +256,9 @@ var D1Store = class extends storage.MastraStorage {
224
256
  */
225
257
  constructor(config) {
226
258
  super({ name: "D1" });
259
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
260
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
261
+ }
227
262
  this.tablePrefix = config.tablePrefix || "";
228
263
  if ("binding" in config) {
229
264
  if (!config.binding) {
@@ -496,7 +531,8 @@ var D1Store = class extends storage.MastraStorage {
496
531
  try {
497
532
  await this.executeQuery({ sql, params });
498
533
  } catch (error) {
499
- this.logger.error(`Error inserting into ${fullTableName}:`, { error });
534
+ const message = error instanceof Error ? error.message : String(error);
535
+ this.logger.error(`Error inserting into ${fullTableName}:`, { message });
500
536
  throw new Error(`Failed to insert into ${fullTableName}: ${error}`);
501
537
  }
502
538
  }
@@ -594,7 +630,8 @@ var D1Store = class extends storage.MastraStorage {
594
630
  await this.executeQuery({ sql, params });
595
631
  return thread;
596
632
  } catch (error) {
597
- this.logger.error(`Error saving thread to ${fullTableName}:`, { error });
633
+ const message = error instanceof Error ? error.message : String(error);
634
+ this.logger.error(`Error saving thread to ${fullTableName}:`, { message });
598
635
  throw error;
599
636
  }
600
637
  }
@@ -628,7 +665,8 @@ var D1Store = class extends storage.MastraStorage {
628
665
  updatedAt: /* @__PURE__ */ new Date()
629
666
  };
630
667
  } catch (error) {
631
- this.logger.error("Error updating thread:", { error });
668
+ const message = error instanceof Error ? error.message : String(error);
669
+ this.logger.error("Error updating thread:", { message });
632
670
  throw error;
633
671
  }
634
672
  }
@@ -710,7 +748,7 @@ var D1Store = class extends storage.MastraStorage {
710
748
  m.role,
711
749
  m.type,
712
750
  m.createdAt,
713
- m.thread_id AS "threadId"
751
+ m.thread_id AS threadId
714
752
  FROM ordered_messages m
715
753
  WHERE m.id IN (${includeIds.map(() => "?").join(",")})
716
754
  OR EXISTS (
@@ -737,7 +775,7 @@ var D1Store = class extends storage.MastraStorage {
737
775
  if (Array.isArray(includeResult)) messages.push(...includeResult);
738
776
  }
739
777
  const excludeIds = messages.map((m) => m.id);
740
- 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);
778
+ 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);
741
779
  const { sql, params } = query.build();
742
780
  const result = await this.executeQuery({ sql, params });
743
781
  if (Array.isArray(result)) messages.push(...result);
@@ -862,7 +900,9 @@ var D1Store = class extends storage.MastraStorage {
862
900
  scope,
863
901
  page,
864
902
  perPage,
865
- attributes
903
+ attributes,
904
+ fromDate,
905
+ toDate
866
906
  }) {
867
907
  const fullTableName = this.getTableName(storage.TABLE_TRACES);
868
908
  try {
@@ -878,6 +918,12 @@ var D1Store = class extends storage.MastraStorage {
878
918
  query.jsonLike("attributes", key, value);
879
919
  }
880
920
  }
921
+ if (fromDate) {
922
+ query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
923
+ }
924
+ if (toDate) {
925
+ query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
926
+ }
881
927
  query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
882
928
  const { sql, params } = query.build();
883
929
  const results = await this.executeQuery({ sql, params });
@@ -929,8 +975,107 @@ var D1Store = class extends storage.MastraStorage {
929
975
  return [];
930
976
  }
931
977
  }
932
- getWorkflowRuns(_args) {
933
- throw new Error("Method not implemented.");
978
+ parseWorkflowRun(row) {
979
+ let parsedSnapshot = row.snapshot;
980
+ if (typeof parsedSnapshot === "string") {
981
+ try {
982
+ parsedSnapshot = JSON.parse(row.snapshot);
983
+ } catch (e) {
984
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
985
+ }
986
+ }
987
+ return {
988
+ workflowName: row.workflow_name,
989
+ runId: row.run_id,
990
+ snapshot: parsedSnapshot,
991
+ createdAt: this.ensureDate(row.createdAt),
992
+ updatedAt: this.ensureDate(row.updatedAt),
993
+ resourceId: row.resourceId
994
+ };
995
+ }
996
+ async hasColumn(table, column) {
997
+ const sql = `PRAGMA table_info(${table});`;
998
+ const result = await this.executeQuery({ sql, params: [] });
999
+ if (!result || !Array.isArray(result)) return false;
1000
+ return result.some((col) => col.name === column || col.name === column.toLowerCase());
1001
+ }
1002
+ async getWorkflowRuns({
1003
+ workflowName,
1004
+ fromDate,
1005
+ toDate,
1006
+ limit,
1007
+ offset,
1008
+ resourceId
1009
+ } = {}) {
1010
+ const fullTableName = this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1011
+ try {
1012
+ const builder = createSqlBuilder().select().from(fullTableName);
1013
+ const countBuilder = createSqlBuilder().count().from(fullTableName);
1014
+ if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
1015
+ if (resourceId) {
1016
+ const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
1017
+ if (hasResourceId) {
1018
+ builder.whereAnd("resourceId = ?", resourceId);
1019
+ countBuilder.whereAnd("resourceId = ?", resourceId);
1020
+ } else {
1021
+ console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1022
+ }
1023
+ }
1024
+ if (fromDate) {
1025
+ builder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1026
+ countBuilder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1027
+ }
1028
+ if (toDate) {
1029
+ builder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1030
+ countBuilder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1031
+ }
1032
+ builder.orderBy("createdAt", "DESC");
1033
+ if (typeof limit === "number") builder.limit(limit);
1034
+ if (typeof offset === "number") builder.offset(offset);
1035
+ const { sql, params } = builder.build();
1036
+ let total = 0;
1037
+ if (limit !== void 0 && offset !== void 0) {
1038
+ const { sql: countSql, params: countParams } = countBuilder.build();
1039
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1040
+ total = Number(countResult?.count ?? 0);
1041
+ }
1042
+ const results = await this.executeQuery({ sql, params });
1043
+ const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1044
+ return { runs, total: total || runs.length };
1045
+ } catch (error) {
1046
+ this.logger.error("Error getting workflow runs:", {
1047
+ message: error instanceof Error ? error.message : String(error)
1048
+ });
1049
+ throw error;
1050
+ }
1051
+ }
1052
+ async getWorkflowRunById({
1053
+ runId,
1054
+ workflowName
1055
+ }) {
1056
+ const fullTableName = this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT);
1057
+ try {
1058
+ const conditions = [];
1059
+ const params = [];
1060
+ if (runId) {
1061
+ conditions.push("run_id = ?");
1062
+ params.push(runId);
1063
+ }
1064
+ if (workflowName) {
1065
+ conditions.push("workflow_name = ?");
1066
+ params.push(workflowName);
1067
+ }
1068
+ const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1069
+ const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1070
+ const result = await this.executeQuery({ sql, params, first: true });
1071
+ if (!result) return null;
1072
+ return this.parseWorkflowRun(result);
1073
+ } catch (error) {
1074
+ this.logger.error("Error getting workflow run by ID:", {
1075
+ message: error instanceof Error ? error.message : String(error)
1076
+ });
1077
+ throw error;
1078
+ }
934
1079
  }
935
1080
  /**
936
1081
  * Close the database connection
package/dist/index.d.cts CHANGED
@@ -1,4 +1,3 @@
1
- export { SqlQueryOptions } from './_tsup-dts-rollup.cjs';
2
1
  export { D1Config } from './_tsup-dts-rollup.cjs';
3
2
  export { D1WorkersConfig } from './_tsup-dts-rollup.cjs';
4
3
  export { D1StoreConfig } from './_tsup-dts-rollup.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { SqlQueryOptions } from './_tsup-dts-rollup.js';
2
1
  export { D1Config } from './_tsup-dts-rollup.js';
3
2
  export { D1WorkersConfig } from './_tsup-dts-rollup.js';
4
3
  export { D1StoreConfig } from './_tsup-dts-rollup.js';
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_TRACES, TABLE_EVALS } from '@mastra/core/storage';
2
2
  import Cloudflare from 'cloudflare';
3
+ import { parseSqlIdentifier } from '@mastra/core/utils';
3
4
 
4
5
  // src/storage/index.ts
5
-
6
- // src/storage/sql-builder.ts
7
6
  var SqlBuilder = class {
8
7
  sql = "";
9
8
  params = [];
@@ -13,12 +12,15 @@ var SqlBuilder = class {
13
12
  if (!columns || Array.isArray(columns) && columns.length === 0) {
14
13
  this.sql = "SELECT *";
15
14
  } else {
16
- this.sql = `SELECT ${Array.isArray(columns) ? columns.join(", ") : columns}`;
15
+ const cols = Array.isArray(columns) ? columns : [columns];
16
+ const parsedCols = cols.map((col) => parseSelectIdentifier(col));
17
+ this.sql = `SELECT ${parsedCols.join(", ")}`;
17
18
  }
18
19
  return this;
19
20
  }
20
21
  from(table) {
21
- this.sql += ` FROM ${table}`;
22
+ const parsedTableName = parseSqlIdentifier(table, "table name");
23
+ this.sql += ` FROM ${parsedTableName}`;
22
24
  return this;
23
25
  }
24
26
  /**
@@ -55,7 +57,11 @@ var SqlBuilder = class {
55
57
  return this;
56
58
  }
57
59
  orderBy(column, direction = "ASC") {
58
- this.sql += ` ORDER BY ${column} ${direction}`;
60
+ const parsedColumn = parseSqlIdentifier(column, "column name");
61
+ if (!["ASC", "DESC"].includes(direction)) {
62
+ throw new Error(`Invalid sort direction: ${direction}`);
63
+ }
64
+ this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
59
65
  return this;
60
66
  }
61
67
  limit(count) {
@@ -68,6 +74,10 @@ var SqlBuilder = class {
68
74
  this.params.push(count);
69
75
  return this;
70
76
  }
77
+ count() {
78
+ this.sql += "SELECT COUNT(*) AS count";
79
+ return this;
80
+ }
71
81
  /**
72
82
  * Insert a row, or update specific columns on conflict (upsert).
73
83
  * @param table Table name
@@ -77,27 +87,33 @@ var SqlBuilder = class {
77
87
  * @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
78
88
  */
79
89
  insert(table, columns, values, conflictColumns, updateMap) {
80
- const placeholders = columns.map(() => "?").join(", ");
90
+ const parsedTableName = parseSqlIdentifier(table, "table name");
91
+ const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
92
+ const placeholders = parsedColumns.map(() => "?").join(", ");
81
93
  if (conflictColumns && updateMap) {
94
+ const parsedConflictColumns = conflictColumns.map((col) => parseSqlIdentifier(col, "column name"));
82
95
  const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
83
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
96
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
84
97
  this.params.push(...values);
85
98
  return this;
86
99
  }
87
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
100
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
88
101
  this.params.push(...values);
89
102
  return this;
90
103
  }
91
104
  // Update operations
92
105
  update(table, columns, values) {
93
- const setClause = columns.map((col) => `${col} = ?`).join(", ");
94
- this.sql = `UPDATE ${table} SET ${setClause}`;
106
+ const parsedTableName = parseSqlIdentifier(table, "table name");
107
+ const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
108
+ const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
109
+ this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
95
110
  this.params.push(...values);
96
111
  return this;
97
112
  }
98
113
  // Delete operations
99
114
  delete(table) {
100
- this.sql = `DELETE FROM ${table}`;
115
+ const parsedTableName = parseSqlIdentifier(table, "table name");
116
+ this.sql = `DELETE FROM ${parsedTableName}`;
101
117
  return this;
102
118
  }
103
119
  /**
@@ -108,9 +124,16 @@ var SqlBuilder = class {
108
124
  * @returns The builder instance
109
125
  */
110
126
  createTable(table, columnDefinitions, tableConstraints) {
111
- const columns = columnDefinitions.join(", ");
127
+ const parsedTableName = parseSqlIdentifier(table, "table name");
128
+ const parsedColumnDefinitions = columnDefinitions.map((def) => {
129
+ const colName = def.split(/\s+/)[0];
130
+ if (!colName) throw new Error("Empty column name in definition");
131
+ parseSqlIdentifier(colName, "column name");
132
+ return def;
133
+ });
134
+ const columns = parsedColumnDefinitions.join(", ");
112
135
  const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
113
- this.sql = `CREATE TABLE IF NOT EXISTS ${table} (${columns}${constraints})`;
136
+ this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
114
137
  return this;
115
138
  }
116
139
  /**
@@ -133,13 +156,10 @@ var SqlBuilder = class {
133
156
  * @returns The builder instance
134
157
  */
135
158
  createIndex(indexName, tableName, columnName, indexType = "") {
136
- this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${indexName} ON ${tableName}(${columnName})`;
137
- return this;
138
- }
139
- // Raw SQL with params
140
- raw(sql, ...params) {
141
- this.sql = sql;
142
- this.params.push(...params);
159
+ const parsedIndexName = parseSqlIdentifier(indexName, "index name");
160
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
161
+ const parsedColumnName = parseSqlIdentifier(columnName, "column name");
162
+ this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
143
163
  return this;
144
164
  }
145
165
  /**
@@ -149,11 +169,12 @@ var SqlBuilder = class {
149
169
  * @param exact If true, will not add % wildcards
150
170
  */
151
171
  like(column, value, exact = false) {
172
+ const parsedColumnName = parseSqlIdentifier(column, "column name");
152
173
  const likeValue = exact ? value : `%${value}%`;
153
174
  if (this.whereAdded) {
154
- this.sql += ` AND ${column} LIKE ?`;
175
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
155
176
  } else {
156
- this.sql += ` WHERE ${column} LIKE ?`;
177
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
157
178
  this.whereAdded = true;
158
179
  }
159
180
  this.params.push(likeValue);
@@ -166,11 +187,13 @@ var SqlBuilder = class {
166
187
  * @param value The value to match
167
188
  */
168
189
  jsonLike(column, key, value) {
169
- const jsonPattern = `%"${key}":"${value}"%`;
190
+ const parsedColumnName = parseSqlIdentifier(column, "column name");
191
+ const parsedKey = parseSqlIdentifier(key, "key name");
192
+ const jsonPattern = `%"${parsedKey}":"${value}"%`;
170
193
  if (this.whereAdded) {
171
- this.sql += ` AND ${column} LIKE ?`;
194
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
172
195
  } else {
173
- this.sql += ` WHERE ${column} LIKE ?`;
196
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
174
197
  this.whereAdded = true;
175
198
  }
176
199
  this.params.push(jsonPattern);
@@ -200,6 +223,15 @@ var SqlBuilder = class {
200
223
  function createSqlBuilder() {
201
224
  return new SqlBuilder();
202
225
  }
226
+ var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
227
+ function parseSelectIdentifier(column) {
228
+ if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
229
+ throw new Error(
230
+ `Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
231
+ );
232
+ }
233
+ return column;
234
+ }
203
235
 
204
236
  // src/storage/index.ts
205
237
  function isArrayOfRecords(value) {
@@ -218,6 +250,9 @@ var D1Store = class extends MastraStorage {
218
250
  */
219
251
  constructor(config) {
220
252
  super({ name: "D1" });
253
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
254
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
255
+ }
221
256
  this.tablePrefix = config.tablePrefix || "";
222
257
  if ("binding" in config) {
223
258
  if (!config.binding) {
@@ -490,7 +525,8 @@ var D1Store = class extends MastraStorage {
490
525
  try {
491
526
  await this.executeQuery({ sql, params });
492
527
  } catch (error) {
493
- this.logger.error(`Error inserting into ${fullTableName}:`, { error });
528
+ const message = error instanceof Error ? error.message : String(error);
529
+ this.logger.error(`Error inserting into ${fullTableName}:`, { message });
494
530
  throw new Error(`Failed to insert into ${fullTableName}: ${error}`);
495
531
  }
496
532
  }
@@ -588,7 +624,8 @@ var D1Store = class extends MastraStorage {
588
624
  await this.executeQuery({ sql, params });
589
625
  return thread;
590
626
  } catch (error) {
591
- this.logger.error(`Error saving thread to ${fullTableName}:`, { error });
627
+ const message = error instanceof Error ? error.message : String(error);
628
+ this.logger.error(`Error saving thread to ${fullTableName}:`, { message });
592
629
  throw error;
593
630
  }
594
631
  }
@@ -622,7 +659,8 @@ var D1Store = class extends MastraStorage {
622
659
  updatedAt: /* @__PURE__ */ new Date()
623
660
  };
624
661
  } catch (error) {
625
- this.logger.error("Error updating thread:", { error });
662
+ const message = error instanceof Error ? error.message : String(error);
663
+ this.logger.error("Error updating thread:", { message });
626
664
  throw error;
627
665
  }
628
666
  }
@@ -704,7 +742,7 @@ var D1Store = class extends MastraStorage {
704
742
  m.role,
705
743
  m.type,
706
744
  m.createdAt,
707
- m.thread_id AS "threadId"
745
+ m.thread_id AS threadId
708
746
  FROM ordered_messages m
709
747
  WHERE m.id IN (${includeIds.map(() => "?").join(",")})
710
748
  OR EXISTS (
@@ -731,7 +769,7 @@ var D1Store = class extends MastraStorage {
731
769
  if (Array.isArray(includeResult)) messages.push(...includeResult);
732
770
  }
733
771
  const excludeIds = messages.map((m) => m.id);
734
- 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);
772
+ 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);
735
773
  const { sql, params } = query.build();
736
774
  const result = await this.executeQuery({ sql, params });
737
775
  if (Array.isArray(result)) messages.push(...result);
@@ -856,7 +894,9 @@ var D1Store = class extends MastraStorage {
856
894
  scope,
857
895
  page,
858
896
  perPage,
859
- attributes
897
+ attributes,
898
+ fromDate,
899
+ toDate
860
900
  }) {
861
901
  const fullTableName = this.getTableName(TABLE_TRACES);
862
902
  try {
@@ -872,6 +912,12 @@ var D1Store = class extends MastraStorage {
872
912
  query.jsonLike("attributes", key, value);
873
913
  }
874
914
  }
915
+ if (fromDate) {
916
+ query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
917
+ }
918
+ if (toDate) {
919
+ query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
920
+ }
875
921
  query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
876
922
  const { sql, params } = query.build();
877
923
  const results = await this.executeQuery({ sql, params });
@@ -923,8 +969,107 @@ var D1Store = class extends MastraStorage {
923
969
  return [];
924
970
  }
925
971
  }
926
- getWorkflowRuns(_args) {
927
- throw new Error("Method not implemented.");
972
+ parseWorkflowRun(row) {
973
+ let parsedSnapshot = row.snapshot;
974
+ if (typeof parsedSnapshot === "string") {
975
+ try {
976
+ parsedSnapshot = JSON.parse(row.snapshot);
977
+ } catch (e) {
978
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
979
+ }
980
+ }
981
+ return {
982
+ workflowName: row.workflow_name,
983
+ runId: row.run_id,
984
+ snapshot: parsedSnapshot,
985
+ createdAt: this.ensureDate(row.createdAt),
986
+ updatedAt: this.ensureDate(row.updatedAt),
987
+ resourceId: row.resourceId
988
+ };
989
+ }
990
+ async hasColumn(table, column) {
991
+ const sql = `PRAGMA table_info(${table});`;
992
+ const result = await this.executeQuery({ sql, params: [] });
993
+ if (!result || !Array.isArray(result)) return false;
994
+ return result.some((col) => col.name === column || col.name === column.toLowerCase());
995
+ }
996
+ async getWorkflowRuns({
997
+ workflowName,
998
+ fromDate,
999
+ toDate,
1000
+ limit,
1001
+ offset,
1002
+ resourceId
1003
+ } = {}) {
1004
+ const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1005
+ try {
1006
+ const builder = createSqlBuilder().select().from(fullTableName);
1007
+ const countBuilder = createSqlBuilder().count().from(fullTableName);
1008
+ if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
1009
+ if (resourceId) {
1010
+ const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
1011
+ if (hasResourceId) {
1012
+ builder.whereAnd("resourceId = ?", resourceId);
1013
+ countBuilder.whereAnd("resourceId = ?", resourceId);
1014
+ } else {
1015
+ console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1016
+ }
1017
+ }
1018
+ if (fromDate) {
1019
+ builder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1020
+ countBuilder.whereAnd("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
1021
+ }
1022
+ if (toDate) {
1023
+ builder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1024
+ countBuilder.whereAnd("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
1025
+ }
1026
+ builder.orderBy("createdAt", "DESC");
1027
+ if (typeof limit === "number") builder.limit(limit);
1028
+ if (typeof offset === "number") builder.offset(offset);
1029
+ const { sql, params } = builder.build();
1030
+ let total = 0;
1031
+ if (limit !== void 0 && offset !== void 0) {
1032
+ const { sql: countSql, params: countParams } = countBuilder.build();
1033
+ const countResult = await this.executeQuery({ sql: countSql, params: countParams, first: true });
1034
+ total = Number(countResult?.count ?? 0);
1035
+ }
1036
+ const results = await this.executeQuery({ sql, params });
1037
+ const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
1038
+ return { runs, total: total || runs.length };
1039
+ } catch (error) {
1040
+ this.logger.error("Error getting workflow runs:", {
1041
+ message: error instanceof Error ? error.message : String(error)
1042
+ });
1043
+ throw error;
1044
+ }
1045
+ }
1046
+ async getWorkflowRunById({
1047
+ runId,
1048
+ workflowName
1049
+ }) {
1050
+ const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
1051
+ try {
1052
+ const conditions = [];
1053
+ const params = [];
1054
+ if (runId) {
1055
+ conditions.push("run_id = ?");
1056
+ params.push(runId);
1057
+ }
1058
+ if (workflowName) {
1059
+ conditions.push("workflow_name = ?");
1060
+ params.push(workflowName);
1061
+ }
1062
+ const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
1063
+ const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
1064
+ const result = await this.executeQuery({ sql, params, first: true });
1065
+ if (!result) return null;
1066
+ return this.parseWorkflowRun(result);
1067
+ } catch (error) {
1068
+ this.logger.error("Error getting workflow run by ID:", {
1069
+ message: error instanceof Error ? error.message : String(error)
1070
+ });
1071
+ throw error;
1072
+ }
928
1073
  }
929
1074
  /**
930
1075
  * Close the database connection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/cloudflare-d1",
3
- "version": "0.0.0-switch-to-core-20250424015131",
3
+ "version": "0.0.0-vector-query-sources-20250516172905",
4
4
  "description": "D1 provider for Mastra - includes db storage capabilities",
5
5
  "type": "module",
6
6
  "files": [
@@ -23,19 +23,19 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "cloudflare": "^4.1.0",
26
- "@mastra/core": "0.0.0-switch-to-core-20250424015131"
26
+ "@mastra/core": "0.0.0-vector-query-sources-20250516172905"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@cloudflare/workers-types": "^4.20250417.0",
30
- "@microsoft/api-extractor": "^7.52.1",
30
+ "@microsoft/api-extractor": "^7.52.5",
31
31
  "@types/node": "^20.17.27",
32
32
  "dotenv": "^16.4.7",
33
33
  "eslint": "^9.23.0",
34
34
  "miniflare": "^4.20250410.1",
35
35
  "tsup": "^8.4.0",
36
36
  "typescript": "^5.8.2",
37
- "vitest": "^3.0.9",
38
- "@internal/lint": "0.0.2"
37
+ "vitest": "^3.1.2",
38
+ "@internal/lint": "0.0.0-vector-query-sources-20250516172905"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",