@mastra/cloudflare-d1 1.0.0-beta.8 → 1.0.0

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.
@@ -0,0 +1,31 @@
1
+ # @mastra/cloudflare-d1 Documentation
2
+
3
+ > Embedded documentation for coding agents
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Read the skill overview
9
+ cat docs/SKILL.md
10
+
11
+ # Get the source map
12
+ cat docs/SOURCE_MAP.json
13
+
14
+ # Read topic documentation
15
+ cat docs/<topic>/01-overview.md
16
+ ```
17
+
18
+ ## Structure
19
+
20
+ ```
21
+ docs/
22
+ ├── SKILL.md # Entry point
23
+ ├── README.md # This file
24
+ ├── SOURCE_MAP.json # Export index
25
+ ├── storage/ (1 files)
26
+ ```
27
+
28
+ ## Version
29
+
30
+ Package: @mastra/cloudflare-d1
31
+ Version: 1.0.0
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: mastra-cloudflare-d1-docs
3
+ description: Documentation for @mastra/cloudflare-d1. Includes links to type definitions and readable implementation code in dist/.
4
+ ---
5
+
6
+ # @mastra/cloudflare-d1 Documentation
7
+
8
+ > **Version**: 1.0.0
9
+ > **Package**: @mastra/cloudflare-d1
10
+
11
+ ## Quick Navigation
12
+
13
+ Use SOURCE_MAP.json to find any export:
14
+
15
+ ```bash
16
+ cat docs/SOURCE_MAP.json
17
+ ```
18
+
19
+ Each export maps to:
20
+ - **types**: `.d.ts` file with JSDoc and API signatures
21
+ - **implementation**: `.js` chunk file with readable source
22
+ - **docs**: Conceptual documentation in `docs/`
23
+
24
+ ## Top Exports
25
+
26
+
27
+
28
+ See SOURCE_MAP.json for the complete list.
29
+
30
+ ## Available Topics
31
+
32
+ - [Storage](storage/) - 1 file(s)
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "package": "@mastra/cloudflare-d1",
4
+ "exports": {},
5
+ "modules": {}
6
+ }
@@ -0,0 +1,110 @@
1
+ # Storage API Reference
2
+
3
+ > API reference for storage - 1 entries
4
+
5
+
6
+ ---
7
+
8
+ ## Reference: Cloudflare D1 Storage
9
+
10
+ > Documentation for the Cloudflare D1 SQL storage implementation in Mastra.
11
+
12
+ The Cloudflare D1 storage implementation provides a serverless SQL database solution using Cloudflare D1, supporting relational operations and transactional consistency.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @mastra/cloudflare-d1@beta
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { D1Store } from "@mastra/cloudflare-d1";
24
+
25
+ type Env = {
26
+ // Add your bindings here, e.g. Workers KV, D1, Workers AI, etc.
27
+ D1Database: D1Database;
28
+ };
29
+
30
+ // --- Example 1: Using Workers Binding ---
31
+ const storageWorkers = new D1Store({
32
+ binding: D1Database, // D1Database binding provided by the Workers runtime
33
+ tablePrefix: "dev_", // Optional: isolate tables per environment
34
+ });
35
+
36
+ // --- Example 2: Using REST API ---
37
+ const storageRest = new D1Store({
38
+ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, // Cloudflare Account ID
39
+ databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID!, // D1 Database ID
40
+ apiToken: process.env.CLOUDFLARE_API_TOKEN!, // Cloudflare API Token
41
+ tablePrefix: "dev_", // Optional: isolate tables per environment
42
+ });
43
+ ```
44
+
45
+ And add the following to your `wrangler.toml` or `wrangler.jsonc` file:
46
+
47
+ ```
48
+ [[d1_databases]]
49
+ binding = "D1Database"
50
+ database_name = "db-name"
51
+ database_id = "db-id"
52
+ ```
53
+
54
+ ## Parameters
55
+
56
+ ## Additional Notes
57
+
58
+ ### Schema Management
59
+
60
+ The storage implementation handles schema creation and updates automatically. It creates the following tables:
61
+
62
+ - `threads`: Stores conversation threads
63
+ - `messages`: Stores individual messages
64
+ - `metadata`: Stores additional metadata for threads and messages
65
+
66
+ ### Initialization
67
+
68
+ When you pass storage to the Mastra class, `init()` is called automatically before any storage operation:
69
+
70
+ ```typescript
71
+ import { Mastra } from "@mastra/core";
72
+ import { D1Store } from "@mastra/cloudflare-d1";
73
+
74
+ const storage = new D1Store({
75
+ binding: D1Database,
76
+ });
77
+
78
+ const mastra = new Mastra({
79
+ storage, // init() is called automatically
80
+ });
81
+ ```
82
+
83
+ If you're using storage directly without Mastra, you must call `init()` explicitly to create the tables:
84
+
85
+ ```typescript
86
+ import { D1Store } from "@mastra/cloudflare-d1";
87
+
88
+ const storage = new D1Store({
89
+ id: 'd1-storage',
90
+ binding: D1Database,
91
+ });
92
+
93
+ // Required when using storage directly
94
+ await storage.init();
95
+
96
+ // Access domain-specific stores via getStore()
97
+ const memoryStore = await storage.getStore('memory');
98
+ const thread = await memoryStore?.getThreadById({ threadId: "..." });
99
+ ```
100
+
101
+ > **Note:**
102
+ If `init()` is not called, tables won't be created and storage operations will fail silently or throw errors.
103
+
104
+ ### Transactions & Consistency
105
+
106
+ Cloudflare D1 provides transactional guarantees for single-row operations. This means that multiple operations can be executed as a single, all-or-nothing unit of work.
107
+
108
+ ### Table Creation & Migrations
109
+
110
+ Tables are created automatically when storage is initialized (and can be isolated per environment using the `tablePrefix` option), but advanced schema changes—such as adding columns, changing data types, or modifying indexes—require manual migration and careful planning to avoid data loss.
package/dist/index.cjs CHANGED
@@ -846,18 +846,33 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
846
846
  return null;
