@tpmjs/tools-cloudflare 0.1.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/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # @tpmjs/tools-cloudflare
2
+
3
+ Cloudflare API tools for AI agents. Manage DNS records, zones, Workers, KV namespaces, and purge cache.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @tpmjs/tools-cloudflare
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ Set your Cloudflare API token and account ID:
14
+
15
+ ```bash
16
+ export CLOUDFLARE_API_TOKEN="..."
17
+ export CLOUDFLARE_ACCOUNT_ID="..." # Required for Workers and KV operations
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { listZones, listDnsRecords, createDnsRecord } from '@tpmjs/tools-cloudflare';
24
+
25
+ const zones = await listZones.execute({ per_page: 10 });
26
+ const records = await listDnsRecords.execute({ zone_id: 'abc123', type: 'A' });
27
+ const newRecord = await createDnsRecord.execute({
28
+ zone_id: 'abc123',
29
+ type: 'A',
30
+ name: 'app.example.com',
31
+ content: '1.2.3.4',
32
+ proxied: true,
33
+ });
34
+ ```
35
+
36
+ ## Tools
37
+
38
+ | Tool | Description |
39
+ |------|-------------|
40
+ | `listZones` | List zones with name and status filters |
41
+ | `getZone` | Get details of a specific zone |
42
+ | `purgeCache` | Purge cached content by URLs or purge everything |
43
+ | `listDnsRecords` | List DNS records with type and name filters |
44
+ | `createDnsRecord` | Create a new DNS record |
45
+ | `updateDnsRecord` | Update an existing DNS record |
46
+ | `deleteDnsRecord` | Delete a DNS record |
47
+ | `listWorkers` | List all Workers scripts |
48
+ | `getWorker` | Get metadata for a Worker script |
49
+ | `deleteWorker` | Delete a Worker script |
50
+ | `listKvNamespaces` | List KV namespaces |
51
+ | `listKvKeys` | List keys in a KV namespace |
52
+ | `getKvValue` | Get a value from KV |
53
+ | `putKvValue` | Write a key-value pair to KV |
54
+ | `deleteKvKey` | Delete a key from KV |
55
+
56
+ ## License
57
+
58
+ MIT
@@ -0,0 +1,350 @@
1
+ import * as ai from 'ai';
2
+
3
+ interface ListZonesInput {
4
+ name?: string;
5
+ status?: string;
6
+ per_page?: number;
7
+ }
8
+ interface GetZoneInput {
9
+ zone_id: string;
10
+ }
11
+ interface PurgeCacheInput {
12
+ zone_id: string;
13
+ purge_everything?: boolean;
14
+ files?: string[];
15
+ }
16
+ interface ListDnsRecordsInput {
17
+ zone_id: string;
18
+ type?: string;
19
+ name?: string;
20
+ per_page?: number;
21
+ }
22
+ interface CreateDnsRecordInput {
23
+ zone_id: string;
24
+ type: string;
25
+ name: string;
26
+ content: string;
27
+ ttl?: number;
28
+ proxied?: boolean;
29
+ }
30
+ interface UpdateDnsRecordInput {
31
+ zone_id: string;
32
+ record_id: string;
33
+ type: string;
34
+ name: string;
35
+ content: string;
36
+ ttl?: number;
37
+ proxied?: boolean;
38
+ }
39
+ interface DeleteDnsRecordInput {
40
+ zone_id: string;
41
+ record_id: string;
42
+ }
43
+ interface ListWorkersInput {
44
+ per_page?: number;
45
+ }
46
+ interface GetWorkerInput {
47
+ script_name: string;
48
+ }
49
+ interface DeleteWorkerInput {
50
+ script_name: string;
51
+ }
52
+ interface ListKvNamespacesInput {
53
+ per_page?: number;
54
+ }
55
+ interface ListKvKeysInput {
56
+ namespace_id: string;
57
+ prefix?: string;
58
+ limit?: number;
59
+ }
60
+ interface GetKvValueInput {
61
+ namespace_id: string;
62
+ key_name: string;
63
+ }
64
+ interface PutKvValueInput {
65
+ namespace_id: string;
66
+ key_name: string;
67
+ value: string;
68
+ }
69
+ interface DeleteKvKeyInput {
70
+ namespace_id: string;
71
+ key_name: string;
72
+ }
73
+ declare const listZones: ai.Tool<ListZonesInput, {
74
+ success: boolean;
75
+ data: unknown;
76
+ error?: undefined;
77
+ } | {
78
+ success: boolean;
79
+ error: string;
80
+ data?: undefined;
81
+ }>;
82
+ declare const getZone: ai.Tool<GetZoneInput, {
83
+ success: boolean;
84
+ data: unknown;
85
+ error?: undefined;
86
+ } | {
87
+ success: boolean;
88
+ error: string;
89
+ data?: undefined;
90
+ }>;
91
+ declare const purgeCache: ai.Tool<PurgeCacheInput, {
92
+ success: boolean;
93
+ data: unknown;
94
+ error?: undefined;
95
+ } | {
96
+ success: boolean;
97
+ error: string;
98
+ data?: undefined;
99
+ }>;
100
+ declare const listDnsRecords: ai.Tool<ListDnsRecordsInput, {
101
+ success: boolean;
102
+ data: unknown;
103
+ error?: undefined;
104
+ } | {
105
+ success: boolean;
106
+ error: string;
107
+ data?: undefined;
108
+ }>;
109
+ declare const createDnsRecord: ai.Tool<CreateDnsRecordInput, {
110
+ success: boolean;
111
+ data: unknown;
112
+ error?: undefined;
113
+ } | {
114
+ success: boolean;
115
+ error: string;
116
+ data?: undefined;
117
+ }>;
118
+ declare const updateDnsRecord: ai.Tool<UpdateDnsRecordInput, {
119
+ success: boolean;
120
+ data: unknown;
121
+ error?: undefined;
122
+ } | {
123
+ success: boolean;
124
+ error: string;
125
+ data?: undefined;
126
+ }>;
127
+ declare const deleteDnsRecord: ai.Tool<DeleteDnsRecordInput, {
128
+ success: boolean;
129
+ data: unknown;
130
+ error?: undefined;
131
+ } | {
132
+ success: boolean;
133
+ error: string;
134
+ data?: undefined;
135
+ }>;
136
+ declare const listWorkers: ai.Tool<ListWorkersInput, {
137
+ success: boolean;
138
+ data: unknown;
139
+ error?: undefined;
140
+ } | {
141
+ success: boolean;
142
+ error: string;
143
+ data?: undefined;
144
+ }>;
145
+ declare const getWorker: ai.Tool<GetWorkerInput, {
146
+ success: boolean;
147
+ data: unknown;
148
+ error?: undefined;
149
+ } | {
150
+ success: boolean;
151
+ error: string;
152
+ data?: undefined;
153
+ }>;
154
+ declare const deleteWorker: ai.Tool<DeleteWorkerInput, {
155
+ success: boolean;
156
+ data: unknown;
157
+ error?: undefined;
158
+ } | {
159
+ success: boolean;
160
+ error: string;
161
+ data?: undefined;
162
+ }>;
163
+ declare const listKvNamespaces: ai.Tool<ListKvNamespacesInput, {
164
+ success: boolean;
165
+ data: unknown;
166
+ error?: undefined;
167
+ } | {
168
+ success: boolean;
169
+ error: string;
170
+ data?: undefined;
171
+ }>;
172
+ declare const listKvKeys: ai.Tool<ListKvKeysInput, {
173
+ success: boolean;
174
+ data: unknown;
175
+ error?: undefined;
176
+ } | {
177
+ success: boolean;
178
+ error: string;
179
+ data?: undefined;
180
+ }>;
181
+ declare const getKvValue: ai.Tool<GetKvValueInput, {
182
+ success: boolean;
183
+ data: {
184
+ value: string;
185
+ };
186
+ error?: undefined;
187
+ } | {
188
+ success: boolean;
189
+ error: string;
190
+ data?: undefined;
191
+ }>;
192
+ declare const putKvValue: ai.Tool<PutKvValueInput, {
193
+ success: boolean;
194
+ data: unknown;
195
+ error?: undefined;
196
+ } | {
197
+ success: boolean;
198
+ error: string;
199
+ data?: undefined;
200
+ }>;
201
+ declare const deleteKvKey: ai.Tool<DeleteKvKeyInput, {
202
+ success: boolean;
203
+ data: unknown;
204
+ error?: undefined;
205
+ } | {
206
+ success: boolean;
207
+ error: string;
208
+ data?: undefined;
209
+ }>;
210
+ declare const _default: {
211
+ listZones: ai.Tool<ListZonesInput, {
212
+ success: boolean;
213
+ data: unknown;
214
+ error?: undefined;
215
+ } | {
216
+ success: boolean;
217
+ error: string;
218
+ data?: undefined;
219
+ }>;
220
+ getZone: ai.Tool<GetZoneInput, {
221
+ success: boolean;
222
+ data: unknown;
223
+ error?: undefined;
224
+ } | {
225
+ success: boolean;
226
+ error: string;
227
+ data?: undefined;
228
+ }>;
229
+ purgeCache: ai.Tool<PurgeCacheInput, {
230
+ success: boolean;
231
+ data: unknown;
232
+ error?: undefined;
233
+ } | {
234
+ success: boolean;
235
+ error: string;
236
+ data?: undefined;
237
+ }>;
238
+ listDnsRecords: ai.Tool<ListDnsRecordsInput, {
239
+ success: boolean;
240
+ data: unknown;
241
+ error?: undefined;
242
+ } | {
243
+ success: boolean;
244
+ error: string;
245
+ data?: undefined;
246
+ }>;
247
+ createDnsRecord: ai.Tool<CreateDnsRecordInput, {
248
+ success: boolean;
249
+ data: unknown;
250
+ error?: undefined;
251
+ } | {
252
+ success: boolean;
253
+ error: string;
254
+ data?: undefined;
255
+ }>;
256
+ updateDnsRecord: ai.Tool<UpdateDnsRecordInput, {
257
+ success: boolean;
258
+ data: unknown;
259
+ error?: undefined;
260
+ } | {
261
+ success: boolean;
262
+ error: string;
263
+ data?: undefined;
264
+ }>;
265
+ deleteDnsRecord: ai.Tool<DeleteDnsRecordInput, {
266
+ success: boolean;
267
+ data: unknown;
268
+ error?: undefined;
269
+ } | {
270
+ success: boolean;
271
+ error: string;
272
+ data?: undefined;
273
+ }>;
274
+ listWorkers: ai.Tool<ListWorkersInput, {
275
+ success: boolean;
276
+ data: unknown;
277
+ error?: undefined;
278
+ } | {
279
+ success: boolean;
280
+ error: string;
281
+ data?: undefined;
282
+ }>;
283
+ getWorker: ai.Tool<GetWorkerInput, {
284
+ success: boolean;
285
+ data: unknown;
286
+ error?: undefined;
287
+ } | {
288
+ success: boolean;
289
+ error: string;
290
+ data?: undefined;
291
+ }>;
292
+ deleteWorker: ai.Tool<DeleteWorkerInput, {
293
+ success: boolean;
294
+ data: unknown;
295
+ error?: undefined;
296
+ } | {
297
+ success: boolean;
298
+ error: string;
299
+ data?: undefined;
300
+ }>;
301
+ listKvNamespaces: ai.Tool<ListKvNamespacesInput, {
302
+ success: boolean;
303
+ data: unknown;
304
+ error?: undefined;
305
+ } | {
306
+ success: boolean;
307
+ error: string;
308
+ data?: undefined;
309
+ }>;
310
+ listKvKeys: ai.Tool<ListKvKeysInput, {
311
+ success: boolean;
312
+ data: unknown;
313
+ error?: undefined;
314
+ } | {
315
+ success: boolean;
316
+ error: string;
317
+ data?: undefined;
318
+ }>;
319
+ getKvValue: ai.Tool<GetKvValueInput, {
320
+ success: boolean;
321
+ data: {
322
+ value: string;
323
+ };
324
+ error?: undefined;
325
+ } | {
326
+ success: boolean;
327
+ error: string;
328
+ data?: undefined;
329
+ }>;
330
+ putKvValue: ai.Tool<PutKvValueInput, {
331
+ success: boolean;
332
+ data: unknown;
333
+ error?: undefined;
334
+ } | {
335
+ success: boolean;
336
+ error: string;
337
+ data?: undefined;
338
+ }>;
339
+ deleteKvKey: ai.Tool<DeleteKvKeyInput, {
340
+ success: boolean;
341
+ data: unknown;
342
+ error?: undefined;
343
+ } | {
344
+ success: boolean;
345
+ error: string;
346
+ data?: undefined;
347
+ }>;
348
+ };
349
+
350
+ export { createDnsRecord, _default as default, deleteDnsRecord, deleteKvKey, deleteWorker, getKvValue, getWorker, getZone, listDnsRecords, listKvKeys, listKvNamespaces, listWorkers, listZones, purgeCache, putKvValue, updateDnsRecord };
package/dist/index.js ADDED
@@ -0,0 +1,772 @@
1
+ import { tool, jsonSchema } from 'ai';
2
+
3
+ // src/index.ts
4
+ var BASE_URL = "https://api.cloudflare.com/client/v4";
5
+ function getApiToken() {
6
+ const token = process.env.CLOUDFLARE_API_TOKEN;
7
+ if (!token) {
8
+ throw new Error(
9
+ "CLOUDFLARE_API_TOKEN environment variable is required. Get your token at https://dash.cloudflare.com/profile/api-tokens"
10
+ );
11
+ }
12
+ return token;
13
+ }
14
+ function getAccountId() {
15
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
16
+ if (!accountId) {
17
+ throw new Error(
18
+ "CLOUDFLARE_ACCOUNT_ID environment variable is required. Find it at https://dash.cloudflare.com/"
19
+ );
20
+ }
21
+ return accountId;
22
+ }
23
+ function buildQueryString(params) {
24
+ const searchParams = new URLSearchParams();
25
+ for (const [key, value] of Object.entries(params)) {
26
+ if (value !== void 0 && value !== null) {
27
+ searchParams.append(key, String(value));
28
+ }
29
+ }
30
+ const query = searchParams.toString();
31
+ return query ? `?${query}` : "";
32
+ }
33
+ async function apiRequest(endpoint, options = {}) {
34
+ const token = getApiToken();
35
+ const url = `${BASE_URL}${endpoint}`;
36
+ const response = await fetch(url, {
37
+ ...options,
38
+ headers: {
39
+ Authorization: `Bearer ${token}`,
40
+ "Content-Type": "application/json",
41
+ ...options.headers
42
+ }
43
+ });
44
+ const data = await response.json();
45
+ if (!data.success) {
46
+ const errorMessages = data.errors.map((err) => `[${err.code}] ${err.message}`).join("; ");
47
+ throw new Error(`Cloudflare API error: ${errorMessages}`);
48
+ }
49
+ return data.result;
50
+ }
51
+ async function apiRequestRaw(endpoint, options = {}) {
52
+ const token = getApiToken();
53
+ const url = `${BASE_URL}${endpoint}`;
54
+ const response = await fetch(url, {
55
+ ...options,
56
+ headers: {
57
+ Authorization: `Bearer ${token}`,
58
+ ...options.headers
59
+ }
60
+ });
61
+ if (!response.ok) {
62
+ const errorText = await response.text();
63
+ throw new Error(
64
+ `Cloudflare API error: ${response.status} ${response.statusText} - ${errorText}`
65
+ );
66
+ }
67
+ return response.text();
68
+ }
69
+ function handleApiError(error) {
70
+ if (error instanceof Error) {
71
+ return error.message;
72
+ }
73
+ return "An unknown error occurred";
74
+ }
75
+ var listZones = tool({
76
+ description: "List all zones (domains) in your Cloudflare account with optional filtering",
77
+ inputSchema: jsonSchema({
78
+ type: "object",
79
+ properties: {
80
+ name: {
81
+ type: "string",
82
+ description: "Filter zones by name (domain)"
83
+ },
84
+ status: {
85
+ type: "string",
86
+ description: 'Filter by zone status (e.g., "active", "pending")'
87
+ },
88
+ per_page: {
89
+ type: "number",
90
+ description: "Number of results per page (default: 20, max: 50)"
91
+ }
92
+ },
93
+ additionalProperties: false
94
+ }),
95
+ execute: async ({ name, status, per_page }) => {
96
+ try {
97
+ const queryParams = {};
98
+ if (name) queryParams.name = name;
99
+ if (status) queryParams.status = status;
100
+ if (per_page) queryParams.per_page = per_page;
101
+ const query = buildQueryString(queryParams);
102
+ const result = await apiRequest(`/zones${query}`);
103
+ return {
104
+ success: true,
105
+ data: result
106
+ };
107
+ } catch (error) {
108
+ return {
109
+ success: false,
110
+ error: handleApiError(error)
111
+ };
112
+ }
113
+ }
114
+ });
115
+ var getZone = tool({
116
+ description: "Get detailed information about a specific zone",
117
+ inputSchema: jsonSchema({
118
+ type: "object",
119
+ properties: {
120
+ zone_id: {
121
+ type: "string",
122
+ description: "The zone ID to retrieve"
123
+ }
124
+ },
125
+ required: ["zone_id"],
126
+ additionalProperties: false
127
+ }),
128
+ execute: async ({ zone_id }) => {
129
+ try {
130
+ if (!zone_id) {
131
+ throw new Error("zone_id is required");
132
+ }
133
+ const result = await apiRequest(`/zones/${zone_id}`);
134
+ return {
135
+ success: true,
136
+ data: result
137
+ };
138
+ } catch (error) {
139
+ return {
140
+ success: false,
141
+ error: handleApiError(error)
142
+ };
143
+ }
144
+ }
145
+ });
146
+ var purgeCache = tool({
147
+ description: "Purge cached content from Cloudflare CDN for a zone (all files or specific URLs)",
148
+ inputSchema: jsonSchema({
149
+ type: "object",
150
+ properties: {
151
+ zone_id: {
152
+ type: "string",
153
+ description: "The zone ID to purge cache for"
154
+ },
155
+ purge_everything: {
156
+ type: "boolean",
157
+ description: "Purge all cached content (default: false)"
158
+ },
159
+ files: {
160
+ type: "array",
161
+ items: { type: "string" },
162
+ description: "Array of URLs to purge (use if purge_everything is false)"
163
+ }
164
+ },
165
+ required: ["zone_id"],
166
+ additionalProperties: false
167
+ }),
168
+ execute: async ({ zone_id, purge_everything, files }) => {
169
+ try {
170
+ if (!zone_id) {
171
+ throw new Error("zone_id is required");
172
+ }
173
+ const body = {};
174
+ if (purge_everything) {
175
+ body.purge_everything = true;
176
+ } else if (files && files.length > 0) {
177
+ body.files = files;
178
+ } else {
179
+ throw new Error(
180
+ "Either purge_everything must be true or files must be provided"
181
+ );
182
+ }
183
+ const result = await apiRequest(
184
+ `/zones/${zone_id}/purge_cache`,
185
+ {
186
+ method: "POST",
187
+ body: JSON.stringify(body)
188
+ }
189
+ );
190
+ return {
191
+ success: true,
192
+ data: result
193
+ };
194
+ } catch (error) {
195
+ return {
196
+ success: false,
197
+ error: handleApiError(error)
198
+ };
199
+ }
200
+ }
201
+ });
202
+ var listDnsRecords = tool({
203
+ description: "List DNS records for a specific zone with optional filtering",
204
+ inputSchema: jsonSchema({
205
+ type: "object",
206
+ properties: {
207
+ zone_id: {
208
+ type: "string",
209
+ description: "The zone ID to list DNS records for"
210
+ },
211
+ type: {
212
+ type: "string",
213
+ description: "Filter by record type (A, AAAA, CNAME, MX, TXT, etc.)"
214
+ },
215
+ name: {
216
+ type: "string",
217
+ description: 'Filter by record name (e.g., "example.com")'
218
+ },
219
+ per_page: {
220
+ type: "number",
221
+ description: "Number of results per page (default: 20, max: 100)"
222
+ }
223
+ },
224
+ required: ["zone_id"],
225
+ additionalProperties: false
226
+ }),
227
+ execute: async ({ zone_id, type, name, per_page }) => {
228
+ try {
229
+ if (!zone_id) {
230
+ throw new Error("zone_id is required");
231
+ }
232
+ const queryParams = {};
233
+ if (type) queryParams.type = type;
234
+ if (name) queryParams.name = name;
235
+ if (per_page) queryParams.per_page = per_page;
236
+ const query = buildQueryString(queryParams);
237
+ const result = await apiRequest(
238
+ `/zones/${zone_id}/dns_records${query}`
239
+ );
240
+ return {
241
+ success: true,
242
+ data: result
243
+ };
244
+ } catch (error) {
245
+ return {
246
+ success: false,
247
+ error: handleApiError(error)
248
+ };
249
+ }
250
+ }
251
+ });
252
+ var createDnsRecord = tool({
253
+ description: "Create a new DNS record in a zone",
254
+ inputSchema: jsonSchema({
255
+ type: "object",
256
+ properties: {
257
+ zone_id: {
258
+ type: "string",
259
+ description: "The zone ID to create the DNS record in"
260
+ },
261
+ type: {
262
+ type: "string",
263
+ description: "DNS record type (A, AAAA, CNAME, MX, TXT, etc.)"
264
+ },
265
+ name: {
266
+ type: "string",
267
+ description: 'DNS record name (e.g., "example.com" or "subdomain.example.com")'
268
+ },
269
+ content: {
270
+ type: "string",
271
+ description: "DNS record content (e.g., IP address for A record, domain for CNAME)"
272
+ },
273
+ ttl: {
274
+ type: "number",
275
+ description: "Time to live in seconds (1 = automatic, default: 1)"
276
+ },
277
+ proxied: {
278
+ type: "boolean",
279
+ description: "Whether the record is proxied through Cloudflare (default: false)"
280
+ }
281
+ },
282
+ required: ["zone_id", "type", "name", "content"],
283
+ additionalProperties: false
284
+ }),
285
+ execute: async ({ zone_id, type, name, content, ttl, proxied }) => {
286
+ try {
287
+ if (!zone_id || !type || !name || !content) {
288
+ throw new Error("zone_id, type, name, and content are required");
289
+ }
290
+ const body = {
291
+ type,
292
+ name,
293
+ content
294
+ };
295
+ if (ttl !== void 0) body.ttl = ttl;
296
+ if (proxied !== void 0) body.proxied = proxied;
297
+ const result = await apiRequest(
298
+ `/zones/${zone_id}/dns_records`,
299
+ {
300
+ method: "POST",
301
+ body: JSON.stringify(body)
302
+ }
303
+ );
304
+ return {
305
+ success: true,
306
+ data: result
307
+ };
308
+ } catch (error) {
309
+ return {
310
+ success: false,
311
+ error: handleApiError(error)
312
+ };
313
+ }
314
+ }
315
+ });
316
+ var updateDnsRecord = tool({
317
+ description: "Update an existing DNS record",
318
+ inputSchema: jsonSchema({
319
+ type: "object",
320
+ properties: {
321
+ zone_id: {
322
+ type: "string",
323
+ description: "The zone ID containing the DNS record"
324
+ },
325
+ record_id: {
326
+ type: "string",
327
+ description: "The DNS record ID to update"
328
+ },
329
+ type: {
330
+ type: "string",
331
+ description: "DNS record type (A, AAAA, CNAME, MX, TXT, etc.)"
332
+ },
333
+ name: {
334
+ type: "string",
335
+ description: 'DNS record name (e.g., "example.com" or "subdomain.example.com")'
336
+ },
337
+ content: {
338
+ type: "string",
339
+ description: "DNS record content (e.g., IP address for A record, domain for CNAME)"
340
+ },
341
+ ttl: {
342
+ type: "number",
343
+ description: "Time to live in seconds (1 = automatic)"
344
+ },
345
+ proxied: {
346
+ type: "boolean",
347
+ description: "Whether the record is proxied through Cloudflare"
348
+ }
349
+ },
350
+ required: ["zone_id", "record_id", "type", "name", "content"],
351
+ additionalProperties: false
352
+ }),
353
+ execute: async ({
354
+ zone_id,
355
+ record_id,
356
+ type,
357
+ name,
358
+ content,
359
+ ttl,
360
+ proxied
361
+ }) => {
362
+ try {
363
+ if (!zone_id || !record_id || !type || !name || !content) {
364
+ throw new Error(
365
+ "zone_id, record_id, type, name, and content are required"
366
+ );
367
+ }
368
+ const body = {
369
+ type,
370
+ name,
371
+ content
372
+ };
373
+ if (ttl !== void 0) body.ttl = ttl;
374
+ if (proxied !== void 0) body.proxied = proxied;
375
+ const result = await apiRequest(
376
+ `/zones/${zone_id}/dns_records/${record_id}`,
377
+ {
378
+ method: "PUT",
379
+ body: JSON.stringify(body)
380
+ }
381
+ );
382
+ return {
383
+ success: true,
384
+ data: result
385
+ };
386
+ } catch (error) {
387
+ return {
388
+ success: false,
389
+ error: handleApiError(error)
390
+ };
391
+ }
392
+ }
393
+ });
394
+ var deleteDnsRecord = tool({
395
+ description: "Delete a DNS record from a zone",
396
+ inputSchema: jsonSchema({
397
+ type: "object",
398
+ properties: {
399
+ zone_id: {
400
+ type: "string",
401
+ description: "The zone ID containing the DNS record"
402
+ },
403
+ record_id: {
404
+ type: "string",
405
+ description: "The DNS record ID to delete"
406
+ }
407
+ },
408
+ required: ["zone_id", "record_id"],
409
+ additionalProperties: false
410
+ }),
411
+ execute: async ({ zone_id, record_id }) => {
412
+ try {
413
+ if (!zone_id || !record_id) {
414
+ throw new Error("zone_id and record_id are required");
415
+ }
416
+ const result = await apiRequest(
417
+ `/zones/${zone_id}/dns_records/${record_id}`,
418
+ {
419
+ method: "DELETE"
420
+ }
421
+ );
422
+ return {
423
+ success: true,
424
+ data: result
425
+ };
426
+ } catch (error) {
427
+ return {
428
+ success: false,
429
+ error: handleApiError(error)
430
+ };
431
+ }
432
+ }
433
+ });
434
+ var listWorkers = tool({
435
+ description: "List all Cloudflare Workers scripts in your account",
436
+ inputSchema: jsonSchema({
437
+ type: "object",
438
+ properties: {
439
+ per_page: {
440
+ type: "number",
441
+ description: "Number of results per page (default: 20)"
442
+ }
443
+ },
444
+ additionalProperties: false
445
+ }),
446
+ execute: async ({ per_page }) => {
447
+ try {
448
+ const accountId = getAccountId();
449
+ const queryParams = {};
450
+ if (per_page) queryParams.per_page = per_page;
451
+ const query = buildQueryString(queryParams);
452
+ const result = await apiRequest(
453
+ `/accounts/${accountId}/workers/scripts${query}`
454
+ );
455
+ return {
456
+ success: true,
457
+ data: result
458
+ };
459
+ } catch (error) {
460
+ return {
461
+ success: false,
462
+ error: handleApiError(error)
463
+ };
464
+ }
465
+ }
466
+ });
467
+ var getWorker = tool({
468
+ description: "Get settings and metadata for a specific Cloudflare Worker",
469
+ inputSchema: jsonSchema({
470
+ type: "object",
471
+ properties: {
472
+ script_name: {
473
+ type: "string",
474
+ description: "The name of the Worker script"
475
+ }
476
+ },
477
+ required: ["script_name"],
478
+ additionalProperties: false
479
+ }),
480
+ execute: async ({ script_name }) => {
481
+ try {
482
+ if (!script_name) {
483
+ throw new Error("script_name is required");
484
+ }
485
+ const accountId = getAccountId();
486
+ const result = await apiRequest(
487
+ `/accounts/${accountId}/workers/scripts/${script_name}/settings`
488
+ );
489
+ return {
490
+ success: true,
491
+ data: result
492
+ };
493
+ } catch (error) {
494
+ return {
495
+ success: false,
496
+ error: handleApiError(error)
497
+ };
498
+ }
499
+ }
500
+ });
501
+ var deleteWorker = tool({
502
+ description: "Delete a Cloudflare Worker script",
503
+ inputSchema: jsonSchema({
504
+ type: "object",
505
+ properties: {
506
+ script_name: {
507
+ type: "string",
508
+ description: "The name of the Worker script to delete"
509
+ }
510
+ },
511
+ required: ["script_name"],
512
+ additionalProperties: false
513
+ }),
514
+ execute: async ({ script_name }) => {
515
+ try {
516
+ if (!script_name) {
517
+ throw new Error("script_name is required");
518
+ }
519
+ const accountId = getAccountId();
520
+ const result = await apiRequest(
521
+ `/accounts/${accountId}/workers/scripts/${script_name}`,
522
+ {
523
+ method: "DELETE"
524
+ }
525
+ );
526
+ return {
527
+ success: true,
528
+ data: result
529
+ };
530
+ } catch (error) {
531
+ return {
532
+ success: false,
533
+ error: handleApiError(error)
534
+ };
535
+ }
536
+ }
537
+ });
538
+ var listKvNamespaces = tool({
539
+ description: "List all KV namespaces in your Cloudflare account",
540
+ inputSchema: jsonSchema({
541
+ type: "object",
542
+ properties: {
543
+ per_page: {
544
+ type: "number",
545
+ description: "Number of results per page (default: 20)"
546
+ }
547
+ },
548
+ additionalProperties: false
549
+ }),
550
+ execute: async ({ per_page }) => {
551
+ try {
552
+ const accountId = getAccountId();
553
+ const queryParams = {};
554
+ if (per_page) queryParams.per_page = per_page;
555
+ const query = buildQueryString(queryParams);
556
+ const result = await apiRequest(
557
+ `/accounts/${accountId}/storage/kv/namespaces${query}`
558
+ );
559
+ return {
560
+ success: true,
561
+ data: result
562
+ };
563
+ } catch (error) {
564
+ return {
565
+ success: false,
566
+ error: handleApiError(error)
567
+ };
568
+ }
569
+ }
570
+ });
571
+ var listKvKeys = tool({
572
+ description: "List all keys in a KV namespace with optional filtering",
573
+ inputSchema: jsonSchema({
574
+ type: "object",
575
+ properties: {
576
+ namespace_id: {
577
+ type: "string",
578
+ description: "The KV namespace ID"
579
+ },
580
+ prefix: {
581
+ type: "string",
582
+ description: "Filter keys by prefix"
583
+ },
584
+ limit: {
585
+ type: "number",
586
+ description: "Maximum number of keys to return (default: 1000)"
587
+ }
588
+ },
589
+ required: ["namespace_id"],
590
+ additionalProperties: false
591
+ }),
592
+ execute: async ({ namespace_id, prefix, limit }) => {
593
+ try {
594
+ if (!namespace_id) {
595
+ throw new Error("namespace_id is required");
596
+ }
597
+ const accountId = getAccountId();
598
+ const queryParams = {};
599
+ if (prefix) queryParams.prefix = prefix;
600
+ if (limit) queryParams.limit = limit;
601
+ const query = buildQueryString(queryParams);
602
+ const result = await apiRequest(
603
+ `/accounts/${accountId}/storage/kv/namespaces/${namespace_id}/keys${query}`
604
+ );
605
+ return {
606
+ success: true,
607
+ data: result
608
+ };
609
+ } catch (error) {
610
+ return {
611
+ success: false,
612
+ error: handleApiError(error)
613
+ };
614
+ }
615
+ }
616
+ });
617
+ var getKvValue = tool({
618
+ description: "Get the value of a key from a KV namespace",
619
+ inputSchema: jsonSchema({
620
+ type: "object",
621
+ properties: {
622
+ namespace_id: {
623
+ type: "string",
624
+ description: "The KV namespace ID"
625
+ },
626
+ key_name: {
627
+ type: "string",
628
+ description: "The key name to retrieve"
629
+ }
630
+ },
631
+ required: ["namespace_id", "key_name"],
632
+ additionalProperties: false
633
+ }),
634
+ execute: async ({ namespace_id, key_name }) => {
635
+ try {
636
+ if (!namespace_id || !key_name) {
637
+ throw new Error("namespace_id and key_name are required");
638
+ }
639
+ const accountId = getAccountId();
640
+ const value = await apiRequestRaw(
641
+ `/accounts/${accountId}/storage/kv/namespaces/${namespace_id}/values/${key_name}`
642
+ );
643
+ return {
644
+ success: true,
645
+ data: { value }
646
+ };
647
+ } catch (error) {
648
+ return {
649
+ success: false,
650
+ error: handleApiError(error)
651
+ };
652
+ }
653
+ }
654
+ });
655
+ var putKvValue = tool({
656
+ description: "Set the value of a key in a KV namespace",
657
+ inputSchema: jsonSchema({
658
+ type: "object",
659
+ properties: {
660
+ namespace_id: {
661
+ type: "string",
662
+ description: "The KV namespace ID"
663
+ },
664
+ key_name: {
665
+ type: "string",
666
+ description: "The key name to set"
667
+ },
668
+ value: {
669
+ type: "string",
670
+ description: "The value to store (will be stored as text)"
671
+ }
672
+ },
673
+ required: ["namespace_id", "key_name", "value"],
674
+ additionalProperties: false
675
+ }),
676
+ execute: async ({ namespace_id, key_name, value }) => {
677
+ try {
678
+ if (!namespace_id || !key_name || value === void 0) {
679
+ throw new Error("namespace_id, key_name, and value are required");
680
+ }
681
+ const accountId = getAccountId();
682
+ const token = getApiToken();
683
+ const url = `${BASE_URL}/accounts/${accountId}/storage/kv/namespaces/${namespace_id}/values/${key_name}`;
684
+ const response = await fetch(url, {
685
+ method: "PUT",
686
+ headers: {
687
+ Authorization: `Bearer ${token}`,
688
+ "Content-Type": "text/plain"
689
+ },
690
+ body: value
691
+ });
692
+ const data = await response.json();
693
+ if (!data.success) {
694
+ const errorMessages = data.errors.map((err) => `[${err.code}] ${err.message}`).join("; ");
695
+ throw new Error(`Cloudflare API error: ${errorMessages}`);
696
+ }
697
+ return {
698
+ success: true,
699
+ data: data.result
700
+ };
701
+ } catch (error) {
702
+ return {
703
+ success: false,
704
+ error: handleApiError(error)
705
+ };
706
+ }
707
+ }
708
+ });
709
+ var deleteKvKey = tool({
710
+ description: "Delete a key from a KV namespace",
711
+ inputSchema: jsonSchema({
712
+ type: "object",
713
+ properties: {
714
+ namespace_id: {
715
+ type: "string",
716
+ description: "The KV namespace ID"
717
+ },
718
+ key_name: {
719
+ type: "string",
720
+ description: "The key name to delete"
721
+ }
722
+ },
723
+ required: ["namespace_id", "key_name"],
724
+ additionalProperties: false
725
+ }),
726
+ execute: async ({ namespace_id, key_name }) => {
727
+ try {
728
+ if (!namespace_id || !key_name) {
729
+ throw new Error("namespace_id and key_name are required");
730
+ }
731
+ const accountId = getAccountId();
732
+ const result = await apiRequest(
733
+ `/accounts/${accountId}/storage/kv/namespaces/${namespace_id}/values/${key_name}`,
734
+ {
735
+ method: "DELETE"
736
+ }
737
+ );
738
+ return {
739
+ success: true,
740
+ data: result
741
+ };
742
+ } catch (error) {
743
+ return {
744
+ success: false,
745
+ error: handleApiError(error)
746
+ };
747
+ }
748
+ }
749
+ });
750
+ var index_default = {
751
+ // Zones
752
+ listZones,
753
+ getZone,
754
+ purgeCache,
755
+ // DNS Records
756
+ listDnsRecords,
757
+ createDnsRecord,
758
+ updateDnsRecord,
759
+ deleteDnsRecord,
760
+ // Workers
761
+ listWorkers,
762
+ getWorker,
763
+ deleteWorker,
764
+ // KV
765
+ listKvNamespaces,
766
+ listKvKeys,
767
+ getKvValue,
768
+ putKvValue,
769
+ deleteKvKey
770
+ };
771
+
772
+ export { createDnsRecord, index_default as default, deleteDnsRecord, deleteKvKey, deleteWorker, getKvValue, getWorker, getZone, listDnsRecords, listKvKeys, listKvNamespaces, listWorkers, listZones, purgeCache, putKvValue, updateDnsRecord };
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "@tpmjs/tools-cloudflare",
3
+ "version": "0.1.0",
4
+ "description": "Cloudflare API tools for AI agents. Manage DNS records, zones, Workers, KV namespaces, and purge cache.",
5
+ "type": "module",
6
+ "keywords": [
7
+ "tpmjs",
8
+ "cloudflare",
9
+ "dns",
10
+ "workers",
11
+ "agent"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "dev": "tsup --watch",
25
+ "type-check": "tsc --noEmit",
26
+ "clean": "rm -rf dist .turbo"
27
+ },
28
+ "devDependencies": {
29
+ "@tpmjs/tsconfig": "workspace:*",
30
+ "tsup": "^8.5.1",
31
+ "typescript": "^5.9.3"
32
+ },
33
+ "dependencies": {
34
+ "ai": "6.0.49"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/tpmjs/tpmjs.git",
42
+ "directory": "packages/tools/official/cloudflare"
43
+ },
44
+ "homepage": "https://tpmjs.com",
45
+ "license": "MIT",
46
+ "tpmjs": {
47
+ "category": "ops",
48
+ "frameworks": [
49
+ "vercel-ai"
50
+ ],
51
+ "tools": [
52
+ {
53
+ "name": "listZones",
54
+ "description": "List Cloudflare zones with optional name and status filtering."
55
+ },
56
+ {
57
+ "name": "getZone",
58
+ "description": "Get details of a specific Cloudflare zone by ID."
59
+ },
60
+ {
61
+ "name": "purgeCache",
62
+ "description": "Purge cached content from a Cloudflare zone by URLs or purge everything."
63
+ },
64
+ {
65
+ "name": "listDnsRecords",
66
+ "description": "List DNS records for a Cloudflare zone with type and name filters."
67
+ },
68
+ {
69
+ "name": "createDnsRecord",
70
+ "description": "Create a new DNS record in a Cloudflare zone."
71
+ },
72
+ {
73
+ "name": "updateDnsRecord",
74
+ "description": "Update an existing DNS record in a Cloudflare zone."
75
+ },
76
+ {
77
+ "name": "deleteDnsRecord",
78
+ "description": "Delete a DNS record from a Cloudflare zone."
79
+ },
80
+ {
81
+ "name": "listWorkers",
82
+ "description": "List all Workers scripts in your Cloudflare account."
83
+ },
84
+ {
85
+ "name": "getWorker",
86
+ "description": "Get metadata and bindings for a specific Worker script."
87
+ },
88
+ {
89
+ "name": "deleteWorker",
90
+ "description": "Delete a Worker script from your Cloudflare account."
91
+ },
92
+ {
93
+ "name": "listKvNamespaces",
94
+ "description": "List KV namespaces in your Cloudflare account."
95
+ },
96
+ {
97
+ "name": "listKvKeys",
98
+ "description": "List keys in a Cloudflare KV namespace with optional prefix filter."
99
+ },
100
+ {
101
+ "name": "getKvValue",
102
+ "description": "Get the value of a key from a Cloudflare KV namespace."
103
+ },
104
+ {
105
+ "name": "putKvValue",
106
+ "description": "Write a key-value pair to a Cloudflare KV namespace."
107
+ },
108
+ {
109
+ "name": "deleteKvKey",
110
+ "description": "Delete a key from a Cloudflare KV namespace."
111
+ }
112
+ ]
113
+ }
114
+ }