@aigne/afs-cloudflare 1.11.0-beta.10

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.
Files changed (42) hide show
  1. package/LICENSE.md +26 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  4. package/dist/cache.cjs +37 -0
  5. package/dist/cache.mjs +37 -0
  6. package/dist/cache.mjs.map +1 -0
  7. package/dist/client.cjs +53 -0
  8. package/dist/client.mjs +53 -0
  9. package/dist/client.mjs.map +1 -0
  10. package/dist/cloudflare-afs.cjs +2754 -0
  11. package/dist/cloudflare-afs.d.cts +382 -0
  12. package/dist/cloudflare-afs.d.cts.map +1 -0
  13. package/dist/cloudflare-afs.d.mts +382 -0
  14. package/dist/cloudflare-afs.d.mts.map +1 -0
  15. package/dist/cloudflare-afs.mjs +2755 -0
  16. package/dist/cloudflare-afs.mjs.map +1 -0
  17. package/dist/errors.cjs +85 -0
  18. package/dist/errors.d.cts +26 -0
  19. package/dist/errors.d.cts.map +1 -0
  20. package/dist/errors.d.mts +26 -0
  21. package/dist/errors.d.mts.map +1 -0
  22. package/dist/errors.mjs +82 -0
  23. package/dist/errors.mjs.map +1 -0
  24. package/dist/index.cjs +22 -0
  25. package/dist/index.d.cts +5 -0
  26. package/dist/index.d.mts +5 -0
  27. package/dist/index.mjs +6 -0
  28. package/dist/platform-ref.cjs +20 -0
  29. package/dist/platform-ref.d.cts +11 -0
  30. package/dist/platform-ref.d.cts.map +1 -0
  31. package/dist/platform-ref.d.mts +11 -0
  32. package/dist/platform-ref.d.mts.map +1 -0
  33. package/dist/platform-ref.mjs +17 -0
  34. package/dist/platform-ref.mjs.map +1 -0
  35. package/dist/types.cjs +59 -0
  36. package/dist/types.d.cts +50 -0
  37. package/dist/types.d.cts.map +1 -0
  38. package/dist/types.d.mts +50 -0
  39. package/dist/types.d.mts.map +1 -0
  40. package/dist/types.mjs +53 -0
  41. package/dist/types.mjs.map +1 -0
  42. package/package.json +61 -0