847
847
  }
848
848
  }
849
- async listThreadsByResourceId(args) {
850
- const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
849
+ async listThreads(args) {
850
+ const { page = 0, perPage: perPageInput, orderBy, filter } = args;
851
+ try {
852
+ this.validatePaginationInput(page, perPageInput ?? 100);
853
+ } catch (error$1) {
854
+ throw new error.MastraError(
855
+ {
856
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_PAGE"),
857
+ domain: error.ErrorDomain.STORAGE,
858
+ category: error.ErrorCategory.USER,
859
+ details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
860
+ },
861
+ error$1 instanceof Error ? error$1 : new Error("Invalid pagination parameters")
862
+ );
863
+ }
851
864
  const perPage = storage.normalizePerPage(perPageInput, 100);
852
- if (page < 0) {
865
+ try {
866
+ this.validateMetadataKeys(filter?.metadata);
867
+ } catch (error$1) {
853
868
  throw new error.MastraError(
854
869
  {
855
- id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
870
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_METADATA_KEY"),
856
871
  domain: error.ErrorDomain.STORAGE,
857
872
  category: error.ErrorCategory.USER,
858
- details: { page }
873
+ details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
859
874
  },
860
- new Error("page must be >= 0")
875
+ error$1 instanceof Error ? error$1 : new Error("Invalid metadata key")
861
876
  );
862
877
  }
863
878
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
@@ -870,11 +885,51 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
870
885
  metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
871
886
  });
872
887
  try {
873
- const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
888
+ let countQuery = createSqlBuilder().count().from(fullTableName);
889
+ let selectQuery = createSqlBuilder().select("*").from(fullTableName);
890
+ if (filter?.resourceId) {
891
+ countQuery = countQuery.whereAnd("resourceId = ?", filter.resourceId);
892
+ selectQuery = selectQuery.whereAnd("resourceId = ?", filter.resourceId);
893
+ }
894
+ if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
895
+ for (const [key, value] of Object.entries(filter.metadata)) {
896
+ if (value !== null && typeof value === "object") {
897
+ throw new error.MastraError(
898
+ {
899
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "INVALID_METADATA_VALUE"),
900
+ domain: error.ErrorDomain.STORAGE,
901
+ category: error.ErrorCategory.USER,
902
+ text: `Metadata filter value for key "${key}" must be a scalar type (string, number, boolean, or null), got ${Array.isArray(value) ? "array" : "object"}`,
903
+ details: { key, valueType: Array.isArray(value) ? "array" : "object" }
904
+ },
905
+ new Error("Invalid metadata filter value type")
906
+ );
907
+ }
908
+ if (value === null) {
909
+ const condition = `json_extract(metadata, '$.${key}') IS NULL`;
910
+ countQuery = countQuery.whereAnd(condition);
911
+ selectQuery = selectQuery.whereAnd(condition);
912
+ } else {
913
+ const condition = `json_extract(metadata, '$.${key}') = ?`;
914
+ const filterValue = value;
915
+ countQuery = countQuery.whereAnd(condition, filterValue);
916
+ selectQuery = selectQuery.whereAnd(condition, filterValue);
917
+ }
918
+ }
919
+ }
874
920
  const countResult = await this.#db.executeQuery(countQuery.build());
875
921
  const total = Number(countResult?.[0]?.count ?? 0);
