[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FGAE4HH3P6V0RG3MMXT3CN":3,"skill-same:01M6FGAE4HH3P6V0RG3MMXT3CN":208},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":22,"linkOnly":23,"markdownContent":24,"markdownBody":25,"frontMatter":26,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":30,"repositoryHtmlUrl":31,"repositoryHomepageUrl":32,"ownerHtmlUrl":33,"ownerBlogUrl":6,"ownerDescription":34,"updatedAt":35,"install":36,"resources":49},"01M6FGAE4HH3P6V0RG3MMXT3CN","cloudflare-durable-objects",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002FSKILL.md",[],[18,19,20,21],"cloudflare","durable objects","objects","cloudflare durable objects","2026-11-10 10:12:30",false,"---\nname: cloudflare-durable-objects\ndescription: Cloudflare Durable Objects for stateful coordination and real-time apps. Use for chat, multiplayer games, WebSocket hibernation, or encountering class export, migration, alarm errors.\n\n  Keywords: durable objects, cloudflare do, DurableObject class, do bindings, websocket hibernation, do state api, ctx.storage.sql, ctx.acceptWebSocket, webSocketMessage, alarm() handler, storage.setAlarm, idFromName, newUniqueId, getByName, DurableObjectStub, serializeAttachment, real-time cloudflare, multiplayer cloudflare, chat room workers, coordination cloudflare, stateful workers, new_sqlite_classes, do migrations, location hints, RPC methods, blockConcurrencyWhile, \"do class export\", \"new_sqlite_classes\", \"migrations required\", \"websocket hibernation\", \"alarm api error\", \"global uniqueness\", \"binding not found\"\nlicense: MIT\n---\n\n# Cloudflare Durable Objects\n\n**Status**: Production Ready ✅\n**Last Updated**: 2025-11-25\n**Dependencies**: cloudflare-worker-base (recommended)\n**Latest Versions**: wrangler@4.50.0+, @cloudflare\u002Fworkers-types@4.20251125.0+\n**Official Docs**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002F\n\n## Table of Contents\n[What are Durable Objects?](#what-are-durable-objects) • [Quick Start](#quick-start-10-minutes) • [When to Load References](#when-to-load-references) • [Class Structure](#durable-object-class-structure) • [State API](#state-api---persistent-storage) • [WebSocket Hibernation](#websocket-hibernation-api) • [Alarms](#alarms-api---scheduled-tasks) • [RPC vs HTTP](#rpc-vs-http-fetch) • [Stubs & Routing](#creating-durable-object-stubs-and-routing) • [Migrations](#migrations---managing-do-classes) • [Common Patterns](#common-patterns) • [Critical Rules](#critical-rules) • [Known Issues](#known-issues-prevention)\n## What are Durable Objects?\n\n**Globally unique, stateful objects** with single-point coordination, strong consistency (ACID), WebSocket Hibernation (thousands of connections), SQLite storage (1GB), and alarms API.\n\n**Use for:** Chat rooms, multiplayer games, rate limiting, session management, leader election, stateful workflows\n---\n## Quick Start (10 Minutes)\n\n### Option 1: Scaffold New DO Project\n\n```bash\nnpm create cloudflare@latest my-durable-app -- \\\n  --template=cloudflare\u002Fdurable-objects-template --ts --git --deploy false\ncd my-durable-app && bun install && npm run dev\n```\n\n### Option 2: Add to Existing Worker\n\n**1. Install types:**\n```bash\nbun add -d @cloudflare\u002Fworkers-types\n```\n\n**2. Create DO class** (`src\u002Fcounter.ts`):\n```typescript\nimport { DurableObject } from 'cloudflare:workers';\n\nexport class Counter extends DurableObject {\n  async increment(): Promise\u003Cnumber> {\n    let value: number = (await this.ctx.storage.get('value')) || 0;\n    await this.ctx.storage.put('value', ++value);\n    return value;\n  }\n}\n\nexport default Counter;  \u002F\u002F CRITICAL\n```\n\n**3. Configure** (`wrangler.jsonc`):\n```jsonc\n{\n  \"durable_objects\": {\n    \"bindings\": [{ \"name\": \"COUNTER\", \"class_name\": \"Counter\" }]\n  },\n  \"migrations\": [\n    { \"tag\": \"v1\", \"new_sqlite_classes\": [\"Counter\"] }\n  ]\n}\n```\n\n**4. Call from Worker** (`src\u002Findex.ts`):\n```typescript\nimport { Counter } from '.\u002Fcounter';\n\ninterface Env {\n  COUNTER: DurableObjectNamespace\u003CCounter>;\n}\n\nexport { Counter };\n\nexport default {\n  async fetch(request: Request, env: Env): Promise\u003CResponse> {\n    const stub = env.COUNTER.getByName('global-counter');\n    return new Response(`Count: ${await stub.increment()}`);\n  },\n};\n```\n\n**Deploy:**\n\n```bash\nbunx wrangler deploy\n```\n\n---\n\n## Available Commands\n\nUse these interactive commands for guided workflows:\n\n- **`\u002Fdo-setup`** - Initialize new DO project with interactive setup wizard\n  - Choose storage backend (SQL, KV, both)\n  - Select use case pattern (WebSocket, Sessions, Rate Limiting, etc.)\n  - Optional Vitest testing setup\n  - Generates complete DO implementation\n\n- **`\u002Fdo-migrate`** - Interactive migration assistant\n  - New class creation (new_sqlite_classes, new_classes)\n  - Rename existing classes (renamed_classes)\n  - Delete classes with safety confirmations (deleted_classes)\n  - Transfer classes between scripts (transferred_classes)\n  - Auto-increments migration tags (v1, v2, v3...)\n\n- **`\u002Fdo-debug`** - Step-by-step debugging workflow\n  - Detects error categories (deployment, runtime, performance, etc.)\n  - Runs diagnostic checks on configuration and code\n  - Provides specific fixes with code examples\n  - Guides local testing and production verification\n\n- **`\u002Fdo-patterns`** - Pattern selection wizard\n  - Recommends DO pattern based on use case\n  - Supports WebSocket, Rate Limiting, Sessions, Analytics, Leader Election\n  - Generates complete pattern implementation\n  - Provides best practices and optimization tips\n\n- **`\u002Fdo-optimize`** - Performance optimization assistant\n  - Analyzes existing DO code for bottlenecks\n  - Provides targeted optimization recommendations\n  - Covers constructor, queries, WebSocket, memory, alarms\n  - Measures performance improvements\n\n## Autonomous Agents\n\nThese agents work autonomously without user interaction:\n\n- **`do-debugger`** - Automatic error detection and fixing\n  - Validates wrangler.jsonc configuration\n  - Detects 16+ common DO errors\n  - Applies fixes automatically with backups\n  - Tests fixes before reporting\n\n- **`do-setup-assistant`** - Automatic project scaffolding\n  - Analyzes user requirements from natural language\n  - Generates complete DO implementation\n  - Creates tests, documentation, validation\n  - Supports all use case patterns\n\n- **`do-pattern-implementer`** - Production pattern implementation\n  - Analyzes existing DO code\n  - Recommends patterns by priority\n  - Implements TTL cleanup, RPC metadata, SQL indexes, etc.\n  - Generates pattern-specific tests\n\n---\n\n## When to Load References\n\n**Load immediately when user mentions:**\n- **`state-api-reference.md`** → \"storage\", \"sql\", \"database\", \"query\", \"get\u002Fput\", \"KV\", \"1GB limit\"\n- **`websocket-hibernation.md`** → \"websocket\", \"real-time\", \"chat\", \"hibernation\", \"serializeAttachment\"\n- **`alarms-api.md`** → \"alarms\", \"scheduled tasks\", \"cron\", \"periodic\", \"batch processing\"\n- **`rpc-patterns.md`** → \"RPC\", \"fetch\", \"HTTP\", \"methods\", \"routing\"\n- **`rpc-metadata.md`** → \"RpcTarget\", \"metadata\", \"DO name\", \"idFromName access\"\n- **`stubs-routing.md`** → \"stubs\", \"idFromName\", \"newUniqueId\", \"location hints\", \"jurisdiction\"\n- **`migrations-guide.md`** → \"migrations\", \"rename\", \"delete\", \"transfer\", \"schema changes\"\n- **`migration-cheatsheet.md`** → \"migration quick reference\", \"migration types\", \"common migrations\"\n- **`common-patterns.md`** → \"patterns\", \"examples\", \"rate limiting\", \"sessions\", \"leader election\"\n- **`vitest-testing.md`** → \"test\", \"testing\", \"vitest\", \"unit test\", \"@cloudflare\u002Fvitest-pool-workers\"\n- **`gradual-deployments.md`** → \"gradual\", \"deployment\", \"traffic split\", \"rollout\", \"canary\"\n- **`typescript-config.md`** → \"TypeScript\", \"types\", \"tsconfig\", \"wrangler.jsonc\", \"bindings\"\n- **`advanced-sql-patterns.md`** → \"CTE\", \"window functions\", \"FTS5\", \"full-text search\", \"JSON functions\", \"complex SQL\"\n- **`security-best-practices.md`** → \"security\", \"authentication\", \"authorization\", \"SQL injection\", \"CORS\", \"encryption\", \"rate limiting\"\n- **`error-codes.md`** → \"error codes\", \"error catalog\", \"specific error\", \"E001\", \"troubleshooting\"\n- **`top-errors.md`** → errors, \"not working\", debugging, \"binding not found\"\n\n**Load proactively when:**\n- Building new feature → Load relevant pattern from `common-patterns.md`\n- Debugging issue → Load `error-codes.md` for specific errors, then `top-errors.md`\n- Implementing WebSocket → Load `websocket-hibernation.md` before coding\n- Setting up storage → Load `state-api-reference.md` for SQL\u002FKV APIs\n- Complex SQL queries → Load `advanced-sql-patterns.md` for CTEs, window functions, FTS5\n- Security review → Load `security-best-practices.md` for authentication, authorization, SQL injection prevention\n- Creating first DO → Load `stubs-routing.md` for ID methods\n- Writing tests → Load `vitest-testing.md` for testing patterns\n- Planning deployment → Load `gradual-deployments.md` for rollout strategy\n- Migration needed → Load `migration-cheatsheet.md` for quick reference\n- Using DO name inside DO → Load `rpc-metadata.md` for RpcTarget pattern\n- TypeScript configuration → Load `typescript-config.md` for setup\n\n---\n\n## Durable Object Class Structure\n\nAll DOs extend `DurableObject` and **MUST be exported**:\n\n```typescript\nimport { DurableObject } from 'cloudflare:workers';\n\nexport class MyDO extends DurableObject {\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);  \u002F\u002F Required first line\n    \u002F\u002F Keep minimal - heavy work blocks hibernation\n    ctx.blockConcurrencyWhile(async () => {\n      \u002F\u002F Load from storage before handling requests\n    });\n  }\n\n  async myMethod(): Promise\u003Cstring> {  \u002F\u002F RPC method (recommended)\n    return 'Hello!';\n  }\n}\n\nexport default MyDO;  \u002F\u002F CRITICAL: Must export\n```\n\n**`this.ctx` provides:** `storage` (SQL\u002FKV), `id` (unique ID), `waitUntil()`, `acceptWebSocket()`\n\n---\n\n## State API - Persistent Storage\n\nDurable Objects provide two storage options:\n\n**SQL API** (SQLite backend, **recommended**):\n- Access via `ctx.storage.sql`\n- Up to 1GB storage per instance\n- SQL queries with transactions, indexes, cursors\n- Atomic operations (deleteAll is all-or-nothing)\n- Use `new_sqlite_classes` in migrations\n\n**Key-Value API** (available on both backends):\n- Access via `ctx.storage` (get\u002Fput\u002Fdelete\u002Flist)\n- Simple key-value operations\n- Async transactions supported\n- 128MB limit on KV backend, 1GB on SQLite\n\n**Quick example**:\n```typescript\nexport class Counter extends DurableObject {\n  sql: SqlStorage;\n\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);\n    this.sql = ctx.storage.sql;\n    this.sql.exec('CREATE TABLE IF NOT EXISTS counts (key TEXT PRIMARY KEY, value INTEGER)');\n  }\n\n  async increment(): Promise\u003Cnumber> {\n    this.sql.exec('INSERT OR REPLACE INTO counts (key, value) VALUES (?, ?)', 'count', 1);\n    return this.sql.exec('SELECT value FROM counts WHERE key = ?', 'count').one\u003C{value: number}>().value;\n  }\n}\n```\n\n**Load `references\u002Fstate-api-reference.md` for complete SQL and KV API documentation, cursor operations, transactions, parameterized queries, storage limits, and migration patterns.**\n\n---\n\n## WebSocket Hibernation API\n\nHandle **thousands of WebSocket connections** per DO instance with automatic hibernation when idle (~10s no activity), saving duration costs. Connections stay open at the edge while DO sleeps.\n\n**CRITICAL Rules**:\n- ✅ Use `ctx.acceptWebSocket(server)` (enables hibernation)\n- ✅ Use `ws.serializeAttachment(data)` to persist metadata across hibernation\n- ✅ Restore connections in constructor with `ctx.getWebSockets()`\n- ❌ Don't use `ws.accept()` (standard API, no hibernation)\n- ❌ Don't use `setTimeout`\u002F`setInterval` (prevents hibernation)\n\n**Handler methods**: `webSocketMessage()`, `webSocketClose()`, `webSocketError()`\n\n**Quick pattern**:\n```typescript\nexport class ChatRoom extends DurableObject {\n  sessions: Map\u003CWebSocket, any>;\n\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);\n    this.sessions = new Map();\n    \u002F\u002F Restore connections after hibernation\n    ctx.getWebSockets().forEach(ws => {\n      this.sessions.set(ws, ws.deserializeAttachment());\n    });\n  }\n\n  async fetch(request: Request): Promise\u003CResponse> {\n    const pair = new WebSocketPair();\n    const [client, server] = Object.values(pair);\n\n    this.ctx.acceptWebSocket(server);  \u002F\u002F ← Enables hibernation\n    server.serializeAttachment({ userId: 'alice' });  \u002F\u002F ← Persists across hibernation\n    this.sessions.set(server, { userId: 'alice' });\n\n    return new Response(null, { status: 101, webSocket: client });\n  }\n\n  async webSocketMessage(ws: WebSocket, message: string): Promise\u003Cvoid> {\n    const session = this.sessions.get(ws);\n    \u002F\u002F Broadcast to all\n    this.sessions.forEach((_, w) => w.send(message));\n  }\n}\n```\n\n**Load `references\u002Fwebsocket-hibernation.md` for complete handler patterns, hibernation lifecycle, serializeAttachment API, connection management, broadcasting patterns, and hibernation troubleshooting.**\n\n---\n\n## Alarms API - Scheduled Tasks\n\nSchedule DO to wake up at a future time for batching, cleanup, reminders, or periodic tasks.\n\n**Core API**:\n- `await ctx.storage.setAlarm(timestamp)` - Schedule alarm\n- `await ctx.storage.getAlarm()` - Get current alarm time (null if not set)\n- `await ctx.storage.deleteAlarm()` - Cancel alarm\n- `async alarm(info)` - Handler called when alarm fires\n\n**Key Features**:\n- ✅ Guaranteed at-least-once execution with automatic retries (up to 6)\n- ✅ Survives hibernation and eviction\n- ✅ Deleted automatically after successful execution\n- ⚠️ Only ONE alarm per DO (setting new one overwrites previous)\n\n**Quick pattern**:\n```typescript\nexport class Batcher extends DurableObject {\n  async addItem(item: string): Promise\u003Cvoid> {\n    await this.ctx.storage.put('items', [...existingItems, item]);\n\n    \u002F\u002F Schedule batch processing if not already scheduled\n    if (await this.ctx.storage.getAlarm() === null) {\n      await this.ctx.storage.setAlarm(Date.now() + 10000);  \u002F\u002F 10 seconds\n    }\n  }\n\n  async alarm(info: { retryCount: number; isRetry: boolean }): Promise\u003Cvoid> {\n    const items = await this.ctx.storage.get('items');\n    await this.processBatch(items);  \u002F\u002F Send to API, write to DB, etc.\n    await this.ctx.storage.put('items', []);  \u002F\u002F Clear buffer\n  }\n}\n```\n\n**Load `references\u002Falarms-api.md` for periodic alarms pattern, retry handling, error scenarios, cleanup jobs, and batching strategies.**\n\n---\n\n## RPC vs HTTP Fetch\n\n**RPC (Recommended)**: Call DO methods directly like `await stub.increment()`. Type-safe, simple, auto-serialization. Requires `compatibility_date >= 2024-04-03`.\n\n**HTTP Fetch**: Traditional HTTP request\u002Fresponse with `async fetch(request)` handler. Required for WebSocket upgrades.\n\n**Quick comparison**:\n```typescript\n\u002F\u002F RPC Pattern (simpler)\nexport class Counter extends DurableObject {\n  async increment(): Promise\u003Cnumber> {  \u002F\u002F ← Direct method\n    let value = await this.ctx.storage.get\u003Cnumber>('count') || 0;\n    return ++value;\n  }\n}\nconst count = await stub.increment();  \u002F\u002F ← Direct call\n\n\u002F\u002F HTTP Fetch Pattern\nexport class Counter extends DurableObject {\n  async fetch(request: Request): Promise\u003CResponse> {  \u002F\u002F ← HTTP handler\n    const url = new URL(request.url);\n    if (url.pathname === '\u002Fincrement') { \u002F* ... *\u002F }\n  }\n}\nconst response = await stub.fetch('\u002Fincrement', { method: 'POST' });\n```\n\n**Use RPC for**: New projects, type safety, simple method calls\n**Use HTTP Fetch for**: WebSocket upgrades, complex routing, legacy code\n\n**Load `references\u002Frpc-patterns.md` for complete RPC vs Fetch comparison, migration guide, error handling patterns, and method visibility control.**\n\n---\n\n## Creating Durable Object Stubs and Routing\n\nTo interact with a Durable Object from a Worker: **get an ID** → **create a stub** → **call methods**.\n\n**Three ID creation methods:**\n\n1. **`idFromName(name)`** - Named DOs (most common): Deterministic routing to same instance globally\n2. **`newUniqueId()`** - Random IDs: New unique instance, must store ID for future access\n3. **`idFromString(idString)`** - Recreate from saved ID string\n\n**Getting stubs:**\n\n```typescript\n\u002F\u002F Method 1: From ID\nconst id = env.CHAT_ROOM.idFromName('room-123');\nconst stub = env.CHAT_ROOM.get(id);\n\n\u002F\u002F Method 2: Shortcut for named DOs (recommended)\nconst stub = env.CHAT_ROOM.getByName('room-123');\n\nawait stub.myMethod();\n```\n\n**Geographic routing with location hints:**\n- Set `locationHint` option when creating stub: `{ locationHint: 'enam' }`\n- 9 regions: wnam, enam, sam, weur, eeur, apac, oc, afr, me\n- Best-effort (not guaranteed), only affects first creation\n\n**Data residency with jurisdiction restrictions:**\n- Use `newUniqueId({ jurisdiction: 'eu' })` or `{ jurisdiction: 'fedramp' }`\n- Strictly enforced (DO never leaves jurisdiction)\n- Cannot combine with location hints\n- Required for GDPR\u002FFedRAMP compliance\n\n**Load `references\u002Fstubs-routing.md` for complete guide to ID methods, stub management, location hints, jurisdiction restrictions, use cases, best practices, and error handling patterns.**\n\n---\n\n## Migrations - Managing DO Classes\n\n**Migrations are REQUIRED** when creating, renaming, deleting, or transferring DO classes between Workers.\n\n**Four migration types:**\n\n1. **Create New DO**: Use `new_sqlite_classes` (recommended, 1GB) or `new_classes` (legacy KV, 128MB)\n2. **Rename DO**: Use `renamed_classes` with `from`\u002F`to` mapping (data preserved, bindings forward)\n3. **Delete DO**: Use `deleted_classes` (⚠️ immediate deletion, cannot undo, all storage lost)\n4. **Transfer DO**: Use `transferred_classes` with `from_script` (moves instances to new Worker)\n\n**Quick example - Create new DO with SQLite:**\n\n```jsonc\n{\n  \"durable_objects\": {\n    \"bindings\": [{ \"name\": \"COUNTER\", \"class_name\": \"Counter\" }]\n  },\n  \"migrations\": [\n    {\n      \"tag\": \"v1\",                    \u002F\u002F Unique identifier (append-only)\n      \"new_sqlite_classes\": [\"Counter\"]\n    }\n  ]\n}\n```\n\n**CRITICAL rules:**\n- ❌ Migrations are ATOMIC (all instances migrate at once, no gradual rollout)\n- ❌ Cannot enable SQLite on existing KV-backed DOs (must create new class)\n- ❌ Migration tags must be unique (cannot reuse, append-only)\n- ✅ Code changes don't need migrations (only schema changes do)\n- ✅ DO class names are unique per account (across all Workers)\n\n**Load `references\u002Fmigrations-guide.md` for complete migration patterns, rename\u002Fdelete\u002Ftransfer procedures, rollback strategies, and migration gotchas.**\n\n---\n\n## Common Patterns\n\n**Four production-ready patterns for Cloudflare Durable Objects:**\n\n1. **Rate Limiting** - Per-user rate limiting with sliding window, KV storage for request tracking\n2. **Session Management** - User sessions with TTL, SQL storage, automatic cleanup via alarms\n3. **Leader Election** - Single leader guarantee using SQL constraints, heartbeat mechanism\n4. **Multi-DO Coordination** - Game coordinator + game rooms pattern, parent-child DO relationships\n\n**Quick example - Rate limiter:**\n\n```typescript\nexport class RateLimiter extends DurableObject {\n  async checkLimit(userId: string, limit: number, window: number): Promise\u003Cboolean> {\n    const requests = await this.ctx.storage.get\u003Cnumber[]>(`rate:${userId}`) || [];\n    const validRequests = requests.filter(t => Date.now() - t \u003C window);\n\n    if (validRequests.length >= limit) return false;\n\n    validRequests.push(Date.now());\n    await this.ctx.storage.put(`rate:${userId}`, validRequests);\n    return true;\n  }\n}\n```\n\n**Load `references\u002Fcommon-patterns.md` for complete implementations of all 4 patterns with full code examples, SQL schemas, alarm usage, error handling, and best practices.**\n\n---\n\n## Critical Rules\n\n**✅ Always:**\n- Export DO class: `export default MyDO`\n- Call `super(ctx, env)` first in constructor\n- Use `new_sqlite_classes` in migrations (1GB vs 128MB KV)\n- Use `ctx.acceptWebSocket()` for hibernation (not `ws.accept()`)\n- Persist state to storage (not just memory)\n- Use alarms instead of setTimeout\u002FsetInterval\n- Use parameterized SQL: `sql.exec('... WHERE id = ?', id)`\n- Minimize constructor work, use `blockConcurrencyWhile()`\n\n**❌ Never:**\n- Create DO without migration (error)\n- Forget to export class (binding not found)\n- Use setTimeout\u002FsetInterval (prevents hibernation)\n- Rely only on in-memory state for WebSockets (use serializeAttachment)\n- Deploy migrations gradually (migrations are atomic)\n- Enable SQLite on existing KV-backed DO (must create new class)\n- Assume location hints are guaranteed (best-effort only)\n\n---\n\n## Known Issues Prevention\n\nThis skill prevents **15+ documented issues**. Top 3 most critical:\n\n### Issue #1: Class Not Exported\n**Error**: `\"binding not found\"` | **Why**: DO class not exported\n**Fix**: `export default MyDO;`\n\n### Issue #2: Missing Migration\n**Error**: `\"migrations required\"` | **Why**: Created DO without migration entry\n**Fix**: Add `{ \"tag\": \"v1\", \"new_sqlite_classes\": [\"MyDO\"] }` to migrations\n\n### Issue #3: setTimeout Breaks Hibernation\n**Error**: DO never hibernates, high charges | **Why**: `setTimeout` prevents hibernation\n**Fix**: Use `await ctx.storage.setAlarm(Date.now() + 1000)` instead\n\n**12 more issues covered**: Wrong migration type, constructor overhead, in-memory state lost, outgoing WebSocket no hibernation, global uniqueness confusion, partial deleteAll, binding mismatch, state size exceeded, migration not atomic, location hint ignored, alarm retry failures, fetch blocks hibernation.\n\n**Load `references\u002Ftop-errors.md` for complete error catalog with all 15+ issues, detailed prevention strategies, debugging steps, and resolution patterns.**\n\n---\n\n## Configuration & TypeScript\n\nConfigure wrangler.jsonc with DO bindings and migrations, set up TypeScript types with proper exports.\n\n**Load `references\u002Ftypescript-config.md` for**: wrangler.jsonc structure, TypeScript types, Env interface, tsconfig.json, common type issues\n\n---\n\n**Official Docs**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002F\n- **State API (SQL)**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fapi\u002Fsqlite-storage-api\u002F\n- **WebSocket Hibernation**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fbest-practices\u002Fwebsockets\u002F\n- **Alarms API**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fapi\u002Falarms\u002F\n- **Migrations**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Freference\u002Fdurable-objects-migrations\u002F\n- **Best Practices**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fbest-practices\u002F \n**Questions?** Load `references\u002Ftop-errors.md` for common problems or check `templates\u002F` for working examples\n","# Cloudflare Durable Objects\n\n**Status**: Production Ready ✅\n**Last Updated**: 2025-11-25\n**Dependencies**: cloudflare-worker-base (recommended)\n**Latest Versions**: wrangler@4.50.0+, @cloudflare\u002Fworkers-types@4.20251125.0+\n**Official Docs**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002F\n\n## Table of Contents\n[What are Durable Objects?](#what-are-durable-objects) • [Quick Start](#quick-start-10-minutes) • [When to Load References](#when-to-load-references) • [Class Structure](#durable-object-class-structure) • [State API](#state-api---persistent-storage) • [WebSocket Hibernation](#websocket-hibernation-api) • [Alarms](#alarms-api---scheduled-tasks) • [RPC vs HTTP](#rpc-vs-http-fetch) • [Stubs & Routing](#creating-durable-object-stubs-and-routing) • [Migrations](#migrations---managing-do-classes) • [Common Patterns](#common-patterns) • [Critical Rules](#critical-rules) • [Known Issues](#known-issues-prevention)\n## What are Durable Objects?\n\n**Globally unique, stateful objects** with single-point coordination, strong consistency (ACID), WebSocket Hibernation (thousands of connections), SQLite storage (1GB), and alarms API.\n\n**Use for:** Chat rooms, multiplayer games, rate limiting, session management, leader election, stateful workflows\n---\n## Quick Start (10 Minutes)\n\n### Option 1: Scaffold New DO Project\n\n```bash\nnpm create cloudflare@latest my-durable-app -- \\\n  --template=cloudflare\u002Fdurable-objects-template --ts --git --deploy false\ncd my-durable-app && bun install && npm run dev\n```\n\n### Option 2: Add to Existing Worker\n\n**1. Install types:**\n```bash\nbun add -d @cloudflare\u002Fworkers-types\n```\n\n**2. Create DO class** (`src\u002Fcounter.ts`):\n```typescript\nimport { DurableObject } from 'cloudflare:workers';\n\nexport class Counter extends DurableObject {\n  async increment(): Promise\u003Cnumber> {\n    let value: number = (await this.ctx.storage.get('value')) || 0;\n    await this.ctx.storage.put('value', ++value);\n    return value;\n  }\n}\n\nexport default Counter;  \u002F\u002F CRITICAL\n```\n\n**3. Configure** (`wrangler.jsonc`):\n```jsonc\n{\n  \"durable_objects\": {\n    \"bindings\": [{ \"name\": \"COUNTER\", \"class_name\": \"Counter\" }]\n  },\n  \"migrations\": [\n    { \"tag\": \"v1\", \"new_sqlite_classes\": [\"Counter\"] }\n  ]\n}\n```\n\n**4. Call from Worker** (`src\u002Findex.ts`):\n```typescript\nimport { Counter } from '.\u002Fcounter';\n\ninterface Env {\n  COUNTER: DurableObjectNamespace\u003CCounter>;\n}\n\nexport { Counter };\n\nexport default {\n  async fetch(request: Request, env: Env): Promise\u003CResponse> {\n    const stub = env.COUNTER.getByName('global-counter');\n    return new Response(`Count: ${await stub.increment()}`);\n  },\n};\n```\n\n**Deploy:**\n\n```bash\nbunx wrangler deploy\n```\n\n---\n\n## Available Commands\n\nUse these interactive commands for guided workflows:\n\n- **`\u002Fdo-setup`** - Initialize new DO project with interactive setup wizard\n  - Choose storage backend (SQL, KV, both)\n  - Select use case pattern (WebSocket, Sessions, Rate Limiting, etc.)\n  - Optional Vitest testing setup\n  - Generates complete DO implementation\n\n- **`\u002Fdo-migrate`** - Interactive migration assistant\n  - New class creation (new_sqlite_classes, new_classes)\n  - Rename existing classes (renamed_classes)\n  - Delete classes with safety confirmations (deleted_classes)\n  - Transfer classes between scripts (transferred_classes)\n  - Auto-increments migration tags (v1, v2, v3...)\n\n- **`\u002Fdo-debug`** - Step-by-step debugging workflow\n  - Detects error categories (deployment, runtime, performance, etc.)\n  - Runs diagnostic checks on configuration and code\n  - Provides specific fixes with code examples\n  - Guides local testing and production verification\n\n- **`\u002Fdo-patterns`** - Pattern selection wizard\n  - Recommends DO pattern based on use case\n  - Supports WebSocket, Rate Limiting, Sessions, Analytics, Leader Election\n  - Generates complete pattern implementation\n  - Provides best practices and optimization tips\n\n- **`\u002Fdo-optimize`** - Performance optimization assistant\n  - Analyzes existing DO code for bottlenecks\n  - Provides targeted optimization recommendations\n  - Covers constructor, queries, WebSocket, memory, alarms\n  - Measures performance improvements\n\n## Autonomous Agents\n\nThese agents work autonomously without user interaction:\n\n- **`do-debugger`** - Automatic error detection and fixing\n  - Validates wrangler.jsonc configuration\n  - Detects 16+ common DO errors\n  - Applies fixes automatically with backups\n  - Tests fixes before reporting\n\n- **`do-setup-assistant`** - Automatic project scaffolding\n  - Analyzes user requirements from natural language\n  - Generates complete DO implementation\n  - Creates tests, documentation, validation\n  - Supports all use case patterns\n\n- **`do-pattern-implementer`** - Production pattern implementation\n  - Analyzes existing DO code\n  - Recommends patterns by priority\n  - Implements TTL cleanup, RPC metadata, SQL indexes, etc.\n  - Generates pattern-specific tests\n\n---\n\n## When to Load References\n\n**Load immediately when user mentions:**\n- **`state-api-reference.md`** → \"storage\", \"sql\", \"database\", \"query\", \"get\u002Fput\", \"KV\", \"1GB limit\"\n- **`websocket-hibernation.md`** → \"websocket\", \"real-time\", \"chat\", \"hibernation\", \"serializeAttachment\"\n- **`alarms-api.md`** → \"alarms\", \"scheduled tasks\", \"cron\", \"periodic\", \"batch processing\"\n- **`rpc-patterns.md`** → \"RPC\", \"fetch\", \"HTTP\", \"methods\", \"routing\"\n- **`rpc-metadata.md`** → \"RpcTarget\", \"metadata\", \"DO name\", \"idFromName access\"\n- **`stubs-routing.md`** → \"stubs\", \"idFromName\", \"newUniqueId\", \"location hints\", \"jurisdiction\"\n- **`migrations-guide.md`** → \"migrations\", \"rename\", \"delete\", \"transfer\", \"schema changes\"\n- **`migration-cheatsheet.md`** → \"migration quick reference\", \"migration types\", \"common migrations\"\n- **`common-patterns.md`** → \"patterns\", \"examples\", \"rate limiting\", \"sessions\", \"leader election\"\n- **`vitest-testing.md`** → \"test\", \"testing\", \"vitest\", \"unit test\", \"@cloudflare\u002Fvitest-pool-workers\"\n- **`gradual-deployments.md`** → \"gradual\", \"deployment\", \"traffic split\", \"rollout\", \"canary\"\n- **`typescript-config.md`** → \"TypeScript\", \"types\", \"tsconfig\", \"wrangler.jsonc\", \"bindings\"\n- **`advanced-sql-patterns.md`** → \"CTE\", \"window functions\", \"FTS5\", \"full-text search\", \"JSON functions\", \"complex SQL\"\n- **`security-best-practices.md`** → \"security\", \"authentication\", \"authorization\", \"SQL injection\", \"CORS\", \"encryption\", \"rate limiting\"\n- **`error-codes.md`** → \"error codes\", \"error catalog\", \"specific error\", \"E001\", \"troubleshooting\"\n- **`top-errors.md`** → errors, \"not working\", debugging, \"binding not found\"\n\n**Load proactively when:**\n- Building new feature → Load relevant pattern from `common-patterns.md`\n- Debugging issue → Load `error-codes.md` for specific errors, then `top-errors.md`\n- Implementing WebSocket → Load `websocket-hibernation.md` before coding\n- Setting up storage → Load `state-api-reference.md` for SQL\u002FKV APIs\n- Complex SQL queries → Load `advanced-sql-patterns.md` for CTEs, window functions, FTS5\n- Security review → Load `security-best-practices.md` for authentication, authorization, SQL injection prevention\n- Creating first DO → Load `stubs-routing.md` for ID methods\n- Writing tests → Load `vitest-testing.md` for testing patterns\n- Planning deployment → Load `gradual-deployments.md` for rollout strategy\n- Migration needed → Load `migration-cheatsheet.md` for quick reference\n- Using DO name inside DO → Load `rpc-metadata.md` for RpcTarget pattern\n- TypeScript configuration → Load `typescript-config.md` for setup\n\n---\n\n## Durable Object Class Structure\n\nAll DOs extend `DurableObject` and **MUST be exported**:\n\n```typescript\nimport { DurableObject } from 'cloudflare:workers';\n\nexport class MyDO extends DurableObject {\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);  \u002F\u002F Required first line\n    \u002F\u002F Keep minimal - heavy work blocks hibernation\n    ctx.blockConcurrencyWhile(async () => {\n      \u002F\u002F Load from storage before handling requests\n    });\n  }\n\n  async myMethod(): Promise\u003Cstring> {  \u002F\u002F RPC method (recommended)\n    return 'Hello!';\n  }\n}\n\nexport default MyDO;  \u002F\u002F CRITICAL: Must export\n```\n\n**`this.ctx` provides:** `storage` (SQL\u002FKV), `id` (unique ID), `waitUntil()`, `acceptWebSocket()`\n\n---\n\n## State API - Persistent Storage\n\nDurable Objects provide two storage options:\n\n**SQL API** (SQLite backend, **recommended**):\n- Access via `ctx.storage.sql`\n- Up to 1GB storage per instance\n- SQL queries with transactions, indexes, cursors\n- Atomic operations (deleteAll is all-or-nothing)\n- Use `new_sqlite_classes` in migrations\n\n**Key-Value API** (available on both backends):\n- Access via `ctx.storage` (get\u002Fput\u002Fdelete\u002Flist)\n- Simple key-value operations\n- Async transactions supported\n- 128MB limit on KV backend, 1GB on SQLite\n\n**Quick example**:\n```typescript\nexport class Counter extends DurableObject {\n  sql: SqlStorage;\n\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);\n    this.sql = ctx.storage.sql;\n    this.sql.exec('CREATE TABLE IF NOT EXISTS counts (key TEXT PRIMARY KEY, value INTEGER)');\n  }\n\n  async increment(): Promise\u003Cnumber> {\n    this.sql.exec('INSERT OR REPLACE INTO counts (key, value) VALUES (?, ?)', 'count', 1);\n    return this.sql.exec('SELECT value FROM counts WHERE key = ?', 'count').one\u003C{value: number}>().value;\n  }\n}\n```\n\n**Load `references\u002Fstate-api-reference.md` for complete SQL and KV API documentation, cursor operations, transactions, parameterized queries, storage limits, and migration patterns.**\n\n---\n\n## WebSocket Hibernation API\n\nHandle **thousands of WebSocket connections** per DO instance with automatic hibernation when idle (~10s no activity), saving duration costs. Connections stay open at the edge while DO sleeps.\n\n**CRITICAL Rules**:\n- ✅ Use `ctx.acceptWebSocket(server)` (enables hibernation)\n- ✅ Use `ws.serializeAttachment(data)` to persist metadata across hibernation\n- ✅ Restore connections in constructor with `ctx.getWebSockets()`\n- ❌ Don't use `ws.accept()` (standard API, no hibernation)\n- ❌ Don't use `setTimeout`\u002F`setInterval` (prevents hibernation)\n\n**Handler methods**: `webSocketMessage()`, `webSocketClose()`, `webSocketError()`\n\n**Quick pattern**:\n```typescript\nexport class ChatRoom extends DurableObject {\n  sessions: Map\u003CWebSocket, any>;\n\n  constructor(ctx: DurableObjectState, env: Env) {\n    super(ctx, env);\n    this.sessions = new Map();\n    \u002F\u002F Restore connections after hibernation\n    ctx.getWebSockets().forEach(ws => {\n      this.sessions.set(ws, ws.deserializeAttachment());\n    });\n  }\n\n  async fetch(request: Request): Promise\u003CResponse> {\n    const pair = new WebSocketPair();\n    const [client, server] = Object.values(pair);\n\n    this.ctx.acceptWebSocket(server);  \u002F\u002F ← Enables hibernation\n    server.serializeAttachment({ userId: 'alice' });  \u002F\u002F ← Persists across hibernation\n    this.sessions.set(server, { userId: 'alice' });\n\n    return new Response(null, { status: 101, webSocket: client });\n  }\n\n  async webSocketMessage(ws: WebSocket, message: string): Promise\u003Cvoid> {\n    const session = this.sessions.get(ws);\n    \u002F\u002F Broadcast to all\n    this.sessions.forEach((_, w) => w.send(message));\n  }\n}\n```\n\n**Load `references\u002Fwebsocket-hibernation.md` for complete handler patterns, hibernation lifecycle, serializeAttachment API, connection management, broadcasting patterns, and hibernation troubleshooting.**\n\n---\n\n## Alarms API - Scheduled Tasks\n\nSchedule DO to wake up at a future time for batching, cleanup, reminders, or periodic tasks.\n\n**Core API**:\n- `await ctx.storage.setAlarm(timestamp)` - Schedule alarm\n- `await ctx.storage.getAlarm()` - Get current alarm time (null if not set)\n- `await ctx.storage.deleteAlarm()` - Cancel alarm\n- `async alarm(info)` - Handler called when alarm fires\n\n**Key Features**:\n- ✅ Guaranteed at-least-once execution with automatic retries (up to 6)\n- ✅ Survives hibernation and eviction\n- ✅ Deleted automatically after successful execution\n- ⚠️ Only ONE alarm per DO (setting new one overwrites previous)\n\n**Quick pattern**:\n```typescript\nexport class Batcher extends DurableObject {\n  async addItem(item: string): Promise\u003Cvoid> {\n    await this.ctx.storage.put('items', [...existingItems, item]);\n\n    \u002F\u002F Schedule batch processing if not already scheduled\n    if (await this.ctx.storage.getAlarm() === null) {\n      await this.ctx.storage.setAlarm(Date.now() + 10000);  \u002F\u002F 10 seconds\n    }\n  }\n\n  async alarm(info: { retryCount: number; isRetry: boolean }): Promise\u003Cvoid> {\n    const items = await this.ctx.storage.get('items');\n    await this.processBatch(items);  \u002F\u002F Send to API, write to DB, etc.\n    await this.ctx.storage.put('items', []);  \u002F\u002F Clear buffer\n  }\n}\n```\n\n**Load `references\u002Falarms-api.md` for periodic alarms pattern, retry handling, error scenarios, cleanup jobs, and batching strategies.**\n\n---\n\n## RPC vs HTTP Fetch\n\n**RPC (Recommended)**: Call DO methods directly like `await stub.increment()`. Type-safe, simple, auto-serialization. Requires `compatibility_date >= 2024-04-03`.\n\n**HTTP Fetch**: Traditional HTTP request\u002Fresponse with `async fetch(request)` handler. Required for WebSocket upgrades.\n\n**Quick comparison**:\n```typescript\n\u002F\u002F RPC Pattern (simpler)\nexport class Counter extends DurableObject {\n  async increment(): Promise\u003Cnumber> {  \u002F\u002F ← Direct method\n    let value = await this.ctx.storage.get\u003Cnumber>('count') || 0;\n    return ++value;\n  }\n}\nconst count = await stub.increment();  \u002F\u002F ← Direct call\n\n\u002F\u002F HTTP Fetch Pattern\nexport class Counter extends DurableObject {\n  async fetch(request: Request): Promise\u003CResponse> {  \u002F\u002F ← HTTP handler\n    const url = new URL(request.url);\n    if (url.pathname === '\u002Fincrement') { \u002F* ... *\u002F }\n  }\n}\nconst response = await stub.fetch('\u002Fincrement', { method: 'POST' });\n```\n\n**Use RPC for**: New projects, type safety, simple method calls\n**Use HTTP Fetch for**: WebSocket upgrades, complex routing, legacy code\n\n**Load `references\u002Frpc-patterns.md` for complete RPC vs Fetch comparison, migration guide, error handling patterns, and method visibility control.**\n\n---\n\n## Creating Durable Object Stubs and Routing\n\nTo interact with a Durable Object from a Worker: **get an ID** → **create a stub** → **call methods**.\n\n**Three ID creation methods:**\n\n1. **`idFromName(name)`** - Named DOs (most common): Deterministic routing to same instance globally\n2. **`newUniqueId()`** - Random IDs: New unique instance, must store ID for future access\n3. **`idFromString(idString)`** - Recreate from saved ID string\n\n**Getting stubs:**\n\n```typescript\n\u002F\u002F Method 1: From ID\nconst id = env.CHAT_ROOM.idFromName('room-123');\nconst stub = env.CHAT_ROOM.get(id);\n\n\u002F\u002F Method 2: Shortcut for named DOs (recommended)\nconst stub = env.CHAT_ROOM.getByName('room-123');\n\nawait stub.myMethod();\n```\n\n**Geographic routing with location hints:**\n- Set `locationHint` option when creating stub: `{ locationHint: 'enam' }`\n- 9 regions: wnam, enam, sam, weur, eeur, apac, oc, afr, me\n- Best-effort (not guaranteed), only affects first creation\n\n**Data residency with jurisdiction restrictions:**\n- Use `newUniqueId({ jurisdiction: 'eu' })` or `{ jurisdiction: 'fedramp' }`\n- Strictly enforced (DO never leaves jurisdiction)\n- Cannot combine with location hints\n- Required for GDPR\u002FFedRAMP compliance\n\n**Load `references\u002Fstubs-routing.md` for complete guide to ID methods, stub management, location hints, jurisdiction restrictions, use cases, best practices, and error handling patterns.**\n\n---\n\n## Migrations - Managing DO Classes\n\n**Migrations are REQUIRED** when creating, renaming, deleting, or transferring DO classes between Workers.\n\n**Four migration types:**\n\n1. **Create New DO**: Use `new_sqlite_classes` (recommended, 1GB) or `new_classes` (legacy KV, 128MB)\n2. **Rename DO**: Use `renamed_classes` with `from`\u002F`to` mapping (data preserved, bindings forward)\n3. **Delete DO**: Use `deleted_classes` (⚠️ immediate deletion, cannot undo, all storage lost)\n4. **Transfer DO**: Use `transferred_classes` with `from_script` (moves instances to new Worker)\n\n**Quick example - Create new DO with SQLite:**\n\n```jsonc\n{\n  \"durable_objects\": {\n    \"bindings\": [{ \"name\": \"COUNTER\", \"class_name\": \"Counter\" }]\n  },\n  \"migrations\": [\n    {\n      \"tag\": \"v1\",                    \u002F\u002F Unique identifier (append-only)\n      \"new_sqlite_classes\": [\"Counter\"]\n    }\n  ]\n}\n```\n\n**CRITICAL rules:**\n- ❌ Migrations are ATOMIC (all instances migrate at once, no gradual rollout)\n- ❌ Cannot enable SQLite on existing KV-backed DOs (must create new class)\n- ❌ Migration tags must be unique (cannot reuse, append-only)\n- ✅ Code changes don't need migrations (only schema changes do)\n- ✅ DO class names are unique per account (across all Workers)\n\n**Load `references\u002Fmigrations-guide.md` for complete migration patterns, rename\u002Fdelete\u002Ftransfer procedures, rollback strategies, and migration gotchas.**\n\n---\n\n## Common Patterns\n\n**Four production-ready patterns for Cloudflare Durable Objects:**\n\n1. **Rate Limiting** - Per-user rate limiting with sliding window, KV storage for request tracking\n2. **Session Management** - User sessions with TTL, SQL storage, automatic cleanup via alarms\n3. **Leader Election** - Single leader guarantee using SQL constraints, heartbeat mechanism\n4. **Multi-DO Coordination** - Game coordinator + game rooms pattern, parent-child DO relationships\n\n**Quick example - Rate limiter:**\n\n```typescript\nexport class RateLimiter extends DurableObject {\n  async checkLimit(userId: string, limit: number, window: number): Promise\u003Cboolean> {\n    const requests = await this.ctx.storage.get\u003Cnumber[]>(`rate:${userId}`) || [];\n    const validRequests = requests.filter(t => Date.now() - t \u003C window);\n\n    if (validRequests.length >= limit) return false;\n\n    validRequests.push(Date.now());\n    await this.ctx.storage.put(`rate:${userId}`, validRequests);\n    return true;\n  }\n}\n```\n\n**Load `references\u002Fcommon-patterns.md` for complete implementations of all 4 patterns with full code examples, SQL schemas, alarm usage, error handling, and best practices.**\n\n---\n\n## Critical Rules\n\n**✅ Always:**\n- Export DO class: `export default MyDO`\n- Call `super(ctx, env)` first in constructor\n- Use `new_sqlite_classes` in migrations (1GB vs 128MB KV)\n- Use `ctx.acceptWebSocket()` for hibernation (not `ws.accept()`)\n- Persist state to storage (not just memory)\n- Use alarms instead of setTimeout\u002FsetInterval\n- Use parameterized SQL: `sql.exec('... WHERE id = ?', id)`\n- Minimize constructor work, use `blockConcurrencyWhile()`\n\n**❌ Never:**\n- Create DO without migration (error)\n- Forget to export class (binding not found)\n- Use setTimeout\u002FsetInterval (prevents hibernation)\n- Rely only on in-memory state for WebSockets (use serializeAttachment)\n- Deploy migrations gradually (migrations are atomic)\n- Enable SQLite on existing KV-backed DO (must create new class)\n- Assume location hints are guaranteed (best-effort only)\n\n---\n\n## Known Issues Prevention\n\nThis skill prevents **15+ documented issues**. Top 3 most critical:\n\n### Issue #1: Class Not Exported\n**Error**: `\"binding not found\"` | **Why**: DO class not exported\n**Fix**: `export default MyDO;`\n\n### Issue #2: Missing Migration\n**Error**: `\"migrations required\"` | **Why**: Created DO without migration entry\n**Fix**: Add `{ \"tag\": \"v1\", \"new_sqlite_classes\": [\"MyDO\"] }` to migrations\n\n### Issue #3: setTimeout Breaks Hibernation\n**Error**: DO never hibernates, high charges | **Why**: `setTimeout` prevents hibernation\n**Fix**: Use `await ctx.storage.setAlarm(Date.now() + 1000)` instead\n\n**12 more issues covered**: Wrong migration type, constructor overhead, in-memory state lost, outgoing WebSocket no hibernation, global uniqueness confusion, partial deleteAll, binding mismatch, state size exceeded, migration not atomic, location hint ignored, alarm retry failures, fetch blocks hibernation.\n\n**Load `references\u002Ftop-errors.md` for complete error catalog with all 15+ issues, detailed prevention strategies, debugging steps, and resolution patterns.**\n\n---\n\n## Configuration & TypeScript\n\nConfigure wrangler.jsonc with DO bindings and migrations, set up TypeScript types with proper exports.\n\n**Load `references\u002Ftypescript-config.md` for**: wrangler.jsonc structure, TypeScript types, Env interface, tsconfig.json, common type issues\n\n---\n\n**Official Docs**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002F\n- **State API (SQL)**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fapi\u002Fsqlite-storage-api\u002F\n- **WebSocket Hibernation**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fbest-practices\u002Fwebsockets\u002F\n- **Alarms API**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fapi\u002Falarms\u002F\n- **Migrations**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Freference\u002Fdurable-objects-migrations\u002F\n- **Best Practices**: https:\u002F\u002Fdevelopers.cloudflare.com\u002Fdurable-objects\u002Fbest-practices\u002F \n**Questions?** Load `references\u002Ftop-errors.md` for common problems or check `templates\u002F` for working examples\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":37,"prompt":47,"zipAvailable":48},[38,41,44],{"tool":39,"command":40},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill cloudflare-durable-objects",{"tool":42,"command":43},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill cloudflare-durable-objects",{"tool":45,"command":46},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill cloudflare-durable-objects","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002FSKILL.md",true,[50,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,142,146,150,154,158,162,168,172,176,180,184,188,192,196,200,204],{"path":51,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":54,"sourceHtmlUrl":55},"references\u002Fadvanced-sql-patterns.md","REFERENCE","参考文档",16168,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fadvanced-sql-patterns.md",{"path":57,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":58,"sourceHtmlUrl":59},"references\u002Falarms-api.md",6664,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Falarms-api.md",{"path":61,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":62,"sourceHtmlUrl":63},"references\u002Fbest-practices.md",8687,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fbest-practices.md",{"path":65,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":66,"sourceHtmlUrl":67},"references\u002Fcommon-patterns.md",17121,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fcommon-patterns.md",{"path":69,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":70,"sourceHtmlUrl":71},"references\u002Fdata-modeling.md",17330,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fdata-modeling.md",{"path":73,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Ferror-codes.md",7844,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Ferror-codes.md",{"path":77,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":78,"sourceHtmlUrl":79},"references\u002Fgradual-deployments.md",14227,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fgradual-deployments.md",{"path":81,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":82,"sourceHtmlUrl":83},"references\u002Fmigration-cheatsheet.md",3246,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fmigration-cheatsheet.md",{"path":85,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":86,"sourceHtmlUrl":87},"references\u002Fmigrations-guide.md",7465,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fmigrations-guide.md",{"path":89,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":90,"sourceHtmlUrl":91},"references\u002Fmonitoring-debugging.md",18643,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fmonitoring-debugging.md",{"path":93,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":94,"sourceHtmlUrl":95},"references\u002Fperformance-optimization.md",16603,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fperformance-optimization.md",{"path":97,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":98,"sourceHtmlUrl":99},"references\u002Frpc-metadata.md",17302,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Frpc-metadata.md",{"path":101,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":102,"sourceHtmlUrl":103},"references\u002Frpc-patterns.md",6613,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Frpc-patterns.md",{"path":105,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":106,"sourceHtmlUrl":107},"references\u002Fsecurity-best-practices.md",16327,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fsecurity-best-practices.md",{"path":109,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":110,"sourceHtmlUrl":111},"references\u002Fstate-api-reference.md",6163,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fstate-api-reference.md",{"path":113,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":114,"sourceHtmlUrl":115},"references\u002Fstubs-routing.md",10804,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fstubs-routing.md",{"path":117,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":118,"sourceHtmlUrl":119},"references\u002Ftop-errors.md",10463,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Ftop-errors.md",{"path":121,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":122,"sourceHtmlUrl":123},"references\u002Ftypescript-config.md",8489,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Ftypescript-config.md",{"path":125,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":126,"sourceHtmlUrl":127},"references\u002Fvitest-testing.md",18502,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fvitest-testing.md",{"path":129,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":130,"sourceHtmlUrl":131},"references\u002Fwebsocket-hibernation.md",6438,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fwebsocket-hibernation.md",{"path":133,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":134,"sourceHtmlUrl":135},"references\u002Fwrangler-commands.md",3478,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Freferences\u002Fwrangler-commands.md",{"path":137,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":140,"sourceHtmlUrl":141},"scripts\u002Fcheck-versions.sh","SCRIPT","脚本",593,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Fscripts\u002Fcheck-versions.sh",{"path":143,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":144,"sourceHtmlUrl":145},"scripts\u002Fmigration-generator.sh",12059,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Fscripts\u002Fmigration-generator.sh",{"path":147,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":148,"sourceHtmlUrl":149},"scripts\u002Fsetup-vitest-do.sh",10457,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Fscripts\u002Fsetup-vitest-do.sh",{"path":151,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":152,"sourceHtmlUrl":153},"scripts\u002Fvalidate-do-config.sh",10264,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Fscripts\u002Fvalidate-do-config.sh",{"path":155,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":156,"sourceHtmlUrl":157},"templates\u002Falarms-api-do.ts",6269,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Falarms-api-do.ts",{"path":159,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":160,"sourceHtmlUrl":161},"templates\u002Fbasic-do.ts",2994,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fbasic-do.ts",{"path":163,"resourceType":164,"resourceTypeDesc":165,"sizeBytes":166,"sourceHtmlUrl":167},"templates\u002Fgradual-deployment-config.jsonc","OTHER","其他",10667,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fgradual-deployment-config.jsonc",{"path":169,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":170,"sourceHtmlUrl":171},"templates\u002Flocation-hints.ts",6940,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Flocation-hints.ts",{"path":173,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":174,"sourceHtmlUrl":175},"templates\u002Fmulti-do-coordination.ts",7957,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fmulti-do-coordination.ts",{"path":177,"resourceType":52,"resourceTypeDesc":53,"sizeBytes":178,"sourceHtmlUrl":179},"templates\u002Fpackage.json",384,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fpackage.json",{"path":181,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":182,"sourceHtmlUrl":183},"templates\u002Frpc-metadata-do.ts",11098,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Frpc-metadata-do.ts",{"path":185,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":186,"sourceHtmlUrl":187},"templates\u002Frpc-vs-fetch.ts",6100,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Frpc-vs-fetch.ts",{"path":189,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":190,"sourceHtmlUrl":191},"templates\u002Fstate-api-patterns.ts",5904,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fstate-api-patterns.ts",{"path":193,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":194,"sourceHtmlUrl":195},"templates\u002Fttl-cleanup-do.ts",18029,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fttl-cleanup-do.ts",{"path":197,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":198,"sourceHtmlUrl":199},"templates\u002Fvitest-do-test.ts",12615,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fvitest-do-test.ts",{"path":201,"resourceType":138,"resourceTypeDesc":139,"sizeBytes":202,"sourceHtmlUrl":203},"templates\u002Fwebsocket-hibernation-do.ts",6170,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fwebsocket-hibernation-do.ts",{"path":205,"resourceType":164,"resourceTypeDesc":165,"sizeBytes":206,"sourceHtmlUrl":207},"templates\u002Fwrangler-do-config.jsonc",2042,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fsecondsky\u002Fclaude-skills\u002Fcloudflare-durable-objects\u002Ftemplates\u002Fwrangler-do-config.jsonc",[209,223,233,242,248,255],{"skillNo":210,"name":211,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":212,"categories":213,"keywords":219,"publishedAt":22},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[214],{"categoryNo":215,"categoryName":216,"taxonomyType":217,"taxonomyTypeDesc":218},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[220,221,222],"model","model hierarchy","model hierarchy skill",{"skillNo":224,"name":225,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":226,"categories":227,"keywords":229,"publishedAt":22},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[228],{"categoryNo":215,"categoryName":216,"taxonomyType":217,"taxonomyTypeDesc":218},[230,231,232],"MCP","zoom","zoom mcp",{"skillNo":234,"name":235,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":236,"categories":237,"keywords":238,"publishedAt":22},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[239,240,241,231],"sdk","zoom apps sdk","apps",{"skillNo":243,"name":244,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":245,"categories":246,"keywords":247,"publishedAt":22},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[244],{"skillNo":249,"name":250,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":251,"categories":252,"keywords":254,"publishedAt":22},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[253],{"categoryNo":215,"categoryName":216,"taxonomyType":217,"taxonomyTypeDesc":218},[250],{"skillNo":256,"name":257,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":258,"categories":259,"keywords":260,"publishedAt":22},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[257]]