bun-cloudflare-workers — скилл для Claude Code: деплой на Workers
Скилл для сборки и деплоя Cloudflare Workers на Bun: подсказывает структуру проекта, биндинги KV, D1, R2 и Durable Objects.
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a claude-codeЧто делает bun-cloudflare-workers
Скилл включается, когда в разговоре всплывают Cloudflare Workers на Bun, wrangler, edge-деплой или перенос приложения на Cloudflare. Внутри — готовые шаблоны wrangler.toml и package.json со скриптами dev, deploy и build, примеры воркеров на чистом TypeScript и на Hono.
Отдельные разделы посвящены хранилищам: KV с expirationTtl, D1 с prepare/bind и батч-транзакциями, R2 для объектов, Durable Objects со счётчиком и миграциями. Для локальной разработки и тестов есть варианты с bun:test и Miniflare.
Один момент стоит держать в голове: bunx create-cloudflare скачивает и выполняет чужой код. Автор советует блокировать post-install скрипты через trustedDependencies, выставлять minimumReleaseAge в bunfig.toml и проверять пакеты через Socket CLI перед установкой. Для полной настройки безопасности скилл отправляет к dependency-upgrade.
Какие задачи решает
- развернуть новый воркер на Cloudflare через Bun
- подключить KV, D1 или R2 к воркеру
- написать роутинг на Hono с типизированными биндингами
- протестировать воркер локально через Miniflare
- настроить безопасную установку пакетов при скаффолдинге
Примеры запросов агенту
- помоги задеплоить воркер на Cloudflare Workers через Bun
- настрой биндинг D1 в wrangler.toml и запросы к базе
- перепиши этот воркер на Hono с типами для KV
Как установить bun-cloudflare-workers
1Через Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a claude-code2Вручную: положить файлы
~/.claude/skills/bun-cloudflare-workers/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/bun-cloudflare-workers/
1Через Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a codex2Вручную: положить файлы
.agents/skills/bun-cloudflare-workers/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a cursor2Вручную: положить файлы
.cursor/skills/bun-cloudflare-workers/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install secondsky/claude-skills bun-cloudflare-workers2Вручную: положить файлы
.github/skills/bun-cloudflare-workers/SKILL.md1Через Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a gemini-cli2Командой платформы
gemini skills install https://github.com/secondsky/claude-skills --path plugins/bun/skills/bun-cloudflare-workersВручную: положить файлы
.devin/skills/bun-cloudflare-workers/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Из того же набора89
Похожие
Рядом в теме «Облака: AWS, Azure, GCP»
Всё по теме «Облака: AWS, Azure, GCP» →Вопросы о bun-cloudflare-workers
Как установить bun-cloudflare-workers в Claude?
Выполните npx skills add secondsky/claude-skills --skill bun-cloudflare-workers -a claude-code. Скилл окажется в ~/.claude/skills/bun-cloudflare-workers/SKILL.md.
Что делает bun-cloudflare-workers?
Даёт шаблоны и примеры для сборки и деплоя Cloudflare Workers на Bun: конфиг wrangler, воркеры на TypeScript и Hono, работа с KV, D1, R2 и Durable Objects.
Что нужно учесть при скаффолдинге проекта?
bunx create-cloudflare выполняет скачанный код. Скилл советует отключить post-install скрипты, задать cooldown для новых версий и проверить пакеты через Socket CLI.
Исходный текст
SKILL.md · MIT
---
name: bun-cloudflare-workers
description: This skill should be used when the user asks about "Cloudflare Workers with Bun", "deploying Bun to Workers", "wrangler with Bun", "edge deployment", "Bun to Cloudflare", or building and deploying applications to Cloudflare Workers using Bun.
license: MIT
---
# Bun Cloudflare Workers
Build and deploy Cloudflare Workers using Bun for development.
## Quick Start
```bash
# Create new Workers project
bunx create-cloudflare my-worker
cd my-worker
# Install dependencies
bun install
# Development
bun run dev
# Deploy
bun run deploy
```
## Secure Installation
Scaffolding tools like `bunx create-cloudflare` download and execute remote code. Before running, follow supply chain security best practices:
- **Block post-install scripts** — Bun disables them by default; allow specific packages via `trustedDependencies` in `package.json`
- **Cooldown period** — Configure `minimumReleaseAge` in `bunfig.toml` to wait 7 days for new versions
- **Audit before installing** — Run `socket package score npm <pkg>` or use `socket npm install <pkg>` to check packages
Load the `dependency-upgrade` skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.
## Project Setup
### package.json
```json
{
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"build": "bun build src/index.ts --outdir=dist --target=browser"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260408.0",
"wrangler": "^4.81.0"
}
}
```
### wrangler.toml
```toml
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
# Use Bun for local dev
[dev]
local_protocol = "http"
# Bindings
[[kv_namespaces]]
binding = "KV"
id = "xxx"
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxx"
```
## Basic Worker
```typescript
// src/index.ts
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/") {
return new Response("Hello from Cloudflare Workers!");
}
if (url.pathname === "/api/data") {
return Response.json({ message: "Hello" });
}
return new Response("Not Found", { status: 404 });
},
};
interface Env {
KV: KVNamespace;
DB: D1Database;
}
```
## Using Hono
```typescript
// src/index.ts
import { Hono } from "hono";
type Bindings = {
KV: KVNamespace;
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/", (c) => c.text("Hello Hono!"));
app.get("/api/users", async (c) => {
const users = await c.env.DB.prepare("SELECT * FROM users").all();
return c.json(users.results);
});
app.post("/api/users", async (c) => {
const { name } = await c.req.json();
await c.env.DB.prepare("INSERT INTO users (name) VALUES (?)").bind(name).run();
return c.json({ success: true });
});
export default app;
```
## KV Storage
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const key = url.searchParams.get("key");
if (request.method === "GET" && key) {
const value = await env.KV.get(key);
return Response.json({ key, value });
}
if (request.method === "PUT" && key) {
const value = await request.text();
await env.KV.put(key, value, { expirationTtl: 3600 });
return Response.json({ success: true });
}
return new Response("Bad Request", { status: 400 });
},
};
```
## D1 Database
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Query
const { results } = await env.DB.prepare(
"SELECT * FROM users WHERE active = ?"
).bind(1).all();
// Insert
const info = await env.DB.prepare(
"INSERT INTO users (name, email) VALUES (?, ?)"
).bind("Alice", "[email protected]").run();
// Transaction
const batch = await env.DB.batch([
env.DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Bob"),
env.DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Charlie"),
]);
return Response.json(results);
},
};
```
## Durable Objects
```typescript
// src/counter.ts
export class Counter {
private state: DurableObjectState;
private value = 0;
constructor(state: DurableObjectState) {
this.state = state;
this.state.blockConcurrencyWhile(async () => {
this.value = (await this.state.storage.get("value")) || 0;
});
}
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/increment") {
this.value++;
await this.state.storage.put("value", this.value);
}
return Response.json({ value: this.value });
}
}
// src/index.ts
export { Counter } from "./counter";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const id = env.COUNTER.idFromName("global");
const stub = env.COUNTER.get(id);
return stub.fetch(request);
},
};
```
```toml
# wrangler.toml
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
[[migrations]]
tag = "v1"
new_classes = ["Counter"]
```
## R2 Storage
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const key = url.pathname.slice(1);
if (request.method === "GET") {
const object = await env.BUCKET.get(key);
if (!object) {
return new Response("Not Found", { status: 404 });
}
return new Response(object.body, {
headers: { "Content-Type": object.httpMetadata?.contentType || "application/octet-stream" },
});
}
if (request.method === "PUT") {
await env.BUCKET.put(key, request.body, {
httpMetadata: { contentType: request.headers.get("Content-Type") || undefined },
});
return Response.json({ success: true });
}
return new Response("Method Not Allowed", { status: 405 });
},
};
```
## Development with Bun
### Local Development
```bash
# Run with wrangler (uses Bun for TypeScript)
bun run dev
# Or directly
bunx wrangler dev
```
### Testing with Bun
```typescript
// src/index.test.ts
import { describe, test, expect } from "bun:test";
// Mock worker
const worker = {
async fetch(request: Request) {
return new Response("Hello");
},
};
describe("Worker", () => {
test("returns hello", async () => {
const request = new Request("http://localhost/");
const response = await worker.fetch(request);
expect(await response.text()).toBe("Hello");
});
});
```
### Miniflare for Testing
```typescript
import { Miniflare } from "miniflare";
const mf = new Miniflare({
script: await Bun.file("./dist/index.js").text(),
kvNamespaces: ["KV"],
});
const response = await mf.dispatchFetch("http://localhost/");
console.log(await response.text());
```
## Build for Production
```typescript
// build.ts
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
target: "browser", // Workers use browser APIs
minify: true,
sourcemap: "external",
});
```
```bash
bun run build.ts
bunx wrangler deploy
```
## Environment Variables
```toml
# wrangler.toml
[vars]
API_URL = "https://api.example.com"
# Secrets (set via CLI)
# wrangler secret put API_KEY
```
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
console.log(env.API_URL); // From vars (non-secret, safe to log)
// Access a Worker secret (NEVER log it — wrangler tail / Logpush persist logs)
if (env.API_KEY) {
// use env.API_KEY to call the upstream API
}
// ❌ NEVER: console.log(env.API_KEY) — secrets must not appear in logs
return new Response("OK");
},
};
```
## Scheduled Workers (Cron)
```typescript
export default {
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
console.log("Cron triggered at:", event.scheduledTime);
// Perform scheduled task
await env.DB.prepare("DELETE FROM logs WHERE created_at < ?")
.bind(Date.now() - 7 * 24 * 60 * 60 * 1000)
.run();
},
async fetch(request: Request, env: Env): Promise<Response> {
return new Response("OK");
},
};
```
```toml
# wrangler.toml
[triggers]
crons = ["0 * * * *"] # Every hour
```
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| `Bun API not available` | Workers use V8 | Use Web APIs only |
| `Module not found` | Build issue | Check bundler config |
| `Script too large` | Exceeds 10MB | Optimize bundle |
| `CPU time exceeded` | Long execution | Optimize or use queues |
## API Compatibility
Workers support Web APIs, NOT Bun-specific APIs:
| Available | Not Available |
|-----------|---------------|
| fetch() | Bun.file() |
| Response | Bun.serve() |
| Request | bun:sqlite |
| URL | bun:ffi |
| crypto | fs |
| TextEncoder | child_process |
## When to Load References
Load `references/bindings.md` when:
- Advanced KV/D1/R2 patterns
- Queue workers
- Service bindings
Load `references/performance.md` when:
- Bundle optimization
- Cold start reduction
- Caching strategies
© secondsky · MIT · secondsky/claude-skills