922
+ if (total === 0) {
923
+ return {
924
+ threads: [],
925
+ total: 0,
926
+ page,
927
+ perPage: perPageForResponse,
928
+ hasMore: false
929
+ };
930
+ }
876
931
  const limitValue = perPageInput === false ? total : perPage;
877
- const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy(field, direction).limit(limitValue).offset(offset);
932
+ selectQuery = selectQuery.orderBy(field, direction).limit(limitValue).offset(offset);
878
933
  const results = await this.#db.executeQuery(selectQuery.build());
879
934
  const threads = results.map(mapRowToStorageThreadType);
880
935
  return {
@@ -885,13 +940,19 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
885
940
  hasMore: perPageInput === false ? false : offset + perPage < total
886
941
  };
887
942
  } catch (error$1) {
943
+ if (error$1 instanceof error.MastraError && error$1.category === error.ErrorCategory.USER) {
944
+ throw error$1;
945
+ }
888
946
  const mastraError = new error.MastraError(
889
947
  {
890
- id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
948
+ id: storage.createStorageErrorId("CLOUDFLARE_D1", "LIST_THREADS", "FAILED"),
891
949
  domain: error.ErrorDomain.STORAGE,
892
950
  category: error.ErrorCategory.THIRD_PARTY,
893
- text: `Error getting threads by resourceId ${resourceId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
894
- details: { resourceId }
951
+ text: `Error listing threads: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
952
+ details: {
953
+ ...filter?.resourceId && { resourceId: filter.resourceId },
954
+ hasMetadataFilter: !!filter?.metadata
955
+ }
895
956
  },
896
957
  error$1
897
958
  );
@@ -1211,12 +1272,14 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1211
1272
  const dateRange = filter?.dateRange;
1212
1273
  if (dateRange?.start) {
1213
1274
  const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
1214
- query += ` AND createdAt >= ?`;
1275
+ const startOp = dateRange.startExclusive ? ">" : ">=";
1276
+ query += ` AND createdAt ${startOp} ?`;
1215
1277
  queryParams.push(startDate);
1216
1278
  }
1217
1279
  if (dateRange?.end) {
1218
1280
  const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
1219
- query += ` AND createdAt <= ?`;
1281
+ const endOp = dateRange.endExclusive ? "<" : "<=";
1282
+ query += ` AND createdAt ${endOp} ?`;
1220
1283
  queryParams.push(endDate);
1221
1284
  }
1222
1285
  const { field, direction } = this.parseOrderBy(orderBy, "ASC");
@@ -1243,12 +1306,14 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1243
1306
  }
1244
1307
  if (dateRange?.start) {
1245
1308
  const startDate = dateRange.start instanceof Date ? storage.serializeDate(dateRange.start) : storage.serializeDate(new Date(dateRange.start));
1246
- countQuery += ` AND createdAt >= ?`;
1309
+ const startOp = dateRange.startExclusive ? ">" : ">=";
1310
+ countQuery += ` AND createdAt ${startOp} ?`;
1247
1311
  countParams.push(startDate);
1248
1312
  }
1249
1313
  if (dateRange?.end) {
1250
1314
  const endDate = dateRange.end instanceof Date ? storage.serializeDate(dateRange.end) : storage.serializeDate(new Date(dateRange.end));
1251
- countQuery += ` AND createdAt <= ?`;
1315
+ const endOp = dateRange.endExclusive ? "<" : "<=";
1316
+ countQuery += ` AND createdAt ${endOp} ?`;
1252
1317
  countParams.push(endDate);
1253
1318
  }
1254
1319
  const countResult = await this.#db.executeQuery({ sql: countQuery, params: countParams });
@@ -1887,7 +1952,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1887
1952
  try {
1888
1953
  parsedSnapshot = JSON.parse(row.snapshot);
1889
1954
  } catch (e) {
1890
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1955
+ this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1891
1956
  }
1892
1957
  }
1893
1958
  return {
@@ -1923,7 +1988,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
1923
1988
  builder.whereAnd("resourceId = ?", resourceId);
1924
1989
  countBuilder.whereAnd("resourceId = ?", resourceId);
1925
1990
  } else {
1926
- console.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1991
+ this.logger.warn(`[${fullTableName}] resourceId column not found. Skipping resourceId filter.`);
1927
1992
  }
1928
1993
  }
1929
1994
  if (fromDate) {
@@ -2026,7 +2091,7 @@ var WorkflowsStorageD1 = class extends storage.WorkflowsStorage {
2026
2091
  };
2027
2092
 
2028
2093
  // src/storage/index.ts
2029
- var D1Store = class extends storage.MastraStorage {
2094
+ var D1Store = class extends storage.MastraCompositeStore {
2030
2095
  client;
2031
2096
  binding;
2032
2097
  tablePrefix;