@@ -0,0 +1,2755 @@
1
+ import { CloudflareCache } from "./cache.mjs";
2
+ import { createCloudflareClient } from "./client.mjs";
3
+ import { confirmationRequired, mapCloudflareError } from "./errors.mjs";
4
+ import { generateKVPlatformRef, generatePagesPlatformRef, generateWorkerPlatformRef } from "./platform-ref.mjs";
5
+ import { AFSCloudflareConfigSchema, KINDS, normalizeConfig } from "./types.mjs";
6
+ import { __decorate } from "./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs";
7
+ import { AFSBaseProvider, AFSNotFoundError, AFSReadonlyError, Actions, Delete, Explain, List, Meta, Read, Search, Stat, Write } from "@aigne/afs";
8
+ import { zodParse } from "@aigne/afs/utils/zod";
9
+ import { minimatch } from "minimatch";
10
+ import { joinURL } from "ufo";
11
+ import { z } from "zod";
12
+
13
+ //#region src/cloudflare-afs.ts
14
+ function camelize(obj) {
15
+ const result = {};
16
+ for (const [key, value] of Object.entries(obj)) {
17
+ const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
18
+ if (value && typeof value === "object" && !Array.isArray(value)) result[camelKey] = camelize(value);
19
+ else result[camelKey] = value;
20
+ }
21
+ return result;
22
+ }
23
+ var AFSCloudflare = class AFSCloudflare extends AFSBaseProvider {
24
+ name;
25
+ description;
26
+ accessMode;
27
+ config;
28
+ cfClient;
29
+ cache;
30
+ destroyed = false;
31
+ constructor(config) {
32
+ super();
33
+ const { uri: _uri, token: _token, auth: _auth, ...cleanConfig } = config;
34
+ this.config = normalizeConfig(AFSCloudflareConfigSchema.parse(cleanConfig));
35
+ this.name = this.config.name;
36
+ this.description = this.config.description;
37
+ this.accessMode = this.config.accessMode;
38
+ this.cfClient = createCloudflareClient(this.config);
39
+ this.cache = new CloudflareCache(this.config.cacheTtl, this.config.cacheDisabled);
40
+ }
41
+ static schema() {
42
+ return AFSCloudflareConfigSchema;
43
+ }
44
+ /**
45
+ * Provider manifest for URI-based discovery
46
+ */
47
+ static manifest() {
48
+ return {
49
+ name: "cloudflare",
50
+ description: "Cloudflare account — Workers, KV namespaces, and Pages projects.\n- Manage Workers: create, deploy, rollback, delete\n- Manage KV: create/delete namespaces, read/write keys\n- Manage Pages: create, deploy, rollback, configure bindings",
51
+ uriTemplate: "cloudflare://{accountId}",
52
+ category: "cloud-platform",
53
+ schema: z.object({
54
+ accountId: z.string().meta({
55
+ env: ["CLOUDFLARE_ACCOUNT_ID"],
56
+ description: "Cloudflare account ID"
57
+ }).optional(),
58
+ apiToken: z.string().meta({
59
+ sensitive: true,
60
+ env: ["CLOUDFLARE_API_TOKEN"],
61
+ description: "Cloudflare API token"
62
+ }).optional()
63
+ }),
64
+ tags: [
65
+ "cloudflare",
66
+ "cloud",
67
+ "workers",
68
+ "kv"
69
+ ]
70
+ };
71
+ }
72
+ static async load({ basePath, config } = {}) {
73
+ return new AFSCloudflare(zodParse(AFSCloudflareConfigSchema, camelize(config ?? {}), { prefix: basePath }));
74
+ }
75
+ setClient(client) {
76
+ this.cfClient.setClient(client);
77
+ }
78
+ get client() {
79
+ return this.cfClient.getClient();
80
+ }
81
+ async accountId() {
82
+ return this.cfClient.getAccountId();
83
+ }
84
+ ensureNotDestroyed() {
85
+ if (this.destroyed) throw new Error("Provider has been destroyed");
86
+ }
87
+ requireReadwrite(path) {
88
+ if (this.config.accessMode !== "readwrite") throw new AFSReadonlyError(`Read-only mode: Cannot perform write operation at ${path}`);
89
+ }
90
+ async resolveKVNamespaceId(title) {
91
+ const cacheKey = `kv:title:${title}`;
92
+ const cached = this.cache.get(cacheKey);
93
+ if (cached) return cached;
94
+ const accountId = await this.accountId();
95
+ const namespaces = this.client.kv.namespaces.list({ account_id: accountId });
96
+ for await (const ns of namespaces) if (ns.title === title) {
97
+ const id = ns.id;
98
+ this.cache.set(cacheKey, id);
99
+ return id;
100
+ }
101
+ throw new AFSNotFoundError(`KV namespace not found: ${title}`);
102
+ }
103
+ async collect(iter) {
104
+ const items = [];
105
+ for await (const item of iter) items.push(item);
106
+ return items;
107
+ }
108
+ validateAfsPath(path) {
109
+ if (!path.startsWith("/") && !path.startsWith("$afs")) throw new Error(`Invalid path: "${path}". Must be an AFS path (starting with / or $afs)`);
110
+ if (/^\/[a-zA-Z]:\//.test(path) || path.includes("..")) throw new Error(`Invalid path: "${path}". System filesystem paths are not allowed. Use an AFS mount path.`);
111
+ }
112
+ getAfsFromContext(ctx) {
113
+ const afs = ctx.options?.context?.afs;
114
+ if (!afs) throw new Error("AFS context not available. Directory operations require the AFS instance in exec context.");
115
+ return afs;
116
+ }
117
+ async readDirectoryFiles(afs, basePath) {
118
+ const files = /* @__PURE__ */ new Map();
119
+ const { data: entries } = await afs.list(basePath, { recursive: true });
120
+ for (const entry of entries) {
121
+ if (entry.meta?.kind === "directory" || entry.meta?.childrenCount !== void 0) continue;
122
+ try {
123
+ const { data } = await afs.read(entry.path);
124
+ if (data?.content !== void 0 && data?.content !== null) {
125
+ const relPath = entry.path.slice(basePath.length).replace(/^\//, "");
126
+ files.set(relPath, typeof data.content === "string" ? data.content : JSON.stringify(data.content));
127
+ }
128
+ } catch {}
129
+ }
130
+ if (files.size === 0) throw new Error(`No files found in directory: ${basePath}`);
131
+ return files;
132
+ }
133
+ detectMainModule(files) {
134
+ for (const candidate of [
135
+ "index.js",
136
+ "index.mjs",
137
+ "index.ts",
138
+ "worker.js",
139
+ "worker.mjs",
140
+ "src/index.js",
141
+ "src/index.ts"
142
+ ]) if (files.has(candidate)) return candidate;
143
+ for (const name of files.keys()) if (name.endsWith(".js") || name.endsWith(".mjs") || name.endsWith(".ts")) return name;
144
+ throw new Error("No JavaScript/TypeScript main module found in directory");
145
+ }
146
+ getContentType(filename) {
147
+ if (filename.endsWith(".html") || filename.endsWith(".htm")) return "text/html";
148
+ if (filename.endsWith(".css")) return "text/css";
149
+ if (filename.endsWith(".js") || filename.endsWith(".mjs")) return "application/javascript+module";
150
+ if (filename.endsWith(".ts")) return "application/typescript";
151
+ if (filename.endsWith(".json")) return "application/json";
152
+ if (filename.endsWith(".svg")) return "image/svg+xml";
153
+ if (filename.endsWith(".png")) return "image/png";
154
+ if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) return "image/jpeg";
155
+ if (filename.endsWith(".gif")) return "image/gif";
156
+ if (filename.endsWith(".ico")) return "image/x-icon";
157
+ if (filename.endsWith(".woff2")) return "font/woff2";
158
+ if (filename.endsWith(".woff")) return "font/woff";
159
+ if (filename.endsWith(".wasm")) return "application/wasm";
160
+ if (filename.endsWith(".xml")) return "application/xml";
161
+ if (filename.endsWith(".txt")) return "text/plain";
162
+ return "application/octet-stream";
163
+ }
164
+ async listRoot(_ctx) {
165
+ this.ensureNotDestroyed();
166
+ const accountId = await this.accountId();
167
+ const [workers, kvNamespaces, pagesProjects, zones] = await Promise.all([
168
+ this.collect(this.client.workers.scripts.list({ account_id: accountId })),
169
+ this.collect(this.client.kv.namespaces.list({ account_id: accountId })),
170
+ this.collect(this.client.pages.projects.list({ account_id: accountId })),
171
+ this.collect(this.client.zones.list())
172
+ ]);
173
+ return { data: [
174
+ {
175
+ id: "WORLD.md",
176
+ path: "/WORLD.md",
177
+ meta: {
178
+ kind: KINDS.NODE,
179
+ kinds: [KINDS.NODE],
180
+ contentType: "text/markdown"
181
+ }
182
+ },
183
+ {
184
+ id: "workers",
185
+ path: "/workers",
186
+ meta: {
187
+ kind: KINDS.NODE,
188
+ kinds: [KINDS.NODE],
189
+ childrenCount: workers.length
190
+ }
191
+ },
192
+ {
193
+ id: "kv",
194
+ path: "/kv",
195
+ meta: {
196
+ kind: KINDS.NODE,
197
+ kinds: [KINDS.NODE],
198
+ childrenCount: kvNamespaces.length
199
+ }
200
+ },
201
+ {
202
+ id: "pages",
203
+ path: "/pages",
204
+ meta: {
205
+ kind: KINDS.NODE,
206
+ kinds: [KINDS.NODE],
207
+ childrenCount: pagesProjects.length
208
+ }
209
+ },
210
+ {
211
+ id: "by-zone",
212
+ path: "/by-zone",
213
+ meta: {
214
+ kind: KINDS.NODE,
215
+ kinds: [KINDS.NODE],
216
+ childrenCount: zones.length
217
+ }
218
+ }
219
+ ] };
220
+ }
221
+ async readCapabilities(_ctx) {
222
+ return {
223
+ id: "/.meta/.capabilities",
224
+ path: "/.meta/.capabilities",
225
+ content: {
226
+ schemaVersion: 1,
227
+ provider: this.name,
228
+ description: this.description ?? "Cloudflare provider",
229
+ tools: [],
230
+ actions: [],
231
+ operations: this.getOperationsDeclaration()
232
+ },
233
+ meta: { kind: "afs:capabilities" }
234
+ };
235
+ }
236
+ async readRoot(_ctx) {
237
+ return {
238
+ id: "/",
239
+ path: "/",
240
+ content: "",
241
+ meta: {
242
+ kind: KINDS.NODE,
243
+ kinds: [KINDS.NODE],
244
+ childrenCount: 5
245
+ }
246
+ };
247
+ }
248
+ async readWorldMd(_ctx) {
249
+ this.ensureNotDestroyed();
250
+ const accountId = await this.accountId();
251
+ const cacheKey = "world-md";
252
+ const cached = this.cache.get(cacheKey);
253
+ if (cached) return {
254
+ id: "WORLD.md",
255
+ path: "/WORLD.md",
256
+ content: cached,
257
+ meta: {
258
+ kind: KINDS.NODE,
259
+ kinds: [KINDS.NODE],
260
+ contentType: "text/markdown"
261
+ }
262
+ };
263
+ const [workers, kvNamespaces, pagesProjects, zones] = await Promise.all([
264
+ this.collect(this.client.workers.scripts.list({ account_id: accountId })),
265
+ this.collect(this.client.kv.namespaces.list({ account_id: accountId })),
266
+ this.collect(this.client.pages.projects.list({ account_id: accountId })),
267
+ this.collect(this.client.zones.list())
268
+ ]);
269
+ const content = `# Cloudflare Account Overview
270
+
271
+ **Account ID**: ${accountId}
272
+
273
+ ## Resources
274
+
275
+ | Resource | Count |
276
+ |----------|-------|
277
+ | Workers | ${workers.length} |
278
+ | KV Namespaces | ${kvNamespaces.length} |
279
+ | Pages Projects | ${pagesProjects.length} |
280
+ | Zones | ${zones.length} |
281
+
282
+ ## Workers
283
+ ${workers.map((w) => `- ${w.id}`).join("\n")}
284
+
285
+ ## KV Namespaces
286
+ ${kvNamespaces.map((ns) => `- ${ns.title}`).join("\n")}
287
+
288
+ ## Pages Projects
289
+ ${pagesProjects.map((p) => `- ${p.name}`).join("\n")}
290
+
291
+ ## Zones
292
+ ${zones.map((z$1) => `- ${z$1.name}`).join("\n")}
293
+ `;
294
+ this.cache.set(cacheKey, content);
295
+ return {
296
+ id: "WORLD.md",
297
+ path: "/WORLD.md",
298
+ content,
299
+ meta: {
300
+ kind: KINDS.NODE,
301
+ kinds: [KINDS.NODE],
302
+ contentType: "text/markdown"
303
+ }
304
+ };
305
+ }
306
+ async metaRoot(_ctx) {
307
+ return {
308
+ id: "",
309
+ path: "/.meta",
310
+ meta: {
311
+ kind: KINDS.NODE,
312
+ kinds: [KINDS.NODE],
313
+ childrenCount: 5
314
+ }
315
+ };
316
+ }
317
+ async statRoot(ctx) {
318
+ if (ctx.path === "/WORLD.md" || ctx.path === "/WORLD.md/.stat") return { data: {
319
+ id: "WORLD.md",
320
+ path: "/WORLD.md",
321
+ meta: {
322
+ kind: KINDS.NODE,
323
+ kinds: [KINDS.NODE],
324
+ contentType: "text/markdown"
325
+ }
326
+ } };
327
+ return { data: {
328
+ id: "/",
329
+ path: "/",
330
+ meta: {
331
+ kind: KINDS.NODE,
332
+ kinds: [KINDS.NODE],
333
+ childrenCount: 5
334
+ }
335
+ } };
336
+ }
337
+ async explainRoot(_ctx) {
338
+ return {
339
+ format: "markdown",
340
+ content: `# Cloudflare Provider
341
+
342
+ This provider gives file-system-like access to Cloudflare Developer Platform resources.
343
+
344
+ **Account ID**: ${await this.accountId()}
345
+
346
+ ## Available Paths
347
+
348
+ - \`/workers\` — Cloudflare Workers (edge functions)
349
+ - \`/kv\` — KV Namespaces (key-value storage)
350
+ - \`/pages\` — Pages Projects (static site hosting)
351
+ - \`/by-zone\` — Resources grouped by DNS zone
352
+ - \`/WORLD.md\` — Account overview and resource statistics
353
+ `
354
+ };
355
+ }
356
+ async listFileNode(_ctx) {
357
+ return { data: [] };
358
+ }
359
+ async metaWorldMd(_ctx) {
360
+ return {
361
+ id: "WORLD.md",
362
+ path: "/WORLD.md/.meta",
363
+ meta: {
364
+ kind: KINDS.NODE,
365
+ kinds: [KINDS.NODE],
366
+ contentType: "text/markdown"
367
+ }
368
+ };
369
+ }
370
+ async metaWorkerScript(ctx) {
371
+ return {
372
+ id: "script.js",
373
+ path: joinURL("/workers", ctx.params.name, "script.js", ".meta"),
374
+ meta: {
375
+ kind: KINDS.NODE,
376
+ kinds: [KINDS.NODE],
377
+ contentType: "application/javascript"
378
+ }
379
+ };
380
+ }
381
+ async metaWorkerSettings(ctx) {
382
+ return {
383
+ id: "settings.json",
384
+ path: joinURL("/workers", ctx.params.name, "settings.json", ".meta"),
385
+ meta: {
386
+ kind: KINDS.NODE,
387
+ kinds: [KINDS.NODE],
388
+ contentType: "application/json"
389
+ }
390
+ };
391
+ }
392
+ async metaWorkerBindings(ctx) {
393
+ return {
394
+ id: "bindings",
395
+ path: joinURL("/workers", ctx.params.name, "bindings", ".meta"),
396
+ meta: {
397
+ kind: KINDS.NODE,
398
+ kinds: [KINDS.NODE]
399
+ }
400
+ };
401
+ }
402
+ async metaWorkerBinding(ctx) {
403
+ return {
404
+ id: ctx.params.binding,
405
+ path: joinURL("/workers", ctx.params.name, "bindings", ctx.params.binding, ".meta"),
406
+ meta: {
407
+ kind: KINDS.BINDING,
408
+ kinds: [KINDS.BINDING, KINDS.NODE]
409
+ }
410
+ };
411
+ }
412
+ async metaWorkerRoutes(ctx) {
413
+ return {
414
+ id: "routes",
415
+ path: joinURL("/workers", ctx.params.name, "routes", ".meta"),
416
+ meta: {
417
+ kind: KINDS.NODE,
418
+ kinds: [KINDS.NODE]
419
+ }
420
+ };
421
+ }
422
+ async metaWorkerRoute(ctx) {
423
+ return {
424
+ id: ctx.params.route,
425
+ path: joinURL("/workers", ctx.params.name, "routes", ctx.params.route, ".meta"),
426
+ meta: {
427
+ kind: KINDS.ROUTE,
428
+ kinds: [KINDS.ROUTE, KINDS.NODE]
429
+ }
430
+ };
431
+ }
432
+ async metaWorkerCronTriggers(ctx) {
433
+ return {
434
+ id: "cron-triggers",
435
+ path: joinURL("/workers", ctx.params.name, "cron-triggers", ".meta"),
436
+ meta: {
437
+ kind: KINDS.NODE,
438
+ kinds: [KINDS.NODE]
439
+ }
440
+ };
441
+ }
442
+ async metaWorkerCronTrigger(ctx) {
443
+ return {
444
+ id: ctx.params.cron,
445
+ path: joinURL("/workers", ctx.params.name, "cron-triggers", ctx.params.cron, ".meta"),
446
+ meta: {
447
+ kind: KINDS.CRON_TRIGGER,
448
+ kinds: [KINDS.CRON_TRIGGER, KINDS.NODE]
449
+ }
450
+ };
451
+ }
452
+ async metaKVMetadataFile(ctx) {
453
+ return {
454
+ id: "metadata.json",
455
+ path: joinURL("/kv", ctx.params.title, "metadata.json", ".meta"),
456
+ meta: {
457
+ kind: KINDS.NODE,
458
+ kinds: [KINDS.NODE],
459
+ contentType: "application/json"
460
+ }
461
+ };
462
+ }
463
+ async metaKVKeys(ctx) {
464
+ return {
465
+ id: "keys",
466
+ path: joinURL("/kv", ctx.params.title, "keys", ".meta"),
467
+ meta: {
468
+ kind: KINDS.NODE,
469
+ kinds: [KINDS.NODE]
470
+ }
471
+ };
472
+ }
473
+ async metaKVKey(ctx) {
474
+ return {
475
+ id: decodeURIComponent(ctx.params.key),
476
+ path: joinURL("/kv", ctx.params.title, "keys", ctx.params.key, ".meta"),
477
+ meta: {
478
+ kind: KINDS.KV_KEY,
479
+ kinds: [KINDS.KV_KEY, KINDS.NODE]
480
+ }
481
+ };
482
+ }
483
+ async metaPagesMetadataFile(ctx) {
484
+ return {
485
+ id: "metadata.json",
486
+ path: joinURL("/pages", ctx.params.project, "metadata.json", ".meta"),
487
+ meta: {
488
+ kind: KINDS.NODE,
489
+ kinds: [KINDS.NODE],
490
+ contentType: "application/json"
491
+ }
492
+ };
493
+ }
494
+ async metaPagesDeployments(ctx) {
495
+ return {
496
+ id: "deployments",
497
+ path: joinURL("/pages", ctx.params.project, "deployments", ".meta"),
498
+ meta: {
499
+ kind: KINDS.NODE,
500
+ kinds: [KINDS.NODE]
501
+ }
502
+ };
503
+ }
504
+ async metaPagesDeployment(ctx) {
505
+ return {
506
+ id: ctx.params.id,
507
+ path: joinURL("/pages", ctx.params.project, "deployments", ctx.params.id, ".meta"),
508
+ meta: {
509
+ kind: KINDS.DEPLOYMENT,
510
+ kinds: [KINDS.DEPLOYMENT, KINDS.NODE]
511
+ }
512
+ };
513
+ }
514
+ async metaPagesDomains(ctx) {
515
+ return {
516
+ id: "domains",
517
+ path: joinURL("/pages", ctx.params.project, "domains", ".meta"),
518
+ meta: {
519
+ kind: KINDS.NODE,
520
+ kinds: [KINDS.NODE]
521
+ }
522
+ };
523
+ }
524
+ async metaPagesDomain(ctx) {
525
+ return {
526
+ id: ctx.params.domain,
527
+ path: joinURL("/pages", ctx.params.project, "domains", ctx.params.domain, ".meta"),
528
+ meta: {
529
+ kind: KINDS.DOMAIN,
530
+ kinds: [KINDS.DOMAIN, KINDS.NODE]
531
+ }
532
+ };
533
+ }
534
+ async metaByZoneDir(ctx) {
535
+ return {
536
+ id: ctx.params.zone,
537
+ path: joinURL("/by-zone", ctx.params.zone, ".meta"),
538
+ meta: {
539
+ kind: KINDS.ZONE,
540
+ kinds: [KINDS.ZONE, KINDS.NODE],
541
+ childrenCount: 2
542
+ }
543
+ };
544
+ }
545
+ async metaByZoneWorkers(ctx) {
546
+ return {
547
+ id: "workers",
548
+ path: joinURL("/by-zone", ctx.params.zone, "workers", ".meta"),
549
+ meta: {
550
+ kind: KINDS.NODE,
551
+ kinds: [KINDS.NODE]
552
+ }
553
+ };
554
+ }
555
+ async metaByZoneWorker(ctx) {
556
+ return {
557
+ id: ctx.params.name,
558
+ path: joinURL("/by-zone", ctx.params.zone, "workers", ctx.params.name, ".meta"),
559
+ meta: {
560
+ kind: KINDS.WORKER,
561
+ kinds: [KINDS.WORKER, KINDS.NODE]
562
+ }
563
+ };
564
+ }
565
+ async metaByZonePages(ctx) {
566
+ return {
567
+ id: "pages",
568
+ path: joinURL("/by-zone", ctx.params.zone, "pages", ".meta"),
569
+ meta: {
570
+ kind: KINDS.NODE,
571
+ kinds: [KINDS.NODE]
572
+ }
573
+ };
574
+ }
575
+ async metaByZoneProject(ctx) {
576
+ return {
577
+ id: ctx.params.project,
578
+ path: joinURL("/by-zone", ctx.params.zone, "pages", ctx.params.project, ".meta"),
579
+ meta: {
580
+ kind: KINDS.PAGES_PROJECT,
581
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE]
582
+ }
583
+ };
584
+ }
585
+ async listGlobalActions(_ctx) {
586
+ return { data: [{
587
+ id: "refresh",
588
+ path: "/.actions/refresh",
589
+ summary: "Refresh all cached data",
590
+ meta: {
591
+ kind: KINDS.EXECUTABLE,
592
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE]
593
+ }
594
+ }] };
595
+ }
596
+ async execRefresh(_ctx, _args) {
597
+ this.ensureNotDestroyed();
598
+ this.cache.clear();
599
+ return {
600
+ success: true,
601
+ data: { message: "Cache cleared" }
602
+ };
603
+ }
604
+ async listWorkers(_ctx) {
605
+ this.ensureNotDestroyed();
606
+ const accountId = await this.accountId();
607
+ const cacheKey = "list:workers";
608
+ const cached = this.cache.get(cacheKey);
609
+ if (cached) return { data: cached };
610
+ const entries = (await this.collect(this.client.workers.scripts.list({ account_id: accountId }))).map((w) => ({
611
+ id: w.id,
612
+ path: joinURL("/workers", w.id),
613
+ summary: w.id,
614
+ meta: {
615
+ kind: KINDS.WORKER,
616
+ kinds: [KINDS.WORKER, KINDS.NODE],
617
+ childrenCount: 5
618
+ }
619
+ }));
620
+ this.cache.set(cacheKey, entries);
621
+ return { data: entries };
622
+ }
623
+ async listWorkerDir(ctx) {
624
+ this.ensureNotDestroyed();
625
+ const { name } = ctx.params;
626
+ const accountId = await this.accountId();
627
+ const basePath = joinURL("/workers", name);
628
+ const bindings = (await this.client.workers.scripts.settings.get(name, { account_id: accountId }))?.result?.bindings || [];
629
+ const triggers = (await this.client.workers.scripts.schedules.get(name, { account_id: accountId }))?.schedules || [];
630
+ const zones = await this.collect(this.client.zones.list());
631
+ let routeCount = 0;
632
+ for (const zone of zones) {
633
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zone.id }));
634
+ routeCount += routes.filter((r) => r.script === name).length;
635
+ }
636
+ return { data: [
637
+ {
638
+ id: "script.js",
639
+ path: joinURL(basePath, "script.js"),
640
+ meta: {
641
+ kind: KINDS.NODE,
642
+ kinds: [KINDS.NODE],
643
+ contentType: "application/javascript"
644
+ }
645
+ },
646
+ {
647
+ id: "settings.json",
648
+ path: joinURL(basePath, "settings.json"),
649
+ meta: {
650
+ kind: KINDS.NODE,
651
+ kinds: [KINDS.NODE],
652
+ contentType: "application/json"
653
+ }
654
+ },
655
+ {
656
+ id: "bindings",
657
+ path: joinURL(basePath, "bindings"),
658
+ meta: {
659
+ kind: KINDS.NODE,
660
+ kinds: [KINDS.NODE],
661
+ childrenCount: bindings.length
662
+ }
663
+ },
664
+ {
665
+ id: "routes",
666
+ path: joinURL(basePath, "routes"),
667
+ meta: {
668
+ kind: KINDS.NODE,
669
+ kinds: [KINDS.NODE],
670
+ childrenCount: routeCount
671
+ }
672
+ },
673
+ {
674
+ id: "cron-triggers",
675
+ path: joinURL(basePath, "cron-triggers"),
676
+ meta: {
677
+ kind: KINDS.NODE,
678
+ kinds: [KINDS.NODE],
679
+ childrenCount: triggers.length
680
+ }
681
+ }
682
+ ] };
683
+ }
684
+ async listWorkerBindings(ctx) {
685
+ this.ensureNotDestroyed();
686
+ const { name } = ctx.params;
687
+ const accountId = await this.accountId();
688
+ return { data: ((await this.client.workers.scripts.settings.get(name, { account_id: accountId }))?.result?.bindings || []).map((b) => ({
689
+ id: b.name,
690
+ path: joinURL("/workers", name, "bindings", b.name),
691
+ content: JSON.stringify(b, null, 2),
692
+ meta: {
693
+ kind: KINDS.BINDING,
694
+ kinds: [KINDS.BINDING, KINDS.NODE],
695
+ bindingType: b.type
696
+ }
697
+ })) };
698
+ }
699
+ async listWorkerRoutes(ctx) {
700
+ this.ensureNotDestroyed();
701
+ const { name } = ctx.params;
702
+ const zones = await this.collect(this.client.zones.list());
703
+ const entries = [];
704
+ for (const zone of zones) {
705
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zone.id }));
706
+ for (const route of routes) if (route.script === name) {
707
+ const pattern = route.pattern;
708
+ entries.push({
709
+ id: pattern,
710
+ path: joinURL("/workers", name, "routes", pattern),
711
+ content: JSON.stringify(route, null, 2),
712
+ meta: {
713
+ kind: KINDS.ROUTE,
714
+ kinds: [KINDS.ROUTE, KINDS.NODE],
715
+ zoneName: zone.name
716
+ }
717
+ });
718
+ }
719
+ }
720
+ return { data: entries };
721
+ }
722
+ async listWorkerCronTriggers(ctx) {
723
+ this.ensureNotDestroyed();
724
+ const { name } = ctx.params;
725
+ const accountId = await this.accountId();
726
+ return { data: ((await this.client.workers.scripts.schedules.get(name, { account_id: accountId }))?.schedules || []).map((t) => ({
727
+ id: t.cron,
728
+ path: joinURL("/workers", name, "cron-triggers", t.cron),
729
+ content: JSON.stringify(t, null, 2),
730
+ meta: {
731
+ kind: KINDS.CRON_TRIGGER,
732
+ kinds: [KINDS.CRON_TRIGGER, KINDS.NODE]
733
+ }
734
+ })) };
735
+ }
736
+ async readWorkers(_ctx) {
737
+ this.ensureNotDestroyed();
738
+ const accountId = await this.accountId();
739
+ const workers = await this.collect(this.client.workers.scripts.list({ account_id: accountId }));
740
+ return {
741
+ id: "workers",
742
+ path: "/workers",
743
+ content: "",
744
+ meta: {
745
+ kind: KINDS.NODE,
746
+ kinds: [KINDS.NODE],
747
+ childrenCount: workers.length
748
+ }
749
+ };
750
+ }
751
+ async readWorkerDir(ctx) {
752
+ return {
753
+ id: ctx.params.name,
754
+ path: joinURL("/workers", ctx.params.name),
755
+ content: "",
756
+ meta: {
757
+ kind: KINDS.WORKER,
758
+ kinds: [KINDS.WORKER, KINDS.NODE],
759
+ childrenCount: 5
760
+ }
761
+ };
762
+ }
763
+ async readWorkerBindingsDir(ctx) {
764
+ this.ensureNotDestroyed();
765
+ const { name } = ctx.params;
766
+ const accountId = await this.accountId();
767
+ const bindings = (await this.client.workers.scripts.settings.get(name, { account_id: accountId }))?.result?.bindings || [];
768
+ return {
769
+ id: "bindings",
770
+ path: joinURL("/workers", name, "bindings"),
771
+ content: "",
772
+ meta: {
773
+ kind: KINDS.NODE,
774
+ kinds: [KINDS.NODE],
775
+ childrenCount: bindings.length
776
+ }
777
+ };
778
+ }
779
+ async readWorkerRoutesDir(ctx) {
780
+ this.ensureNotDestroyed();
781
+ const { name } = ctx.params;
782
+ const zones = await this.collect(this.client.zones.list());
783
+ let routeCount = 0;
784
+ for (const zone of zones) {
785
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zone.id }));
786
+ routeCount += routes.filter((r) => r.script === name).length;
787
+ }
788
+ return {
789
+ id: "routes",
790
+ path: joinURL("/workers", name, "routes"),
791
+ content: "",
792
+ meta: {
793
+ kind: KINDS.NODE,
794
+ kinds: [KINDS.NODE],
795
+ childrenCount: routeCount
796
+ }
797
+ };
798
+ }
799
+ async readWorkerCronTriggersDir(ctx) {
800
+ this.ensureNotDestroyed();
801
+ const { name } = ctx.params;
802
+ const accountId = await this.accountId();
803
+ const triggers = (await this.client.workers.scripts.schedules.get(name, { account_id: accountId }))?.schedules || [];
804
+ return {
805
+ id: "cron-triggers",
806
+ path: joinURL("/workers", name, "cron-triggers"),
807
+ content: "",
808
+ meta: {
809
+ kind: KINDS.NODE,
810
+ kinds: [KINDS.NODE],
811
+ childrenCount: triggers.length
812
+ }
813
+ };
814
+ }
815
+ async readWorkerScript(ctx) {
816
+ this.ensureNotDestroyed();
817
+ const { name } = ctx.params;
818
+ const accountId = await this.accountId();
819
+ try {
820
+ const response = await this.client.workers.scripts.content.get(name, { account_id: accountId });
821
+ const content = response instanceof Response ? await response.text() : typeof response === "string" ? response : "";
822
+ return {
823
+ id: "script.js",
824
+ path: joinURL("/workers", name, "script.js"),
825
+ content,
826
+ meta: {
827
+ kind: KINDS.NODE,
828
+ kinds: [KINDS.NODE],
829
+ contentType: "application/javascript"
830
+ }
831
+ };
832
+ } catch (error) {
833
+ throw mapCloudflareError(error, ctx.path);
834
+ }
835
+ }
836
+ async readWorkerSettings(ctx) {
837
+ this.ensureNotDestroyed();
838
+ const { name } = ctx.params;
839
+ const accountId = await this.accountId();
840
+ try {
841
+ const settings = await this.client.workers.scripts.settings.get(name, { account_id: accountId });
842
+ const content = JSON.stringify(settings?.result || {}, null, 2);
843
+ return {
844
+ id: "settings.json",
845
+ path: joinURL("/workers", name, "settings.json"),
846
+ content,
847
+ meta: {
848
+ kind: KINDS.NODE,
849
+ kinds: [KINDS.NODE],
850
+ contentType: "application/json"
851
+ }
852
+ };
853
+ } catch (error) {
854
+ throw mapCloudflareError(error, ctx.path);
855
+ }
856
+ }
857
+ async readWorkerBinding(ctx) {
858
+ this.ensureNotDestroyed();
859
+ const { name, binding } = ctx.params;
860
+ const accountId = await this.accountId();
861
+ const found = ((await this.client.workers.scripts.settings.get(name, { account_id: accountId }))?.result?.bindings || []).find((b) => b.name === binding);
862
+ if (!found) throw new AFSNotFoundError(`Binding not found: ${binding}`);
863
+ return {
864
+ id: binding,
865
+ path: joinURL("/workers", name, "bindings", binding),
866
+ content: JSON.stringify(found, null, 2),
867
+ meta: {
868
+ kind: KINDS.BINDING,
869
+ kinds: [KINDS.BINDING, KINDS.NODE],
870
+ bindingType: found.type
871
+ }
872
+ };
873
+ }
874
+ async readWorkerRoute(ctx) {
875
+ this.ensureNotDestroyed();
876
+ const { name, route } = ctx.params;
877
+ const decodedRoute = route;
878
+ const zones = await this.collect(this.client.zones.list());
879
+ for (const zone of zones) {
880
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zone.id }));
881
+ for (const r of routes) if (r.script === name && r.pattern === decodedRoute) return {
882
+ id: decodedRoute,
883
+ path: joinURL("/workers", name, "routes", route),
884
+ content: JSON.stringify(r, null, 2),
885
+ meta: {
886
+ kind: KINDS.ROUTE,
887
+ kinds: [KINDS.ROUTE, KINDS.NODE],
888
+ zoneName: zone.name
889
+ }
890
+ };
891
+ }
892
+ throw new AFSNotFoundError(`Route not found: ${decodedRoute}`);
893
+ }
894
+ async readWorkerCronTrigger(ctx) {
895
+ this.ensureNotDestroyed();
896
+ const { name, cron } = ctx.params;
897
+ const decodedCron = cron;
898
+ const accountId = await this.accountId();
899
+ const found = ((await this.client.workers.scripts.schedules.get(name, { account_id: accountId }))?.schedules || []).find((t) => t.cron === decodedCron);
900
+ if (!found) throw new AFSNotFoundError(`Cron trigger not found: ${decodedCron}`);
901
+ return {
902
+ id: decodedCron,
903
+ path: joinURL("/workers", name, "cron-triggers", cron),
904
+ content: JSON.stringify(found, null, 2),
905
+ meta: {
906
+ kind: KINDS.CRON_TRIGGER,
907
+ kinds: [KINDS.CRON_TRIGGER, KINDS.NODE]
908
+ }
909
+ };
910
+ }
911
+ async metaWorkers(_ctx) {
912
+ return {
913
+ id: "workers",
914
+ path: "/workers/.meta",
915
+ meta: {
916
+ kind: KINDS.NODE,
917
+ kinds: [KINDS.NODE]
918
+ }
919
+ };
920
+ }
921
+ async metaWorker(ctx) {
922
+ this.ensureNotDestroyed();
923
+ const { name } = ctx.params;
924
+ const accountId = await this.accountId();
925
+ const worker = await this.client.workers.scripts.get(name, { account_id: accountId });
926
+ if (!worker) throw new AFSNotFoundError(`Worker not found: ${name}`);
927
+ const settings = await this.client.workers.scripts.settings.get(name, { account_id: accountId });
928
+ const bindings = settings?.result?.bindings || [];
929
+ const cronTriggers = (await this.client.workers.scripts.schedules.get(name, { account_id: accountId }))?.schedules || [];
930
+ const zones = await this.collect(this.client.zones.list());
931
+ let routeCount = 0;
932
+ for (const zone of zones) {
933
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zone.id }));
934
+ routeCount += routes.filter((r) => r.script === name).length;
935
+ }
936
+ return {
937
+ id: name,
938
+ path: joinURL("/workers", name, ".meta"),
939
+ meta: {
940
+ kind: KINDS.WORKER,
941
+ kinds: [KINDS.WORKER, KINDS.NODE],
942
+ childrenCount: 5,
943
+ scriptName: name,
944
+ createdOn: worker.created_on,
945
+ modifiedOn: worker.modified_on,
946
+ compatibilityDate: settings?.result?.compatibility_date,
947
+ usageModel: settings?.result?.usage_model,
948
+ routeCount,
949
+ bindingCount: bindings.length,
950
+ cronTriggerCount: cronTriggers.length,
951
+ platformRef: generateWorkerPlatformRef(accountId, name)
952
+ }
953
+ };
954
+ }
955
+ async statWorkers(ctx) {
956
+ const parts = ctx.path.replace(/\/.stat$/, "").split("/").filter(Boolean);
957
+ return { data: {
958
+ id: parts[parts.length - 1] || "workers",
959
+ path: ctx.path.replace(/\/.stat$/, ""),
960
+ meta: {
961
+ kind: KINDS.NODE,
962
+ kinds: [KINDS.NODE]
963
+ }
964
+ } };
965
+ }
966
+ async explainWorkers(_ctx) {
967
+ return {
968
+ format: "markdown",
969
+ content: `# Workers
970
+
971
+ Cloudflare Workers are serverless edge functions. Each worker contains:
972
+ - \`script.js\` — The worker source code
973
+ - \`settings.json\` — Configuration (compatibility_date, usage_model)
974
+ - \`bindings/\` — Resource bindings (KV, R2, D1, etc.)
975
+ - \`routes/\` — URL patterns that trigger this worker
976
+ - \`cron-triggers/\` — Scheduled execution patterns
977
+ `
978
+ };
979
+ }
980
+ async explainWorker(ctx) {
981
+ this.ensureNotDestroyed();
982
+ const { name } = ctx.params;
983
+ const accountId = await this.accountId();
984
+ const worker = await this.client.workers.scripts.get(name, { account_id: accountId });
985
+ if (!worker) throw new AFSNotFoundError(`Worker not found: ${name}`);
986
+ return {
987
+ format: "markdown",
988
+ content: `# Worker: ${name}
989
+
990
+ **Created**: ${worker.created_on}
991
+ **Modified**: ${worker.modified_on}
992
+
993
+ ## Structure
994
+ - \`script.js\` — Source code (read/write)
995
+ - \`settings.json\` — Configuration
996
+ - \`bindings/\` — Resource bindings
997
+ - \`routes/\` — URL route patterns
998
+ - \`cron-triggers/\` — Scheduled triggers
999
+
1000
+ ## Actions
1001
+ - \`deploy\` — Deploy latest version to production
1002
+ - \`rollback\` — Rollback to previous version
1003
+ - \`delete\` — Delete this worker (requires confirm: true)
1004
+ `
1005
+ };
1006
+ }
1007
+ async writeWorkerScript(ctx, payload) {
1008
+ this.ensureNotDestroyed();
1009
+ this.requireReadwrite(ctx.path);
1010
+ const { name } = ctx.params;
1011
+ const accountId = await this.accountId();
1012
+ const content = typeof payload.content === "string" ? payload.content : "";
1013
+ try {
1014
+ const scriptFile = new File([content], "script.js", { type: "application/javascript+module" });
1015
+ const result = await this.client.workers.scripts.update(name, {
1016
+ account_id: accountId,
1017
+ metadata: { main_module: "script.js" },
1018
+ files: { "script.js": scriptFile }
1019
+ });
1020
+ this.cache.invalidate("list:workers");
1021
+ this.cache.invalidate(`worker:${name}`);
1022
+ return { data: {
1023
+ id: "script.js",
1024
+ path: joinURL("/workers", name, "script.js"),
1025
+ content,
1026
+ meta: {
1027
+ kind: KINDS.NODE,
1028
+ kinds: [KINDS.NODE],
1029
+ contentType: "application/javascript",
1030
+ etag: result?.etag
1031
+ }
1032
+ } };
1033
+ } catch (error) {
1034
+ throw mapCloudflareError(error, ctx.path);
1035
+ }
1036
+ }
1037
+ async writeWorkerSettings(ctx, payload) {
1038
+ this.ensureNotDestroyed();
1039
+ this.requireReadwrite(ctx.path);
1040
+ const { name } = ctx.params;
1041
+ const accountId = await this.accountId();
1042
+ try {
1043
+ const settings = typeof payload.content === "string" ? JSON.parse(payload.content) : payload.content || {};
1044
+ const applied = {};
1045
+ if ("workers_dev" in settings) {
1046
+ await this.client.workers.scripts.subdomain.create(name, {
1047
+ account_id: accountId,
1048
+ enabled: !!settings.workers_dev
1049
+ });
1050
+ applied.workers_dev = !!settings.workers_dev;
1051
+ }
1052
+ this.cache.invalidate(`worker:${name}`);
1053
+ return { data: {
1054
+ id: "settings.json",
1055
+ path: joinURL("/workers", name, "settings.json"),
1056
+ content: JSON.stringify(applied, null, 2),
1057
+ meta: {
1058
+ kind: KINDS.NODE,
1059
+ kinds: [KINDS.NODE],
1060
+ contentType: "application/json"
1061
+ }
1062
+ } };
1063
+ } catch (error) {
1064
+ throw mapCloudflareError(error, ctx.path);
1065
+ }
1066
+ }
1067
+ async listRootWorkerActions(_ctx) {
1068
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
1069
+ return { data: [{
1070
+ id: "create",
1071
+ path: "/workers/.actions/create",
1072
+ summary: "Create and deploy a new worker",
1073
+ meta: {
1074
+ kind: KINDS.EXECUTABLE,
1075
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
1076
+ inputSchema: {
1077
+ type: "object",
1078
+ required: ["name"],
1079
+ properties: {
1080
+ name: {
1081
+ type: "string",
1082
+ description: "Worker name"
1083
+ },
1084
+ script: {
1085
+ type: "string",
1086
+ description: "Inline script content (for single-file workers)"
1087
+ },
1088
+ directory: {
1089
+ type: "string",
1090
+ description: "AFS directory path containing worker files (must be an AFS mount path)"
1091
+ },
1092
+ mainModule: {
1093
+ type: "string",
1094
+ description: "Main module filename (auto-detected if not provided)"
1095
+ },
1096
+ bindings: {
1097
+ type: "array",
1098
+ description: "KV/R2/etc bindings, e.g. [{\"type\":\"kv_namespace\",\"name\":\"KV\",\"namespace_id\":\"...\"}]",
1099
+ items: { type: "object" }
1100
+ },
1101
+ compatibilityDate: {
1102
+ type: "string",
1103
+ description: "Compatibility date (default: today)"
1104
+ }
1105
+ }
1106
+ }
1107
+ }
1108
+ }] };
1109
+ }
1110
+ async execWorkerCreate(ctx, args) {
1111
+ this.ensureNotDestroyed();
1112
+ this.requireReadwrite(ctx.path);
1113
+ const accountId = await this.accountId();
1114
+ const name = args.name;
1115
+ const script = args.script;
1116
+ const directory = args.directory;
1117
+ const mainModuleArg = args.mainModule;
1118
+ const rawBindings = args.bindings;
1119
+ let bindings;
1120
+ if (typeof rawBindings === "string") try {
1121
+ bindings = JSON.parse(rawBindings);
1122
+ } catch {
1123
+ return {
1124
+ success: false,
1125
+ error: {
1126
+ code: "VALIDATION_ERROR",
1127
+ message: "bindings must be valid JSON array"
1128
+ }
1129
+ };
1130
+ }
1131
+ else bindings = rawBindings;
1132
+ const compatibilityDate = args.compatibilityDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1133
+ if (!name) return {
1134
+ success: false,
1135
+ error: {
1136
+ code: "VALIDATION_ERROR",
1137
+ message: "name is required"
1138
+ }
1139
+ };
1140
+ if (!script && !directory) return {
1141
+ success: false,
1142
+ error: {
1143
+ code: "VALIDATION_ERROR",
1144
+ message: "Either script (inline content) or directory (AFS path) is required"
1145
+ }
1146
+ };
1147
+ try {
1148
+ const hasBindings = bindings && bindings.length > 0;
1149
+ let fileCount = 1;
1150
+ if (script) {
1151
+ const scriptFile = new File([script], "index.js", { type: "application/javascript+module" });
1152
+ await this.client.workers.scripts.update(name, {
1153
+ account_id: accountId,
1154
+ metadata: {
1155
+ main_module: "index.js",
1156
+ ...hasBindings ? { bindings } : {},
1157
+ compatibility_date: compatibilityDate
1158
+ },
1159
+ files: { "index.js": scriptFile }
1160
+ });
1161
+ } else if (directory) {
1162
+ this.validateAfsPath(directory);
1163
+ const afs = this.getAfsFromContext(ctx);
1164
+ const files = await this.readDirectoryFiles(afs, directory);
1165
+ const mainModule = mainModuleArg || this.detectMainModule(files);
1166
+ fileCount = files.size;
1167
+ const fileUploads = {};
1168
+ for (const [filename, content] of files) fileUploads[filename] = new File([content], filename, { type: this.getContentType(filename) });
1169
+ await this.client.workers.scripts.update(name, {
1170
+ account_id: accountId,
1171
+ metadata: {
1172
+ main_module: mainModule,
1173
+ ...hasBindings ? { bindings } : {},
1174
+ compatibility_date: compatibilityDate
1175
+ },
1176
+ files: fileUploads
1177
+ });
1178
+ }
1179
+ try {
1180
+ await this.client.workers.scripts.subdomain.create(name, {
1181
+ account_id: accountId,
1182
+ enabled: true
1183
+ });
1184
+ } catch {}
1185
+ this.cache.invalidate("list:workers");
1186
+ this.cache.invalidate(`worker:${name}`);
1187
+ return {
1188
+ success: true,
1189
+ data: {
1190
+ name,
1191
+ type: script ? "single-file" : "directory",
1192
+ fileCount
1193
+ }
1194
+ };
1195
+ } catch (error) {
1196
+ throw mapCloudflareError(error, ctx.path);
1197
+ }
1198
+ }
1199
+ async listWorkerActions(ctx) {
1200
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
1201
+ const basePath = joinURL("/workers", ctx.params.name, ".actions");
1202
+ return { data: [
1203
+ {
1204
+ id: "deploy",
1205
+ path: joinURL(basePath, "deploy"),
1206
+ summary: "Deploy version to production",
1207
+ meta: {
1208
+ kind: KINDS.EXECUTABLE,
1209
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE]
1210
+ }
1211
+ },
1212
+ {
1213
+ id: "rollback",
1214
+ path: joinURL(basePath, "rollback"),
1215
+ summary: "Rollback to previous version",
1216
+ meta: {
1217
+ kind: KINDS.EXECUTABLE,
1218
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE]
1219
+ }
1220
+ },
1221
+ {
1222
+ id: "delete",
1223
+ path: joinURL(basePath, "delete"),
1224
+ summary: "Delete worker (requires confirm: true)",
1225
+ meta: {
1226
+ kind: KINDS.EXECUTABLE,
1227
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
1228
+ inputSchema: {
1229
+ type: "object",
1230
+ required: ["confirm"],
1231
+ properties: { confirm: {
1232
+ type: "boolean",
1233
+ description: "Must be true to confirm deletion"
1234
+ } }
1235
+ }
1236
+ }
1237
+ }
1238
+ ] };
1239
+ }
1240
+ async execWorkerDeploy(ctx, args) {
1241
+ this.ensureNotDestroyed();
1242
+ this.requireReadwrite(ctx.path);
1243
+ const { name } = ctx.params;
1244
+ const accountId = await this.accountId();
1245
+ try {
1246
+ const directory = args.directory;
1247
+ if (directory) {
1248
+ this.validateAfsPath(directory);
1249
+ const afs = this.getAfsFromContext(ctx);
1250
+ const files = await this.readDirectoryFiles(afs, directory);
1251
+ const mainModule = args.mainModule || this.detectMainModule(files);
1252
+ const fileUploads = {};
1253
+ for (const [filename, content] of files) fileUploads[filename] = new File([content], filename, { type: this.getContentType(filename) });
1254
+ await this.client.workers.scripts.update(name, {
1255
+ account_id: accountId,
1256
+ metadata: { main_module: mainModule },
1257
+ files: fileUploads
1258
+ });
1259
+ }
1260
+ let versionId = args.versionId;
1261
+ if (!versionId) {
1262
+ const versions$1 = await this.collect(this.client.workers.scripts.versions.list(name, { account_id: accountId }));
1263
+ if (versions$1.length > 0) versionId = versions$1[0].id;
1264
+ }
1265
+ const versions = versionId ? [{
1266
+ version_id: versionId,
1267
+ percentage: 100
1268
+ }] : [];
1269
+ const deployment = await this.client.workers.scripts.deployments.create(name, {
1270
+ account_id: accountId,
1271
+ strategy: "percentage",
1272
+ versions
1273
+ });
1274
+ this.cache.invalidate("list:workers");
1275
+ this.cache.invalidate(`worker:${name}`);
1276
+ return {
1277
+ success: true,
1278
+ data: {
1279
+ deploymentId: deployment?.id,
1280
+ versionId
1281
+ }
1282
+ };
1283
+ } catch (error) {
1284
+ throw mapCloudflareError(error, ctx.path);
1285
+ }
1286
+ }
1287
+ async execWorkerRollback(ctx, _args) {
1288
+ this.ensureNotDestroyed();
1289
+ this.requireReadwrite(ctx.path);
1290
+ const { name } = ctx.params;
1291
+ const accountId = await this.accountId();
1292
+ try {
1293
+ const versions = await this.collect(this.client.workers.scripts.versions.list(name, { account_id: accountId }));
1294
+ if (versions.length < 2) return {
1295
+ success: false,
1296
+ error: {
1297
+ code: "NO_PREVIOUS_VERSION",
1298
+ message: "No previous version to rollback to"
1299
+ }
1300
+ };
1301
+ const previousVersionId = versions[1].id;
1302
+ const deployment = await this.client.workers.scripts.deployments.create(name, {
1303
+ account_id: accountId,
1304
+ strategy: "percentage",
1305
+ versions: [{
1306
+ version_id: previousVersionId,
1307
+ percentage: 100
1308
+ }]
1309
+ });
1310
+ this.cache.invalidate("list:workers");
1311
+ this.cache.invalidate(`worker:${name}`);
1312
+ return {
1313
+ success: true,
1314
+ data: {
1315
+ deploymentId: deployment?.id,
1316
+ versionId: previousVersionId
1317
+ }
1318
+ };
1319
+ } catch (error) {
1320
+ throw mapCloudflareError(error, ctx.path);
1321
+ }
1322
+ }
1323
+ async execWorkerDelete(ctx, args) {
1324
+ this.ensureNotDestroyed();
1325
+ this.requireReadwrite(ctx.path);
1326
+ if (args.confirm !== true) throw confirmationRequired("delete", ctx.path);
1327
+ const { name } = ctx.params;
1328
+ const accountId = await this.accountId();
1329
+ try {
1330
+ await this.client.workers.scripts.delete(name, { account_id: accountId });
1331
+ this.cache.invalidate("list:workers");
1332
+ this.cache.invalidate(`worker:${name}`);
1333
+ return {
1334
+ success: true,
1335
+ data: { deleted: name }
1336
+ };
1337
+ } catch (error) {
1338
+ throw mapCloudflareError(error, ctx.path);
1339
+ }
1340
+ }
1341
+ async searchWorkers(_ctx, query, options) {
1342
+ this.ensureNotDestroyed();
1343
+ const accountId = await this.accountId();
1344
+ const matched = (await this.collect(this.client.workers.scripts.list({ account_id: accountId }))).filter((w) => minimatch(w.id, query));
1345
+ const limit = options?.limit ?? 100;
1346
+ return { data: matched.slice(0, limit).map((w) => ({
1347
+ id: w.id,
1348
+ path: joinURL("/workers", w.id),
1349
+ summary: w.id,
1350
+ meta: {
1351
+ kind: KINDS.WORKER,
1352
+ kinds: [KINDS.WORKER, KINDS.NODE]
1353
+ }
1354
+ })) };
1355
+ }
1356
+ async listKV(_ctx) {
1357
+ this.ensureNotDestroyed();
1358
+ const accountId = await this.accountId();
1359
+ const cacheKey = "list:kv";
1360
+ const cached = this.cache.get(cacheKey);
1361
+ if (cached) return { data: cached };
1362
+ const entries = (await this.collect(this.client.kv.namespaces.list({ account_id: accountId }))).map((ns) => ({
1363
+ id: ns.title,
1364
+ path: joinURL("/kv", ns.title),
1365
+ summary: ns.title,
1366
+ meta: {
1367
+ kind: KINDS.KV_NAMESPACE,
1368
+ kinds: [KINDS.KV_NAMESPACE, KINDS.NODE],
1369
+ childrenCount: 2
1370
+ }
1371
+ }));
1372
+ this.cache.set(cacheKey, entries);
1373
+ return { data: entries };
1374
+ }
1375
+ async listKVNamespaceDir(ctx) {
1376
+ this.ensureNotDestroyed();
1377
+ const { title } = ctx.params;
1378
+ const accountId = await this.accountId();
1379
+ const namespaceId = await this.resolveKVNamespaceId(title);
1380
+ const basePath = joinURL("/kv", title);
1381
+ const keys = await this.collect(this.client.kv.namespaces.keys.list(namespaceId, { account_id: accountId }));
1382
+ return { data: [{
1383
+ id: "metadata.json",
1384
+ path: joinURL(basePath, "metadata.json"),
1385
+ meta: {
1386
+ kind: KINDS.NODE,
1387
+ kinds: [KINDS.NODE],
1388
+ contentType: "application/json"
1389
+ }
1390
+ }, {
1391
+ id: "keys",
1392
+ path: joinURL(basePath, "keys"),
1393
+ meta: {
1394
+ kind: KINDS.NODE,
1395
+ kinds: [KINDS.NODE],
1396
+ childrenCount: keys.length
1397
+ }
1398
+ }] };
1399
+ }
1400
+ async listKVKeys(ctx) {
1401
+ this.ensureNotDestroyed();
1402
+ const { title } = ctx.params;
1403
+ const accountId = await this.accountId();
1404
+ const namespaceId = await this.resolveKVNamespaceId(title);
1405
+ return { data: (await this.collect(this.client.kv.namespaces.keys.list(namespaceId, { account_id: accountId }))).map((k) => ({
1406
+ id: k.name,
1407
+ path: joinURL("/kv", title, "keys", k.name),
1408
+ meta: {
1409
+ kind: KINDS.KV_KEY,
1410
+ kinds: [KINDS.KV_KEY, KINDS.NODE]
1411
+ }
1412
+ })) };
1413
+ }
1414
+ async readKV(_ctx) {
1415
+ this.ensureNotDestroyed();
1416
+ const accountId = await this.accountId();
1417
+ const namespaces = await this.collect(this.client.kv.namespaces.list({ account_id: accountId }));
1418
+ return {
1419
+ id: "kv",
1420
+ path: "/kv",
1421
+ content: "",
1422
+ meta: {
1423
+ kind: KINDS.NODE,
1424
+ kinds: [KINDS.NODE],
1425
+ childrenCount: namespaces.length
1426
+ }
1427
+ };
1428
+ }
1429
+ async readKVNamespaceDir(ctx) {
1430
+ return {
1431
+ id: ctx.params.title,
1432
+ path: joinURL("/kv", ctx.params.title),
1433
+ content: "",
1434
+ meta: {
1435
+ kind: KINDS.KV_NAMESPACE,
1436
+ kinds: [KINDS.KV_NAMESPACE, KINDS.NODE],
1437
+ childrenCount: 2
1438
+ }
1439
+ };
1440
+ }
1441
+ async readKVMetadata(ctx) {
1442
+ this.ensureNotDestroyed();
1443
+ const { title } = ctx.params;
1444
+ const namespaceId = await this.resolveKVNamespaceId(title);
1445
+ const content = JSON.stringify({
1446
+ id: namespaceId,
1447
+ title
1448
+ }, null, 2);
1449
+ return {
1450
+ id: "metadata.json",
1451
+ path: joinURL("/kv", title, "metadata.json"),
1452
+ content,
1453
+ meta: {
1454
+ kind: KINDS.NODE,
1455
+ kinds: [KINDS.NODE],
1456
+ contentType: "application/json"
1457
+ }
1458
+ };
1459
+ }
1460
+ async readKVKeysDir(ctx) {
1461
+ this.ensureNotDestroyed();
1462
+ const { title } = ctx.params;
1463
+ const accountId = await this.accountId();
1464
+ const namespaceId = await this.resolveKVNamespaceId(title);
1465
+ const keys = await this.collect(this.client.kv.namespaces.keys.list(namespaceId, { account_id: accountId }));
1466
+ return {
1467
+ id: "keys",
1468
+ path: joinURL("/kv", title, "keys"),
1469
+ content: "",
1470
+ meta: {
1471
+ kind: KINDS.NODE,
1472
+ kinds: [KINDS.NODE],
1473
+ childrenCount: keys.length
1474
+ }
1475
+ };
1476
+ }
1477
+ async readKVKey(ctx) {
1478
+ this.ensureNotDestroyed();
1479
+ const { title, key } = ctx.params;
1480
+ const accountId = await this.accountId();
1481
+ const namespaceId = await this.resolveKVNamespaceId(title);
1482
+ const decodedKey = key;
1483
+ try {
1484
+ const response = await this.client.kv.namespaces.values.get(namespaceId, decodedKey, { account_id: accountId });
1485
+ if (!response) throw new AFSNotFoundError(`KV key not found: ${decodedKey}`);
1486
+ const content = response instanceof Response ? await response.text() : typeof response === "string" ? response : String(response);
1487
+ return {
1488
+ id: decodedKey,
1489
+ path: joinURL("/kv", title, "keys", key),
1490
+ content,
1491
+ meta: {
1492
+ kind: KINDS.KV_KEY,
1493
+ kinds: [KINDS.KV_KEY, KINDS.NODE]
1494
+ }
1495
+ };
1496
+ } catch (error) {
1497
+ if (error instanceof AFSNotFoundError) throw error;
1498
+ throw mapCloudflareError(error, ctx.path);
1499
+ }
1500
+ }
1501
+ async metaKV(_ctx) {
1502
+ return {
1503
+ id: "kv",
1504
+ path: "/kv/.meta",
1505
+ meta: {
1506
+ kind: KINDS.NODE,
1507
+ kinds: [KINDS.NODE]
1508
+ }
1509
+ };
1510
+ }
1511
+ async metaKVNamespace(ctx) {
1512
+ this.ensureNotDestroyed();
1513
+ const { title } = ctx.params;
1514
+ const accountId = await this.accountId();
1515
+ const namespaceId = await this.resolveKVNamespaceId(title);
1516
+ return {
1517
+ id: title,
1518
+ path: joinURL("/kv", title, ".meta"),
1519
+ meta: {
1520
+ kind: KINDS.KV_NAMESPACE,
1521
+ kinds: [KINDS.KV_NAMESPACE, KINDS.NODE],
1522
+ childrenCount: 2,
1523
+ namespaceId,
1524
+ title,
1525
+ platformRef: generateKVPlatformRef(accountId, namespaceId)
1526
+ }
1527
+ };
1528
+ }
1529
+ async statKV(ctx) {
1530
+ const parts = ctx.path.replace(/\/.stat$/, "").split("/").filter(Boolean);
1531
+ return { data: {
1532
+ id: parts[parts.length - 1] || "kv",
1533
+ path: ctx.path.replace(/\/.stat$/, ""),
1534
+ meta: {
1535
+ kind: KINDS.NODE,
1536
+ kinds: [KINDS.NODE]
1537
+ }
1538
+ } };
1539
+ }
1540
+ async explainKV(_ctx) {
1541
+ return {
1542
+ format: "markdown",
1543
+ content: `# KV Namespaces
1544
+
1545
+ Cloudflare KV is a global, low-latency key-value data store. Each namespace contains:
1546
+ - \`metadata.json\` — Namespace configuration
1547
+ - \`keys/\` — Key-value pairs (read/write/delete)
1548
+ `
1549
+ };
1550
+ }
1551
+ async explainKVNamespace(ctx) {
1552
+ return {
1553
+ format: "markdown",
1554
+ content: `# KV Namespace: ${ctx.params.title}
1555
+
1556
+ ## Structure
1557
+ - \`metadata.json\` — Namespace metadata
1558
+ - \`keys/\` — All key-value pairs
1559
+
1560
+ ## Actions
1561
+ - \`delete\` — Delete this namespace (requires confirm: true)
1562
+ `
1563
+ };
1564
+ }
1565
+ async writeKVKey(ctx, payload) {
1566
+ this.ensureNotDestroyed();
1567
+ this.requireReadwrite(ctx.path);
1568
+ const { title, key } = ctx.params;
1569
+ const accountId = await this.accountId();
1570
+ const namespaceId = await this.resolveKVNamespaceId(title);
1571
+ const decodedKey = key;
1572
+ const content = typeof payload.content === "string" ? payload.content : JSON.stringify(payload.content);
1573
+ try {
1574
+ await this.client.kv.namespaces.values.update(namespaceId, decodedKey, {
1575
+ account_id: accountId,
1576
+ value: content
1577
+ });
1578
+ this.cache.invalidate(`list:kv:${title}`);
1579
+ return { data: {
1580
+ id: decodedKey,
1581
+ path: joinURL("/kv", title, "keys", key),
1582
+ content,
1583
+ meta: {
1584
+ kind: KINDS.KV_KEY,
1585
+ kinds: [KINDS.KV_KEY, KINDS.NODE]
1586
+ }
1587
+ } };
1588
+ } catch (error) {
1589
+ throw mapCloudflareError(error, ctx.path);
1590
+ }
1591
+ }
1592
+ async deleteKVKey(ctx) {
1593
+ this.ensureNotDestroyed();
1594
+ this.requireReadwrite(ctx.path);
1595
+ const { title, key } = ctx.params;
1596
+ const accountId = await this.accountId();
1597
+ const namespaceId = await this.resolveKVNamespaceId(title);
1598
+ const decodedKey = key;
1599
+ try {
1600
+ await this.client.kv.namespaces.values.delete(namespaceId, decodedKey, { account_id: accountId });
1601
+ this.cache.invalidate(`list:kv:${title}`);
1602
+ return { message: `Key '${decodedKey}' deleted` };
1603
+ } catch (error) {
1604
+ throw mapCloudflareError(error, ctx.path);
1605
+ }
1606
+ }
1607
+ async listRootKVActions(_ctx) {
1608
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
1609
+ return { data: [{
1610
+ id: "create",
1611
+ path: "/kv/.actions/create",
1612
+ summary: "Create a new KV namespace",
1613
+ meta: {
1614
+ kind: KINDS.EXECUTABLE,
1615
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
1616
+ inputSchema: {
1617
+ type: "object",
1618
+ required: ["title"],
1619
+ properties: { title: {
1620
+ type: "string",
1621
+ description: "Namespace title"
1622
+ } }
1623
+ }
1624
+ }
1625
+ }] };
1626
+ }
1627
+ async execKVCreate(ctx, args) {
1628
+ this.ensureNotDestroyed();
1629
+ this.requireReadwrite(ctx.path);
1630
+ const accountId = await this.accountId();
1631
+ const title = args.title;
1632
+ if (!title) return {
1633
+ success: false,
1634
+ error: {
1635
+ code: "VALIDATION_ERROR",
1636
+ message: "title is required"
1637
+ }
1638
+ };
1639
+ try {
1640
+ const namespace = await this.client.kv.namespaces.create({
1641
+ account_id: accountId,
1642
+ title
1643
+ });
1644
+ this.cache.invalidate("list:kv");
1645
+ return {
1646
+ success: true,
1647
+ data: {
1648
+ id: namespace.id,
1649
+ title: namespace.title
1650
+ }
1651
+ };
1652
+ } catch (error) {
1653
+ throw mapCloudflareError(error, ctx.path);
1654
+ }
1655
+ }
1656
+ async listKVActions(ctx) {
1657
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
1658
+ return { data: [{
1659
+ id: "delete",
1660
+ path: joinURL(joinURL("/kv", ctx.params.title, ".actions"), "delete"),
1661
+ summary: "Delete namespace (requires confirm: true)",
1662
+ meta: {
1663
+ kind: KINDS.EXECUTABLE,
1664
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
1665
+ inputSchema: {
1666
+ type: "object",
1667
+ required: ["confirm"],
1668
+ properties: { confirm: {
1669
+ type: "boolean",
1670
+ description: "Must be true to confirm deletion"
1671
+ } }
1672
+ }
1673
+ }
1674
+ }] };
1675
+ }
1676
+ async execKVDelete(ctx, args) {
1677
+ this.ensureNotDestroyed();
1678
+ this.requireReadwrite(ctx.path);
1679
+ if (args.confirm !== true) throw confirmationRequired("delete", ctx.path);
1680
+ const { title } = ctx.params;
1681
+ const accountId = await this.accountId();
1682
+ const namespaceId = await this.resolveKVNamespaceId(title);
1683
+ try {
1684
+ await this.client.kv.namespaces.delete(namespaceId, { account_id: accountId });
1685
+ this.cache.invalidate("list:kv");
1686
+ this.cache.invalidate(`kv:title:${title}`);
1687
+ return {
1688
+ success: true,
1689
+ data: { deleted: title }
1690
+ };
1691
+ } catch (error) {
1692
+ throw mapCloudflareError(error, ctx.path);
1693
+ }
1694
+ }
1695
+ async searchKV(_ctx, query, options) {
1696
+ this.ensureNotDestroyed();
1697
+ const accountId = await this.accountId();
1698
+ const matched = (await this.collect(this.client.kv.namespaces.list({ account_id: accountId }))).filter((ns) => minimatch(ns.title, query));
1699
+ const limit = options?.limit ?? 100;
1700
+ return { data: matched.slice(0, limit).map((ns) => ({
1701
+ id: ns.title,
1702
+ path: joinURL("/kv", ns.title),
1703
+ summary: ns.title,
1704
+ meta: {
1705
+ kind: KINDS.KV_NAMESPACE,
1706
+ kinds: [KINDS.KV_NAMESPACE, KINDS.NODE]
1707
+ }
1708
+ })) };
1709
+ }
1710
+ async listPages(_ctx) {
1711
+ this.ensureNotDestroyed();
1712
+ const accountId = await this.accountId();
1713
+ const cacheKey = "list:pages";
1714
+ const cached = this.cache.get(cacheKey);
1715
+ if (cached) return { data: cached };
1716
+ const entries = (await this.collect(this.client.pages.projects.list({ account_id: accountId }))).map((p) => ({
1717
+ id: p.name,
1718
+ path: joinURL("/pages", p.name),
1719
+ summary: p.name,
1720
+ meta: {
1721
+ kind: KINDS.PAGES_PROJECT,
1722
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE],
1723
+ childrenCount: 3
1724
+ }
1725
+ }));
1726
+ this.cache.set(cacheKey, entries);
1727
+ return { data: entries };
1728
+ }
1729
+ async listPagesProjectDir(ctx) {
1730
+ this.ensureNotDestroyed();
1731
+ const { project } = ctx.params;
1732
+ const accountId = await this.accountId();
1733
+ const basePath = joinURL("/pages", project);
1734
+ const [deployments, domains] = await Promise.all([this.collect(this.client.pages.projects.deployments.list(project, { account_id: accountId })), this.collect(this.client.pages.projects.domains.list(project, { account_id: accountId }))]);
1735
+ return { data: [
1736
+ {
1737
+ id: "metadata.json",
1738
+ path: joinURL(basePath, "metadata.json"),
1739
+ meta: {
1740
+ kind: KINDS.NODE,
1741
+ kinds: [KINDS.NODE],
1742
+ contentType: "application/json"
1743
+ }
1744
+ },
1745
+ {
1746
+ id: "deployments",
1747
+ path: joinURL(basePath, "deployments"),
1748
+ meta: {
1749
+ kind: KINDS.NODE,
1750
+ kinds: [KINDS.NODE],
1751
+ childrenCount: deployments.length
1752
+ }
1753
+ },
1754
+ {
1755
+ id: "domains",
1756
+ path: joinURL(basePath, "domains"),
1757
+ meta: {
1758
+ kind: KINDS.NODE,
1759
+ kinds: [KINDS.NODE],
1760
+ childrenCount: domains.length
1761
+ }
1762
+ }
1763
+ ] };
1764
+ }
1765
+ async listPagesDeployments(ctx) {
1766
+ this.ensureNotDestroyed();
1767
+ const { project } = ctx.params;
1768
+ const accountId = await this.accountId();
1769
+ return { data: (await this.collect(this.client.pages.projects.deployments.list(project, { account_id: accountId }))).map((d) => ({
1770
+ id: d.id,
1771
+ path: joinURL("/pages", project, "deployments", d.id),
1772
+ summary: `${d.environment} - ${d.created_on}`,
1773
+ meta: {
1774
+ kind: KINDS.DEPLOYMENT,
1775
+ kinds: [KINDS.DEPLOYMENT, KINDS.NODE]
1776
+ }
1777
+ })) };
1778
+ }
1779
+ async listPagesDomains(ctx) {
1780
+ this.ensureNotDestroyed();
1781
+ const { project } = ctx.params;
1782
+ const accountId = await this.accountId();
1783
+ return { data: (await this.collect(this.client.pages.projects.domains.list(project, { account_id: accountId }))).map((d) => ({
1784
+ id: d.name,
1785
+ path: joinURL("/pages", project, "domains", d.name),
1786
+ content: JSON.stringify(d, null, 2),
1787
+ meta: {
1788
+ kind: KINDS.DOMAIN,
1789
+ kinds: [KINDS.DOMAIN, KINDS.NODE]
1790
+ }
1791
+ })) };
1792
+ }
1793
+ async readPages(_ctx) {
1794
+ this.ensureNotDestroyed();
1795
+ const accountId = await this.accountId();
1796
+ const projects = await this.collect(this.client.pages.projects.list({ account_id: accountId }));
1797
+ return {
1798
+ id: "pages",
1799
+ path: "/pages",
1800
+ content: "",
1801
+ meta: {
1802
+ kind: KINDS.NODE,
1803
+ kinds: [KINDS.NODE],
1804
+ childrenCount: projects.length
1805
+ }
1806
+ };
1807
+ }
1808
+ async readPagesProjectDir(ctx) {
1809
+ return {
1810
+ id: ctx.params.project,
1811
+ path: joinURL("/pages", ctx.params.project),
1812
+ content: "",
1813
+ meta: {
1814
+ kind: KINDS.PAGES_PROJECT,
1815
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE],
1816
+ childrenCount: 3
1817
+ }
1818
+ };
1819
+ }
1820
+ async readPagesMetadata(ctx) {
1821
+ this.ensureNotDestroyed();
1822
+ const { project } = ctx.params;
1823
+ const accountId = await this.accountId();
1824
+ const projectData = await this.client.pages.projects.get(project, { account_id: accountId });
1825
+ if (!projectData) throw new AFSNotFoundError(`Pages project not found: ${project}`);
1826
+ const content = JSON.stringify(projectData, null, 2);
1827
+ return {
1828
+ id: "metadata.json",
1829
+ path: joinURL("/pages", project, "metadata.json"),
1830
+ content,
1831
+ meta: {
1832
+ kind: KINDS.NODE,
1833
+ kinds: [KINDS.NODE],
1834
+ contentType: "application/json"
1835
+ }
1836
+ };
1837
+ }
1838
+ async readPagesDeploymentsDir(ctx) {
1839
+ this.ensureNotDestroyed();
1840
+ const { project } = ctx.params;
1841
+ const accountId = await this.accountId();
1842
+ const deployments = await this.collect(this.client.pages.projects.deployments.list(project, { account_id: accountId }));
1843
+ return {
1844
+ id: "deployments",
1845
+ path: joinURL("/pages", project, "deployments"),
1846
+ content: "",
1847
+ meta: {
1848
+ kind: KINDS.NODE,
1849
+ kinds: [KINDS.NODE],
1850
+ childrenCount: deployments.length
1851
+ }
1852
+ };
1853
+ }
1854
+ async readPagesDeployment(ctx) {
1855
+ this.ensureNotDestroyed();
1856
+ const { project, id } = ctx.params;
1857
+ const accountId = await this.accountId();
1858
+ const deployment = await this.client.pages.projects.deployments.get(project, id, { account_id: accountId });
1859
+ if (!deployment) throw new AFSNotFoundError(`Deployment not found: ${id}`);
1860
+ return {
1861
+ id,
1862
+ path: joinURL("/pages", project, "deployments", id),
1863
+ content: JSON.stringify(deployment, null, 2),
1864
+ meta: {
1865
+ kind: KINDS.DEPLOYMENT,
1866
+ kinds: [KINDS.DEPLOYMENT, KINDS.NODE]
1867
+ }
1868
+ };
1869
+ }
1870
+ async readPagesDomainsDir(ctx) {
1871
+ this.ensureNotDestroyed();
1872
+ const { project } = ctx.params;
1873
+ const accountId = await this.accountId();
1874
+ const domains = await this.collect(this.client.pages.projects.domains.list(project, { account_id: accountId }));
1875
+ return {
1876
+ id: "domains",
1877
+ path: joinURL("/pages", project, "domains"),
1878
+ content: "",
1879
+ meta: {
1880
+ kind: KINDS.NODE,
1881
+ kinds: [KINDS.NODE],
1882
+ childrenCount: domains.length
1883
+ }
1884
+ };
1885
+ }
1886
+ async readPagesDomain(ctx) {
1887
+ this.ensureNotDestroyed();
1888
+ const { project, domain } = ctx.params;
1889
+ const accountId = await this.accountId();
1890
+ const found = (await this.collect(this.client.pages.projects.domains.list(project, { account_id: accountId }))).find((d) => d.name === domain);
1891
+ if (!found) throw new AFSNotFoundError(`Domain not found: ${domain}`);
1892
+ return {
1893
+ id: domain,
1894
+ path: joinURL("/pages", project, "domains", domain),
1895
+ content: JSON.stringify(found, null, 2),
1896
+ meta: {
1897
+ kind: KINDS.DOMAIN,
1898
+ kinds: [KINDS.DOMAIN, KINDS.NODE]
1899
+ }
1900
+ };
1901
+ }
1902
+ async metaPages(_ctx) {
1903
+ return {
1904
+ id: "pages",
1905
+ path: "/pages/.meta",
1906
+ meta: {
1907
+ kind: KINDS.NODE,
1908
+ kinds: [KINDS.NODE]
1909
+ }
1910
+ };
1911
+ }
1912
+ async metaPagesProject(ctx) {
1913
+ this.ensureNotDestroyed();
1914
+ const { project } = ctx.params;
1915
+ const accountId = await this.accountId();
1916
+ const projectData = await this.client.pages.projects.get(project, { account_id: accountId });
1917
+ if (!projectData) throw new AFSNotFoundError(`Pages project not found: ${project}`);
1918
+ const domains = await this.collect(this.client.pages.projects.domains.list(project, { account_id: accountId }));
1919
+ return {
1920
+ id: project,
1921
+ path: joinURL("/pages", project, ".meta"),
1922
+ meta: {
1923
+ kind: KINDS.PAGES_PROJECT,
1924
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE],
1925
+ childrenCount: 3,
1926
+ projectName: project,
1927
+ subdomain: projectData.subdomain,
1928
+ productionBranch: projectData.production_branch,
1929
+ latestDeployment: projectData.latest_deployment ? {
1930
+ id: projectData.latest_deployment.id,
1931
+ url: projectData.latest_deployment.url,
1932
+ environment: projectData.latest_deployment.environment,
1933
+ createdOn: projectData.latest_deployment.created_on
1934
+ } : void 0,
1935
+ domainCount: domains.length,
1936
+ platformRef: generatePagesPlatformRef(accountId, project)
1937
+ }
1938
+ };
1939
+ }
1940
+ async statPages(ctx) {
1941
+ const parts = ctx.path.replace(/\/.stat$/, "").split("/").filter(Boolean);
1942
+ return { data: {
1943
+ id: parts[parts.length - 1] || "pages",
1944
+ path: ctx.path.replace(/\/.stat$/, ""),
1945
+ meta: {
1946
+ kind: KINDS.NODE,
1947
+ kinds: [KINDS.NODE]
1948
+ }
1949
+ } };
1950
+ }
1951
+ async explainPages(_ctx) {
1952
+ return {
1953
+ format: "markdown",
1954
+ content: `# Pages Projects
1955
+
1956
+ Cloudflare Pages provides static site hosting with CI/CD. Each project contains:
1957
+ - \`metadata.json\` — Project configuration
1958
+ - \`deployments/\` — Deployment history
1959
+ - \`domains/\` — Custom domains
1960
+ `
1961
+ };
1962
+ }
1963
+ async explainPagesProject(ctx) {
1964
+ return {
1965
+ format: "markdown",
1966
+ content: `# Pages Project: ${ctx.params.project}
1967
+
1968
+ ## Structure
1969
+ - \`metadata.json\` — Project metadata
1970
+ - \`deployments/\` — Deployment history
1971
+ - \`domains/\` — Custom domain mappings
1972
+
1973
+ ## Actions
1974
+ - \`deploy\` — Deploy new version
1975
+ - \`rollback\` — Rollback to a specific deployment
1976
+ - \`delete\` — Delete project (requires confirm: true)
1977
+ `
1978
+ };
1979
+ }
1980
+ async listRootPagesActions(_ctx) {
1981
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
1982
+ return { data: [{
1983
+ id: "create",
1984
+ path: "/pages/.actions/create",
1985
+ summary: "Create a new Pages project and deploy files",
1986
+ meta: {
1987
+ kind: KINDS.EXECUTABLE,
1988
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
1989
+ inputSchema: {
1990
+ type: "object",
1991
+ required: ["name", "directory"],
1992
+ properties: {
1993
+ name: {
1994
+ type: "string",
1995
+ description: "Project name"
1996
+ },
1997
+ directory: {
1998
+ type: "string",
1999
+ description: "AFS directory path containing static files to deploy"
2000
+ },
2001
+ productionBranch: {
2002
+ type: "string",
2003
+ description: "Production branch name (default: \"main\")"
2004
+ }
2005
+ }
2006
+ }
2007
+ }
2008
+ }] };
2009
+ }
2010
+ async execPagesCreate(ctx, args) {
2011
+ this.ensureNotDestroyed();
2012
+ this.requireReadwrite(ctx.path);
2013
+ const accountId = await this.accountId();
2014
+ const name = args.name;
2015
+ const directory = args.directory;
2016
+ const productionBranch = args.productionBranch || "main";
2017
+ if (!name) return {
2018
+ success: false,
2019
+ error: {
2020
+ code: "VALIDATION_ERROR",
2021
+ message: "name is required"
2022
+ }
2023
+ };
2024
+ if (!directory) return {
2025
+ success: false,
2026
+ error: {
2027
+ code: "VALIDATION_ERROR",
2028
+ message: "directory (AFS path) is required"
2029
+ }
2030
+ };
2031
+ this.validateAfsPath(directory);
2032
+ const afs = this.getAfsFromContext(ctx);
2033
+ try {
2034
+ await this.client.pages.projects.create({
2035
+ account_id: accountId,
2036
+ name,
2037
+ production_branch: productionBranch
2038
+ });
2039
+ const deployment = await this.uploadPagesFiles(name, afs, directory);
2040
+ this.cache.invalidate("list:pages");
2041
+ return {
2042
+ success: true,
2043
+ data: {
2044
+ name,
2045
+ deploymentId: deployment.id,
2046
+ url: deployment.url
2047
+ }
2048
+ };
2049
+ } catch (error) {
2050
+ throw mapCloudflareError(error, ctx.path);
2051
+ }
2052
+ }
2053
+ /**
2054
+ * Upload files to a Pages project via the Direct Upload API.
2055
+ *
2056
+ * Follows the same multi-step flow as wrangler:
2057
+ * 1. Read files from AFS directory
2058
+ * 2. Hash each file with BLAKE3 (base64Content + extension, truncated to 32 hex chars)
2059
+ * 3. Get upload JWT token
2060
+ * 4. Check which files are missing (deduplication)
2061
+ * 5. Upload missing files as JSON with base64 content
2062
+ * 6. Upsert all hashes
2063
+ * 7. Create deployment with manifest
2064
+ */
2065
+ async uploadPagesFiles(projectName, afs, directory) {
2066
+ const accountId = await this.accountId();
2067
+ const apiToken = this.config.apiToken || process.env.CLOUDFLARE_API_TOKEN;
2068
+ if (!apiToken) throw new Error("API token is required for Pages Direct Upload. Set apiToken in config or CLOUDFLARE_API_TOKEN env var.");
2069
+ const baseUrl = "https://api.cloudflare.com/client/v4";
2070
+ const files = await this.readDirectoryFiles(afs, directory);
2071
+ let workerScript;
2072
+ const staticFiles = /* @__PURE__ */ new Map();
2073
+ for (const [filePath, content] of files) if (filePath === "_worker.js") workerScript = content;
2074
+ else staticFiles.set(filePath, content);
2075
+ const { hash: blake3hash } = await import("blake3-wasm");
2076
+ const manifest = {};
2077
+ const uploadEntries = [];
2078
+ for (const [filePath, content] of staticFiles) {
2079
+ const base64Content = Buffer.from(content, "utf-8").toString("base64");
2080
+ const hash = blake3hash(base64Content + (filePath.includes(".") ? filePath.split(".").pop() : "")).toString("hex").slice(0, 32);
2081
+ manifest[`/${filePath}`] = hash;
2082
+ uploadEntries.push({
2083
+ key: hash,
2084
+ value: base64Content,
2085
+ metadata: { contentType: this.getContentType(filePath) },
2086
+ base64: true
2087
+ });
2088
+ }
2089
+ const tokenRes = await fetch(`${baseUrl}/accounts/${accountId}/pages/projects/${projectName}/upload-token`, { headers: { Authorization: `Bearer ${apiToken}` } });
2090
+ if (!tokenRes.ok) throw new Error(`Failed to get upload token: ${tokenRes.status} ${await tokenRes.text()}`);
2091
+ const jwt = (await tokenRes.json()).result?.jwt;
2092
+ if (!jwt) throw new Error("Failed to get upload JWT from Cloudflare");
2093
+ const allHashes = uploadEntries.map((e) => e.key);
2094
+ const checkRes = await fetch(`${baseUrl}/pages/assets/check-missing`, {
2095
+ method: "POST",
2096
+ headers: {
2097
+ Authorization: `Bearer ${jwt}`,
2098
+ "Content-Type": "application/json"
2099
+ },
2100
+ body: JSON.stringify({ hashes: allHashes })
2101
+ });
2102
+ if (!checkRes.ok) throw new Error(`Failed to check missing assets: ${checkRes.status} ${await checkRes.text()}`);
2103
+ const missingHashes = new Set((await checkRes.json()).result || []);
2104
+ const toUpload = uploadEntries.filter((e) => missingHashes.has(e.key));
2105
+ if (toUpload.length > 0) {
2106
+ const uploadRes = await fetch(`${baseUrl}/pages/assets/upload`, {
2107
+ method: "POST",
2108
+ headers: {
2109
+ Authorization: `Bearer ${jwt}`,
2110
+ "Content-Type": "application/json"
2111
+ },
2112
+ body: JSON.stringify(toUpload)
2113
+ });
2114
+ if (!uploadRes.ok) throw new Error(`Failed to upload files: ${uploadRes.status} ${await uploadRes.text()}`);
2115
+ }
2116
+ const upsertRes = await fetch(`${baseUrl}/pages/assets/upsert-hashes`, {
2117
+ method: "POST",
2118
+ headers: {
2119
+ Authorization: `Bearer ${jwt}`,
2120
+ "Content-Type": "application/json"
2121
+ },
2122
+ body: JSON.stringify({ hashes: allHashes })
2123
+ });
2124
+ if (!upsertRes.ok) throw new Error(`Failed to upsert hashes: ${upsertRes.status} ${await upsertRes.text()}`);
2125
+ const formData = new FormData();
2126
+ formData.append("manifest", JSON.stringify(manifest));
2127
+ if (workerScript) formData.append("_worker.js", new Blob([workerScript], { type: "application/javascript+module" }), "_worker.js");
2128
+ const deployRes = await fetch(`${baseUrl}/accounts/${accountId}/pages/projects/${projectName}/deployments`, {
2129
+ method: "POST",
2130
+ headers: { Authorization: `Bearer ${apiToken}` },
2131
+ body: formData
2132
+ });
2133
+ if (!deployRes.ok) throw new Error(`Failed to create deployment: ${deployRes.status} ${await deployRes.text()}`);
2134
+ const { result } = await deployRes.json();
2135
+ return {
2136
+ id: result?.id || "unknown",
2137
+ url: result?.url || `https://${projectName}.pages.dev`
2138
+ };
2139
+ }
2140
+ async listPagesActions(ctx) {
2141
+ if (this.config.accessMode !== "readwrite") throw new AFSNotFoundError("Actions not available in readonly mode");
2142
+ const basePath = joinURL("/pages", ctx.params.project, ".actions");
2143
+ return { data: [
2144
+ {
2145
+ id: "deploy",
2146
+ path: joinURL(basePath, "deploy"),
2147
+ summary: "Deploy new version",
2148
+ meta: {
2149
+ kind: KINDS.EXECUTABLE,
2150
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE]
2151
+ }
2152
+ },
2153
+ {
2154
+ id: "rollback",
2155
+ path: joinURL(basePath, "rollback"),
2156
+ summary: "Rollback to specific deployment",
2157
+ meta: {
2158
+ kind: KINDS.EXECUTABLE,
2159
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE]
2160
+ }
2161
+ },
2162
+ {
2163
+ id: "delete",
2164
+ path: joinURL(basePath, "delete"),
2165
+ summary: "Delete project (requires confirm: true)",
2166
+ meta: {
2167
+ kind: KINDS.EXECUTABLE,
2168
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
2169
+ inputSchema: {
2170
+ type: "object",
2171
+ required: ["confirm"],
2172
+ properties: { confirm: {
2173
+ type: "boolean",
2174
+ description: "Must be true to confirm deletion"
2175
+ } }
2176
+ }
2177
+ }
2178
+ },
2179
+ {
2180
+ id: "configure-bindings",
2181
+ path: joinURL(basePath, "configure-bindings"),
2182
+ summary: "Configure Pages Functions bindings (KV, D1, R2, etc.)",
2183
+ meta: {
2184
+ kind: KINDS.EXECUTABLE,
2185
+ kinds: [KINDS.EXECUTABLE, KINDS.NODE],
2186
+ inputSchema: {
2187
+ type: "object",
2188
+ properties: {
2189
+ environment: {
2190
+ type: "string",
2191
+ description: "Environment to configure (default: production)"
2192
+ },
2193
+ kv_namespaces: {
2194
+ type: "object",
2195
+ description: "KV namespace bindings, e.g. {\"KV\":{\"namespace_id\":\"...\"}}"
2196
+ },
2197
+ d1_databases: {
2198
+ type: "object",
2199
+ description: "D1 database bindings, e.g. {\"DB\":{\"id\":\"...\"}}"
2200
+ },
2201
+ r2_buckets: {
2202
+ type: "object",
2203
+ description: "R2 bucket bindings, e.g. {\"BUCKET\":{\"name\":\"...\"}}"
2204
+ },
2205
+ compatibility_date: {
2206
+ type: "string",
2207
+ description: "Compatibility date for Pages Functions"
2208
+ }
2209
+ }
2210
+ }
2211
+ }
2212
+ }
2213
+ ] };
2214
+ }
2215
+ async execPagesDeploy(ctx, args) {
2216
+ this.ensureNotDestroyed();
2217
+ this.requireReadwrite(ctx.path);
2218
+ const { project } = ctx.params;
2219
+ const accountId = await this.accountId();
2220
+ try {
2221
+ const directory = args.directory;
2222
+ if (directory) {
2223
+ this.validateAfsPath(directory);
2224
+ const afs = this.getAfsFromContext(ctx);
2225
+ const deployment$1 = await this.uploadPagesFiles(project, afs, directory);
2226
+ this.cache.invalidate("list:pages");
2227
+ return {
2228
+ success: true,
2229
+ data: {
2230
+ deploymentId: deployment$1.id,
2231
+ url: deployment$1.url
2232
+ }
2233
+ };
2234
+ }
2235
+ const deployment = await this.client.pages.projects.deployments.create(project, { account_id: accountId });
2236
+ this.cache.invalidate("list:pages");
2237
+ return {
2238
+ success: true,
2239
+ data: {
2240
+ deploymentId: deployment?.id,
2241
+ url: deployment?.url
2242
+ }
2243
+ };
2244
+ } catch (error) {
2245
+ throw mapCloudflareError(error, ctx.path);
2246
+ }
2247
+ }
2248
+ async execPagesRollback(ctx, args) {
2249
+ this.ensureNotDestroyed();
2250
+ this.requireReadwrite(ctx.path);
2251
+ const { project } = ctx.params;
2252
+ const accountId = await this.accountId();
2253
+ const deploymentId = args.deploymentId;
2254
+ try {
2255
+ const deployment = await this.client.pages.projects.deployments.create(project, { account_id: accountId });
2256
+ this.cache.invalidate("list:pages");
2257
+ return {
2258
+ success: true,
2259
+ data: {
2260
+ deploymentId: deployment?.id,
2261
+ rolledBackTo: deploymentId
2262
+ }
2263
+ };
2264
+ } catch (error) {
2265
+ throw mapCloudflareError(error, ctx.path);
2266
+ }
2267
+ }
2268
+ async execPagesDelete(ctx, args) {
2269
+ this.ensureNotDestroyed();
2270
+ this.requireReadwrite(ctx.path);
2271
+ if (args.confirm !== true) throw confirmationRequired("delete", ctx.path);
2272
+ const { project } = ctx.params;
2273
+ const accountId = await this.accountId();
2274
+ try {
2275
+ await this.client.pages.projects.delete(project, { account_id: accountId });
2276
+ this.cache.invalidate("list:pages");
2277
+ return {
2278
+ success: true,
2279
+ data: { deleted: project }
2280
+ };
2281
+ } catch (error) {
2282
+ throw mapCloudflareError(error, ctx.path);
2283
+ }
2284
+ }
2285
+ async execPagesConfigureBindings(ctx, args) {
2286
+ this.ensureNotDestroyed();
2287
+ this.requireReadwrite(ctx.path);
2288
+ const { project } = ctx.params;
2289
+ const accountId = await this.accountId();
2290
+ const environment = args.environment || "production";
2291
+ const envConfig = {};
2292
+ if (args.kv_namespaces) envConfig.kv_namespaces = args.kv_namespaces;
2293
+ if (args.d1_databases) envConfig.d1_databases = args.d1_databases;
2294
+ if (args.r2_buckets) envConfig.r2_buckets = args.r2_buckets;
2295
+ if (args.compatibility_date) envConfig.compatibility_date = args.compatibility_date;
2296
+ try {
2297
+ await this.client.pages.projects.edit(project, {
2298
+ account_id: accountId,
2299
+ deployment_configs: { [environment]: envConfig }
2300
+ });
2301
+ this.cache.invalidate("list:pages");
2302
+ return {
2303
+ success: true,
2304
+ data: {
2305
+ project,
2306
+ environment,
2307
+ bindings: Object.keys(envConfig)
2308
+ }
2309
+ };
2310
+ } catch (error) {
2311
+ throw mapCloudflareError(error, ctx.path);
2312
+ }
2313
+ }
2314
+ async searchPages(_ctx, query, options) {
2315
+ this.ensureNotDestroyed();
2316
+ const accountId = await this.accountId();
2317
+ const matched = (await this.collect(this.client.pages.projects.list({ account_id: accountId }))).filter((p) => minimatch(p.name, query));
2318
+ const limit = options?.limit ?? 100;
2319
+ return { data: matched.slice(0, limit).map((p) => ({
2320
+ id: p.name,
2321
+ path: joinURL("/pages", p.name),
2322
+ summary: p.name,
2323
+ meta: {
2324
+ kind: KINDS.PAGES_PROJECT,
2325
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE]
2326
+ }
2327
+ })) };
2328
+ }
2329
+ async listByZone(_ctx) {
2330
+ this.ensureNotDestroyed();
2331
+ const cacheKey = "list:by-zone";
2332
+ const cached = this.cache.get(cacheKey);
2333
+ if (cached) return { data: cached };
2334
+ const entries = (await this.collect(this.client.zones.list())).map((z$1) => ({
2335
+ id: z$1.name,
2336
+ path: joinURL("/by-zone", z$1.name),
2337
+ summary: z$1.name,
2338
+ meta: {
2339
+ kind: KINDS.ZONE,
2340
+ kinds: [KINDS.ZONE, KINDS.NODE],
2341
+ childrenCount: 2
2342
+ }
2343
+ }));
2344
+ this.cache.set(cacheKey, entries);
2345
+ return { data: entries };
2346
+ }
2347
+ async listByZoneDir(ctx) {
2348
+ this.ensureNotDestroyed();
2349
+ const { zone } = ctx.params;
2350
+ const accountId = await this.accountId();
2351
+ const basePath = joinURL("/by-zone", zone);
2352
+ const zoneData = (await this.collect(this.client.zones.list())).find((z$1) => z$1.name === zone);
2353
+ let workerCount = 0;
2354
+ if (zoneData) {
2355
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zoneData.id }));
2356
+ workerCount = [...new Set(routes.map((r) => r.script).filter(Boolean))].length;
2357
+ }
2358
+ const projects = await this.collect(this.client.pages.projects.list({ account_id: accountId }));
2359
+ let pagesCount = 0;
2360
+ for (const project of projects) if ((await this.collect(this.client.pages.projects.domains.list(project.name, { account_id: accountId }))).some((d) => d.name.endsWith(zone))) pagesCount++;
2361
+ return { data: [{
2362
+ id: "workers",
2363
+ path: joinURL(basePath, "workers"),
2364
+ meta: {
2365
+ kind: KINDS.NODE,
2366
+ kinds: [KINDS.NODE],
2367
+ childrenCount: workerCount
2368
+ }
2369
+ }, {
2370
+ id: "pages",
2371
+ path: joinURL(basePath, "pages"),
2372
+ meta: {
2373
+ kind: KINDS.NODE,
2374
+ kinds: [KINDS.NODE],
2375
+ childrenCount: pagesCount
2376
+ }
2377
+ }] };
2378
+ }
2379
+ async listByZoneWorkers(ctx) {
2380
+ this.ensureNotDestroyed();
2381
+ const { zone } = ctx.params;
2382
+ const zoneData = (await this.collect(this.client.zones.list())).find((z$1) => z$1.name === zone);
2383
+ if (!zoneData) throw new AFSNotFoundError(`Zone not found: ${zone}`);
2384
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zoneData.id }));
2385
+ return { data: [...new Set(routes.map((r) => r.script).filter(Boolean))].map((name) => ({
2386
+ id: name,
2387
+ path: joinURL("/by-zone", zone, "workers", name),
2388
+ meta: {
2389
+ kind: KINDS.WORKER,
2390
+ kinds: [KINDS.WORKER, KINDS.NODE]
2391
+ }
2392
+ })) };
2393
+ }
2394
+ async listByZonePages(ctx) {
2395
+ this.ensureNotDestroyed();
2396
+ const { zone } = ctx.params;
2397
+ const accountId = await this.accountId();
2398
+ const projects = await this.collect(this.client.pages.projects.list({ account_id: accountId }));
2399
+ const matchingProjects = [];
2400
+ for (const project of projects) if ((await this.collect(this.client.pages.projects.domains.list(project.name, { account_id: accountId }))).some((d) => d.name.endsWith(zone))) matchingProjects.push({
2401
+ id: project.name,
2402
+ path: joinURL("/by-zone", zone, "pages", project.name),
2403
+ meta: {
2404
+ kind: KINDS.PAGES_PROJECT,
2405
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE]
2406
+ }
2407
+ });
2408
+ return { data: matchingProjects };
2409
+ }
2410
+ async readByZone(_ctx) {
2411
+ this.ensureNotDestroyed();
2412
+ const zones = await this.collect(this.client.zones.list());
2413
+ return {
2414
+ id: "by-zone",
2415
+ path: "/by-zone",
2416
+ content: "",
2417
+ meta: {
2418
+ kind: KINDS.NODE,
2419
+ kinds: [KINDS.NODE],
2420
+ childrenCount: zones.length
2421
+ }
2422
+ };
2423
+ }
2424
+ async readByZoneDir(ctx) {
2425
+ return {
2426
+ id: ctx.params.zone,
2427
+ path: joinURL("/by-zone", ctx.params.zone),
2428
+ content: "",
2429
+ meta: {
2430
+ kind: KINDS.ZONE,
2431
+ kinds: [KINDS.ZONE, KINDS.NODE],
2432
+ childrenCount: 2
2433
+ }
2434
+ };
2435
+ }
2436
+ async readByZoneWorkersDir(ctx) {
2437
+ this.ensureNotDestroyed();
2438
+ const { zone } = ctx.params;
2439
+ const zoneData = (await this.collect(this.client.zones.list())).find((z$1) => z$1.name === zone);
2440
+ if (!zoneData) throw new AFSNotFoundError(`Zone not found: ${zone}`);
2441
+ const routes = await this.collect(this.client.workers.routes.list({ zone_id: zoneData.id }));
2442
+ const workerNames = [...new Set(routes.map((r) => r.script).filter(Boolean))];
2443
+ return {
2444
+ id: "workers",
2445
+ path: joinURL("/by-zone", zone, "workers"),
2446
+ content: "",
2447
+ meta: {
2448
+ kind: KINDS.NODE,
2449
+ kinds: [KINDS.NODE],
2450
+ childrenCount: workerNames.length
2451
+ }
2452
+ };
2453
+ }
2454
+ async readByZoneWorker(ctx) {
2455
+ return {
2456
+ id: ctx.params.name,
2457
+ path: joinURL("/by-zone", ctx.params.zone, "workers", ctx.params.name),
2458
+ content: "",
2459
+ meta: {
2460
+ kind: KINDS.WORKER,
2461
+ kinds: [KINDS.WORKER, KINDS.NODE]
2462
+ }
2463
+ };
2464
+ }
2465
+ async readByZonePagesDir(ctx) {
2466
+ this.ensureNotDestroyed();
2467
+ const { zone } = ctx.params;
2468
+ const accountId = await this.accountId();
2469
+ const projects = await this.collect(this.client.pages.projects.list({ account_id: accountId }));
2470
+ let matchCount = 0;
2471
+ for (const project of projects) if ((await this.collect(this.client.pages.projects.domains.list(project.name, { account_id: accountId }))).some((d) => d.name.endsWith(zone))) matchCount++;
2472
+ return {
2473
+ id: "pages",
2474
+ path: joinURL("/by-zone", zone, "pages"),
2475
+ content: "",
2476
+ meta: {
2477
+ kind: KINDS.NODE,
2478
+ kinds: [KINDS.NODE],
2479
+ childrenCount: matchCount
2480
+ }
2481
+ };
2482
+ }
2483
+ async readByZoneProject(ctx) {
2484
+ return {
2485
+ id: ctx.params.project,
2486
+ path: joinURL("/by-zone", ctx.params.zone, "pages", ctx.params.project),
2487
+ content: "",
2488
+ meta: {
2489
+ kind: KINDS.PAGES_PROJECT,
2490
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE]
2491
+ }
2492
+ };
2493
+ }
2494
+ async metaByZone(_ctx) {
2495
+ return {
2496
+ id: "by-zone",
2497
+ path: "/by-zone/.meta",
2498
+ meta: {
2499
+ kind: KINDS.NODE,
2500
+ kinds: [KINDS.NODE]
2501
+ }
2502
+ };
2503
+ }
2504
+ async statByZone(ctx) {
2505
+ const parts = ctx.path.replace(/\/.stat$/, "").split("/").filter(Boolean);
2506
+ return { data: {
2507
+ id: parts[parts.length - 1] || "by-zone",
2508
+ path: ctx.path.replace(/\/.stat$/, ""),
2509
+ meta: {
2510
+ kind: KINDS.NODE,
2511
+ kinds: [KINDS.NODE]
2512
+ }
2513
+ } };
2514
+ }
2515
+ async explainByZone(_ctx) {
2516
+ return {
2517
+ format: "markdown",
2518
+ content: `# By Zone
2519
+
2520
+ Resources grouped by DNS zone. Workers are associated through route bindings, Pages through custom domains.
2521
+ `
2522
+ };
2523
+ }
2524
+ async searchRoot(_ctx, query, options) {
2525
+ this.ensureNotDestroyed();
2526
+ const accountId = await this.accountId();
2527
+ const limit = options?.limit ?? 100;
2528
+ const results = [];
2529
+ const [workers, kvNamespaces, pagesProjects] = await Promise.all([
2530
+ this.collect(this.client.workers.scripts.list({ account_id: accountId })),
2531
+ this.collect(this.client.kv.namespaces.list({ account_id: accountId })),
2532
+ this.collect(this.client.pages.projects.list({ account_id: accountId }))
2533
+ ]);
2534
+ for (const w of workers) if (minimatch(w.id, query) && results.length < limit) results.push({
2535
+ id: w.id,
2536
+ path: joinURL("/workers", w.id),
2537
+ summary: w.id,
2538
+ meta: {
2539
+ kind: KINDS.WORKER,
2540
+ kinds: [KINDS.WORKER, KINDS.NODE]
2541
+ }
2542
+ });
2543
+ for (const ns of kvNamespaces) if (minimatch(ns.title, query) && results.length < limit) results.push({
2544
+ id: ns.title,
2545
+ path: joinURL("/kv", ns.title),
2546
+ summary: ns.title,
2547
+ meta: {
2548
+ kind: KINDS.KV_NAMESPACE,
2549
+ kinds: [KINDS.KV_NAMESPACE, KINDS.NODE]
2550
+ }
2551
+ });
2552
+ for (const p of pagesProjects) if (minimatch(p.name, query) && results.length < limit) results.push({
2553
+ id: p.name,
2554
+ path: joinURL("/pages", p.name),
2555
+ summary: p.name,
2556
+ meta: {
2557
+ kind: KINDS.PAGES_PROJECT,
2558
+ kinds: [KINDS.PAGES_PROJECT, KINDS.NODE]
2559
+ }
2560
+ });
2561
+ return { data: results };
2562
+ }
2563
+ async deleteCatchAll(ctx) {
2564
+ this.ensureNotDestroyed();
2565
+ this.requireReadwrite(ctx.path);
2566
+ throw new AFSNotFoundError(`Cannot delete: ${ctx.path}`);
2567
+ }
2568
+ async destroy() {
2569
+ if (this.destroyed) return;
2570
+ this.destroyed = true;
2571
+ await this.cfClient.destroy();
2572
+ this.cache.clear();
2573
+ }
2574
+ clearCache() {
2575
+ this.cache.clear();
2576
+ }
2577
+ toJSON() {
2578
+ return {
2579
+ name: this.name,
2580
+ description: this.description,
2581
+ accessMode: this.accessMode,
2582
+ accountId: this.config.accountId
2583
+ };
2584
+ }
2585
+ };
2586
+ __decorate([List("/")], AFSCloudflare.prototype, "listRoot", null);
2587
+ __decorate([Read("/.meta/.capabilities")], AFSCloudflare.prototype, "readCapabilities", null);
2588
+ __decorate([Read("/")], AFSCloudflare.prototype, "readRoot", null);
2589
+ __decorate([Read("/WORLD.md")], AFSCloudflare.prototype, "readWorldMd", null);
2590
+ __decorate([Meta("/")], AFSCloudflare.prototype, "metaRoot", null);
2591
+ __decorate([Stat("/"), Stat("/WORLD.md")], AFSCloudflare.prototype, "statRoot", null);
2592
+ __decorate([Explain("/")], AFSCloudflare.prototype, "explainRoot", null);
2593
+ __decorate([
2594
+ List("/WORLD.md"),
2595
+ List("/workers/:name/script.js"),
2596
+ List("/workers/:name/settings.json"),
2597
+ List("/workers/:name/bindings/:binding"),
2598
+ List("/workers/:name/routes/:route+"),
2599
+ List("/workers/:name/cron-triggers/:cron+"),
2600
+ List("/kv/:title/metadata.json"),
2601
+ List("/kv/:title/keys/:key+"),
2602
+ List("/pages/:project/metadata.json"),
2603
+ List("/pages/:project/deployments/:id"),
2604
+ List("/pages/:project/domains/:domain"),
2605
+ List("/by-zone/:zone/workers/:name"),
2606
+ List("/by-zone/:zone/pages/:project")
2607
+ ], AFSCloudflare.prototype, "listFileNode", null);
2608
+ __decorate([Meta("/WORLD.md")], AFSCloudflare.prototype, "metaWorldMd", null);
2609
+ __decorate([Meta("/workers/:name/script.js")], AFSCloudflare.prototype, "metaWorkerScript", null);
2610
+ __decorate([Meta("/workers/:name/settings.json")], AFSCloudflare.prototype, "metaWorkerSettings", null);
2611
+ __decorate([Meta("/workers/:name/bindings")], AFSCloudflare.prototype, "metaWorkerBindings", null);
2612
+ __decorate([Meta("/workers/:name/bindings/:binding")], AFSCloudflare.prototype, "metaWorkerBinding", null);
2613
+ __decorate([Meta("/workers/:name/routes")], AFSCloudflare.prototype, "metaWorkerRoutes", null);
2614
+ __decorate([Meta("/workers/:name/routes/:route+")], AFSCloudflare.prototype, "metaWorkerRoute", null);
2615
+ __decorate([Meta("/workers/:name/cron-triggers")], AFSCloudflare.prototype, "metaWorkerCronTriggers", null);
2616
+ __decorate([Meta("/workers/:name/cron-triggers/:cron+")], AFSCloudflare.prototype, "metaWorkerCronTrigger", null);
2617
+ __decorate([Meta("/kv/:title/metadata.json")], AFSCloudflare.prototype, "metaKVMetadataFile", null);
2618
+ __decorate([Meta("/kv/:title/keys")], AFSCloudflare.prototype, "metaKVKeys", null);
2619
+ __decorate([Meta("/kv/:title/keys/:key+")], AFSCloudflare.prototype, "metaKVKey", null);
2620
+ __decorate([Meta("/pages/:project/metadata.json")], AFSCloudflare.prototype, "metaPagesMetadataFile", null);
2621
+ __decorate([Meta("/pages/:project/deployments")], AFSCloudflare.prototype, "metaPagesDeployments", null);
2622
+ __decorate([Meta("/pages/:project/deployments/:id")], AFSCloudflare.prototype, "metaPagesDeployment", null);
2623
+ __decorate([Meta("/pages/:project/domains")], AFSCloudflare.prototype, "metaPagesDomains", null);
2624
+ __decorate([Meta("/pages/:project/domains/:domain")], AFSCloudflare.prototype, "metaPagesDomain", null);
2625
+ __decorate([Meta("/by-zone/:zone")], AFSCloudflare.prototype, "metaByZoneDir", null);
2626
+ __decorate([Meta("/by-zone/:zone/workers")], AFSCloudflare.prototype, "metaByZoneWorkers", null);
2627
+ __decorate([Meta("/by-zone/:zone/workers/:name")], AFSCloudflare.prototype, "metaByZoneWorker", null);
2628
+ __decorate([Meta("/by-zone/:zone/pages")], AFSCloudflare.prototype, "metaByZonePages", null);
2629
+ __decorate([Meta("/by-zone/:zone/pages/:project")], AFSCloudflare.prototype, "metaByZoneProject", null);
2630
+ __decorate([Actions("")], AFSCloudflare.prototype, "listGlobalActions", null);
2631
+ __decorate([Actions.Exec("", "refresh")], AFSCloudflare.prototype, "execRefresh", null);
2632
+ __decorate([List("/workers")], AFSCloudflare.prototype, "listWorkers", null);
2633
+ __decorate([List("/workers/:name")], AFSCloudflare.prototype, "listWorkerDir", null);
2634
+ __decorate([List("/workers/:name/bindings")], AFSCloudflare.prototype, "listWorkerBindings", null);
2635
+ __decorate([List("/workers/:name/routes")], AFSCloudflare.prototype, "listWorkerRoutes", null);
2636
+ __decorate([List("/workers/:name/cron-triggers")], AFSCloudflare.prototype, "listWorkerCronTriggers", null);
2637
+ __decorate([Read("/workers")], AFSCloudflare.prototype, "readWorkers", null);
2638
+ __decorate([Read("/workers/:name")], AFSCloudflare.prototype, "readWorkerDir", null);
2639
+ __decorate([Read("/workers/:name/bindings")], AFSCloudflare.prototype, "readWorkerBindingsDir", null);
2640
+ __decorate([Read("/workers/:name/routes")], AFSCloudflare.prototype, "readWorkerRoutesDir", null);
2641
+ __decorate([Read("/workers/:name/cron-triggers")], AFSCloudflare.prototype, "readWorkerCronTriggersDir", null);
2642
+ __decorate([Read("/workers/:name/script.js")], AFSCloudflare.prototype, "readWorkerScript", null);
2643
+ __decorate([Read("/workers/:name/settings.json")], AFSCloudflare.prototype, "readWorkerSettings", null);
2644
+ __decorate([Read("/workers/:name/bindings/:binding")], AFSCloudflare.prototype, "readWorkerBinding", null);
2645
+ __decorate([Read("/workers/:name/routes/:route+")], AFSCloudflare.prototype, "readWorkerRoute", null);
2646
+ __decorate([Read("/workers/:name/cron-triggers/:cron+")], AFSCloudflare.prototype, "readWorkerCronTrigger", null);
2647
+ __decorate([Meta("/workers")], AFSCloudflare.prototype, "metaWorkers", null);
2648
+ __decorate([Meta("/workers/:name")], AFSCloudflare.prototype, "metaWorker", null);
2649
+ __decorate([
2650
+ Stat("/workers"),
2651
+ Stat("/workers/:name"),
2652
+ Stat("/workers/:name/script.js"),
2653
+ Stat("/workers/:name/settings.json"),
2654
+ Stat("/workers/:name/bindings"),
2655
+ Stat("/workers/:name/bindings/:binding"),
2656
+ Stat("/workers/:name/routes"),
2657
+ Stat("/workers/:name/routes/:route+"),
2658
+ Stat("/workers/:name/cron-triggers"),
2659
+ Stat("/workers/:name/cron-triggers/:cron+")
2660
+ ], AFSCloudflare.prototype, "statWorkers", null);
2661
+ __decorate([Explain("/workers")], AFSCloudflare.prototype, "explainWorkers", null);
2662
+ __decorate([Explain("/workers/:name")], AFSCloudflare.prototype, "explainWorker", null);
2663
+ __decorate([Write("/workers/:name/script.js")], AFSCloudflare.prototype, "writeWorkerScript", null);
2664
+ __decorate([Write("/workers/:name/settings.json")], AFSCloudflare.prototype, "writeWorkerSettings", null);
2665
+ __decorate([Actions("/workers")], AFSCloudflare.prototype, "listRootWorkerActions", null);
2666
+ __decorate([Actions.Exec("/workers", "create")], AFSCloudflare.prototype, "execWorkerCreate", null);
2667
+ __decorate([Actions("/workers/:name")], AFSCloudflare.prototype, "listWorkerActions", null);
2668
+ __decorate([Actions.Exec("/workers/:name", "deploy")], AFSCloudflare.prototype, "execWorkerDeploy", null);
2669
+ __decorate([Actions.Exec("/workers/:name", "rollback")], AFSCloudflare.prototype, "execWorkerRollback", null);
2670
+ __decorate([Actions.Exec("/workers/:name", "delete")], AFSCloudflare.prototype, "execWorkerDelete", null);
2671
+ __decorate([Search("/workers")], AFSCloudflare.prototype, "searchWorkers", null);
2672
+ __decorate([List("/kv")], AFSCloudflare.prototype, "listKV", null);
2673
+ __decorate([List("/kv/:title")], AFSCloudflare.prototype, "listKVNamespaceDir", null);
2674
+ __decorate([List("/kv/:title/keys")], AFSCloudflare.prototype, "listKVKeys", null);
2675
+ __decorate([Read("/kv")], AFSCloudflare.prototype, "readKV", null);
2676
+ __decorate([Read("/kv/:title")], AFSCloudflare.prototype, "readKVNamespaceDir", null);
2677
+ __decorate([Read("/kv/:title/metadata.json")], AFSCloudflare.prototype, "readKVMetadata", null);
2678
+ __decorate([Read("/kv/:title/keys")], AFSCloudflare.prototype, "readKVKeysDir", null);
2679
+ __decorate([Read("/kv/:title/keys/:key+")], AFSCloudflare.prototype, "readKVKey", null);
2680
+ __decorate([Meta("/kv")], AFSCloudflare.prototype, "metaKV", null);
2681
+ __decorate([Meta("/kv/:title")], AFSCloudflare.prototype, "metaKVNamespace", null);
2682
+ __decorate([
2683
+ Stat("/kv"),
2684
+ Stat("/kv/:title"),
2685
+ Stat("/kv/:title/metadata.json"),
2686
+ Stat("/kv/:title/keys"),
2687
+ Stat("/kv/:title/keys/:key+")
2688
+ ], AFSCloudflare.prototype, "statKV", null);
2689
+ __decorate([Explain("/kv")], AFSCloudflare.prototype, "explainKV", null);
2690
+ __decorate([Explain("/kv/:title")], AFSCloudflare.prototype, "explainKVNamespace", null);
2691
+ __decorate([Write("/kv/:title/keys/:key+")], AFSCloudflare.prototype, "writeKVKey", null);
2692
+ __decorate([Delete("/kv/:title/keys/:key+")], AFSCloudflare.prototype, "deleteKVKey", null);
2693
+ __decorate([Actions("/kv")], AFSCloudflare.prototype, "listRootKVActions", null);
2694
+ __decorate([Actions.Exec("/kv", "create")], AFSCloudflare.prototype, "execKVCreate", null);
2695
+ __decorate([Actions("/kv/:title")], AFSCloudflare.prototype, "listKVActions", null);
2696
+ __decorate([Actions.Exec("/kv/:title", "delete")], AFSCloudflare.prototype, "execKVDelete", null);
2697
+ __decorate([Search("/kv")], AFSCloudflare.prototype, "searchKV", null);
2698
+ __decorate([List("/pages")], AFSCloudflare.prototype, "listPages", null);
2699
+ __decorate([List("/pages/:project")], AFSCloudflare.prototype, "listPagesProjectDir", null);
2700
+ __decorate([List("/pages/:project/deployments")], AFSCloudflare.prototype, "listPagesDeployments", null);
2701
+ __decorate([List("/pages/:project/domains")], AFSCloudflare.prototype, "listPagesDomains", null);
2702
+ __decorate([Read("/pages")], AFSCloudflare.prototype, "readPages", null);
2703
+ __decorate([Read("/pages/:project")], AFSCloudflare.prototype, "readPagesProjectDir", null);
2704
+ __decorate([Read("/pages/:project/metadata.json")], AFSCloudflare.prototype, "readPagesMetadata", null);
2705
+ __decorate([Read("/pages/:project/deployments")], AFSCloudflare.prototype, "readPagesDeploymentsDir", null);
2706
+ __decorate([Read("/pages/:project/deployments/:id")], AFSCloudflare.prototype, "readPagesDeployment", null);
2707
+ __decorate([Read("/pages/:project/domains")], AFSCloudflare.prototype, "readPagesDomainsDir", null);
2708
+ __decorate([Read("/pages/:project/domains/:domain")], AFSCloudflare.prototype, "readPagesDomain", null);
2709
+ __decorate([Meta("/pages")], AFSCloudflare.prototype, "metaPages", null);
2710
+ __decorate([Meta("/pages/:project")], AFSCloudflare.prototype, "metaPagesProject", null);
2711
+ __decorate([
2712
+ Stat("/pages"),
2713
+ Stat("/pages/:project"),
2714
+ Stat("/pages/:project/metadata.json"),
2715
+ Stat("/pages/:project/deployments"),
2716
+ Stat("/pages/:project/deployments/:id"),
2717
+ Stat("/pages/:project/domains"),
2718
+ Stat("/pages/:project/domains/:domain")
2719
+ ], AFSCloudflare.prototype, "statPages", null);
2720
+ __decorate([Explain("/pages")], AFSCloudflare.prototype, "explainPages", null);
2721
+ __decorate([Explain("/pages/:project")], AFSCloudflare.prototype, "explainPagesProject", null);
2722
+ __decorate([Actions("/pages")], AFSCloudflare.prototype, "listRootPagesActions", null);
2723
+ __decorate([Actions.Exec("/pages", "create")], AFSCloudflare.prototype, "execPagesCreate", null);
2724
+ __decorate([Actions("/pages/:project")], AFSCloudflare.prototype, "listPagesActions", null);
2725
+ __decorate([Actions.Exec("/pages/:project", "deploy")], AFSCloudflare.prototype, "execPagesDeploy", null);
2726
+ __decorate([Actions.Exec("/pages/:project", "rollback")], AFSCloudflare.prototype, "execPagesRollback", null);
2727
+ __decorate([Actions.Exec("/pages/:project", "delete")], AFSCloudflare.prototype, "execPagesDelete", null);
2728
+ __decorate([Actions.Exec("/pages/:project", "configure-bindings")], AFSCloudflare.prototype, "execPagesConfigureBindings", null);
2729
+ __decorate([Search("/pages")], AFSCloudflare.prototype, "searchPages", null);
2730
+ __decorate([List("/by-zone")], AFSCloudflare.prototype, "listByZone", null);
2731
+ __decorate([List("/by-zone/:zone")], AFSCloudflare.prototype, "listByZoneDir", null);
2732
+ __decorate([List("/by-zone/:zone/workers")], AFSCloudflare.prototype, "listByZoneWorkers", null);
2733
+ __decorate([List("/by-zone/:zone/pages")], AFSCloudflare.prototype, "listByZonePages", null);
2734
+ __decorate([Read("/by-zone")], AFSCloudflare.prototype, "readByZone", null);
2735
+ __decorate([Read("/by-zone/:zone")], AFSCloudflare.prototype, "readByZoneDir", null);
2736
+ __decorate([Read("/by-zone/:zone/workers")], AFSCloudflare.prototype, "readByZoneWorkersDir", null);
2737
+ __decorate([Read("/by-zone/:zone/workers/:name")], AFSCloudflare.prototype, "readByZoneWorker", null);
2738
+ __decorate([Read("/by-zone/:zone/pages")], AFSCloudflare.prototype, "readByZonePagesDir", null);
2739
+ __decorate([Read("/by-zone/:zone/pages/:project")], AFSCloudflare.prototype, "readByZoneProject", null);
2740
+ __decorate([Meta("/by-zone")], AFSCloudflare.prototype, "metaByZone", null);
2741
+ __decorate([
2742
+ Stat("/by-zone"),
2743
+ Stat("/by-zone/:zone"),
2744
+ Stat("/by-zone/:zone/workers"),
2745
+ Stat("/by-zone/:zone/workers/:name"),
2746
+ Stat("/by-zone/:zone/pages"),
2747
+ Stat("/by-zone/:zone/pages/:project")
2748
+ ], AFSCloudflare.prototype, "statByZone", null);
2749
+ __decorate([Explain("/by-zone")], AFSCloudflare.prototype, "explainByZone", null);
2750
+ __decorate([Search("/")], AFSCloudflare.prototype, "searchRoot", null);
2751
+ __decorate([Delete("/:path+")], AFSCloudflare.prototype, "deleteCatchAll", null);
2752
+
2753
+ //#endregion
2754
+ export { AFSCloudflare };
2755
+ //# sourceMappingURL=cloudflare-afs.mjs.map