@mastra/cloudflare 0.1.0-alpha.5 → 0.1.0-alpha.7

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/README.md CHANGED
@@ -0,0 +1,175 @@
1
+ # @mastra/cloudflare
2
+
3
+ Cloudflare KV store for Mastra, providing scalable and serverless storage for threads, messages, workflow snapshots, and evaluations. Supports both Cloudflare Workers KV Bindings and the REST API for flexible deployment in serverless and Node.js environments.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mastra/cloudflare
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ - Cloudflare account with KV namespaces set up
14
+ - Node.js 16 or higher
15
+ - (Optional) Cloudflare Worker for Workers API mode
16
+
17
+ ## Usage
18
+
19
+ ```typescript
20
+ import { CloudflareStore } from '@mastra/cloudflare';
21
+
22
+ // Using Workers Binding API
23
+ const store = new CloudflareStore({
24
+ bindings: {
25
+ threads: THREADS_KV_NAMESPACE,
26
+ messages: MESSAGES_KV_NAMESPACE,
27
+ workflow_snapshot: WORKFLOW_KV_NAMESPACE,
28
+ evals: EVALS_KV_NAMESPACE,
29
+ traces: TRACES_KV_NAMESPACE,
30
+ },
31
+ keyPrefix: 'myapp_', // Optional
32
+ });
33
+
34
+ // Or using REST API
35
+ const store = new CloudflareStore({
36
+ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
37
+ apiToken: process.env.CLOUDFLARE_API_TOKEN!,
38
+ namespacePrefix: 'myapp_', // Optional
39
+ });
40
+
41
+ // Save a thread
42
+ await store.saveThread({
43
+ id: 'thread-123',
44
+ resourceId: 'resource-456',
45
+ title: 'My Thread',
46
+ metadata: { key: 'value' },
47
+ createdAt: new Date(),
48
+ updatedAt: new Date(),
49
+ });
50
+
51
+ // Add messages
52
+ await store.saveMessages({
53
+ messages: [
54
+ {
55
+ id: 'msg-1',
56
+ threadId: 'thread-123',
57
+ content: 'Hello Cloudflare!',
58
+ role: 'user',
59
+ createdAt: new Date(),
60
+ },
61
+ ],
62
+ });
63
+
64
+ // Query messages
65
+ const messages = await store.getMessages({ threadId: 'thread-123' });
66
+ ```
67
+
68
+ ## Configuration
69
+
70
+ - **Workers API**: Use the `bindings` option to pass KV namespaces directly (for Cloudflare Workers).
71
+ - **REST API**: Use `accountId`, `apiToken`, and (optionally) `namespacePrefix` for server-side usage.
72
+ - `keyPrefix`/`namespacePrefix`: Useful for isolating environments (e.g., dev/test/prod).
73
+
74
+ ## Features
75
+
76
+ ### Storage Features
77
+
78
+ - Thread and message storage with JSON support
79
+ - Rich metadata support (JSON-encoded)
80
+ - Timestamp tracking for all records
81
+ - Workflow snapshot persistence
82
+ - Trace and evaluation storage
83
+ - Sorted message order using simulated sorted sets
84
+ - Supports both Cloudflare Workers KV Bindings and REST API
85
+ - Automatic JSON serialization/deserialization for metadata and custom fields
86
+ - Error handling and logging for all operations
87
+
88
+ ### Consistency & Performance
89
+
90
+ - Eventually consistent (see Limitations)
91
+ - Low-latency access via Workers Binding API
92
+ - Scalable and serverless
93
+
94
+ ## Supported Methods
95
+
96
+ ### Thread Operations
97
+
98
+ - `saveThread(thread)`: Create or update a thread
99
+ - `getThreadById({ threadId })`: Get a thread by ID
100
+ - `getThreadsByResourceId({ resourceId })`: Fetch all threads associated with a resource.
101
+ - `updateThread({ id, title, metadata })`: Update thread title and metadata
102
+ - `deleteThread({ threadId })`: Delete a thread and its messages
103
+
104
+ ### Message Operations
105
+
106
+ - `saveMessages({ messages })`: Save multiple messages
107
+ - `getMessages({ threadId, selectBy? })`: Get messages for a thread with optional filtering (last N, includes, etc)
108
+
109
+ ### Workflow Operations
110
+
111
+ - `persistWorkflowSnapshot({ workflowName, runId, snapshot })`: Save workflow state for a given workflow/run.
112
+ - `loadWorkflowSnapshot({ workflowName, runId })`: Load ed workflow state.
113
+
114
+ ### Trace Operations
115
+
116
+ - `getTraces({ name?, scope?, page, perPage, attributes? })`: Query trace records with optional filters and pagination.
117
+
118
+ ### Utility
119
+
120
+ - `clearTable({ tableName })`: Remove all records from a logical table
121
+ - `batchInsert({ tableName, records })`: Batch insert multiple records.
122
+ - `insert({ tableName, record })`: Insert a single record into a table.
123
+
124
+ ## Data Types
125
+
126
+ - `text`: String
127
+ - `timestamp`: ISO8601 string (converted to/from Date)
128
+ - `uuid`: String
129
+ - `jsonb`: JSON-encoded object
130
+
131
+ All records are stored as JSON in KV, with automatic serialization/deserialization for metadata, arrays, and custom fields.
132
+
133
+ ## Configuration Reference
134
+
135
+ - **Workers Binding API**: Use the `bindings` option to pass KV namespaces directly (for Cloudflare Workers).
136
+ - **REST API**: Use `accountId`, `apiToken`, and (optionally) `namespacePrefix` for server-side usage.
137
+ - `keyPrefix`/`namespacePrefix`: Useful for isolating environments (e.g., dev/test/prod).
138
+
139
+ Example:
140
+
141
+ ```typescript
142
+ const store = new CloudflareStore({
143
+ bindings: { ... }, // for Workers
144
+ keyPrefix: 'dev_',
145
+ });
146
+ // or
147
+ const store = new CloudflareStore({
148
+ accountId: '...',
149
+ apiToken: '...',
150
+ namespacePrefix: 'prod_',
151
+ });
152
+ ```
153
+
154
+ ## Table/Namespace Mapping
155
+
156
+ Each logical Mastra table (threads, messages, workflow_snapshot, evals, traces) maps to a separate KV namespace. Keys are structured as `${prefix}${tableName}:${primaryKey}` or `${prefix}${tableName}:${threadId}:${messageId}` for messages. The prefix is set by `keyPrefix`/`namespacePrefix`.
157
+
158
+ ## Limitations
159
+
160
+ - **Eventual Consistency:** Cloudflare KV is eventually consistent; concurrent operations may not be immediately visible across all reads.
161
+ - **No Transactions:** Atomic multi-key operations are not supported.
162
+ - **Rate Limits:** Large objects or high-frequency updates may be subject to Cloudflare KV rate limits.
163
+ - **Query Limitations:** No native querying; all filtering is done in-memory after fetching keys/records.
164
+ - **Best for:** Use for serverless, low-latency, and moderate-volume workloads. For relational or strongly consistent needs, consider D1 or a SQL backend.
165
+
166
+ ## Cloudflare-Specific Notes
167
+
168
+ - **Workers Binding API** is recommended for production Workers deployments (low-latency, no API token required at runtime).
169
+ - **REST API** is ideal for server-side Node.js or test environments.
170
+ - Ensure your KV namespaces are provisioned and accessible by your Worker or API token.
171
+ - Namespaces and keys are automatically created as needed.
172
+
173
+ ## Cleanup/Disconnect
174
+
175
+ No explicit cleanup or disconnect is required; Cloudflare KV is fully managed.
@@ -3,6 +3,7 @@ import type { KVNamespace as KVNamespace_2 } from '@cloudflare/workers-types';
3
3
  import { KVNamespaceListKey as KVNamespaceListKey_2 } from '@cloudflare/workers-types';
