@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.
- package/CHANGELOG.md +870 -0
- package/dist/docs/README.md +31 -0
- package/dist/docs/SKILL.md +32 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/storage/01-reference.md +110 -0
- package/dist/index.cjs +83 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +84 -19
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +2 -2
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +9 -8
|
@@ -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,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
|
|
850
|
-
const {
|
|
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
|
-
|
|
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", "
|
|
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: {
|
|
873
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
859
874
|
},
|
|
860
|
-
new Error("
|
|
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
|
-
|
|
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
|
-
|
|
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", "
|
|
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
|
|
894
|
-
details: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
2094
|
+
var D1Store = class extends storage.MastraCompositeStore {
|
|
2030
2095
|
client;
|
|
2031
2096
|
binding;
|
|
2032
2097
|
tablePrefix;
|