├── .cursor └── rules │ └── mcp.mdc ├── .gitignore ├── Cloudflare Typescript SDK.md ├── LICENSE ├── README.md ├── biome.json ├── bun.lock ├── package.json ├── src ├── cloudflare │ ├── cache.ts │ ├── dns.ts │ ├── hyperdrive.ts │ ├── kv.ts │ ├── queues.ts │ ├── r2.ts │ ├── worker-cron.ts │ ├── workers-domains.ts │ ├── workflows.ts │ └── zones.ts ├── index.ts └── types.ts ├── tsconfig.json ├── worker-configuration.d.ts └── wrangler.jsonc /.cursor/rules/mcp.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Cloudflare API MCP Server 7 | 8 | ## Project Context 9 | 10 | This is a Model Control Protocol (MCP) server. It is a cloudflare worker that exposes a set of tools to an LLM. We will build a lightweight wrapper for LLMs to interact with the Cloudflare API. The full Typescript API docs is at `Cloudflare Typescript SDK.md`, you can search this file for the API calls you need. 11 | 12 | ### What is MCP? 13 | 14 | MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools. 15 | 16 | MCP Clients are protocol clients that maintain 1:1 connections with servers. 17 | 18 | MCP Servers, such as this one, are lightweight programs that each expose specific capabilities through the standardized Model Context Protocol. 19 | 20 | # Format for Defining Tools 21 | 22 | Each method in the `MyWorker` class automatically becomes an MCP tool that can be used by AI agents. The method signature and JSDoc comments define how the tool appears to the agent. 23 | 24 | ```typescript 25 | /** 26 | * List all Cloudflare zones for the account. 27 | * @return {Promise} List of zones. 28 | */ 29 | async listZones() { 30 | const response = await listZones(this.env); 31 | return response; 32 | } 33 | ``` 34 | 35 | For tools with parameters: 36 | 37 | ```typescript 38 | /** 39 | * Create a new DNS record. 40 | * @param zoneId {string} The ID of the zone to create the record in. 41 | * @param name {string} The name of the DNS record. 42 | * @param content {string} The content of the DNS record. 43 | * @param type {string} The type of DNS record (CNAME, A, TXT, or MX). 44 | * @return {Promise} The created DNS record. 45 | */ 46 | async createDNSRecord(zoneId: string, name: string, content: string, type: string) { 47 | return await createDNSRecord(this.env, zoneId, name, content, type); 48 | } 49 | ``` 50 | 51 | The JSDoc structure is critical: 52 | - The first line becomes the tool's description 53 | - Each `@param` defines a parameter with its type and description 54 | - The `@return` specifies what the tool returns 55 | 56 | # Handling Complex Types (Arrays and Objects) 57 | 58 | The docgen script in workers-mcp has a limitation: it can only handle primitive types like `string`, `number`, and `boolean` in the JSDoc. To work with complex types like arrays or objects, follow this pattern: 59 | 60 | 1. Define the parameter as a `string` in JSDoc 61 | 2. Document that it should be a JSON representation of the complex type 62 | 3. Parse the JSON string in your implementation 63 | 64 | **Example with Array Parameters:** 65 | 66 | ```typescript 67 | /** 68 | * Bulk delete keys from a KV namespace. 69 | * @param accountId {string} The Cloudflare account ID. 70 | * @param namespaceId {string} The ID of the namespace. 71 | * @param keys {string} JSON string array of key names to delete. Format: ["key1", "key2", "key3"] 72 | * @return {Promise} Response from the bulk delete operation. 73 | */ 74 | async bulkDeleteKVKeys(accountId: string, namespaceId: string, keys: string) { 75 | // Parse the JSON string to get the array of keys 76 | const parsedKeys = JSON.parse(keys) as string[]; 77 | 78 | return await bulkDeleteKeys(this.env, accountId, namespaceId, parsedKeys); 79 | } 80 | ``` 81 | 82 | **Example with Object Array Parameters:** 83 | 84 | ```typescript 85 | /** 86 | * Acknowledge messages from a queue. 87 | * @param accountId {string} The Cloudflare account ID. 88 | * @param queueId {string} The ID of the queue. 89 | * @param acks {string} JSON string of message lease IDs. Format: [{lease_id: "string"}] 90 | * @return {Promise} Response from the acknowledge operation. 91 | */ 92 | async acknowledgeQueueMessages(accountId: string, queueId: string, acks: string) { 93 | // Parse the JSON string to get the array of objects 94 | const parsedAcks = JSON.parse(acks) as Array<{ lease_id: string }>; 95 | 96 | return await acknowledgeMessages(this.env, accountId, queueId, parsedAcks); 97 | } 98 | ``` 99 | 100 | **Key Points:** 101 | - Always use `{string}` type in JSDoc for any complex data structure 102 | - Always include a clear format example in the description 103 | - Parse the JSON in the implementation using `JSON.parse()` 104 | - Use TypeScript's `as` operator to apply the correct type to the parsed data 105 | 106 | # How to Write Functions to Wrap APIs 107 | 108 | When implementing tools that interact with external APIs, follow this pattern: 109 | 110 | 1. Import the necessary functions from your API wrapper modules 111 | 2. Create a method that calls these functions with the appropriate parameters 112 | 3. Return the response in the standardized MCP format 113 | 114 | All responses must conform to the MCP Tools Spec, which requires this shape: 115 | 116 | ```typescript 117 | { 118 | content: [ 119 | { 120 | type: "text", 121 | text: string 122 | } 123 | ] 124 | } 125 | ``` 126 | 127 | **Implementation Example:** 128 | 129 | ```typescript 130 | /** 131 | * List all Cloudflare zones for the account. 132 | * @return {Promise} List of zones. 133 | */ 134 | async listZones() { 135 | const client = new Cloudflare({ 136 | apiKey: this.env.CLOUDFLARE_API_KEY, 137 | apiEmail: this.env.CLOUDFLARE_API_EMAIL 138 | }); 139 | 140 | const response = await client.zones.list(); 141 | 142 | // Format response according to MCP spec 143 | return { 144 | content: [ 145 | { 146 | type: "text", 147 | text: JSON.stringify(response, null, 2) 148 | } 149 | ] 150 | }; 151 | } 152 | ``` 153 | 154 | For API implementations, you typically: 155 | 1. Create an API client using credentials from environment variables 156 | 2. Make the API call with parameters passed to your tool 157 | 3. Convert the API response to a JSON string 158 | 4. Wrap that string in the MCP response format 159 | 160 | Most of your implementation files (like `cloudflare/zones.ts`) should handle the MCP response formatting, allowing your tool methods to simply pass through parameters and return the result. 161 | 162 | ## Deployment 163 | 164 | Run `bun run deploy` to deploy your changes to Cloudflare Workers. 165 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | .dev.vars 4 | dist/ 5 | secrets.json 6 | .wrangler/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cloudflare-api-mcp 2 | 3 | This is a lightweight Model Control Protocol (MCP) server bootstrapped with [create-mcp](https://github.com/zueai/create-mcp) and deployed on Cloudflare Workers. 4 | 5 | This MCP server allows agents (such as Cursor) to interface with the [Cloudflare REST API](https://developers.cloudflare.com/api/). 6 | 7 | It's still under development, I will be adding more tools as I find myself needing them. 8 | 9 | ## Available Tools 10 | 11 | See [src/index.ts](src/index.ts) for the current list of tools. Every method in the class is an MCP tool. 12 | 13 | ## Installation 14 | 15 | 1. Run the automated install script to clone this MCP server and deploy it to your Cloudflare account: 16 | 17 | ```bash 18 | bun create mcp --clone https://github.com/zueai/cloudflare-api-mcp 19 | ``` 20 | 21 | 2. Open `Cursor Settings -> MCP -> Add new MCP server` and paste the command that was copied to your clipboard. 22 | 23 | 3. Upload your Cloudflare API key and email to your worker secrets: 24 | 25 | ```bash 26 | bunx wrangler secret put CLOUDFLARE_API_KEY 27 | bunx wrangler secret put CLOUDFLARE_API_EMAIL 28 | ``` 29 | 30 | ## Local Development 31 | 32 | Add your Cloudflare API key and email to the `.dev.vars` file: 33 | 34 | ```bash 35 | CLOUDFLARE_API_KEY= 36 | CLOUDFLARE_API_EMAIL= 37 | ``` 38 | 39 | ## Deploying 40 | 41 | 1. Run the deploy script: 42 | 43 | ```bash 44 | bun run deploy 45 | ``` 46 | 47 | 2. Reload your Cursor window to see the new tools. 48 | 49 | ## How to Create New MCP Tools 50 | 51 | To create new MCP tools, add methods to the `MyWorker` class in `src/index.ts`. Each function will automatically become an MCP tool that your agent can use. 52 | 53 | Example: 54 | 55 | ```typescript 56 | /** 57 | * Create a new DNS record in a zone. 58 | * @param zoneId {string} The ID of the zone to create the record in. 59 | * @param name {string} The name of the DNS record. 60 | * @param content {string} The content of the DNS record. 61 | * @param type {string} The type of DNS record (CNAME, A, TXT, or MX). 62 | * @param comment {string} Optional comment for the DNS record. 63 | * @param proxied {boolean} Optional whether to proxy the record through Cloudflare. 64 | * @return {object} The created DNS record. 65 | */ 66 | createDNSRecord(zoneId: string, name: string, content: string, type: string, comment?: string, proxied?: boolean) { 67 | // Implementation 68 | } 69 | ``` 70 | 71 | The JSDoc comments are important: 72 | 73 | - First line becomes the tool's description 74 | - `@param` tags define the tool's parameters with types and descriptions 75 | - `@return` tag specifies the return value and type 76 | 77 | ## Learn More 78 | 79 | - [Model Control Protocol Documentation](https://modelcontextprotocol.io) 80 | - [create-mcp Documentation](https://github.com/zueai/create-mcp) 81 | - [workers-mcp](https://github.com/cloudflare/workers-mcp) 82 | - [Cloudflare Workers documentation](https://developers.cloudflare.com/workers/) 83 | - [Cloudflare API Documentation](https://developers.cloudflare.com/api/) 84 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "ignore": [ 4 | "dist/**/*", 5 | "node_modules/**/*", 6 | "public/**/*", 7 | "**/*.css", 8 | ".wrangler/**/*", 9 | "drizzle/**/*" 10 | ] 11 | }, 12 | "linter": { 13 | "enabled": true, 14 | "rules": { 15 | "recommended": true 16 | }, 17 | "ignore": [ 18 | "**/*.md", 19 | "**/*.css", 20 | ".wrangler/**/*", 21 | "node_modules/**/*", 22 | "drizzle/**/*" 23 | ] 24 | }, 25 | "formatter": { 26 | "enabled": true, 27 | "indentStyle": "tab", 28 | "indentWidth": 4 29 | }, 30 | "javascript": { 31 | "formatter": { 32 | "semicolons": "asNeeded", 33 | "trailingCommas": "none" 34 | } 35 | }, 36 | "json": { 37 | "parser": { 38 | "allowComments": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "cloudflare-api-mcp", 6 | "dependencies": { 7 | "cloudflare": "^4.1.0", 8 | "workers-mcp": "^0.0.13", 9 | }, 10 | "devDependencies": { 11 | "@biomejs/biome": "^1.9.4", 12 | "@cloudflare/workers-types": "^4.20250109.0", 13 | "wrangler": "^3.101.0", 14 | }, 15 | }, 16 | }, 17 | "packages": { 18 | "@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], 19 | 20 | "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], 21 | 22 | "@babel/parser": ["@babel/parser@7.26.9", "", { "dependencies": { "@babel/types": "^7.26.9" }, "bin": "./bin/babel-parser.js" }, "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A=="], 23 | 24 | "@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="], 25 | 26 | "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], 27 | 28 | "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], 29 | 30 | "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], 31 | 32 | "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], 33 | 34 | "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], 35 | 36 | "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], 37 | 38 | "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], 39 | 40 | "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], 41 | 42 | "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], 43 | 44 | "@clack/core": ["@clack/core@0.3.5", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ=="], 45 | 46 | "@clack/prompts": ["@clack/prompts@0.8.2", "", { "dependencies": { "@clack/core": "0.3.5", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-6b9Ab2UiZwJYA9iMyboYyW9yJvAO9V753ZhS+DHKEjZRKAxPPOb7MXXu84lsPFG+vZt6FRFniZ8rXi+zCIw4yQ=="], 47 | 48 | "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.3.4", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="], 49 | 50 | "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250214.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cDvvedWDc5zrgDnuXe2qYcz/TwBvzmweO55C7XpPuAWJ9Oqxv81PkdekYxD8mH989aQ/GI5YD0Fe6fDYlM+T3Q=="], 51 | 52 | "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250214.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-NytCvRveVzu0mRKo+tvZo3d/gCUway3B2ZVqSi/TS6NXDGBYIJo7g6s3BnTLS74kgyzeDOjhu9j/RBJBS809qw=="], 53 | 54 | "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250214.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pQ7+aHNHj8SiYEs4d/6cNoimE5xGeCMfgU1yfDFtA9YGN9Aj2BITZgOWPec+HW7ZkOy9oWlNrO6EvVjGgB4tbQ=="], 55 | 56 | "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250214.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Vhlfah6Yd9ny1npNQjNgElLIjR6OFdEbuR3LCfbLDCwzWEBFhIf7yC+Tpp/a0Hq7kLz3sLdktaP7xl3PJhyOjA=="], 57 | 58 | "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250214.0", "", { "os": "win32", "cpu": "x64" }, "sha512-GMwMyFbkjBKjYJoKDhGX8nuL4Gqe3IbVnVWf2Q6086CValyIknupk5J6uQWGw2EBU3RGO3x4trDXT5WphQJZDQ=="], 59 | 60 | "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250214.0", "", {}, "sha512-+M8oOFVbyXT5GeJrYLWMUGyPf5wGB4+k59PPqdedtOig7NjZ5r4S79wMdaZ/EV5IV8JPtZBSNjTKpDnNmfxjaQ=="], 61 | 62 | "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], 63 | 64 | "@emnapi/runtime": ["@emnapi/runtime@1.3.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw=="], 65 | 66 | "@esbuild-plugins/node-globals-polyfill": ["@esbuild-plugins/node-globals-polyfill@0.2.3", "", { "peerDependencies": { "esbuild": "*" } }, "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw=="], 67 | 68 | "@esbuild-plugins/node-modules-polyfill": ["@esbuild-plugins/node-modules-polyfill@0.2.2", "", { "dependencies": { "escape-string-regexp": "^4.0.0", "rollup-plugin-node-polyfills": "^0.2.1" }, "peerDependencies": { "esbuild": "*" } }, "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA=="], 69 | 70 | "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ=="], 71 | 72 | "@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="], 73 | 74 | "@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="], 75 | 76 | "@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="], 77 | 78 | "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="], 79 | 80 | "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="], 81 | 82 | "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="], 83 | 84 | "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="], 85 | 86 | "@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="], 87 | 88 | "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="], 89 | 90 | "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="], 91 | 92 | "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="], 93 | 94 | "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="], 95 | 96 | "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="], 97 | 98 | "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="], 99 | 100 | "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="], 101 | 102 | "@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="], 103 | 104 | "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.0", "", { "os": "none", "cpu": "arm64" }, "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw=="], 105 | 106 | "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="], 107 | 108 | "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw=="], 109 | 110 | "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="], 111 | 112 | "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="], 113 | 114 | "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="], 115 | 116 | "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="], 117 | 118 | "@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="], 119 | 120 | "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], 121 | 122 | "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], 123 | 124 | "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], 125 | 126 | "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], 127 | 128 | "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], 129 | 130 | "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], 131 | 132 | "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], 133 | 134 | "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], 135 | 136 | "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], 137 | 138 | "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], 139 | 140 | "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], 141 | 142 | "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], 143 | 144 | "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], 145 | 146 | "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], 147 | 148 | "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], 149 | 150 | "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], 151 | 152 | "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], 153 | 154 | "@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], 155 | 156 | "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], 157 | 158 | "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], 159 | 160 | "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 161 | 162 | "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 163 | 164 | "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], 165 | 166 | "@jsdoc/salty": ["@jsdoc/salty@0.2.9", "", { "dependencies": { "lodash": "^4.17.21" } }, "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw=="], 167 | 168 | "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.5.0", "", { "dependencies": { "content-type": "^1.0.5", "eventsource": "^3.0.2", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-IJ+5iVVs8FCumIHxWqpwgkwOzyhtHVKy45s6Ug7Dv0MfRpaYisH8QQ87rIWeWdOzlk8sfhitZ7HCyQZk7d6b8w=="], 169 | 170 | "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], 171 | 172 | "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 173 | 174 | "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], 175 | 176 | "@silvia-odwyer/photon-node": ["@silvia-odwyer/photon-node@0.3.3", "", {}, "sha512-30nDWTHQ7/d1xGnO41ol5tnBA1Bmo2N6h9HNPByBbIYU2xCYB9g4o4zB6vxAq15ixrBRTjb1Nnz1K0Jli3Hxnw=="], 177 | 178 | "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], 179 | 180 | "@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], 181 | 182 | "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], 183 | 184 | "@types/node": ["@types/node@18.19.76", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-yvR7Q9LdPz2vGpmpJX5LolrgRdWvB67MJKDPSgIIzpFbaf9a1j/f5DnLp5VDyHGMR0QZHlTr1afsD87QCXFHKw=="], 185 | 186 | "@types/node-fetch": ["@types/node-fetch@2.6.12", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="], 187 | 188 | "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], 189 | 190 | "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], 191 | 192 | "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], 193 | 194 | "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], 195 | 196 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 197 | 198 | "array-back": ["array-back@6.2.2", "", {}, "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw=="], 199 | 200 | "as-table": ["as-table@1.0.55", "", { "dependencies": { "printable-characters": "^1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="], 201 | 202 | "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], 203 | 204 | "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], 205 | 206 | "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], 207 | 208 | "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 209 | 210 | "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], 211 | 212 | "cache-point": ["cache-point@3.0.1", "", { "dependencies": { "array-back": "^6.2.2" }, "peerDependencies": { "@75lb/nature": "latest" }, "optionalPeers": ["@75lb/nature"] }, "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA=="], 213 | 214 | "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], 215 | 216 | "catharsis": ["catharsis@0.9.0", "", { "dependencies": { "lodash": "^4.17.15" } }, "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A=="], 217 | 218 | "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], 219 | 220 | "cloudflare": ["cloudflare@4.1.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-TySwSEGGQhuVHFVjKRUHkzZum0MSGJkgfVjep+KBJxuxScEvjoTckQFbxlYThPp5kLm8IUi4C7oJeVr5e9etVw=="], 221 | 222 | "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], 223 | 224 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 225 | 226 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 227 | 228 | "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], 229 | 230 | "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], 231 | 232 | "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], 233 | 234 | "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], 235 | 236 | "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], 237 | 238 | "cookie": ["cookie@0.5.0", "", {}, "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="], 239 | 240 | "current-module-paths": ["current-module-paths@1.1.2", "", {}, "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ=="], 241 | 242 | "data-uri-to-buffer": ["data-uri-to-buffer@2.0.2", "", {}, "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA=="], 243 | 244 | "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], 245 | 246 | "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], 247 | 248 | "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], 249 | 250 | "detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], 251 | 252 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], 253 | 254 | "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], 255 | 256 | "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], 257 | 258 | "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], 259 | 260 | "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], 261 | 262 | "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], 263 | 264 | "esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="], 265 | 266 | "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 267 | 268 | "estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="], 269 | 270 | "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], 271 | 272 | "eventsource": ["eventsource@3.0.5", "", { "dependencies": { "eventsource-parser": "^3.0.0" } }, "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw=="], 273 | 274 | "eventsource-parser": ["eventsource-parser@3.0.0", "", {}, "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA=="], 275 | 276 | "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], 277 | 278 | "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], 279 | 280 | "fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="], 281 | 282 | "file-set": ["file-set@5.2.2", "", { "dependencies": { "array-back": "^6.2.2", "fast-glob": "^3.3.2" }, "peerDependencies": { "@75lb/nature": "latest" }, "optionalPeers": ["@75lb/nature"] }, "sha512-/KgJI1V/QaDK4enOk/E2xMFk1cTWJghEr7UmWiRZfZ6upt6gQCfMn4jJ7aOm64OKurj4TaVnSSgSDqv5ZKYA3A=="], 283 | 284 | "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 285 | 286 | "form-data": ["form-data@4.0.2", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" } }, "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w=="], 287 | 288 | "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], 289 | 290 | "formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="], 291 | 292 | "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], 293 | 294 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 295 | 296 | "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 297 | 298 | "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], 299 | 300 | "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], 301 | 302 | "get-source": ["get-source@2.0.12", "", { "dependencies": { "data-uri-to-buffer": "^2.0.0", "source-map": "^0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="], 303 | 304 | "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], 305 | 306 | "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 307 | 308 | "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], 309 | 310 | "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], 311 | 312 | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], 313 | 314 | "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], 315 | 316 | "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], 317 | 318 | "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 319 | 320 | "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], 321 | 322 | "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], 323 | 324 | "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], 325 | 326 | "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], 327 | 328 | "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], 329 | 330 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 331 | 332 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 333 | 334 | "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 335 | 336 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 337 | 338 | "js2xmlparser": ["js2xmlparser@4.0.2", "", { "dependencies": { "xmlcreate": "^2.0.4" } }, "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA=="], 339 | 340 | "jsdoc": ["jsdoc@4.0.4", "", { "dependencies": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", "markdown-it": "^14.1.0", "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "underscore": "~1.13.2" }, "bin": { "jsdoc": "./jsdoc.js" } }, "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw=="], 341 | 342 | "jsdoc-api": ["jsdoc-api@9.3.4", "", { "dependencies": { "array-back": "^6.2.2", "cache-point": "^3.0.0", "current-module-paths": "^1.1.2", "file-set": "^5.2.2", "jsdoc": "^4.0.4", "object-to-spawn-args": "^2.0.1", "walk-back": "^5.1.1" }, "peerDependencies": { "@75lb/nature": "latest" }, "optionalPeers": ["@75lb/nature"] }, "sha512-di8lggLACEttpyAZ6WjKKafUP4wC4prAGjt40nMl7quDpp2nD7GmLt6/WxhRu9Q6IYoAAySsNeidBXYVAMwlqg=="], 343 | 344 | "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], 345 | 346 | "just-filter-object": ["just-filter-object@3.2.0", "", {}, "sha512-OeorYJxmp2zhy/0LxjS1UjbJ7XMY8M4gVa1RRKxnIVheCYmng2E2hE0lEbDGv4aRh/HI7FgNUXtOMnmNxpoXRQ=="], 347 | 348 | "just-map-values": ["just-map-values@3.2.0", "", {}, "sha512-TyqCKtK3NxiUgOjRYMIKURvBTHesi3XzomDY0QVPZ3rYzLCF+nNq5rSi0B/L5aOd/WMTZo6ukzA4wih4HUbrDg=="], 349 | 350 | "klaw": ["klaw@3.0.0", "", { "dependencies": { "graceful-fs": "^4.1.9" } }, "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g=="], 351 | 352 | "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], 353 | 354 | "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], 355 | 356 | "magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="], 357 | 358 | "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], 359 | 360 | "markdown-it-anchor": ["markdown-it-anchor@8.6.7", "", { "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" } }, "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA=="], 361 | 362 | "marked": ["marked@4.3.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A=="], 363 | 364 | "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], 365 | 366 | "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], 367 | 368 | "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], 369 | 370 | "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], 371 | 372 | "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], 373 | 374 | "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], 375 | 376 | "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], 377 | 378 | "miniflare": ["miniflare@3.20250214.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250214.0", "ws": "8.18.0", "youch": "3.2.3", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-XKwn+X/V2CEpbRhoeaIcJHpV/Duz5Md5rxVT8I6S1oqd3aLZkn8cUX1tuxHpUvfQSPuXwWH+2ESLNnTf9PKEWg=="], 379 | 380 | "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], 381 | 382 | "mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="], 383 | 384 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 385 | 386 | "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], 387 | 388 | "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], 389 | 390 | "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], 391 | 392 | "npm-path": ["npm-path@2.0.4", "", { "dependencies": { "which": "^1.2.10" }, "bin": { "npm-path": "bin/npm-path" } }, "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw=="], 393 | 394 | "npm-which": ["npm-which@3.0.1", "", { "dependencies": { "commander": "^2.9.0", "npm-path": "^2.0.2", "which": "^1.2.10" }, "bin": { "npm-which": "bin/npm-which.js" } }, "sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A=="], 395 | 396 | "object-to-spawn-args": ["object-to-spawn-args@2.0.1", "", {}, "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w=="], 397 | 398 | "ohash": ["ohash@1.1.4", "", {}, "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="], 399 | 400 | "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], 401 | 402 | "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], 403 | 404 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 405 | 406 | "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 407 | 408 | "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], 409 | 410 | "printable-characters": ["printable-characters@1.0.42", "", {}, "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ=="], 411 | 412 | "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], 413 | 414 | "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 415 | 416 | "raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="], 417 | 418 | "requizzle": ["requizzle@0.2.4", "", { "dependencies": { "lodash": "^4.17.21" } }, "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw=="], 419 | 420 | "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], 421 | 422 | "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], 423 | 424 | "rollup-plugin-inject": ["rollup-plugin-inject@3.0.2", "", { "dependencies": { "estree-walker": "^0.6.1", "magic-string": "^0.25.3", "rollup-pluginutils": "^2.8.1" } }, "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w=="], 425 | 426 | "rollup-plugin-node-polyfills": ["rollup-plugin-node-polyfills@0.2.1", "", { "dependencies": { "rollup-plugin-inject": "^3.0.0" } }, "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA=="], 427 | 428 | "rollup-pluginutils": ["rollup-pluginutils@2.8.2", "", { "dependencies": { "estree-walker": "^0.6.1" } }, "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ=="], 429 | 430 | "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 431 | 432 | "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], 433 | 434 | "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], 435 | 436 | "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], 437 | 438 | "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], 439 | 440 | "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], 441 | 442 | "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], 443 | 444 | "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], 445 | 446 | "sourcemap-codec": ["sourcemap-codec@1.4.8", "", {}, "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="], 447 | 448 | "stacktracey": ["stacktracey@2.1.8", "", { "dependencies": { "as-table": "^1.0.36", "get-source": "^2.0.12" } }, "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw=="], 449 | 450 | "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], 451 | 452 | "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], 453 | 454 | "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 455 | 456 | "tmp": ["tmp@0.2.3", "", {}, "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w=="], 457 | 458 | "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], 459 | 460 | "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 461 | 462 | "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], 463 | 464 | "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], 465 | 466 | "ts-blank-space": ["ts-blank-space@0.4.4", "", { "dependencies": { "typescript": "5.1.6 - 5.7.x" } }, "sha512-G6GkD6oEJ7j5gG2e5qAizfE4Ap7JXMpnN0CEp9FEt4LExdaqsdwB90aQsaAwcKhiSxVk5KoqFW9xfxTQ4lBUnQ=="], 467 | 468 | "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 469 | 470 | "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], 471 | 472 | "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], 473 | 474 | "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], 475 | 476 | "ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], 477 | 478 | "underscore": ["underscore@1.13.7", "", {}, "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g=="], 479 | 480 | "undici": ["undici@5.28.5", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA=="], 481 | 482 | "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], 483 | 484 | "unenv": ["unenv@2.0.0-rc.1", "", { "dependencies": { "defu": "^6.1.4", "mlly": "^1.7.4", "ohash": "^1.1.4", "pathe": "^1.1.2", "ufo": "^1.5.4" } }, "sha512-PU5fb40H8X149s117aB4ytbORcCvlASdtF97tfls4BPIyj4PeVxvpSuy1jAptqYHqB0vb2w2sHvzM0XWcp2OKg=="], 485 | 486 | "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], 487 | 488 | "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], 489 | 490 | "walk-back": ["walk-back@5.1.1", "", {}, "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw=="], 491 | 492 | "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], 493 | 494 | "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], 495 | 496 | "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], 497 | 498 | "which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], 499 | 500 | "workerd": ["workerd@1.20250214.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250214.0", "@cloudflare/workerd-darwin-arm64": "1.20250214.0", "@cloudflare/workerd-linux-64": "1.20250214.0", "@cloudflare/workerd-linux-arm64": "1.20250214.0", "@cloudflare/workerd-windows-64": "1.20250214.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-QWcqXZLiMpV12wiaVnb3nLmfs/g4ZsFQq2mX85z546r3AX4CTIkXl0VP50W3CwqLADej3PGYiRDOTelDOwVG1g=="], 501 | 502 | "workers-mcp": ["workers-mcp@0.0.13", "", { "dependencies": { "@clack/prompts": "^0.8.2", "@modelcontextprotocol/sdk": "^1.0.3", "@silvia-odwyer/photon-node": "^0.3.3", "chalk": "^5.3.0", "fs-extra": "^11.2.0", "jsdoc-api": "^9.3.4", "just-filter-object": "^3.2.0", "just-map-values": "^3.2.0", "npm-which": "^3.0.1", "tmp-promise": "^3.0.3", "ts-blank-space": "^0.4.4", "tsx": "^4.19.2" }, "bin": { "workers-mcp": "dist/cli.js" } }, "sha512-JoFASGioyaVAI1Rn+a4PJcV66cWthL7wnwZZYl1u3pwUz014Ym76sBPvGLuODWXjOkE7D3z+6CM4nH8pW4tlcA=="], 503 | 504 | "wrangler": ["wrangler@3.109.2", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250214.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.1", "workerd": "1.20250214.0" }, "optionalDependencies": { "fsevents": "~2.3.2", "sharp": "^0.33.5" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250214.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-CT8izugPBth5o1o4gLNcQrDkHKSX2Jthy6gkyhaWiy2pFrx+536NMn/atWilLA1t1uhIgddEI5BXDNudIkPPHA=="], 505 | 506 | "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], 507 | 508 | "xmlcreate": ["xmlcreate@2.0.4", "", {}, "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg=="], 509 | 510 | "youch": ["youch@3.2.3", "", { "dependencies": { "cookie": "^0.5.0", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-ZBcWz/uzZaQVdCvfV4uk616Bbpf2ee+F/AvuKDR5EwX/Y4v06xWdtMluqTD7+KlZdM93lLm9gMZYo0sKBS0pgw=="], 511 | 512 | "zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], 513 | 514 | "zod-to-json-schema": ["zod-to-json-schema@3.24.2", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-pNUqrcSxuuB3/+jBbU8qKUbTbDqYUaG1vf5cXFjbhGgoUuA1amO/y4Q8lzfOhHU8HNPK6VFJ18lBDKj3OHyDsg=="], 515 | 516 | "@modelcontextprotocol/sdk/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], 517 | 518 | "jsdoc/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], 519 | 520 | "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 521 | 522 | "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 523 | 524 | "tsx/esbuild": ["esbuild@0.25.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.0", "@esbuild/android-arm": "0.25.0", "@esbuild/android-arm64": "0.25.0", "@esbuild/android-x64": "0.25.0", "@esbuild/darwin-arm64": "0.25.0", "@esbuild/darwin-x64": "0.25.0", "@esbuild/freebsd-arm64": "0.25.0", "@esbuild/freebsd-x64": "0.25.0", "@esbuild/linux-arm": "0.25.0", "@esbuild/linux-arm64": "0.25.0", "@esbuild/linux-ia32": "0.25.0", "@esbuild/linux-loong64": "0.25.0", "@esbuild/linux-mips64el": "0.25.0", "@esbuild/linux-ppc64": "0.25.0", "@esbuild/linux-riscv64": "0.25.0", "@esbuild/linux-s390x": "0.25.0", "@esbuild/linux-x64": "0.25.0", "@esbuild/netbsd-arm64": "0.25.0", "@esbuild/netbsd-x64": "0.25.0", "@esbuild/openbsd-arm64": "0.25.0", "@esbuild/openbsd-x64": "0.25.0", "@esbuild/sunos-x64": "0.25.0", "@esbuild/win32-arm64": "0.25.0", "@esbuild/win32-ia32": "0.25.0", "@esbuild/win32-x64": "0.25.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw=="], 525 | 526 | "zod-to-json-schema/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], 527 | 528 | "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.0", "", { "os": "android", "cpu": "arm" }, "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g=="], 529 | 530 | "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.0", "", { "os": "android", "cpu": "arm64" }, "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g=="], 531 | 532 | "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.0", "", { "os": "android", "cpu": "x64" }, "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg=="], 533 | 534 | "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw=="], 535 | 536 | "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg=="], 537 | 538 | "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w=="], 539 | 540 | "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A=="], 541 | 542 | "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg=="], 543 | 544 | "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg=="], 545 | 546 | "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg=="], 547 | 548 | "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw=="], 549 | 550 | "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ=="], 551 | 552 | "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw=="], 553 | 554 | "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA=="], 555 | 556 | "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA=="], 557 | 558 | "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw=="], 559 | 560 | "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.0", "", { "os": "none", "cpu": "x64" }, "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA=="], 561 | 562 | "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg=="], 563 | 564 | "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg=="], 565 | 566 | "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw=="], 567 | 568 | "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA=="], 569 | 570 | "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ=="], 571 | } 572 | } 573 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare-api-mcp", 3 | "scripts": { 4 | "dev": "bun check && wrangler dev", 5 | "deploy": "workers-mcp docgen src/index.ts && bun check && wrangler deploy --minify", 6 | "check": "bunx biome check --write .", 7 | "secrets": "wrangler secret bulk secrets.json" 8 | }, 9 | "dependencies": { 10 | "cloudflare": "^4.1.0", 11 | "workers-mcp": "^0.0.13" 12 | }, 13 | "devDependencies": { 14 | "@biomejs/biome": "^1.9.4", 15 | "@cloudflare/workers-types": "^4.20250109.0", 16 | "wrangler": "^3.101.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cloudflare/cache.ts: -------------------------------------------------------------------------------- 1 | import { Cloudflare } from "cloudflare" 2 | 3 | export async function purgeEverything(env: Env, zoneId: string) { 4 | const client = new Cloudflare({ 5 | apiKey: env.CLOUDFLARE_API_KEY, 6 | apiEmail: env.CLOUDFLARE_API_EMAIL 7 | }) 8 | 9 | const response = await client.cache.purge({ 10 | zone_id: zoneId, 11 | purge_everything: true 12 | }) 13 | 14 | return { 15 | content: [ 16 | { 17 | type: "text", 18 | text: JSON.stringify(response, null, 2) 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/cloudflare/dns.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | import type { DNSRecordType } from "../types" 3 | 4 | export async function createDNSRecord( 5 | env: Env, 6 | zoneId: string, 7 | name: string, 8 | content: string, 9 | type: DNSRecordType, 10 | comment?: string, 11 | proxied?: boolean 12 | ) { 13 | const client = new Cloudflare({ 14 | apiKey: env.CLOUDFLARE_API_KEY, 15 | apiEmail: env.CLOUDFLARE_API_EMAIL 16 | }) 17 | 18 | const response = await client.dns.records.create({ 19 | zone_id: zoneId, 20 | name, 21 | content, 22 | comment, 23 | type, 24 | ttl: 60, 25 | proxied 26 | }) 27 | 28 | return { 29 | content: [ 30 | { 31 | type: "text", 32 | text: JSON.stringify(response, null, 2) 33 | } 34 | ] 35 | } 36 | } 37 | 38 | export async function deleteDNSRecord( 39 | env: Env, 40 | zoneId: string, 41 | recordId: string 42 | ) { 43 | const client = new Cloudflare({ 44 | apiKey: env.CLOUDFLARE_API_KEY, 45 | apiEmail: env.CLOUDFLARE_API_EMAIL 46 | }) 47 | 48 | const response = await client.dns.records.delete(recordId, { 49 | zone_id: zoneId 50 | }) 51 | 52 | return { 53 | content: [ 54 | { 55 | type: "text", 56 | text: JSON.stringify(response, null, 2) 57 | } 58 | ] 59 | } 60 | } 61 | 62 | export async function editDNSRecord( 63 | env: Env, 64 | zoneId: string, 65 | recordId: string, 66 | content: string, 67 | type: DNSRecordType, 68 | comment?: string, 69 | proxied?: boolean 70 | ) { 71 | const client = new Cloudflare({ 72 | apiKey: env.CLOUDFLARE_API_KEY, 73 | apiEmail: env.CLOUDFLARE_API_EMAIL 74 | }) 75 | 76 | const response = await client.dns.records.update(recordId, { 77 | zone_id: zoneId, 78 | content, 79 | comment, 80 | type, 81 | ttl: 60, 82 | proxied 83 | }) 84 | 85 | return { 86 | content: [ 87 | { 88 | type: "text", 89 | text: JSON.stringify(response, null, 2) 90 | } 91 | ] 92 | } 93 | } 94 | 95 | export async function listDNSRecords(env: Env, zoneId: string) { 96 | const client = new Cloudflare({ 97 | apiKey: env.CLOUDFLARE_API_KEY, 98 | apiEmail: env.CLOUDFLARE_API_EMAIL 99 | }) 100 | 101 | const response = await client.dns.records.list({ 102 | zone_id: zoneId 103 | }) 104 | 105 | return { 106 | content: [ 107 | { 108 | type: "text", 109 | text: JSON.stringify(response, null, 2) 110 | } 111 | ] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/cloudflare/hyperdrive.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | export async function createHyperdriveConfig( 4 | env: Env, 5 | accountId: string, 6 | name: string, 7 | origin: 8 | | { 9 | database: string 10 | host: string 11 | password: string 12 | port: number 13 | scheme: "postgres" | "postgresql" 14 | user: string 15 | } 16 | | { 17 | access_client_id: string 18 | access_client_secret: string 19 | database: string 20 | host: string 21 | password: string 22 | scheme: "postgres" | "postgresql" 23 | user: string 24 | }, 25 | caching?: { 26 | disabled?: boolean 27 | max_age?: number 28 | stale_while_revalidate?: number 29 | } 30 | ) { 31 | const client = new Cloudflare({ 32 | apiKey: env.CLOUDFLARE_API_KEY, 33 | apiEmail: env.CLOUDFLARE_API_EMAIL 34 | }) 35 | 36 | const response = await client.hyperdrive.configs.create({ 37 | account_id: accountId, 38 | name, 39 | origin, 40 | caching 41 | }) 42 | 43 | return { 44 | content: [ 45 | { 46 | type: "text", 47 | text: JSON.stringify(response, null, 2) 48 | } 49 | ] 50 | } 51 | } 52 | 53 | export async function deleteHyperdriveConfig( 54 | env: Env, 55 | accountId: string, 56 | hyperdriveId: string 57 | ) { 58 | const client = new Cloudflare({ 59 | apiKey: env.CLOUDFLARE_API_KEY, 60 | apiEmail: env.CLOUDFLARE_API_EMAIL 61 | }) 62 | 63 | const response = await client.hyperdrive.configs.delete(hyperdriveId, { 64 | account_id: accountId 65 | }) 66 | 67 | return { 68 | content: [ 69 | { 70 | type: "text", 71 | text: JSON.stringify(response, null, 2) 72 | } 73 | ] 74 | } 75 | } 76 | 77 | export async function editHyperdriveConfig( 78 | env: Env, 79 | accountId: string, 80 | hyperdriveId: string, 81 | params: { 82 | name?: string 83 | caching?: { 84 | disabled?: boolean 85 | max_age?: number 86 | stale_while_revalidate?: number 87 | } 88 | origin?: { 89 | database?: string 90 | host?: string 91 | password?: string 92 | port?: number 93 | scheme?: "postgres" | "postgresql" 94 | user?: string 95 | access_client_id?: string 96 | access_client_secret?: string 97 | } 98 | } 99 | ) { 100 | const client = new Cloudflare({ 101 | apiKey: env.CLOUDFLARE_API_KEY, 102 | apiEmail: env.CLOUDFLARE_API_EMAIL 103 | }) 104 | 105 | const response = await client.hyperdrive.configs.edit(hyperdriveId, { 106 | account_id: accountId, 107 | ...params 108 | }) 109 | 110 | return { 111 | content: [ 112 | { 113 | type: "text", 114 | text: JSON.stringify(response, null, 2) 115 | } 116 | ] 117 | } 118 | } 119 | 120 | export async function getHyperdriveConfig( 121 | env: Env, 122 | accountId: string, 123 | hyperdriveId: string 124 | ) { 125 | const client = new Cloudflare({ 126 | apiKey: env.CLOUDFLARE_API_KEY, 127 | apiEmail: env.CLOUDFLARE_API_EMAIL 128 | }) 129 | 130 | const response = await client.hyperdrive.configs.get(hyperdriveId, { 131 | account_id: accountId 132 | }) 133 | 134 | return { 135 | content: [ 136 | { 137 | type: "text", 138 | text: JSON.stringify(response, null, 2) 139 | } 140 | ] 141 | } 142 | } 143 | 144 | export async function listHyperdriveConfigs(env: Env, accountId: string) { 145 | const client = new Cloudflare({ 146 | apiKey: env.CLOUDFLARE_API_KEY, 147 | apiEmail: env.CLOUDFLARE_API_EMAIL 148 | }) 149 | 150 | const response = await client.hyperdrive.configs.list({ 151 | account_id: accountId 152 | }) 153 | 154 | return { 155 | content: [ 156 | { 157 | type: "text", 158 | text: JSON.stringify(response, null, 2) 159 | } 160 | ] 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/cloudflare/kv.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | // Namespace functions 4 | 5 | export async function createNamespace( 6 | env: Env, 7 | accountId: string, 8 | title: string 9 | ) { 10 | const client = new Cloudflare({ 11 | apiKey: env.CLOUDFLARE_API_KEY, 12 | apiEmail: env.CLOUDFLARE_API_EMAIL 13 | }) 14 | 15 | const response = await client.kv.namespaces.create({ 16 | account_id: accountId, 17 | title 18 | }) 19 | 20 | return { 21 | content: [ 22 | { 23 | type: "text", 24 | text: JSON.stringify(response, null, 2) 25 | } 26 | ] 27 | } 28 | } 29 | 30 | export async function updateNamespace( 31 | env: Env, 32 | accountId: string, 33 | namespaceId: string, 34 | title: string 35 | ) { 36 | const client = new Cloudflare({ 37 | apiKey: env.CLOUDFLARE_API_KEY, 38 | apiEmail: env.CLOUDFLARE_API_EMAIL 39 | }) 40 | 41 | const response = await client.kv.namespaces.update(namespaceId, { 42 | account_id: accountId, 43 | title 44 | }) 45 | 46 | return { 47 | content: [ 48 | { 49 | type: "text", 50 | text: JSON.stringify(response, null, 2) 51 | } 52 | ] 53 | } 54 | } 55 | 56 | export async function listNamespaces( 57 | env: Env, 58 | accountId: string, 59 | order?: "id" | "title", 60 | direction?: "asc" | "desc" 61 | ) { 62 | const client = new Cloudflare({ 63 | apiKey: env.CLOUDFLARE_API_KEY, 64 | apiEmail: env.CLOUDFLARE_API_EMAIL 65 | }) 66 | 67 | const response = await client.kv.namespaces.list({ 68 | account_id: accountId, 69 | order, 70 | direction 71 | }) 72 | 73 | return { 74 | content: [ 75 | { 76 | type: "text", 77 | text: JSON.stringify(response, null, 2) 78 | } 79 | ] 80 | } 81 | } 82 | 83 | export async function deleteNamespace( 84 | env: Env, 85 | accountId: string, 86 | namespaceId: string 87 | ) { 88 | const client = new Cloudflare({ 89 | apiKey: env.CLOUDFLARE_API_KEY, 90 | apiEmail: env.CLOUDFLARE_API_EMAIL 91 | }) 92 | 93 | const response = await client.kv.namespaces.delete(namespaceId, { 94 | account_id: accountId 95 | }) 96 | 97 | return { 98 | content: [ 99 | { 100 | type: "text", 101 | text: JSON.stringify(response, null, 2) 102 | } 103 | ] 104 | } 105 | } 106 | 107 | export async function getNamespace( 108 | env: Env, 109 | accountId: string, 110 | namespaceId: string 111 | ) { 112 | const client = new Cloudflare({ 113 | apiKey: env.CLOUDFLARE_API_KEY, 114 | apiEmail: env.CLOUDFLARE_API_EMAIL 115 | }) 116 | 117 | const response = await client.kv.namespaces.get(namespaceId, { 118 | account_id: accountId 119 | }) 120 | 121 | return { 122 | content: [ 123 | { 124 | type: "text", 125 | text: JSON.stringify(response, null, 2) 126 | } 127 | ] 128 | } 129 | } 130 | 131 | export async function bulkDeleteKeys( 132 | env: Env, 133 | accountId: string, 134 | namespaceId: string, 135 | keys: string[] 136 | ) { 137 | const client = new Cloudflare({ 138 | apiKey: env.CLOUDFLARE_API_KEY, 139 | apiEmail: env.CLOUDFLARE_API_EMAIL 140 | }) 141 | 142 | const response = await client.kv.namespaces.bulkDelete(namespaceId, { 143 | account_id: accountId, 144 | body: keys 145 | }) 146 | 147 | return { 148 | content: [ 149 | { 150 | type: "text", 151 | text: JSON.stringify(response, null, 2) 152 | } 153 | ] 154 | } 155 | } 156 | 157 | export async function bulkUpdateKeys( 158 | env: Env, 159 | accountId: string, 160 | namespaceId: string, 161 | keyValues: Array<{ 162 | key: string 163 | value: string 164 | expiration?: number 165 | expiration_ttl?: number 166 | base64?: boolean 167 | metadata?: Record 168 | }> 169 | ) { 170 | const client = new Cloudflare({ 171 | apiKey: env.CLOUDFLARE_API_KEY, 172 | apiEmail: env.CLOUDFLARE_API_EMAIL 173 | }) 174 | 175 | const response = await client.kv.namespaces.bulkUpdate(namespaceId, { 176 | account_id: accountId, 177 | body: keyValues 178 | }) 179 | 180 | return { 181 | content: [ 182 | { 183 | type: "text", 184 | text: JSON.stringify(response, null, 2) 185 | } 186 | ] 187 | } 188 | } 189 | 190 | // Keys functions 191 | 192 | export async function listKeys( 193 | env: Env, 194 | accountId: string, 195 | namespaceId: string, 196 | prefix?: string, 197 | cursor?: string, 198 | limit?: number 199 | ) { 200 | const client = new Cloudflare({ 201 | apiKey: env.CLOUDFLARE_API_KEY, 202 | apiEmail: env.CLOUDFLARE_API_EMAIL 203 | }) 204 | 205 | const response = await client.kv.namespaces.keys.list(namespaceId, { 206 | account_id: accountId, 207 | prefix, 208 | cursor, 209 | limit 210 | }) 211 | 212 | return { 213 | content: [ 214 | { 215 | type: "text", 216 | text: JSON.stringify(response, null, 2) 217 | } 218 | ] 219 | } 220 | } 221 | 222 | // Metadata functions 223 | 224 | export async function getMetadata( 225 | env: Env, 226 | accountId: string, 227 | namespaceId: string, 228 | keyName: string 229 | ) { 230 | const client = new Cloudflare({ 231 | apiKey: env.CLOUDFLARE_API_KEY, 232 | apiEmail: env.CLOUDFLARE_API_EMAIL 233 | }) 234 | 235 | const response = await client.kv.namespaces.metadata.get( 236 | namespaceId, 237 | keyName, 238 | { 239 | account_id: accountId 240 | } 241 | ) 242 | 243 | return { 244 | content: [ 245 | { 246 | type: "text", 247 | text: JSON.stringify(response, null, 2) 248 | } 249 | ] 250 | } 251 | } 252 | 253 | // Values functions 254 | 255 | export async function updateValue( 256 | env: Env, 257 | accountId: string, 258 | namespaceId: string, 259 | keyName: string, 260 | value: string, 261 | metadata?: string, 262 | expiration?: number, 263 | expiration_ttl?: number 264 | ) { 265 | const client = new Cloudflare({ 266 | apiKey: env.CLOUDFLARE_API_KEY, 267 | apiEmail: env.CLOUDFLARE_API_EMAIL 268 | }) 269 | 270 | // Create the base params with required fields 271 | const params = { 272 | account_id: accountId, 273 | value, 274 | metadata: metadata || "" // Always provide a string for metadata 275 | } 276 | 277 | // Add optional expiration parameters directly to the API call 278 | const response = await client.kv.namespaces.values.update( 279 | namespaceId, 280 | keyName, 281 | { 282 | ...params, 283 | expiration, 284 | expiration_ttl 285 | } 286 | ) 287 | 288 | return { 289 | content: [ 290 | { 291 | type: "text", 292 | text: JSON.stringify(response, null, 2) 293 | } 294 | ] 295 | } 296 | } 297 | 298 | export async function deleteValue( 299 | env: Env, 300 | accountId: string, 301 | namespaceId: string, 302 | keyName: string 303 | ) { 304 | const client = new Cloudflare({ 305 | apiKey: env.CLOUDFLARE_API_KEY, 306 | apiEmail: env.CLOUDFLARE_API_EMAIL 307 | }) 308 | 309 | const response = await client.kv.namespaces.values.delete( 310 | namespaceId, 311 | keyName, 312 | { 313 | account_id: accountId 314 | } 315 | ) 316 | 317 | return { 318 | content: [ 319 | { 320 | type: "text", 321 | text: JSON.stringify(response, null, 2) 322 | } 323 | ] 324 | } 325 | } 326 | 327 | export async function getValue( 328 | env: Env, 329 | accountId: string, 330 | namespaceId: string, 331 | keyName: string 332 | ) { 333 | const client = new Cloudflare({ 334 | apiKey: env.CLOUDFLARE_API_KEY, 335 | apiEmail: env.CLOUDFLARE_API_EMAIL 336 | }) 337 | 338 | const response = await client.kv.namespaces.values.get( 339 | namespaceId, 340 | keyName, 341 | { 342 | account_id: accountId 343 | } 344 | ) 345 | 346 | // Since the response is a binary stream, we need to convert it to text 347 | const text = await response.text() 348 | 349 | return { 350 | content: [ 351 | { 352 | type: "text", 353 | text 354 | } 355 | ] 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/cloudflare/queues.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | /** 4 | * Create a new queue 5 | */ 6 | export async function createQueue( 7 | env: Env, 8 | accountId: string, 9 | queueName: string 10 | ) { 11 | const client = new Cloudflare({ 12 | apiKey: env.CLOUDFLARE_API_KEY, 13 | apiEmail: env.CLOUDFLARE_API_EMAIL 14 | }) 15 | 16 | const response = await client.queues.create({ 17 | account_id: accountId, 18 | queue_name: queueName 19 | }) 20 | 21 | return { 22 | content: [ 23 | { 24 | type: "text", 25 | text: JSON.stringify(response, null, 2) 26 | } 27 | ] 28 | } 29 | } 30 | 31 | /** 32 | * Get details about a specific queue 33 | */ 34 | export async function getQueue(env: Env, accountId: string, queueId: string) { 35 | const client = new Cloudflare({ 36 | apiKey: env.CLOUDFLARE_API_KEY, 37 | apiEmail: env.CLOUDFLARE_API_EMAIL 38 | }) 39 | 40 | const response = await client.queues.get(queueId, { 41 | account_id: accountId 42 | }) 43 | 44 | return { 45 | content: [ 46 | { 47 | type: "text", 48 | text: JSON.stringify(response, null, 2) 49 | } 50 | ] 51 | } 52 | } 53 | 54 | /** 55 | * List all queues for an account 56 | */ 57 | export async function listQueues(env: Env, accountId: string) { 58 | const client = new Cloudflare({ 59 | apiKey: env.CLOUDFLARE_API_KEY, 60 | apiEmail: env.CLOUDFLARE_API_EMAIL 61 | }) 62 | 63 | const response = await client.queues.list({ 64 | account_id: accountId 65 | }) 66 | 67 | return { 68 | content: [ 69 | { 70 | type: "text", 71 | text: JSON.stringify(response, null, 2) 72 | } 73 | ] 74 | } 75 | } 76 | 77 | /** 78 | * Acknowledge messages from a queue 79 | */ 80 | export async function acknowledgeMessages( 81 | env: Env, 82 | accountId: string, 83 | queueId: string, 84 | acks: Array<{ lease_id: string }>, 85 | retries?: Array<{ lease_id: string; delay_seconds?: number }> 86 | ) { 87 | const client = new Cloudflare({ 88 | apiKey: env.CLOUDFLARE_API_KEY, 89 | apiEmail: env.CLOUDFLARE_API_EMAIL 90 | }) 91 | 92 | const params: { 93 | account_id: string 94 | acks?: Array<{ lease_id: string }> 95 | retries?: Array<{ lease_id: string; delay_seconds?: number }> 96 | } = { 97 | account_id: accountId 98 | } 99 | 100 | if (acks && acks.length > 0) { 101 | params.acks = acks 102 | } 103 | 104 | if (retries && retries.length > 0) { 105 | params.retries = retries 106 | } 107 | 108 | const response = await client.queues.messages.ack(queueId, params) 109 | 110 | return { 111 | content: [ 112 | { 113 | type: "text", 114 | text: JSON.stringify(response, null, 2) 115 | } 116 | ] 117 | } 118 | } 119 | 120 | /** 121 | * Pull a batch of messages from a queue 122 | */ 123 | export async function pullMessages( 124 | env: Env, 125 | accountId: string, 126 | queueId: string, 127 | batchSize?: number, 128 | visibilityTimeoutMs?: number 129 | ) { 130 | const client = new Cloudflare({ 131 | apiKey: env.CLOUDFLARE_API_KEY, 132 | apiEmail: env.CLOUDFLARE_API_EMAIL 133 | }) 134 | 135 | const params: { 136 | account_id: string 137 | batch_size?: number 138 | visibility_timeout_ms?: number 139 | } = { 140 | account_id: accountId 141 | } 142 | 143 | if (batchSize !== undefined) { 144 | params.batch_size = batchSize 145 | } 146 | 147 | if (visibilityTimeoutMs !== undefined) { 148 | params.visibility_timeout_ms = visibilityTimeoutMs 149 | } 150 | 151 | const response = await client.queues.messages.pull(queueId, params) 152 | 153 | return { 154 | content: [ 155 | { 156 | type: "text", 157 | text: JSON.stringify(response, null, 2) 158 | } 159 | ] 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/cloudflare/r2.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | // Bucket functions 4 | 5 | export async function createBucket(env: Env, accountId: string, name: string) { 6 | const client = new Cloudflare({ 7 | apiKey: env.CLOUDFLARE_API_KEY, 8 | apiEmail: env.CLOUDFLARE_API_EMAIL 9 | }) 10 | 11 | const response = await client.r2.buckets.create({ 12 | account_id: accountId, 13 | name 14 | }) 15 | 16 | return { 17 | content: [ 18 | { 19 | type: "text", 20 | text: JSON.stringify(response, null, 2) 21 | } 22 | ] 23 | } 24 | } 25 | 26 | export async function getBucket( 27 | env: Env, 28 | accountId: string, 29 | bucketName: string 30 | ) { 31 | const client = new Cloudflare({ 32 | apiKey: env.CLOUDFLARE_API_KEY, 33 | apiEmail: env.CLOUDFLARE_API_EMAIL 34 | }) 35 | 36 | const response = await client.r2.buckets.get(bucketName, { 37 | account_id: accountId 38 | }) 39 | 40 | return { 41 | content: [ 42 | { 43 | type: "text", 44 | text: JSON.stringify(response, null, 2) 45 | } 46 | ] 47 | } 48 | } 49 | 50 | export async function listBuckets(env: Env, accountId: string) { 51 | const client = new Cloudflare({ 52 | apiKey: env.CLOUDFLARE_API_KEY, 53 | apiEmail: env.CLOUDFLARE_API_EMAIL 54 | }) 55 | 56 | const response = await client.r2.buckets.list({ 57 | account_id: accountId 58 | }) 59 | 60 | return { 61 | content: [ 62 | { 63 | type: "text", 64 | text: JSON.stringify(response, null, 2) 65 | } 66 | ] 67 | } 68 | } 69 | 70 | // CORS functions 71 | 72 | export async function deleteBucketCORS( 73 | env: Env, 74 | accountId: string, 75 | bucketName: string 76 | ) { 77 | const client = new Cloudflare({ 78 | apiKey: env.CLOUDFLARE_API_KEY, 79 | apiEmail: env.CLOUDFLARE_API_EMAIL 80 | }) 81 | 82 | const response = await client.r2.buckets.cors.delete(bucketName, { 83 | account_id: accountId 84 | }) 85 | 86 | return { 87 | content: [ 88 | { 89 | type: "text", 90 | text: JSON.stringify(response, null, 2) 91 | } 92 | ] 93 | } 94 | } 95 | 96 | export async function getBucketCORS( 97 | env: Env, 98 | accountId: string, 99 | bucketName: string 100 | ) { 101 | const client = new Cloudflare({ 102 | apiKey: env.CLOUDFLARE_API_KEY, 103 | apiEmail: env.CLOUDFLARE_API_EMAIL 104 | }) 105 | 106 | const response = await client.r2.buckets.cors.get(bucketName, { 107 | account_id: accountId 108 | }) 109 | 110 | return { 111 | content: [ 112 | { 113 | type: "text", 114 | text: JSON.stringify(response, null, 2) 115 | } 116 | ] 117 | } 118 | } 119 | 120 | export async function putBucketCORS( 121 | env: Env, 122 | accountId: string, 123 | bucketName: string, 124 | corsRules: Array<{ 125 | allowedOrigins: string[] 126 | allowedMethods?: Array<"GET" | "PUT" | "POST" | "DELETE" | "HEAD"> 127 | allowedHeaders?: string[] 128 | exposeHeaders?: string[] 129 | maxAge?: number 130 | }> 131 | ) { 132 | const client = new Cloudflare({ 133 | apiKey: env.CLOUDFLARE_API_KEY, 134 | apiEmail: env.CLOUDFLARE_API_EMAIL 135 | }) 136 | 137 | // Transform the input corsRules to the format expected by the Cloudflare API 138 | const rules = corsRules.map((rule) => ({ 139 | allowed: { 140 | origins: rule.allowedOrigins, 141 | methods: rule.allowedMethods || ["GET"], 142 | headers: rule.allowedHeaders 143 | }, 144 | exposeHeaders: rule.exposeHeaders, 145 | maxAgeSeconds: rule.maxAge 146 | })) 147 | 148 | const response = await client.r2.buckets.cors.update(bucketName, { 149 | account_id: accountId, 150 | rules 151 | }) 152 | 153 | return { 154 | content: [ 155 | { 156 | type: "text", 157 | text: JSON.stringify(response, null, 2) 158 | } 159 | ] 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/cloudflare/worker-cron.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | export async function getWorkerSchedules( 4 | env: Env, 5 | accountId: string, 6 | scriptName: string 7 | ) { 8 | const client = new Cloudflare({ 9 | apiKey: env.CLOUDFLARE_API_KEY, 10 | apiEmail: env.CLOUDFLARE_API_EMAIL 11 | }) 12 | 13 | const response = await client.workers.scripts.schedules.get(scriptName, { 14 | account_id: accountId 15 | }) 16 | 17 | return { 18 | content: [ 19 | { 20 | type: "text", 21 | text: JSON.stringify(response, null, 2) 22 | } 23 | ] 24 | } 25 | } 26 | 27 | export async function updateWorkerSchedules( 28 | env: Env, 29 | accountId: string, 30 | scriptName: string, 31 | schedules: Array<{ cron: string }> 32 | ) { 33 | const client = new Cloudflare({ 34 | apiKey: env.CLOUDFLARE_API_KEY, 35 | apiEmail: env.CLOUDFLARE_API_EMAIL 36 | }) 37 | 38 | const response = await client.workers.scripts.schedules.update(scriptName, { 39 | account_id: accountId, 40 | body: schedules 41 | }) 42 | 43 | return { 44 | content: [ 45 | { 46 | type: "text", 47 | text: JSON.stringify(response, null, 2) 48 | } 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/cloudflare/workers-domains.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | export async function deleteDomain( 4 | env: Env, 5 | accountId: string, 6 | domainId: string 7 | ) { 8 | const client = new Cloudflare({ 9 | apiKey: env.CLOUDFLARE_API_KEY, 10 | apiEmail: env.CLOUDFLARE_API_EMAIL 11 | }) 12 | 13 | const response = await client.workers.domains.delete(domainId, { 14 | account_id: accountId 15 | }) 16 | 17 | return { 18 | content: [ 19 | { 20 | type: "text", 21 | text: JSON.stringify(response, null, 2) 22 | } 23 | ] 24 | } 25 | } 26 | 27 | export async function getDomain(env: Env, accountId: string, domainId: string) { 28 | const client = new Cloudflare({ 29 | apiKey: env.CLOUDFLARE_API_KEY, 30 | apiEmail: env.CLOUDFLARE_API_EMAIL 31 | }) 32 | 33 | const response = await client.workers.domains.get(domainId, { 34 | account_id: accountId 35 | }) 36 | 37 | return { 38 | content: [ 39 | { 40 | type: "text", 41 | text: JSON.stringify(response, null, 2) 42 | } 43 | ] 44 | } 45 | } 46 | 47 | export async function listDomains( 48 | env: Env, 49 | accountId: string, 50 | environment?: string, 51 | hostname?: string, 52 | service?: string, 53 | zoneId?: string, 54 | zoneName?: string 55 | ) { 56 | const client = new Cloudflare({ 57 | apiKey: env.CLOUDFLARE_API_KEY, 58 | apiEmail: env.CLOUDFLARE_API_EMAIL 59 | }) 60 | 61 | const response = await client.workers.domains.list({ 62 | account_id: accountId, 63 | environment, 64 | hostname, 65 | service, 66 | zone_id: zoneId, 67 | zone_name: zoneName 68 | }) 69 | 70 | return { 71 | content: [ 72 | { 73 | type: "text", 74 | text: JSON.stringify(response, null, 2) 75 | } 76 | ] 77 | } 78 | } 79 | 80 | export async function updateDomain( 81 | env: Env, 82 | accountId: string, 83 | environment: string, 84 | hostname: string, 85 | service: string, 86 | zoneId: string 87 | ) { 88 | const client = new Cloudflare({ 89 | apiKey: env.CLOUDFLARE_API_KEY, 90 | apiEmail: env.CLOUDFLARE_API_EMAIL 91 | }) 92 | 93 | const response = await client.workers.domains.update({ 94 | account_id: accountId, 95 | environment, 96 | hostname, 97 | service, 98 | zone_id: zoneId 99 | }) 100 | 101 | return { 102 | content: [ 103 | { 104 | type: "text", 105 | text: JSON.stringify(response, null, 2) 106 | } 107 | ] 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/cloudflare/workflows.ts: -------------------------------------------------------------------------------- 1 | import Cloudflare from "cloudflare" 2 | 3 | // Workflow functions 4 | 5 | export async function getWorkflow( 6 | env: Env, 7 | accountId: string, 8 | workflowName: string 9 | ) { 10 | const client = new Cloudflare({ 11 | apiKey: env.CLOUDFLARE_API_KEY, 12 | apiEmail: env.CLOUDFLARE_API_EMAIL 13 | }) 14 | 15 | const response = await client.workflows.get(workflowName, { 16 | account_id: accountId 17 | }) 18 | 19 | return { 20 | content: [ 21 | { 22 | type: "text", 23 | text: JSON.stringify(response, null, 2) 24 | } 25 | ] 26 | } 27 | } 28 | 29 | export async function listWorkflows(env: Env, accountId: string) { 30 | const client = new Cloudflare({ 31 | apiKey: env.CLOUDFLARE_API_KEY, 32 | apiEmail: env.CLOUDFLARE_API_EMAIL 33 | }) 34 | 35 | const response = await client.workflows.list({ 36 | account_id: accountId 37 | }) 38 | 39 | return { 40 | content: [ 41 | { 42 | type: "text", 43 | text: JSON.stringify(response, null, 2) 44 | } 45 | ] 46 | } 47 | } 48 | 49 | // Workflow Instance functions 50 | 51 | export async function getWorkflowInstance( 52 | env: Env, 53 | accountId: string, 54 | workflowName: string, 55 | instanceId: string 56 | ) { 57 | const client = new Cloudflare({ 58 | apiKey: env.CLOUDFLARE_API_KEY, 59 | apiEmail: env.CLOUDFLARE_API_EMAIL 60 | }) 61 | 62 | const response = await client.workflows.instances.get( 63 | workflowName, 64 | instanceId, 65 | { 66 | account_id: accountId 67 | } 68 | ) 69 | 70 | return { 71 | content: [ 72 | { 73 | type: "text", 74 | text: JSON.stringify(response, null, 2) 75 | } 76 | ] 77 | } 78 | } 79 | 80 | export async function listWorkflowInstances( 81 | env: Env, 82 | accountId: string, 83 | workflowName: string, 84 | dateStart?: string, 85 | dateEnd?: string, 86 | status?: 87 | | "queued" 88 | | "running" 89 | | "paused" 90 | | "errored" 91 | | "terminated" 92 | | "complete" 93 | | "waitingForPause" 94 | | "waiting" 95 | | "unknown" 96 | ) { 97 | const client = new Cloudflare({ 98 | apiKey: env.CLOUDFLARE_API_KEY, 99 | apiEmail: env.CLOUDFLARE_API_EMAIL 100 | }) 101 | 102 | const params: { 103 | account_id: string 104 | date_start?: string 105 | date_end?: string 106 | status?: 107 | | "queued" 108 | | "running" 109 | | "paused" 110 | | "errored" 111 | | "terminated" 112 | | "complete" 113 | | "waitingForPause" 114 | | "waiting" 115 | | "unknown" 116 | } = { 117 | account_id: accountId 118 | } 119 | 120 | if (dateStart) params.date_start = dateStart 121 | if (dateEnd) params.date_end = dateEnd 122 | if (status) params.status = status 123 | 124 | const response = await client.workflows.instances.list(workflowName, params) 125 | 126 | return { 127 | content: [ 128 | { 129 | type: "text", 130 | text: JSON.stringify(response, null, 2) 131 | } 132 | ] 133 | } 134 | } 135 | 136 | export async function updateWorkflowInstanceStatus( 137 | env: Env, 138 | accountId: string, 139 | workflowName: string, 140 | instanceId: string, 141 | status: "resume" | "pause" | "terminate" 142 | ) { 143 | const client = new Cloudflare({ 144 | apiKey: env.CLOUDFLARE_API_KEY, 145 | apiEmail: env.CLOUDFLARE_API_EMAIL 146 | }) 147 | 148 | const response = await client.workflows.instances.status.edit( 149 | workflowName, 150 | instanceId, 151 | { 152 | account_id: accountId, 153 | status 154 | } 155 | ) 156 | 157 | return { 158 | content: [ 159 | { 160 | type: "text", 161 | text: JSON.stringify(response, null, 2) 162 | } 163 | ] 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/cloudflare/zones.ts: -------------------------------------------------------------------------------- 1 | import { Cloudflare } from "cloudflare" 2 | 3 | export async function listZones(env: Env) { 4 | const client = new Cloudflare({ 5 | apiKey: env.CLOUDFLARE_API_KEY, 6 | apiEmail: env.CLOUDFLARE_API_EMAIL 7 | }) 8 | 9 | const response = await client.zones.list() 10 | 11 | return { 12 | content: [ 13 | { 14 | type: "text", 15 | text: JSON.stringify(response, null, 2) 16 | } 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { WorkerEntrypoint } from "cloudflare:workers" 2 | import { ProxyToSelf } from "workers-mcp" 3 | import { purgeEverything } from "./cloudflare/cache" 4 | import { 5 | createDNSRecord, 6 | deleteDNSRecord, 7 | editDNSRecord, 8 | listDNSRecords 9 | } from "./cloudflare/dns" 10 | import { 11 | createHyperdriveConfig, 12 | deleteHyperdriveConfig, 13 | editHyperdriveConfig, 14 | getHyperdriveConfig, 15 | listHyperdriveConfigs 16 | } from "./cloudflare/hyperdrive" 17 | import { 18 | bulkDeleteKeys, 19 | bulkUpdateKeys, 20 | createNamespace, 21 | deleteNamespace, 22 | deleteValue, 23 | getMetadata, 24 | getNamespace, 25 | getValue, 26 | listKeys, 27 | listNamespaces, 28 | updateNamespace, 29 | updateValue 30 | } from "./cloudflare/kv" 31 | import { 32 | acknowledgeMessages, 33 | createQueue, 34 | getQueue, 35 | listQueues, 36 | pullMessages 37 | } from "./cloudflare/queues" 38 | import { 39 | createBucket, 40 | deleteBucketCORS, 41 | getBucket, 42 | getBucketCORS, 43 | listBuckets, 44 | putBucketCORS 45 | } from "./cloudflare/r2" 46 | import { 47 | getWorkerSchedules, 48 | updateWorkerSchedules 49 | } from "./cloudflare/worker-cron" 50 | import { 51 | deleteDomain, 52 | getDomain, 53 | listDomains, 54 | updateDomain 55 | } from "./cloudflare/workers-domains" 56 | import { 57 | getWorkflow, 58 | getWorkflowInstance, 59 | listWorkflowInstances, 60 | listWorkflows, 61 | updateWorkflowInstanceStatus 62 | } from "./cloudflare/workflows" 63 | import { listZones } from "./cloudflare/zones" 64 | import type { DNSRecordType } from "./types" 65 | 66 | export default class MyWorker extends WorkerEntrypoint { 67 | /** 68 | * @ignore 69 | */ 70 | async fetch(request: Request): Promise { 71 | return new ProxyToSelf(this).fetch(request) 72 | } 73 | 74 | /** 75 | * List all Cloudflare zones for the account. 76 | * @return {Promise} List of zones. 77 | */ 78 | async listZones() { 79 | return await listZones(this.env) 80 | } 81 | 82 | /** 83 | * Purge everything from Cloudflare's cache for a zone. 84 | * @param zoneId {string} The ID of the zone to purge cache for. 85 | * @return {Promise} Response from the purge operation. 86 | */ 87 | async purgeCache(zoneId: string) { 88 | return await purgeEverything(this.env, zoneId) 89 | } 90 | 91 | /** 92 | * Create a new DNS record. 93 | * @param zoneId {string} The ID of the zone to create the record in. 94 | * @param name {string} The name of the DNS record. 95 | * @param content {string} The content of the DNS record. 96 | * @param type {string} The type of DNS record (CNAME, A, TXT, or MX). 97 | * @param comment {string} Optional comment for the DNS record. 98 | * @param proxied {boolean} Optional whether to proxy the record through Cloudflare. 99 | * @return {Promise} The created DNS record. 100 | */ 101 | async createDNSRecord( 102 | zoneId: string, 103 | name: string, 104 | content: string, 105 | type: string, 106 | comment?: string, 107 | proxied?: boolean 108 | ) { 109 | return await createDNSRecord( 110 | this.env, 111 | zoneId, 112 | name, 113 | content, 114 | type as DNSRecordType, 115 | comment, 116 | proxied 117 | ) 118 | } 119 | 120 | /** 121 | * Delete a DNS record. 122 | * @param zoneId {string} The ID of the zone containing the record. 123 | * @param recordId {string} The ID of the DNS record to delete. 124 | * @return {Promise} Response from the delete operation. 125 | */ 126 | async deleteDNSRecord(zoneId: string, recordId: string) { 127 | return await deleteDNSRecord(this.env, zoneId, recordId) 128 | } 129 | 130 | /** 131 | * Edit an existing DNS record. 132 | * @param zoneId {string} The ID of the zone containing the record. 133 | * @param recordId {string} The ID of the DNS record to edit. 134 | * @param content {string} The new content for the DNS record. 135 | * @param type {string} The type of DNS record (CNAME, A, TXT, or MX). 136 | * @param comment {string} Optional comment for the DNS record. 137 | * @param proxied {boolean} Optional whether to proxy the record through Cloudflare. 138 | * @return {Promise} The updated DNS record. 139 | */ 140 | async editDNSRecord( 141 | zoneId: string, 142 | recordId: string, 143 | content: string, 144 | type: string, 145 | comment?: string, 146 | proxied?: boolean 147 | ) { 148 | return await editDNSRecord( 149 | this.env, 150 | zoneId, 151 | recordId, 152 | content, 153 | type as DNSRecordType, 154 | comment, 155 | proxied 156 | ) 157 | } 158 | 159 | /** 160 | * List all DNS records for a zone. 161 | * @param zoneId {string} The ID of the zone to list records for. 162 | * @return {Promise} List of DNS records. 163 | */ 164 | async listDNSRecords(zoneId: string) { 165 | return await listDNSRecords(this.env, zoneId) 166 | } 167 | 168 | /** 169 | * Create a new Hyperdrive configuration. 170 | * @param accountId {string} The Cloudflare account ID. 171 | * @param name {string} The name for the new Hyperdrive configuration. 172 | * @param originType {string} The type of origin ("standard" or "access"). 173 | * @param database {string} The name of your origin database. 174 | * @param host {string} The host (hostname or IP) of your origin database. 175 | * @param password {string} The password required to access your origin database. 176 | * @param port {number} The port of your origin database. 177 | * @param scheme {string} The URL scheme used to connect to your origin database. 178 | * @param user {string} The user of your origin database. 179 | * @param accessClientId {string} The Client ID of the Access token (required if originType is "access"). 180 | * @param accessClientSecret {string} The Client Secret of the Access token (required if originType is "access"). 181 | * @param cachingDisabled {boolean} When true, disables caching of SQL responses. 182 | * @param cachingMaxAge {number} Optional max duration for which items should persist in cache. 183 | * @param cachingStaleWhileRevalidate {number} Optional duration cache may serve stale responses. 184 | * @return {Promise} The created Hyperdrive configuration. 185 | */ 186 | async createHyperdriveConfig( 187 | accountId: string, 188 | name: string, 189 | originType: string, 190 | database: string, 191 | host: string, 192 | password: string, 193 | port: number, 194 | scheme: string, 195 | user: string, 196 | accessClientId?: string, 197 | accessClientSecret?: string, 198 | cachingDisabled?: boolean, 199 | cachingMaxAge?: number, 200 | cachingStaleWhileRevalidate?: number 201 | ) { 202 | type StandardOrigin = { 203 | database: string 204 | host: string 205 | password: string 206 | port: number 207 | scheme: "postgres" | "postgresql" 208 | user: string 209 | } 210 | 211 | type AccessOrigin = { 212 | access_client_id: string 213 | access_client_secret: string 214 | database: string 215 | host: string 216 | password: string 217 | scheme: "postgres" | "postgresql" 218 | user: string 219 | } 220 | 221 | let origin: StandardOrigin | AccessOrigin 222 | if (originType === "access" && accessClientId && accessClientSecret) { 223 | // Origin for Access-protected database 224 | origin = { 225 | access_client_id: accessClientId, 226 | access_client_secret: accessClientSecret, 227 | database, 228 | host, 229 | password, 230 | scheme: scheme as "postgres" | "postgresql", 231 | user 232 | } 233 | } else { 234 | // Standard origin 235 | origin = { 236 | database, 237 | host, 238 | password, 239 | port, 240 | scheme: scheme as "postgres" | "postgresql", 241 | user 242 | } 243 | } 244 | 245 | const caching = 246 | cachingDisabled !== undefined || 247 | cachingMaxAge !== undefined || 248 | cachingStaleWhileRevalidate !== undefined 249 | ? { 250 | disabled: cachingDisabled, 251 | max_age: cachingMaxAge, 252 | stale_while_revalidate: cachingStaleWhileRevalidate 253 | } 254 | : undefined 255 | 256 | return await createHyperdriveConfig( 257 | this.env, 258 | accountId, 259 | name, 260 | origin, 261 | caching 262 | ) 263 | } 264 | 265 | /** 266 | * Delete a Hyperdrive configuration. 267 | * @param accountId {string} The Cloudflare account ID. 268 | * @param hyperdriveId {string} The ID of the Hyperdrive configuration to delete. 269 | * @return {Promise} Response from the delete operation. 270 | */ 271 | async deleteHyperdriveConfig(accountId: string, hyperdriveId: string) { 272 | return await deleteHyperdriveConfig(this.env, accountId, hyperdriveId) 273 | } 274 | 275 | /** 276 | * Edit a Hyperdrive configuration. 277 | * @param accountId {string} The Cloudflare account ID. 278 | * @param hyperdriveId {string} The ID of the Hyperdrive configuration to edit. 279 | * @param name {string} Optional new name for the Hyperdrive configuration. 280 | * @param cachingDisabled {boolean} Optional when true, disables caching of SQL responses. 281 | * @param cachingMaxAge {number} Optional max duration for which items should persist in cache. 282 | * @param cachingStaleWhileRevalidate {number} Optional duration cache may serve stale responses. 283 | * @return {Promise} The updated Hyperdrive configuration. 284 | */ 285 | async editHyperdriveConfig( 286 | accountId: string, 287 | hyperdriveId: string, 288 | name?: string, 289 | cachingDisabled?: boolean, 290 | cachingMaxAge?: number, 291 | cachingStaleWhileRevalidate?: number 292 | ) { 293 | const params: { 294 | name?: string 295 | caching?: { 296 | disabled?: boolean 297 | max_age?: number 298 | stale_while_revalidate?: number 299 | } 300 | } = {} 301 | 302 | if (name !== undefined) { 303 | params.name = name 304 | } 305 | 306 | if ( 307 | cachingDisabled !== undefined || 308 | cachingMaxAge !== undefined || 309 | cachingStaleWhileRevalidate !== undefined 310 | ) { 311 | params.caching = { 312 | disabled: cachingDisabled, 313 | max_age: cachingMaxAge, 314 | stale_while_revalidate: cachingStaleWhileRevalidate 315 | } 316 | } 317 | 318 | return await editHyperdriveConfig( 319 | this.env, 320 | accountId, 321 | hyperdriveId, 322 | params 323 | ) 324 | } 325 | 326 | /** 327 | * Get a Hyperdrive configuration. 328 | * @param accountId {string} The Cloudflare account ID. 329 | * @param hyperdriveId {string} The ID of the Hyperdrive configuration to retrieve. 330 | * @return {Promise} The Hyperdrive configuration. 331 | */ 332 | async getHyperdriveConfig(accountId: string, hyperdriveId: string) { 333 | return await getHyperdriveConfig(this.env, accountId, hyperdriveId) 334 | } 335 | 336 | /** 337 | * List all Hyperdrive configurations in an account. 338 | * @param accountId {string} The Cloudflare account ID. 339 | * @return {Promise} List of Hyperdrive configurations. 340 | */ 341 | async listHyperdriveConfigs(accountId: string) { 342 | return await listHyperdriveConfigs(this.env, accountId) 343 | } 344 | 345 | /** 346 | * Create a KV namespace. 347 | * @param accountId {string} The Cloudflare account ID. 348 | * @param title {string} A human-readable string name for a Namespace. 349 | * @return {Promise} The created namespace. 350 | */ 351 | async createKVNamespace(accountId: string, title: string) { 352 | return await createNamespace(this.env, accountId, title) 353 | } 354 | 355 | /** 356 | * Update a KV namespace title. 357 | * @param accountId {string} The Cloudflare account ID. 358 | * @param namespaceId {string} The ID of the namespace to update. 359 | * @param title {string} New human-readable string name for the Namespace. 360 | * @return {Promise} Response from the update operation. 361 | */ 362 | async updateKVNamespace( 363 | accountId: string, 364 | namespaceId: string, 365 | title: string 366 | ) { 367 | return await updateNamespace(this.env, accountId, namespaceId, title) 368 | } 369 | 370 | /** 371 | * List KV namespaces for an account. 372 | * @param accountId {string} The Cloudflare account ID. 373 | * @param order {string} Optional field to order results by: 'id' or 'title'. 374 | * @param direction {string} Optional direction to order namespaces: 'asc' or 'desc'. 375 | * @return {Promise} List of namespaces. 376 | */ 377 | async listKVNamespaces( 378 | accountId: string, 379 | order?: "id" | "title", 380 | direction?: "asc" | "desc" 381 | ) { 382 | return await listNamespaces(this.env, accountId, order, direction) 383 | } 384 | 385 | /** 386 | * Delete a KV namespace. 387 | * @param accountId {string} The Cloudflare account ID. 388 | * @param namespaceId {string} The ID of the namespace to delete. 389 | * @return {Promise} Response from the delete operation. 390 | */ 391 | async deleteKVNamespace(accountId: string, namespaceId: string) { 392 | return await deleteNamespace(this.env, accountId, namespaceId) 393 | } 394 | 395 | /** 396 | * Get a specific KV namespace. 397 | * @param accountId {string} The Cloudflare account ID. 398 | * @param namespaceId {string} The ID of the namespace to retrieve. 399 | * @return {Promise} The namespace details. 400 | */ 401 | async getKVNamespace(accountId: string, namespaceId: string) { 402 | return await getNamespace(this.env, accountId, namespaceId) 403 | } 404 | 405 | /** 406 | * List keys in a KV namespace. 407 | * @param accountId {string} The Cloudflare account ID. 408 | * @param namespaceId {string} The ID of the namespace. 409 | * @param prefix {string} Optional string prefix to filter key names. 410 | * @param cursor {string} Optional cursor for pagination. 411 | * @param limit {number} Optional limit on number of keys to return. 412 | * @return {Promise} List of keys. 413 | */ 414 | async listKVKeys( 415 | accountId: string, 416 | namespaceId: string, 417 | prefix?: string, 418 | cursor?: string, 419 | limit?: number 420 | ) { 421 | return await listKeys( 422 | this.env, 423 | accountId, 424 | namespaceId, 425 | prefix, 426 | cursor, 427 | limit 428 | ) 429 | } 430 | 431 | /** 432 | * Get metadata for a key in a KV namespace. 433 | * @param accountId {string} The Cloudflare account ID. 434 | * @param namespaceId {string} The ID of the namespace. 435 | * @param keyName {string} The name of the key. 436 | * @return {Promise} The metadata for the key. 437 | */ 438 | async getKVMetadata( 439 | accountId: string, 440 | namespaceId: string, 441 | keyName: string 442 | ) { 443 | return await getMetadata(this.env, accountId, namespaceId, keyName) 444 | } 445 | 446 | /** 447 | * Update a value in a KV namespace. 448 | * @param accountId {string} The Cloudflare account ID. 449 | * @param namespaceId {string} The ID of the namespace. 450 | * @param keyName {string} The name of the key. 451 | * @param value {string} The value to store. 452 | * @param metadata {string} Optional JSON metadata to associate with the key/value pair. 453 | * @param expiration {number} Optional time at which the key should expire. 454 | * @param expiration_ttl {number} Optional time-to-live in seconds for the key. 455 | * @return {Promise} Response from the update operation. 456 | */ 457 | async updateKVValue( 458 | accountId: string, 459 | namespaceId: string, 460 | keyName: string, 461 | value: string, 462 | metadata?: string, 463 | expiration?: number, 464 | expiration_ttl?: number 465 | ) { 466 | return await updateValue( 467 | this.env, 468 | accountId, 469 | namespaceId, 470 | keyName, 471 | value, 472 | metadata, 473 | expiration, 474 | expiration_ttl 475 | ) 476 | } 477 | 478 | /** 479 | * Delete a value from a KV namespace. 480 | * @param accountId {string} The Cloudflare account ID. 481 | * @param namespaceId {string} The ID of the namespace. 482 | * @param keyName {string} The name of the key to delete. 483 | * @return {Promise} Response from the delete operation. 484 | */ 485 | async deleteKVValue( 486 | accountId: string, 487 | namespaceId: string, 488 | keyName: string 489 | ) { 490 | return await deleteValue(this.env, accountId, namespaceId, keyName) 491 | } 492 | 493 | /** 494 | * Get a value from a KV namespace. 495 | * @param accountId {string} The Cloudflare account ID. 496 | * @param namespaceId {string} The ID of the namespace. 497 | * @param keyName {string} The name of the key to retrieve. 498 | * @return {Promise} The value associated with the key. 499 | */ 500 | async getKVValue(accountId: string, namespaceId: string, keyName: string) { 501 | return await getValue(this.env, accountId, namespaceId, keyName) 502 | } 503 | 504 | /** 505 | * Create a new queue. 506 | * @param accountId {string} The Cloudflare account ID. 507 | * @param queueName {string} Name for the new queue. 508 | * @return {Promise} The created queue. 509 | */ 510 | async createQueue(accountId: string, queueName: string) { 511 | return await createQueue(this.env, accountId, queueName) 512 | } 513 | 514 | /** 515 | * Get details about a specific queue. 516 | * @param accountId {string} The Cloudflare account ID. 517 | * @param queueId {string} The ID of the queue to retrieve. 518 | * @return {Promise} The queue details. 519 | */ 520 | async getQueue(accountId: string, queueId: string) { 521 | return await getQueue(this.env, accountId, queueId) 522 | } 523 | 524 | /** 525 | * List all queues for an account. 526 | * @param accountId {string} The Cloudflare account ID. 527 | * @return {Promise} List of queues. 528 | */ 529 | async listQueues(accountId: string) { 530 | return await listQueues(this.env, accountId) 531 | } 532 | 533 | /** 534 | * Acknowledge messages from a queue. 535 | * @param accountId {string} The Cloudflare account ID. 536 | * @param queueId {string} The ID of the queue. 537 | * @param acks {string} JSON string of message lease IDs to acknowledge. Format: [{lease_id: "string"}] 538 | * @param retries {string} Optional JSON string of message lease IDs to retry with optional delay. Format: [{lease_id: "string", delay_seconds?: number}] 539 | * @return {Promise} Response from the acknowledge operation. 540 | */ 541 | async acknowledgeQueueMessages( 542 | accountId: string, 543 | queueId: string, 544 | acks: string, 545 | retries?: string 546 | ) { 547 | // Parse the JSON strings to get the actual objects 548 | const parsedAcks = JSON.parse(acks) as Array<{ lease_id: string }> 549 | const parsedRetries = retries 550 | ? (JSON.parse(retries) as Array<{ 551 | lease_id: string 552 | delay_seconds?: number 553 | }>) 554 | : undefined 555 | 556 | return await acknowledgeMessages( 557 | this.env, 558 | accountId, 559 | queueId, 560 | parsedAcks, 561 | parsedRetries 562 | ) 563 | } 564 | 565 | /** 566 | * Pull a batch of messages from a queue. 567 | * @param accountId {string} The Cloudflare account ID. 568 | * @param queueId {string} The ID of the queue. 569 | * @param batchSize {number} Optional maximum number of messages to include in the batch. 570 | * @param visibilityTimeoutMs {number} Optional number of milliseconds that messages are exclusively leased. 571 | * @return {Promise} The pulled messages. 572 | */ 573 | async pullQueueMessages( 574 | accountId: string, 575 | queueId: string, 576 | batchSize?: number, 577 | visibilityTimeoutMs?: number 578 | ) { 579 | return await pullMessages( 580 | this.env, 581 | accountId, 582 | queueId, 583 | batchSize, 584 | visibilityTimeoutMs 585 | ) 586 | } 587 | 588 | /** 589 | * Bulk delete keys from a KV namespace. 590 | * @param accountId {string} The Cloudflare account ID. 591 | * @param namespaceId {string} The ID of the namespace. 592 | * @param keys {string} JSON string array of key names to delete. Format: ["key1", "key2", "key3"] 593 | * @return {Promise} Response from the bulk delete operation. 594 | */ 595 | async bulkDeleteKVKeys( 596 | accountId: string, 597 | namespaceId: string, 598 | keys: string 599 | ) { 600 | // Parse the JSON string to get the array of keys 601 | const parsedKeys = JSON.parse(keys) as string[] 602 | 603 | return await bulkDeleteKeys( 604 | this.env, 605 | accountId, 606 | namespaceId, 607 | parsedKeys 608 | ) 609 | } 610 | 611 | /** 612 | * Bulk update key-value pairs in a KV namespace. 613 | * @param accountId {string} The Cloudflare account ID. 614 | * @param namespaceId {string} The ID of the namespace. 615 | * @param keyValues {string} JSON string array of key-value objects. Format: [{key: "string", value: "string", expiration?: number, expiration_ttl?: number, base64?: boolean}] 616 | * @return {Promise} Response from the bulk update operation. 617 | */ 618 | async bulkUpdateKVKeys( 619 | accountId: string, 620 | namespaceId: string, 621 | keyValues: string 622 | ) { 623 | // Parse the JSON string to get the array of key-value objects 624 | const parsedKeyValues = JSON.parse(keyValues) as Array<{ 625 | key: string 626 | value: string 627 | expiration?: number 628 | expiration_ttl?: number 629 | base64?: boolean 630 | metadata?: Record 631 | }> 632 | 633 | return await bulkUpdateKeys( 634 | this.env, 635 | accountId, 636 | namespaceId, 637 | parsedKeyValues 638 | ) 639 | } 640 | 641 | /** 642 | * Create a new R2 bucket. 643 | * @param accountId {string} The Cloudflare account ID. 644 | * @param name {string} The name for the new bucket. 645 | * @return {Promise} The created bucket. 646 | */ 647 | async createR2Bucket(accountId: string, name: string) { 648 | return await createBucket(this.env, accountId, name) 649 | } 650 | 651 | /** 652 | * Get a specific R2 bucket. 653 | * @param accountId {string} The Cloudflare account ID. 654 | * @param bucketName {string} The name of the bucket to retrieve. 655 | * @return {Promise} The bucket details. 656 | */ 657 | async getR2Bucket(accountId: string, bucketName: string) { 658 | return await getBucket(this.env, accountId, bucketName) 659 | } 660 | 661 | /** 662 | * List all R2 buckets for an account. 663 | * @param accountId {string} The Cloudflare account ID. 664 | * @return {Promise} List of buckets. 665 | */ 666 | async listR2Buckets(accountId: string) { 667 | return await listBuckets(this.env, accountId) 668 | } 669 | 670 | /** 671 | * Delete CORS configuration for an R2 bucket. 672 | * @param accountId {string} The Cloudflare account ID. 673 | * @param bucketName {string} The name of the bucket. 674 | * @return {Promise} Response from the delete operation. 675 | */ 676 | async deleteR2BucketCORS(accountId: string, bucketName: string) { 677 | return await deleteBucketCORS(this.env, accountId, bucketName) 678 | } 679 | 680 | /** 681 | * Get CORS configuration for an R2 bucket. 682 | * @param accountId {string} The Cloudflare account ID. 683 | * @param bucketName {string} The name of the bucket. 684 | * @return {Promise} The CORS configuration. 685 | */ 686 | async getR2BucketCORS(accountId: string, bucketName: string) { 687 | return await getBucketCORS(this.env, accountId, bucketName) 688 | } 689 | 690 | /** 691 | * Update CORS configuration for an R2 bucket. 692 | * @param accountId {string} The Cloudflare account ID. 693 | * @param bucketName {string} The name of the bucket. 694 | * @param corsRules {string} JSON string array of CORS rules. Format: [{allowedOrigins: ["example.com"], allowedMethods: ["GET"], allowedHeaders: ["Content-Type"], exposeHeaders: ["Content-Length"], maxAge: 86400}] 695 | * @return {Promise} Response from the update operation. 696 | */ 697 | async updateR2BucketCORS( 698 | accountId: string, 699 | bucketName: string, 700 | corsRules: string 701 | ) { 702 | // Parse the JSON string to get the array of CORS rules 703 | const parsedRules = JSON.parse(corsRules) as Array<{ 704 | allowedOrigins: string[] 705 | allowedMethods?: Array<"GET" | "PUT" | "POST" | "DELETE" | "HEAD"> 706 | allowedHeaders?: string[] 707 | exposeHeaders?: string[] 708 | maxAge?: number 709 | }> 710 | 711 | return await putBucketCORS(this.env, accountId, bucketName, parsedRules) 712 | } 713 | 714 | /** 715 | * Delete a Worker domain. 716 | * @param accountId {string} The Cloudflare account ID. 717 | * @param domainId {string} The ID of the domain to delete. 718 | * @return {Promise} Response from the delete operation. 719 | */ 720 | async deleteWorkerDomain(accountId: string, domainId: string) { 721 | return await deleteDomain(this.env, accountId, domainId) 722 | } 723 | 724 | /** 725 | * Get a Worker domain. 726 | * @param accountId {string} The Cloudflare account ID. 727 | * @param domainId {string} The ID of the domain to retrieve. 728 | * @return {Promise} The domain details. 729 | */ 730 | async getWorkerDomain(accountId: string, domainId: string) { 731 | return await getDomain(this.env, accountId, domainId) 732 | } 733 | 734 | /** 735 | * List all Worker domains for an account. 736 | * @param accountId {string} The Cloudflare account ID. 737 | * @param environment {string} Optional worker environment to filter by. 738 | * @param hostname {string} Optional hostname to filter by. 739 | * @param service {string} Optional worker service to filter by. 740 | * @param zoneId {string} Optional zone ID to filter by. 741 | * @param zoneName {string} Optional zone name to filter by. 742 | * @return {Promise} List of domains. 743 | */ 744 | async listWorkerDomains( 745 | accountId: string, 746 | environment?: string, 747 | hostname?: string, 748 | service?: string, 749 | zoneId?: string, 750 | zoneName?: string 751 | ) { 752 | return await listDomains( 753 | this.env, 754 | accountId, 755 | environment, 756 | hostname, 757 | service, 758 | zoneId, 759 | zoneName 760 | ) 761 | } 762 | 763 | /** 764 | * Attach a Worker to a zone and hostname. 765 | * @param accountId {string} The Cloudflare account ID. 766 | * @param environment {string} Worker environment to associate with the zone and hostname. 767 | * @param hostname {string} Hostname of the Worker Domain. 768 | * @param service {string} Worker service to associate with the zone and hostname. 769 | * @param zoneId {string} ID of the zone. 770 | * @return {Promise} The updated domain. 771 | */ 772 | async updateWorkerDomain( 773 | accountId: string, 774 | environment: string, 775 | hostname: string, 776 | service: string, 777 | zoneId: string 778 | ) { 779 | return await updateDomain( 780 | this.env, 781 | accountId, 782 | environment, 783 | hostname, 784 | service, 785 | zoneId 786 | ) 787 | } 788 | 789 | /** 790 | * Get Cron Triggers for a Worker. 791 | * @param accountId {string} The Cloudflare account ID. 792 | * @param scriptName {string} The name of the Worker script. 793 | * @return {Promise} The Worker's cron schedules. 794 | */ 795 | async getWorkerCronTriggers(accountId: string, scriptName: string) { 796 | return await getWorkerSchedules(this.env, accountId, scriptName) 797 | } 798 | 799 | /** 800 | * Update Cron Triggers for a Worker. 801 | * @param accountId {string} The Cloudflare account ID. 802 | * @param scriptName {string} The name of the Worker script. 803 | * @param schedules {string} JSON string array of cron schedules. Format: [{"cron": "* * * * *"}] 804 | * @return {Promise} The updated cron schedules. 805 | */ 806 | async updateWorkerCronTriggers( 807 | accountId: string, 808 | scriptName: string, 809 | schedules: string 810 | ) { 811 | // Parse the JSON string to get the array of schedules 812 | const parsedSchedules = JSON.parse(schedules) as Array<{ cron: string }> 813 | 814 | return await updateWorkerSchedules( 815 | this.env, 816 | accountId, 817 | scriptName, 818 | parsedSchedules 819 | ) 820 | } 821 | 822 | /** 823 | * Get details about a workflow. 824 | * @param accountId {string} The Cloudflare account ID. 825 | * @param workflowName {string} The name of the workflow. 826 | * @return {Promise} The workflow details. 827 | */ 828 | async getWorkflow(accountId: string, workflowName: string) { 829 | return await getWorkflow(this.env, accountId, workflowName) 830 | } 831 | 832 | /** 833 | * List all workflows for an account. 834 | * @param accountId {string} The Cloudflare account ID. 835 | * @return {Promise} List of workflows. 836 | */ 837 | async listWorkflows(accountId: string) { 838 | return await listWorkflows(this.env, accountId) 839 | } 840 | 841 | /** 842 | * Get details about a workflow instance including logs and status. 843 | * @param accountId {string} The Cloudflare account ID. 844 | * @param workflowName {string} The name of the workflow. 845 | * @param instanceId {string} The ID of the workflow instance. 846 | * @return {Promise} The workflow instance details. 847 | */ 848 | async getWorkflowInstance( 849 | accountId: string, 850 | workflowName: string, 851 | instanceId: string 852 | ) { 853 | return await getWorkflowInstance( 854 | this.env, 855 | accountId, 856 | workflowName, 857 | instanceId 858 | ) 859 | } 860 | 861 | /** 862 | * List all instances of a workflow. 863 | * @param accountId {string} The Cloudflare account ID. 864 | * @param workflowName {string} The name of the workflow. 865 | * @param dateStart {string} Optional start date in ISO 8601 format (UTC). 866 | * @param dateEnd {string} Optional end date in ISO 8601 format (UTC). 867 | * @param status {string} Optional status to filter by (queued, running, paused, errored, terminated, complete, waitingForPause, waiting, unknown). 868 | * @return {Promise} List of workflow instances. 869 | */ 870 | async listWorkflowInstances( 871 | accountId: string, 872 | workflowName: string, 873 | dateStart?: string, 874 | dateEnd?: string, 875 | status?: 876 | | "queued" 877 | | "running" 878 | | "paused" 879 | | "errored" 880 | | "terminated" 881 | | "complete" 882 | | "waitingForPause" 883 | | "waiting" 884 | | "unknown" 885 | ) { 886 | return await listWorkflowInstances( 887 | this.env, 888 | accountId, 889 | workflowName, 890 | dateStart, 891 | dateEnd, 892 | status 893 | ) 894 | } 895 | 896 | /** 897 | * Change the status of a workflow instance. 898 | * @param accountId {string} The Cloudflare account ID. 899 | * @param workflowName {string} The name of the workflow. 900 | * @param instanceId {string} The ID of the workflow instance. 901 | * @param status {string} The new status (resume, pause, or terminate). 902 | * @return {Promise} The updated workflow instance status. 903 | */ 904 | async updateWorkflowInstanceStatus( 905 | accountId: string, 906 | workflowName: string, 907 | instanceId: string, 908 | status: "resume" | "pause" | "terminate" 909 | ) { 910 | return await updateWorkflowInstanceStatus( 911 | this.env, 912 | accountId, 913 | workflowName, 914 | instanceId, 915 | status 916 | ) 917 | } 918 | } 919 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type DNSRecordType = "CNAME" | "A" | "TXT" | "MX" 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Bundler", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "lib": ["ESNext"], 9 | "types": ["@cloudflare/workers-types/2023-07-01"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "hono/jsx", 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*": ["./src/*"] 15 | } 16 | }, 17 | "include": ["src/**/*", "worker-configuration.d.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env { 4 | SHARED_SECRET: string 5 | CLOUDFLARE_API_KEY: string 6 | CLOUDFLARE_API_EMAIL: string 7 | } 8 | -------------------------------------------------------------------------------- /wrangler.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/wrangler/config-schema.json", 3 | "name": "cloudflare-api-mcp", 4 | "main": "src/index.ts", 5 | "compatibility_date": "2025-02-22", 6 | "compatibility_flags": ["nodejs_compat"], 7 | // "kv_namespaces": [ 8 | // { 9 | // "binding": "MY_KV_NAMESPACE", 10 | // "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 11 | // } 12 | // ], 13 | // "r2_buckets": [ 14 | // { 15 | // "binding": "MY_BUCKET", 16 | // "bucket_name": "my-bucket" 17 | // } 18 | // ], 19 | // "d1_databases": [ 20 | // { 21 | // "binding": "MY_DB", 22 | // "database_name": "my-database", 23 | // "database_id": "" 24 | // } 25 | // ], 26 | // "ai": { 27 | // "binding": "AI" 28 | // }, 29 | "observability": { 30 | "enabled": true, 31 | "head_sampling_rate": 1 32 | } 33 | } 34 | --------------------------------------------------------------------------------