4
4
  import { MastraStorage } from '@mastra/core/storage';
5
5
  import type { MessageType } from '@mastra/core/memory';
6
+ 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,6 +15,7 @@ import type { TABLE_TRACES } from '@mastra/core/storage';
14
15
  import type { TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
15
16
  import type { WorkflowRuns } from '@mastra/core/storage';
16
17
  import type { WorkflowRunState } from '@mastra/core/workflows';
18
+ import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
17
19
 
18
20
  /**
19
21
  * Configuration for Cloudflare KV using REST API
@@ -190,6 +192,19 @@ export declare interface CloudflareWorkersConfig {
190
192
  keyPrefix?: string;
191
193
  }
192
194
 
195
+ export declare const createSampleMessage: (threadId: string) => MessageType_2;
196
+
197
+ export declare const createSampleThread: () => {
198
+ id: string;
199
+ resourceId: string;
200
+ title: string;
201
+ createdAt: Date;
202
+ updatedAt: Date;
203
+ metadata: {
204
+ key: string;
205
+ };
206
+ };
207
+
193
208
  export declare const createSampleTrace: (name: string, scope?: string, attributes?: Record<string, string>) => {
194
209
  id: string;
195
210
  parentSpanId: string;
@@ -207,6 +222,8 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
207
222
  createdAt: string;
208
223
  };
209
224
 
225
+ export declare const createSampleWorkflowSnapshot: (threadId: string) => WorkflowRunState_2;
226
+
210
227
  /**
211
228
  * Helper to determine if a config is using Workers bindings
212
229
  */
@@ -234,4 +251,7 @@ export declare type RecordTypes = {
234
251
  [TABLE_TRACES]: any;
235
252
  };
236
253
 
254
+ export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
255
+ interval?: number) => Promise<T>;
256
+
237
257
  export { }
