@mastra/cloudflare-d1 0.0.0-separate-trace-data-from-component-20250501141108 → 0.0.0-taofeeqInngest-20250603090617

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,8 +1,9 @@
1
1
  import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
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';
3
6
  import { MastraStorage } from '@mastra/core/storage';
4
- import type { MessageType } from '@mastra/core/memory';
5
- import type { MessageType as MessageType_2 } from '@mastra/core';
6
7
  import type { StorageColumn } from '@mastra/core/storage';
7
8
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
8
9
  import type { StorageThreadType } from '@mastra/core/memory';
@@ -14,7 +15,7 @@ import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
14
15
 
15
16
  export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
16
17
 
17
- export declare const createSampleMessage: (threadId: string) => MessageType_2;
18
+ export declare const createSampleMessage: (threadId: string, parts?: MastraMessageV2_2["content"]["parts"]) => MastraMessageV2_2;
18
19
 
19
20
  export declare const createSampleThread: () => {
20
21
  id: string;
@@ -92,7 +93,6 @@ declare class D1Store extends MastraStorage {
92
93
  constructor(config: D1StoreConfig);
93
94
  private getTableName;
94
95
  private formatSqlParams;
95
- private createIndexIfNotExists;
96
96
  private executeWorkersBindingQuery;
97
97
  private executeRestQuery;
98
98
  /**
@@ -139,10 +139,20 @@ declare class D1Store extends MastraStorage {
139
139
  deleteThread({ threadId }: {
140
140
  threadId: string;
141
141
  }): Promise<void>;
142
- saveMessages({ messages }: {
143
- messages: MessageType[];
144
- }): Promise<MessageType[]>;
145
- getMessages<T = MessageType>({ threadId, selectBy }: StorageGetMessagesArg): Promise<T[]>;
142
+ saveMessages(args: {
143
+ messages: MastraMessageV1[];
144
+ format?: undefined | 'v1';
145
+ }): Promise<MastraMessageV1[]>;
146
+ saveMessages(args: {
147
+ messages: MastraMessageV2[];
148
+ format: 'v2';
149
+ }): Promise<MastraMessageV2[]>;
150
+ getMessages(args: StorageGetMessagesArg & {
151
+ format?: 'v1';
152
+ }): Promise<MastraMessageV1[]>;
153
+ getMessages(args: StorageGetMessagesArg & {
154
+ format: 'v2';
155
+ }): Promise<MastraMessageV2[]>;
146
156
  persistWorkflowSnapshot({ workflowName, runId, snapshot, }: {
147
157
  workflowName: string;
148
158
  runId: string;
@@ -161,12 +171,14 @@ declare class D1Store extends MastraStorage {
161
171
  tableName: TABLE_NAMES;
162
172
  records: Record<string, any>[];
163
173
  }): Promise<void>;
164
- getTraces({ name, scope, page, perPage, attributes, }: {
174
+ getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
165
175
  name?: string;
166
176
  scope?: string;
167
177
  page: number;
168
178
  perPage: number;
169
179
  attributes?: Record<string, string>;
180
+ fromDate?: Date;
181
+ toDate?: Date;
170
182
  }): Promise<Record<string, any>[]>;
171
183
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
172
184
  private parseWorkflowRun;
@@ -211,9 +223,30 @@ declare interface D1WorkersConfig {
211
223
  export { D1WorkersConfig }
212
224
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
213
225
 
226
+ /**
227
+ * Parses and returns a valid SQL SELECT column identifier.
228
+ * Allows a single identifier (letters, numbers, underscores), or '*', optionally with 'AS alias'.
229
+ *
230
+ * @param column - The column identifier string to parse.
231
+ * @returns The validated column identifier as a branded type.
232
+ * @throws {Error} If invalid.
233
+ *
234
+ * @example
235
+ * const col = parseSelectIdentifier('user_id'); // Ok
236
+ * parseSelectIdentifier('user_id AS uid'); // Ok
237
+ * parseSelectIdentifier('*'); // Ok
238
+ * parseSelectIdentifier('user id'); // Throws error
239
+ */
240
+ export declare function parseSelectIdentifier(column: string): SelectIdentifier;
241
+
214
242
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
215
243
  interval?: number) => Promise<T>;
216
244
 
245
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
246
+ declare type SelectIdentifier = string & {
247
+ __brand: 'SelectIdentifier';
248
+ };
249
+
217
250
  /**
218
251
  * SQL Builder class for constructing type-safe SQL queries
219
252
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -277,7 +310,6 @@ export declare class SqlBuilder {
277
310
  * @returns The builder instance
278
311
  */
279
312
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
280
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
281
313
  /**
282
314
  * Add a LIKE condition to the query
283
315
  * @param column The column to check
@@ -315,7 +347,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
315
347
  /**
316
348
  * Interface for SQL query options with generic type support
317
349
  */
318
- declare interface SqlQueryOptions {
350
+ export declare interface SqlQueryOptions {
319
351
  /** SQL query to execute */
320
352
  sql: string;
321
353
  /** Parameters to bind to the query */
@@ -323,7 +355,5 @@ declare interface SqlQueryOptions {
323
355
  /** Whether to return only the first result */
324
356
  first?: boolean;
325
357
  }
326
- export { SqlQueryOptions }
327
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
328
358
 
329
359
  export { }
@@ -1,8 +1,9 @@
1
1
  import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
2
2
  import type { EvalRow } from '@mastra/core/storage';
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';
3
6
  import { MastraStorage } from '@mastra/core/storage';
4
- import type { MessageType } from '@mastra/core/memory';
5
- import type { MessageType as MessageType_2 } from '@mastra/core';
6
7
  import type { StorageColumn } from '@mastra/core/storage';
7
8
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
8
9
  import type { StorageThreadType } from '@mastra/core/memory';
@@ -14,7 +15,7 @@ import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
14
15
 
15
16
  export declare const checkWorkflowSnapshot: (snapshot: WorkflowRunState_2 | string, stepId: string, status: string) => void;
16
17
 
17
- export declare const createSampleMessage: (threadId: string) => MessageType_2;
18
+ export declare const createSampleMessage: (threadId: string, parts?: MastraMessageV2_2["content"]["parts"]) => MastraMessageV2_2;
18
19
 
19
20
  export declare const createSampleThread: () => {
20
21
  id: string;
@@ -92,7 +93,6 @@ declare class D1Store extends MastraStorage {
92
93
  constructor(config: D1StoreConfig);
93
94
  private getTableName;
94
95
  private formatSqlParams;
95
- private createIndexIfNotExists;
96
96
  private executeWorkersBindingQuery;
97
97
  private executeRestQuery;
98
98
  /**
@@ -139,10 +139,20 @@ declare class D1Store extends MastraStorage {
139
139
  deleteThread({ threadId }: {
140
140
  threadId: string;
141
141
  }): Promise<void>;
142
- saveMessages({ messages }: {
143
- messages: MessageType[];
144
- }): Promise<MessageType[]>;
145
- getMessages<T = MessageType>({ threadId, selectBy }: StorageGetMessagesArg): Promise<T[]>;
142
+ saveMessages(args: {
143
+ messages: MastraMessageV1[];
144
+ format?: undefined | 'v1';
145
+ }): Promise<MastraMessageV1[]>;
146
+ saveMessages(args: {
147
+ messages: MastraMessageV2[];
148
+ format: 'v2';
149
+ }): Promise<MastraMessageV2[]>;
150
+ getMessages(args: StorageGetMessagesArg & {
151
+ format?: 'v1';
152
+ }): Promise<MastraMessageV1[]>;
153
+ getMessages(args: StorageGetMessagesArg & {
154
+ format: 'v2';
155
+ }): Promise<MastraMessageV2[]>;
146
156
  persistWorkflowSnapshot({ workflowName, runId, snapshot, }: {
147
157
  workflowName: string;
148
158
  runId: string;
@@ -161,12 +171,14 @@ declare class D1Store extends MastraStorage {
161
171
  tableName: TABLE_NAMES;
162
172
  records: Record<string, any>[];
163
173
  }): Promise<void>;
164
- getTraces({ name, scope, page, perPage, attributes, }: {
174
+ getTraces({ name, scope, page, perPage, attributes, fromDate, toDate, }: {
165
175
  name?: string;
166
176
  scope?: string;
167
177
  page: number;
168
178
  perPage: number;
169
179
  attributes?: Record<string, string>;
180
+ fromDate?: Date;
181
+ toDate?: Date;
170
182
  }): Promise<Record<string, any>[]>;
171
183
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
172
184
  private parseWorkflowRun;
@@ -211,9 +223,30 @@ declare interface D1WorkersConfig {
211
223
  export { D1WorkersConfig }
212
224
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
213
225
 
226
+ /**
227
+ * Parses and returns a valid SQL SELECT column identifier.
228
+ * Allows a single identifier (letters, numbers, underscores), or '*', optionally with 'AS alias'.
229
+ *
230
+ * @param column - The column identifier string to parse.
231
+ * @returns The validated column identifier as a branded type.
232
+ * @throws {Error} If invalid.
233
+ *
234
+ * @example
235
+ * const col = parseSelectIdentifier('user_id'); // Ok
236
+ * parseSelectIdentifier('user_id AS uid'); // Ok
237
+ * parseSelectIdentifier('*'); // Ok
238
+ * parseSelectIdentifier('user id'); // Throws error
239
+ */
240
+ export declare function parseSelectIdentifier(column: string): SelectIdentifier;
241
+
214
242
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
215
243
  interval?: number) => Promise<T>;
216
244
 
245
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
246
+ declare type SelectIdentifier = string & {
247
+ __brand: 'SelectIdentifier';
248
+ };
249
+
217
250
  /**
218
251
  * SQL Builder class for constructing type-safe SQL queries
219
252
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -277,7 +310,6 @@ export declare class SqlBuilder {
277
310
  * @returns The builder instance
278
311
  */
279
312
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
280
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
281
313
  /**
282
314
  * Add a LIKE condition to the query
283
315
  * @param column The column to check
@@ -315,7 +347,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
315
347
  /**
316
348
  * Interface for SQL query options with generic type support
317
349
  */
318
- declare interface SqlQueryOptions {
350
+ export declare interface SqlQueryOptions {
319
351
  /** SQL query to execute */
320
352
  sql: string;
321
353
  /** Parameters to bind to the query */
@@ -323,7 +355,5 @@ declare interface SqlQueryOptions {
323
355
  /** Whether to return only the first result */
324
356
  first?: boolean;
325
357
  }
326
- export { SqlQueryOptions }
327
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
328
358
 
329
359
  export { }
package/dist/index.cjs CHANGED
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
+ var agent = require('@mastra/core/agent');
3
4
  var storage = require('@mastra/core/storage');
4
5
  var Cloudflare = require('cloudflare');
6
+ var utils = require('@mastra/core/utils');
5
7
 
6
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
9
 
8
10
  var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
9
11
 
10
12
  // src/storage/index.ts
11
-
12
- // src/storage/sql-builder.ts
13
13
  var SqlBuilder = class {
14
14
  sql = "";
15
15
  params = [];
@@ -19,12 +19,15 @@ var SqlBuilder = class {
19
19
  if (!columns || Array.isArray(columns) && columns.length === 0) {
20
20
  this.sql = "SELECT *";
21
21
  } else {
22
- this.sql = `SELECT ${Array.isArray(columns) ? columns.join(", ") : columns}`;
22
+ const cols = Array.isArray(columns) ? columns : [columns];
23
+ const parsedCols = cols.map((col) => parseSelectIdentifier(col));
24
+ this.sql = `SELECT ${parsedCols.join(", ")}`;
23
25
  }
24
26
  return this;
25
27
  }
26
28
  from(table) {
27
- this.sql += ` FROM ${table}`;
29
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
30
+ this.sql += ` FROM ${parsedTableName}`;
28
31
  return this;
29
32
  }
30
33
  /**
@@ -61,7 +64,11 @@ var SqlBuilder = class {
61
64
  return this;
62
65
  }
63
66
  orderBy(column, direction = "ASC") {
64
- this.sql += ` ORDER BY ${column} ${direction}`;
67
+ const parsedColumn = utils.parseSqlIdentifier(column, "column name");
68
+ if (!["ASC", "DESC"].includes(direction)) {
69
+ throw new Error(`Invalid sort direction: ${direction}`);
70
+ }
71
+ this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
65
72
  return this;
66
73
  }
67
74
  limit(count) {
@@ -87,27 +94,33 @@ var SqlBuilder = class {
87
94
  * @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
88
95
  */
89
96
  insert(table, columns, values, conflictColumns, updateMap) {
90
- const placeholders = columns.map(() => "?").join(", ");
97
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
98
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
99
+ const placeholders = parsedColumns.map(() => "?").join(", ");
91
100
  if (conflictColumns && updateMap) {
101
+ const parsedConflictColumns = conflictColumns.map((col) => utils.parseSqlIdentifier(col, "column name"));
92
102
  const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
93
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
103
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
94
104
  this.params.push(...values);
95
105
  return this;
96
106
  }
97
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
107
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
98
108
  this.params.push(...values);
99
109
  return this;
100
110
  }
101
111
  // Update operations
102
112
  update(table, columns, values) {
103
- const setClause = columns.map((col) => `${col} = ?`).join(", ");
104
- this.sql = `UPDATE ${table} SET ${setClause}`;
113
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
114
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
115
+ const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
116
+ this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
105
117
  this.params.push(...values);
106
118
  return this;
107
119
  }
108
120
  // Delete operations
109
121
  delete(table) {
110
- this.sql = `DELETE FROM ${table}`;
122
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
123
+ this.sql = `DELETE FROM ${parsedTableName}`;
111
124
  return this;
112
125
  }
113
126
  /**
@@ -118,9 +131,16 @@ var SqlBuilder = class {
118
131
  * @returns The builder instance
119
132
  */
120
133
  createTable(table, columnDefinitions, tableConstraints) {
121
- const columns = columnDefinitions.join(", ");
134
+ const parsedTableName = utils.parseSqlIdentifier(table, "table name");
135
+ const parsedColumnDefinitions = columnDefinitions.map((def) => {
136
+ const colName = def.split(/\s+/)[0];
137
+ if (!colName) throw new Error("Empty column name in definition");
138
+ utils.parseSqlIdentifier(colName, "column name");
139
+ return def;
140
+ });
141
+ const columns = parsedColumnDefinitions.join(", ");
122
142
  const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
123
- this.sql = `CREATE TABLE IF NOT EXISTS ${table} (${columns}${constraints})`;
143
+ this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
124
144
  return this;
125
145
  }
126
146
  /**
@@ -143,13 +163,10 @@ var SqlBuilder = class {
143
163
  * @returns The builder instance
144
164
  */
145
165
  createIndex(indexName, tableName, columnName, indexType = "") {
146
- this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${indexName} ON ${tableName}(${columnName})`;
147
- return this;
148
- }
149
- // Raw SQL with params
150
- raw(sql, ...params) {
151
- this.sql = sql;
152
- this.params.push(...params);
166
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
167
+ const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
168
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
169
+ this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
153
170
  return this;
154
171
  }
155
172
  /**
@@ -159,11 +176,12 @@ var SqlBuilder = class {
159
176
  * @param exact If true, will not add % wildcards
160
177
  */
161
178
  like(column, value, exact = false) {
179
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
162
180
  const likeValue = exact ? value : `%${value}%`;
163
181
  if (this.whereAdded) {
164
- this.sql += ` AND ${column} LIKE ?`;
182
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
165
183
  } else {
166
- this.sql += ` WHERE ${column} LIKE ?`;
184
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
167
185
  this.whereAdded = true;
168
186
  }
169
187
  this.params.push(likeValue);
@@ -176,11 +194,13 @@ var SqlBuilder = class {
176
194
  * @param value The value to match
177
195
  */
178
196
  jsonLike(column, key, value) {
179
- const jsonPattern = `%"${key}":"${value}"%`;
197
+ const parsedColumnName = utils.parseSqlIdentifier(column, "column name");
198
+ const parsedKey = utils.parseSqlIdentifier(key, "key name");
199
+ const jsonPattern = `%"${parsedKey}":"${value}"%`;
180
200
  if (this.whereAdded) {
181
- this.sql += ` AND ${column} LIKE ?`;
201
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
182
202
  } else {
183
- this.sql += ` WHERE ${column} LIKE ?`;
203
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
184
204
  this.whereAdded = true;
185
205
  }
186
206
  this.params.push(jsonPattern);
@@ -210,6 +230,15 @@ var SqlBuilder = class {
210
230
  function createSqlBuilder() {
211
231
  return new SqlBuilder();
212
232
  }
233
+ var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
234
+ function parseSelectIdentifier(column) {
235
+ if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
236
+ throw new Error(
237
+ `Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
238
+ );
239
+ }
240
+ return column;
241
+ }
213
242
 
214
243
  // src/storage/index.ts
215
244
  function isArrayOfRecords(value) {
@@ -228,6 +257,9 @@ var D1Store = class extends storage.MastraStorage {
228
257
  */
229
258
  constructor(config) {
230
259
  super({ name: "D1" });
260
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
261
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
262
+ }
231
263
  this.tablePrefix = config.tablePrefix || "";
232
264
  if ("binding" in config) {
233
265
  if (!config.binding) {
@@ -254,30 +286,6 @@ var D1Store = class extends storage.MastraStorage {
254
286
  formatSqlParams(params) {
255
287
  return params.map((p) => p === void 0 || p === null ? null : p);
256
288
  }
257
- // Helper method to create SQL indexes for better query performance
258
- async createIndexIfNotExists(tableName, columnName, indexType = "") {
259
- const fullTableName = this.getTableName(tableName);
260
- const indexName = `idx_${tableName}_${columnName}`;
261
- try {
262
- const checkQuery = createSqlBuilder().checkIndexExists(indexName, fullTableName);
263
- const { sql: checkSql, params: checkParams } = checkQuery.build();
264
- const indexExists = await this.executeQuery({
265
- sql: checkSql,
266
- params: checkParams,
267
- first: true
268
- });
269
- if (!indexExists) {
270
- const createQuery = createSqlBuilder().createIndex(indexName, fullTableName, columnName, indexType);
271
- const { sql: createSql, params: createParams } = createQuery.build();
272
- await this.executeQuery({ sql: createSql, params: createParams });
273
- this.logger.debug(`Created index ${indexName} on ${fullTableName}(${columnName})`);
274
- }
275
- } catch (error) {
276
- this.logger.error(`Error creating index on ${fullTableName}(${columnName}):`, {
277
- message: error instanceof Error ? error.message : String(error)
278
- });
279
- }
280
- }
281
289
  async executeWorkersBindingQuery({
282
290
  sql,
283
291
  params = [],
@@ -656,8 +664,8 @@ var D1Store = class extends storage.MastraStorage {
656
664
  throw new Error(`Failed to delete thread ${threadId}: ${error}`);
657
665
  }
658
666
  }
659
- // Thread and message management methods
660
- async saveMessages({ messages }) {
667
+ async saveMessages(args) {
668
+ const { messages, format = "v1" } = args;
661
669
  if (messages.length === 0) return [];
662
670
  try {
663
671
  const now = /* @__PURE__ */ new Date();
@@ -679,7 +687,7 @@ var D1Store = class extends storage.MastraStorage {
679
687
  content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
680
688
  createdAt: createdAt.toISOString(),
681
689
  role: message.role,
682
- type: message.type
690
+ type: message.type || "v2"
683
691
  };
684
692
  });
685
693
  await this.batchInsert({
@@ -687,13 +695,19 @@ var D1Store = class extends storage.MastraStorage {
687
695
  records: messagesToInsert
688
696
  });
689
697
  this.logger.debug(`Saved ${messages.length} messages`);
690
- return messages;
698
+ const list = new agent.MessageList().add(messages, "memory");
699
+ if (format === `v2`) return list.get.all.v2();
700
+ return list.get.all.v1();
691
701
  } catch (error) {
692
702
  this.logger.error("Error saving messages:", { message: error instanceof Error ? error.message : String(error) });
693
703
  throw error;
694
704
  }
695
705
  }
696
- async getMessages({ threadId, selectBy }) {
706
+ async getMessages({
707
+ threadId,
708
+ selectBy,
709
+ format
710
+ }) {
697
711
  const fullTableName = this.getTableName(storage.TABLE_MESSAGES);
698
712
  const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
699
713
  const include = selectBy?.include || [];
@@ -717,7 +731,7 @@ var D1Store = class extends storage.MastraStorage {
717
731
  m.role,
718
732
  m.type,
719
733
  m.createdAt,
720
- m.thread_id AS "threadId"
734
+ m.thread_id AS threadId
721
735
  FROM ordered_messages m
722
736
  WHERE m.id IN (${includeIds.map(() => "?").join(",")})
723
737
  OR EXISTS (
@@ -744,7 +758,7 @@ var D1Store = class extends storage.MastraStorage {
744
758
  if (Array.isArray(includeResult)) messages.push(...includeResult);
745
759
  }
746
760
  const excludeIds = messages.map((m) => m.id);
747
- 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);
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);
748
762
  const { sql, params } = query.build();
749
763
  const result = await this.executeQuery({ sql, params });
750
764
  if (Array.isArray(result)) messages.push(...result);
@@ -758,12 +772,15 @@ var D1Store = class extends storage.MastraStorage {
758
772
  const processedMessages = messages.map((message) => {
759
773
  const processedMsg = {};
760
774
  for (const [key, value] of Object.entries(message)) {
775
+ if (key === `type` && value === `v2`) continue;
761
776
  processedMsg[key] = this.deserializeValue(value);
762
777
  }
763
778
  return processedMsg;
764
779
  });
765
780
  this.logger.debug(`Retrieved ${messages.length} messages for thread ${threadId}`);
766
- return processedMessages;
781
+ const list = new agent.MessageList().add(processedMessages, "memory");
782
+ if (format === `v2`) return list.get.all.v2();
783
+ return list.get.all.v1();
767
784
  } catch (error) {
768
785
  this.logger.error("Error retrieving messages for thread", {
769
786
  threadId,
@@ -869,7 +886,9 @@ var D1Store = class extends storage.MastraStorage {
869
886
  scope,
870
887
  page,
871
888
  perPage,
872
- attributes
889
+ attributes,
890
+ fromDate,
891
+ toDate
873
892
  }) {
874
893
  const fullTableName = this.getTableName(storage.TABLE_TRACES);
875
894
  try {
@@ -885,6 +904,12 @@ var D1Store = class extends storage.MastraStorage {
885
904
  query.jsonLike("attributes", key, value);
886
905
  }
887
906
  }
907
+ if (fromDate) {
908
+ query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
909
+ }
910
+ if (toDate) {
911
+ query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
912
+ }
888
913
  query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
889
914
  const { sql, params } = query.build();
890
915
  const results = await this.executeQuery({ sql, params });
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,9 @@
1
+ import { MessageList } from '@mastra/core/agent';
1
2
  import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_TRACES, TABLE_EVALS } from '@mastra/core/storage';
2
3
  import Cloudflare from 'cloudflare';
4
+ import { parseSqlIdentifier } from '@mastra/core/utils';
3
5
 
4
6
  // src/storage/index.ts
5
-
6
- // src/storage/sql-builder.ts
7
7
  var SqlBuilder = class {
8
8
  sql = "";
9
9
  params = [];
@@ -13,12 +13,15 @@ var SqlBuilder = class {
13
13
  if (!columns || Array.isArray(columns) && columns.length === 0) {
14
14
  this.sql = "SELECT *";
15
15
  } else {
16
- this.sql = `SELECT ${Array.isArray(columns) ? columns.join(", ") : columns}`;
16
+ const cols = Array.isArray(columns) ? columns : [columns];
17
+ const parsedCols = cols.map((col) => parseSelectIdentifier(col));
18
+ this.sql = `SELECT ${parsedCols.join(", ")}`;
17
19
  }
18
20
  return this;
19
21
  }
20
22
  from(table) {
21
- this.sql += ` FROM ${table}`;
23
+ const parsedTableName = parseSqlIdentifier(table, "table name");
24
+ this.sql += ` FROM ${parsedTableName}`;
22
25
  return this;
23
26
  }
24
27
  /**
@@ -55,7 +58,11 @@ var SqlBuilder = class {
55
58
  return this;
56
59
  }
57
60
  orderBy(column, direction = "ASC") {
58
- this.sql += ` ORDER BY ${column} ${direction}`;
61
+ const parsedColumn = parseSqlIdentifier(column, "column name");
62
+ if (!["ASC", "DESC"].includes(direction)) {
63
+ throw new Error(`Invalid sort direction: ${direction}`);
64
+ }
65
+ this.sql += ` ORDER BY ${parsedColumn} ${direction}`;
59
66
  return this;
60
67
  }
61
68
  limit(count) {
@@ -81,27 +88,33 @@ var SqlBuilder = class {
81
88
  * @param updateMap Object mapping columns to update to their new value (e.g. { name: 'excluded.name' })
82
89
  */
83
90
  insert(table, columns, values, conflictColumns, updateMap) {
84
- const placeholders = columns.map(() => "?").join(", ");
91
+ const parsedTableName = parseSqlIdentifier(table, "table name");
92
+ const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
93
+ const placeholders = parsedColumns.map(() => "?").join(", ");
85
94
  if (conflictColumns && updateMap) {
95
+ const parsedConflictColumns = conflictColumns.map((col) => parseSqlIdentifier(col, "column name"));
86
96
  const updateClause = Object.entries(updateMap).map(([col, expr]) => `${col} = ${expr}`).join(", ");
87
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
97
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${parsedConflictColumns.join(", ")}) DO UPDATE SET ${updateClause}`;
88
98
  this.params.push(...values);
89
99
  return this;
90
100
  }
91
- this.sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
101
+ this.sql = `INSERT INTO ${parsedTableName} (${parsedColumns.join(", ")}) VALUES (${placeholders})`;
92
102
  this.params.push(...values);
93
103
  return this;
94
104
  }
95
105
  // Update operations
96
106
  update(table, columns, values) {
97
- const setClause = columns.map((col) => `${col} = ?`).join(", ");
98
- this.sql = `UPDATE ${table} SET ${setClause}`;
107
+ const parsedTableName = parseSqlIdentifier(table, "table name");
108
+ const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
109
+ const setClause = parsedColumns.map((col) => `${col} = ?`).join(", ");
110
+ this.sql = `UPDATE ${parsedTableName} SET ${setClause}`;
99
111
  this.params.push(...values);
100
112
  return this;
101
113
  }
102
114
  // Delete operations
103
115
  delete(table) {
104
- this.sql = `DELETE FROM ${table}`;
116
+ const parsedTableName = parseSqlIdentifier(table, "table name");
117
+ this.sql = `DELETE FROM ${parsedTableName}`;
105
118
  return this;
106
119
  }
107
120
  /**
@@ -112,9 +125,16 @@ var SqlBuilder = class {
112
125
  * @returns The builder instance
113
126
  */
114
127
  createTable(table, columnDefinitions, tableConstraints) {
115
- const columns = columnDefinitions.join(", ");
128
+ const parsedTableName = parseSqlIdentifier(table, "table name");
129
+ const parsedColumnDefinitions = columnDefinitions.map((def) => {
130
+ const colName = def.split(/\s+/)[0];
131
+ if (!colName) throw new Error("Empty column name in definition");
132
+ parseSqlIdentifier(colName, "column name");
133
+ return def;
134
+ });
135
+ const columns = parsedColumnDefinitions.join(", ");
116
136
  const constraints = tableConstraints && tableConstraints.length > 0 ? ", " + tableConstraints.join(", ") : "";
117
- this.sql = `CREATE TABLE IF NOT EXISTS ${table} (${columns}${constraints})`;
137
+ this.sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns}${constraints})`;
118
138
  return this;
119
139
  }
120
140
  /**
@@ -137,13 +157,10 @@ var SqlBuilder = class {
137
157
  * @returns The builder instance
138
158
  */
139
159
  createIndex(indexName, tableName, columnName, indexType = "") {
140
- this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${indexName} ON ${tableName}(${columnName})`;
141
- return this;
142
- }
143
- // Raw SQL with params
144
- raw(sql, ...params) {
145
- this.sql = sql;
146
- this.params.push(...params);
160
+ const parsedIndexName = parseSqlIdentifier(indexName, "index name");
161
+ const parsedTableName = parseSqlIdentifier(tableName, "table name");
162
+ const parsedColumnName = parseSqlIdentifier(columnName, "column name");
163
+ this.sql = `CREATE ${indexType ? indexType + " " : ""}INDEX IF NOT EXISTS ${parsedIndexName} ON ${parsedTableName}(${parsedColumnName})`;
147
164
  return this;
148
165
  }
149
166
  /**
@@ -153,11 +170,12 @@ var SqlBuilder = class {
153
170
  * @param exact If true, will not add % wildcards
154
171
  */
155
172
  like(column, value, exact = false) {
173
+ const parsedColumnName = parseSqlIdentifier(column, "column name");
156
174
  const likeValue = exact ? value : `%${value}%`;
157
175
  if (this.whereAdded) {
158
- this.sql += ` AND ${column} LIKE ?`;
176
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
159
177
  } else {
160
- this.sql += ` WHERE ${column} LIKE ?`;
178
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
161
179
  this.whereAdded = true;
162
180
  }
163
181
  this.params.push(likeValue);
@@ -170,11 +188,13 @@ var SqlBuilder = class {
170
188
  * @param value The value to match
171
189
  */
172
190
  jsonLike(column, key, value) {
173
- const jsonPattern = `%"${key}":"${value}"%`;
191
+ const parsedColumnName = parseSqlIdentifier(column, "column name");
192
+ const parsedKey = parseSqlIdentifier(key, "key name");
193
+ const jsonPattern = `%"${parsedKey}":"${value}"%`;
174
194
  if (this.whereAdded) {
175
- this.sql += ` AND ${column} LIKE ?`;
195
+ this.sql += ` AND ${parsedColumnName} LIKE ?`;
176
196
  } else {
177
- this.sql += ` WHERE ${column} LIKE ?`;
197
+ this.sql += ` WHERE ${parsedColumnName} LIKE ?`;
178
198
  this.whereAdded = true;
179
199
  }
180
200
  this.params.push(jsonPattern);
@@ -204,6 +224,15 @@ var SqlBuilder = class {
204
224
  function createSqlBuilder() {
205
225
  return new SqlBuilder();
206
226
  }
227
+ var SQL_IDENTIFIER_PATTERN = /^[a-zA-Z0-9_]+(\s+AS\s+[a-zA-Z0-9_]+)?$/;
228
+ function parseSelectIdentifier(column) {
229
+ if (column !== "*" && !SQL_IDENTIFIER_PATTERN.test(column)) {
230
+ throw new Error(
231
+ `Invalid column name: "${column}". Must be "*" or a valid identifier (letters, numbers, underscores), optionally with "AS alias".`
232
+ );
233
+ }
234
+ return column;
235
+ }
207
236
 
208
237
  // src/storage/index.ts
209
238
  function isArrayOfRecords(value) {
@@ -222,6 +251,9 @@ var D1Store = class extends MastraStorage {
222
251
  */
223
252
  constructor(config) {
224
253
  super({ name: "D1" });
254
+ if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
255
+ throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
256
+ }
225
257
  this.tablePrefix = config.tablePrefix || "";
226
258
  if ("binding" in config) {
227
259
  if (!config.binding) {
@@ -248,30 +280,6 @@ var D1Store = class extends MastraStorage {
248
280
  formatSqlParams(params) {
249
281
  return params.map((p) => p === void 0 || p === null ? null : p);
250
282
  }
251
- // Helper method to create SQL indexes for better query performance
252
- async createIndexIfNotExists(tableName, columnName, indexType = "") {
253
- const fullTableName = this.getTableName(tableName);
254
- const indexName = `idx_${tableName}_${columnName}`;
255
- try {
256
- const checkQuery = createSqlBuilder().checkIndexExists(indexName, fullTableName);
257
- const { sql: checkSql, params: checkParams } = checkQuery.build();
258
- const indexExists = await this.executeQuery({
259
- sql: checkSql,
260
- params: checkParams,
261
- first: true
262
- });
263
- if (!indexExists) {
264
- const createQuery = createSqlBuilder().createIndex(indexName, fullTableName, columnName, indexType);
265
- const { sql: createSql, params: createParams } = createQuery.build();
266
- await this.executeQuery({ sql: createSql, params: createParams });
267
- this.logger.debug(`Created index ${indexName} on ${fullTableName}(${columnName})`);
268
- }
269
- } catch (error) {
270
- this.logger.error(`Error creating index on ${fullTableName}(${columnName}):`, {
271
- message: error instanceof Error ? error.message : String(error)
272
- });
273
- }
274
- }
275
283
  async executeWorkersBindingQuery({
276
284
  sql,
277
285
  params = [],
@@ -650,8 +658,8 @@ var D1Store = class extends MastraStorage {
650
658
  throw new Error(`Failed to delete thread ${threadId}: ${error}`);
651
659
  }
652
660
  }
653
- // Thread and message management methods
654
- async saveMessages({ messages }) {
661
+ async saveMessages(args) {
662
+ const { messages, format = "v1" } = args;
655
663
  if (messages.length === 0) return [];
656
664
  try {
657
665
  const now = /* @__PURE__ */ new Date();
@@ -673,7 +681,7 @@ var D1Store = class extends MastraStorage {
673
681
  content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
674
682
  createdAt: createdAt.toISOString(),
675
683
  role: message.role,
676
- type: message.type
684
+ type: message.type || "v2"
677
685
  };
678
686
  });
679
687
  await this.batchInsert({
@@ -681,13 +689,19 @@ var D1Store = class extends MastraStorage {
681
689
  records: messagesToInsert
682
690
  });
683
691
  this.logger.debug(`Saved ${messages.length} messages`);
684
- return messages;
692
+ const list = new MessageList().add(messages, "memory");
693
+ if (format === `v2`) return list.get.all.v2();
694
+ return list.get.all.v1();
685
695
  } catch (error) {
686
696
  this.logger.error("Error saving messages:", { message: error instanceof Error ? error.message : String(error) });
687
697
  throw error;
688
698
  }
689
699
  }
690
- async getMessages({ threadId, selectBy }) {
700
+ async getMessages({
701
+ threadId,
702
+ selectBy,
703
+ format
704
+ }) {
691
705
  const fullTableName = this.getTableName(TABLE_MESSAGES);
692
706
  const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
693
707
  const include = selectBy?.include || [];
@@ -711,7 +725,7 @@ var D1Store = class extends MastraStorage {
711
725
  m.role,
712
726
  m.type,
713
727
  m.createdAt,
714
- m.thread_id AS "threadId"
728
+ m.thread_id AS threadId
715
729
  FROM ordered_messages m
716
730
  WHERE m.id IN (${includeIds.map(() => "?").join(",")})
717
731
  OR EXISTS (
@@ -738,7 +752,7 @@ var D1Store = class extends MastraStorage {
738
752
  if (Array.isArray(includeResult)) messages.push(...includeResult);
739
753
  }
740
754
  const excludeIds = messages.map((m) => m.id);
741
- 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);
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);
742
756
  const { sql, params } = query.build();
743
757
  const result = await this.executeQuery({ sql, params });
744
758
  if (Array.isArray(result)) messages.push(...result);
@@ -752,12 +766,15 @@ var D1Store = class extends MastraStorage {
752
766
  const processedMessages = messages.map((message) => {
753
767
  const processedMsg = {};
754
768
  for (const [key, value] of Object.entries(message)) {
769
+ if (key === `type` && value === `v2`) continue;
755
770
  processedMsg[key] = this.deserializeValue(value);
756
771
  }
757
772
  return processedMsg;
758
773
  });
759
774
  this.logger.debug(`Retrieved ${messages.length} messages for thread ${threadId}`);
760
- return processedMessages;
775
+ const list = new MessageList().add(processedMessages, "memory");
776
+ if (format === `v2`) return list.get.all.v2();
777
+ return list.get.all.v1();
761
778
  } catch (error) {
762
779
  this.logger.error("Error retrieving messages for thread", {
763
780
  threadId,
@@ -863,7 +880,9 @@ var D1Store = class extends MastraStorage {
863
880
  scope,
864
881
  page,
865
882
  perPage,
866
- attributes
883
+ attributes,
884
+ fromDate,
885
+ toDate
867
886
  }) {
868
887
  const fullTableName = this.getTableName(TABLE_TRACES);
869
888
  try {
@@ -879,6 +898,12 @@ var D1Store = class extends MastraStorage {
879
898
  query.jsonLike("attributes", key, value);
880
899
  }
881
900
  }
901
+ if (fromDate) {
902
+ query.andWhere("createdAt >= ?", fromDate instanceof Date ? fromDate.toISOString() : fromDate);
903
+ }
904
+ if (toDate) {
905
+ query.andWhere("createdAt <= ?", toDate instanceof Date ? toDate.toISOString() : toDate);
906
+ }
882
907
  query.orderBy("startTime", "DESC").limit(perPage).offset((page - 1) * perPage);
883
908
  const { sql, params } = query.build();
884
909
  const results = await this.executeQuery({ sql, params });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/cloudflare-d1",
3
- "version": "0.0.0-separate-trace-data-from-component-20250501141108",
3
+ "version": "0.0.0-taofeeqInngest-20250603090617",
4
4
  "description": "D1 provider for Mastra - includes db storage capabilities",
5
5
  "type": "module",
6
6
  "files": [
@@ -22,8 +22,7 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "dependencies": {
25
- "cloudflare": "^4.1.0",
26
- "@mastra/core": "0.0.0-separate-trace-data-from-component-20250501141108"
25
+ "cloudflare": "^4.1.0"
27
26
  },
28
27
  "devDependencies": {
29
28
  "@cloudflare/workers-types": "^4.20250417.0",
@@ -35,7 +34,11 @@
35
34
  "tsup": "^8.4.0",
36
35
  "typescript": "^5.8.2",
37
36
  "vitest": "^3.1.2",
38
- "@internal/lint": "0.0.2"
37
+ "@mastra/core": "0.0.0-taofeeqInngest-20250603090617",
38
+ "@internal/lint": "0.0.0-taofeeqInngest-20250603090617"
39
+ },
40
+ "peerDependencies": {
41
+ "@mastra/core": "^0.10.0-alpha.0"
39
42
  },
40
43
  "scripts": {
41
44
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",