用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/InugamiDev/ultrathink-oss --skill cloudflare命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | cloudflare |
| description | Cloudflare Workers, Pages, D1, R2, KV, Durable Objects, DNS, and edge computing patterns |
| layer | domain |
| category | devops |
| triggers | ["cloudflare","workers","cloudflare pages","d1","r2","kv","durable objects","edge function","wrangler"] |
| inputs | ["application requirements","edge computing needs","storage requirements"] |
| outputs | ["Worker scripts","wrangler configs","D1 schemas","R2 policies","DNS configs"] |
| linksTo | ["nginx","terraform","monitoring","authentication"] |
| linkedFrom | ["ship","optimize","caching"] |
| preferredNextSkills | ["monitoring","authentication","terraform"] |
| fallbackSkills | ["vercel","aws"] |
| riskLevel | low |
| memoryReadPolicy | selective |
| memoryWritePolicy | none |
| sideEffects | ["edge deployments","DNS changes","storage writes"] |
Design and implement edge-first applications using the Cloudflare platform. This skill covers Workers, Pages, D1 (SQLite at the edge), R2 (object storage), KV (key-value), Durable Objects, DNS management, and performance optimization patterns.
// src/index.ts
export interface Env {
DB: D1Database;
KV: KVNamespace;
R2: R2Bucket;
RATE_LIMITER: DurableObjectNamespace;
API_KEY: string;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
try {
if (url.pathname.startsWith("/api/")) {
return handleAPI(request, env, ctx);
}
return new Response("Not Found", { status: 404 });
} catch (error) {
console.error("Worker error:", error);
(, { : });
}
},
} <>;
(): <> {
cacheKey = (request.).;
cached = env..(cacheKey);
(cached) {
(cached, {
: { : , : },
});
}
result = env..().();
json = .(result.);
ctx.(env..(cacheKey, json, { : }));
(json, {
: { : , : },
});
}
name = "my-app"
main = "src/index.ts"
compatibility_date = "2024-12-01"
[vars]
ENVIRONMENT = "production"
[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "xxx-xxx-xxx"
[[kv_namespaces]]
binding = "KV"
id = "xxx-xxx-xxx"
[[r2_buckets]]
binding = "R2"
bucket_name = "my-app-uploads"
[[durable_objects.bindings]]
name = "RATE_LIMITER"
class_name = "RateLimiter"
[[migrations]]
tag = "v1"
new_classes = ["RateLimiter"]
[triggers]
crons = ["*/5 * * * *"]
// Parameterized queries (always use bind parameters)
const user = await env.DB.prepare("SELECT * FROM users WHERE id = ?").bind(userId).first();
// Batch operations (single round trip)
const results = await env.DB.batch([
env.DB.prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)").bind(userId, total),
env.DB.prepare("UPDATE inventory SET stock = stock - ? WHERE product_id = ?").bind(qty, productId),
]);
// Migrations
// wrangler d1 migrations create my-app-db create_users
// migrations/0001_create_users.sql
/*
CREATE TABLE users (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX idx_users_email ON users(email);
*/
export class RateLimiter implements DurableObject {
private state: DurableObjectState;
private requests: Map<string, number[]> = new Map();
constructor(state: DurableObjectState, env: Env) {
this.state = state;
}
async fetch(request: Request): Promise<Response> {
const ip = request.headers.get("CF-Connecting-IP") || "unknown";
const now = Date.now();
const windowMs = 60_000; // 1 minute
const maxRequests = 100;
const timestamps = this.requests.get(ip) || [];
const recent = timestamps.filter((t) => now - t < windowMs);
if (recent.length >= maxRequests) {
return new Response("Rate limit exceeded", {
status: 429,
headers: { "Retry-After": "60" },
});
}
recent.push(now);
this.requests.set(ip, recent);
return new Response("OK", { status: 200 });
}
}
async function handleUpload(request: Request, env: Env): Promise<Response> {
const formData = await request.formData();
const file = formData.get("file") as File;
if (!file) return new Response("No file", { status: 400 });
const key = `uploads/${Date.now()}-${file.name}`;
await env.R2.put(key, file.stream(), {
httpMetadata: { contentType: file.type },
customMetadata: { originalName: file.name },
});
return Response.json({ key, url: `/files/${key}` });
}
ctx.waitUntil() for non-blocking async work (analytics, caching)Cache API for computed responsesrequest.headers.get("Origin")wrangler secret for API keys, never .env filesRETURNING clause to avoid extra reads after writeswrangler deploy with --env for staging vs productionwrangler devwrangler tail for real-time log streaming| Pitfall | Fix |
|---|---|
| String interpolation in D1 queries | Always use .bind() parameters |
Ignoring ctx.waitUntil() | Use it for fire-and-forget async work |
| KV reads in hot loops | Batch reads or use Cache API |
| Large Worker bundle | Use dynamic imports, tree shake |
| No error handling | Wrap handler in try/catch, log errors |
| Missing CORS headers | Add explicit Access-Control-* headers |
export default {
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) {
// Runs every 5 minutes per wrangler.toml crons config
const staleItems = await env.DB.prepare(
"SELECT id FROM cache_entries WHERE expires_at < datetime('now')"
).all();
if (staleItems.results.length > 0) {
const ids = staleItems.results.map((r) => r.id);
await env.DB.prepare(
`DELETE FROM cache_entries WHERE id IN (${ids.map(() => "?").join(",")})`
).bind(...ids).run();
}
},
} satisfies ExportedHandler<Env>;
// functions/api/posts.ts (Cloudflare Pages Functions)
export const onRequestGet: PagesFunction<Env> = async (context) => {
const posts = await context.env.DB.prepare("SELECT * FROM posts LIMIT 20").all();
return Response.json(posts.results);
};
基于 SOC 职业分类