@@ -3,6 +3,7 @@ import type { KVNamespace as KVNamespace_2 } from '@cloudflare/workers-types';
3
3
  import { KVNamespaceListKey as KVNamespaceListKey_2 } from '@cloudflare/workers-types';
4
4
  import { MastraStorage } from '@mastra/core/storage';
5
5
  import type { MessageType } from '@mastra/core/memory';
6
+ 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,6 +15,7 @@ import type { TABLE_TRACES } from '@mastra/core/storage';
14
15
  import type { TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
15
16
  import type { WorkflowRuns } from '@mastra/core/storage';
16
17
  import type { WorkflowRunState } from '@mastra/core/workflows';
18
+ import type { WorkflowRunState as WorkflowRunState_2 } from '@mastra/core';
17
19
 
18
20
  /**
19
21
  * Configuration for Cloudflare KV using REST API
@@ -190,6 +192,19 @@ export declare interface CloudflareWorkersConfig {
190
192
  keyPrefix?: string;
191
193
  }
192
194
 
195
+ export declare const createSampleMessage: (threadId: string) => MessageType_2;
196
+
197
+ export declare const createSampleThread: () => {
198
+ id: string;
199
+ resourceId: string;
200
+ title: string;
201
+ createdAt: Date;
202
+ updatedAt: Date;
203
+ metadata: {
204
+ key: string;
205
+ };
206
+ };
207
+
193
208
  export declare const createSampleTrace: (name: string, scope?: string, attributes?: Record<string, string>) => {
194
209
  id: string;
195
210
  parentSpanId: string;
@@ -207,6 +222,8 @@ export declare const createSampleTrace: (name: string, scope?: string, attribute
207
222
  createdAt: string;
208
223
  };
209
224
 
225
+ export declare const createSampleWorkflowSnapshot: (threadId: string) => WorkflowRunState_2;
226
+
210
227
  /**
211
228
  * Helper to determine if a config is using Workers bindings
212
229
  */
@@ -234,4 +251,7 @@ export declare type RecordTypes = {
234
251
  [TABLE_TRACES]: any;
235
252
  };
236
253
 
254
+ export declare const retryUntil: <T>(fn: () => Promise<T>, condition: (result: T) => boolean, timeout?: number, // REST API needs longer timeout due to higher latency
255
+ interval?: number) => Promise<T>;
256
+
237
257
  export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/cloudflare",
3
- "version": "0.1.0-alpha.5",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "Cloudflare provider for Mastra - includes db storage capabilities",
5
5
  "type": "module",
6
6
  "files": [
@@ -24,7 +24,7 @@
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
26
  "cloudflare": "^4.1.0",
27
- "@mastra/core": "^0.9.0-alpha.5"
27
+ "@mastra/core": "^0.9.0-alpha.7"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@cloudflare/workers-types": "^4.20250313.0",