@mastra/cloudflare-d1 0.0.0-vnext-inngest-20250508131921 → 0.0.0-vnextAgentNetwork-20250602134426

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;
@@ -213,9 +223,30 @@ declare interface D1WorkersConfig {
213
223
  export { D1WorkersConfig }
214
224
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
215
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
+
216
242
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
217
243
  interval?: number) => Promise<T>;
218
244
 
245
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
246
+ declare type SelectIdentifier = string & {
247
+ __brand: 'SelectIdentifier';
248
+ };
249
+
219
250
  /**
220
251
  * SQL Builder class for constructing type-safe SQL queries
221
252
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -279,7 +310,6 @@ export declare class SqlBuilder {
279
310
  * @returns The builder instance
280
311
  */
281
312
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
282
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
283
313
  /**
284
314
  * Add a LIKE condition to the query
285
315
  * @param column The column to check
@@ -317,7 +347,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
317
347
  /**
318
348
  * Interface for SQL query options with generic type support
319
349
  */
320
- declare interface SqlQueryOptions {
350
+ export declare interface SqlQueryOptions {
321
351
  /** SQL query to execute */
322
352
  sql: string;
323
353
  /** Parameters to bind to the query */
@@ -325,7 +355,5 @@ declare interface SqlQueryOptions {
325
355
  /** Whether to return only the first result */
326
356
  first?: boolean;
327
357
  }
328
- export { SqlQueryOptions }
329
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
330
358
 
331
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;
@@ -213,9 +223,30 @@ declare interface D1WorkersConfig {
213
223
  export { D1WorkersConfig }
214
224
  export { D1WorkersConfig as D1WorkersConfig_alias_1 }
215
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
+
216
242
  export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
217
243
  interval?: number) => Promise<T>;
218
244
 
245
+ /** Represents a validated SQL SELECT column identifier (or '*', optionally with 'AS alias'). */
246
+ declare type SelectIdentifier = string & {
247
+ __brand: 'SelectIdentifier';
248
+ };
249
+
219
250
  /**
220
251
  * SQL Builder class for constructing type-safe SQL queries
221
252
  * This helps create maintainable and secure SQL queries with proper parameter handling
@@ -279,7 +310,6 @@ export declare class SqlBuilder {
279
310
  * @returns The builder instance
280
311
  */
281
312
  createIndex(indexName: string, tableName: string, columnName: string, indexType?: string): SqlBuilder;
282
- raw(sql: string, ...params: SqlParam[]): SqlBuilder;
283
313
  /**
284
314
  * Add a LIKE condition to the query
285
315
  * @param column The column to check
@@ -317,7 +347,7 @@ export declare type SqlParam = string | number | boolean | null | undefined;
317
347
  /**
318
348
  * Interface for SQL query options with generic type support
319
349
  */
320
- declare interface SqlQueryOptions {
350
+ export declare interface SqlQueryOptions {
321
351
  /** SQL query to execute */
322
352
  sql: string;
323
353
  /** Parameters to bind to the query */
@@ -325,7 +355,5 @@ declare interface SqlQueryOptions {
325
355
  /** Whether to return only the first result */
326
356
  first?: boolean;
327
357
  }
328
- export { SqlQueryOptions }
329
- export { SqlQueryOptions as SqlQueryOptions_alias_1 }
330
358
 
331
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,
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/cloudflare-d1",
3
- "version": "0.0.0-vnext-inngest-20250508131921",
3
+ "version": "0.0.0-vnextAgentNetwork-20250602134426",
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-vnext-inngest-20250508131921"
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.0-vnext-inngest-20250508131921"
37
+ "@internal/lint": "0.0.0-vnextAgentNetwork-20250602134426",
38
+ "@mastra/core": "0.0.0-vnextAgentNetwork-20250602134426"
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",