opencodekit 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +209 -77
- package/dist/template/.opencode/agent/plan.md +4 -0
- package/dist/template/.opencode/command/cloudflare.md +70 -0
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/skill/cloudflare/SKILL.md +233 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/README.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/api.md +100 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/configuration.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/gotchas.md +59 -0
- package/dist/template/.opencode/skill/cloudflare/references/agents-sdk/patterns.md +89 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-gateway/README.md +695 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/api.md +38 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/configuration.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/gotchas.md +41 -0
- package/dist/template/.opencode/skill/cloudflare/references/ai-search/patterns.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/api.md +27 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/configuration.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/gotchas.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/analytics-engine/patterns.md +36 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/README.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/api.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/configuration.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/gotchas.md +28 -0
- package/dist/template/.opencode/skill/cloudflare/references/api/patterns.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/README.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/api.md +78 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/configuration.md +128 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/gotchas.md +51 -0
- package/dist/template/.opencode/skill/cloudflare/references/api-shield/patterns.md +145 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/api.md +50 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/configuration.md +53 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/gotchas.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/argo-smart-routing/patterns.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/configuration.md +58 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/gotchas.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/bindings/patterns.md +37 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/README.md +71 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/api.md +168 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/configuration.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/gotchas.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/bot-management/patterns.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/api.md +54 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/configuration.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/gotchas.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/browser-rendering/patterns.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/c3/README.md +264 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/README.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/api.md +176 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/configuration.md +164 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/gotchas.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/cache-reserve/patterns.md +180 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/api.md +43 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/configuration.md +56 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/gotchas.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/containers/patterns.md +40 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/README.md +85 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/api.md +198 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/configuration.md +151 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/gotchas.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/cron-triggers/patterns.md +122 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/README.md +92 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/api.md +141 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/gotchas.md +70 -0
- package/dist/template/.opencode/skill/cloudflare/references/d1/patterns.md +144 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/README.md +34 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/api.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/configuration.md +67 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/gotchas.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/ddos/patterns.md +158 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/api.md +89 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/configuration.md +116 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/gotchas.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/do-storage/patterns.md +112 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/README.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/api.md +152 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/configuration.md +148 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/gotchas.md +158 -0
- package/dist/template/.opencode/skill/cloudflare/references/durable-objects/patterns.md +255 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/api.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/configuration.md +63 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/gotchas.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-routing/patterns.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/email-workers/README.md +598 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/api.md +137 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/configuration.md +133 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/gotchas.md +184 -0
- package/dist/template/.opencode/skill/cloudflare/references/hyperdrive/patterns.md +176 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/configuration.md +45 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/gotchas.md +23 -0
- package/dist/template/.opencode/skill/cloudflare/references/images/patterns.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/README.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/api.md +114 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/configuration.md +92 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/gotchas.md +117 -0
- package/dist/template/.opencode/skill/cloudflare/references/kv/patterns.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/README.md +64 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/api.md +144 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/configuration.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/gotchas.md +187 -0
- package/dist/template/.opencode/skill/cloudflare/references/miniflare/patterns.md +211 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/README.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/api.md +240 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/gotchas.md +171 -0
- package/dist/template/.opencode/skill/cloudflare/references/network-interconnect/patterns.md +171 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/api.md +51 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/configuration.md +60 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/gotchas.md +36 -0
- package/dist/template/.opencode/skill/cloudflare/references/observability/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/README.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/api.md +200 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/configuration.md +228 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/gotchas.md +161 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages/patterns.md +145 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/README.md +57 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/api.md +201 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/configuration.md +159 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/gotchas.md +151 -0
- package/dist/template/.opencode/skill/cloudflare/references/pages-functions/patterns.md +190 -0
- package/dist/template/.opencode/skill/cloudflare/references/pipelines/README.md +664 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/README.md +107 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/api.md +194 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/configuration.md +216 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/gotchas.md +223 -0
- package/dist/template/.opencode/skill/cloudflare/references/pulumi/patterns.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/README.md +69 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/api.md +138 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/configuration.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/gotchas.md +112 -0
- package/dist/template/.opencode/skill/cloudflare/references/queues/patterns.md +155 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/README.md +61 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/api.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/configuration.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/gotchas.md +94 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2/patterns.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/README.md +18 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/api.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/configuration.md +39 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/gotchas.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-data-catalog/patterns.md +46 -0
- package/dist/template/.opencode/skill/cloudflare/references/r2-sql/README.md +512 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/README.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/api.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/configuration.md +63 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/gotchas.md +75 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtime-sfu/patterns.md +102 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/README.md +81 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/api.md +164 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/configuration.md +147 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/gotchas.md +172 -0
- package/dist/template/.opencode/skill/cloudflare/references/realtimekit/patterns.md +155 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/README.md +90 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/api.md +178 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/configuration.md +131 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/gotchas.md +156 -0
- package/dist/template/.opencode/skill/cloudflare/references/sandbox/patterns.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/README.md +58 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/api.md +182 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/configuration.md +140 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/gotchas.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/secrets-store/patterns.md +218 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/README.md +91 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/api.md +139 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/configuration.md +129 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/gotchas.md +87 -0
- package/dist/template/.opencode/skill/cloudflare/references/smart-placement/patterns.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/README.md +15 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/api.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/configuration.md +33 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/gotchas.md +21 -0
- package/dist/template/.opencode/skill/cloudflare/references/snippets/patterns.md +34 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/api.md +24 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/configuration.md +43 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/gotchas.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/spectrum/patterns.md +40 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/configuration.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/gotchas.md +44 -0
- package/dist/template/.opencode/skill/cloudflare/references/static-assets/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/README.md +103 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/api.md +204 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/configuration.md +127 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/gotchas.md +131 -0
- package/dist/template/.opencode/skill/cloudflare/references/stream/patterns.md +152 -0
- package/dist/template/.opencode/skill/cloudflare/references/tail-workers/README.md +640 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/README.md +76 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/api.md +159 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/configuration.md +156 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/gotchas.md +207 -0
- package/dist/template/.opencode/skill/cloudflare/references/terraform/patterns.md +135 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/README.md +82 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/api.md +105 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/configuration.md +113 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/gotchas.md +115 -0
- package/dist/template/.opencode/skill/cloudflare/references/tunnel/patterns.md +157 -0
- package/dist/template/.opencode/skill/cloudflare/references/turn/README.md +699 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/configuration.md +19 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/gotchas.md +27 -0
- package/dist/template/.opencode/skill/cloudflare/references/turnstile/patterns.md +41 -0
- package/dist/template/.opencode/skill/cloudflare/references/vectorize/README.md +682 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/README.md +14 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/api.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/configuration.md +44 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/gotchas.md +24 -0
- package/dist/template/.opencode/skill/cloudflare/references/waf/patterns.md +29 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/README.md +19 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/api.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/configuration.md +31 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/gotchas.md +28 -0
- package/dist/template/.opencode/skill/cloudflare/references/web-analytics/patterns.md +52 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/README.md +47 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/api.md +199 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/configuration.md +185 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/gotchas.md +203 -0
- package/dist/template/.opencode/skill/cloudflare/references/workerd/patterns.md +216 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/README.md +96 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/api.md +137 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/configuration.md +147 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/gotchas.md +99 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers/patterns.md +149 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-ai/README.md +116 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/README.md +48 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/api.md +169 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/configuration.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/gotchas.md +130 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-for-platforms/patterns.md +170 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/README.md +16 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/api.md +20 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/configuration.md +3 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/gotchas.md +35 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-playground/patterns.md +42 -0
- package/dist/template/.opencode/skill/cloudflare/references/workers-vpc/README.md +579 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/README.md +62 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/api.md +125 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/configuration.md +177 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/gotchas.md +136 -0
- package/dist/template/.opencode/skill/cloudflare/references/workflows/patterns.md +132 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/README.md +90 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/api.md +140 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/configuration.md +128 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/gotchas.md +93 -0
- package/dist/template/.opencode/skill/cloudflare/references/wrangler/patterns.md +150 -0
- package/dist/template/.opencode/skill/cloudflare/references/zaraz/README.md +360 -0
- package/dist/template/.opencode/skill/react-best-practices/AGENTS.md +2410 -0
- package/dist/template/.opencode/skill/react-best-practices/README.md +123 -0
- package/dist/template/.opencode/skill/react-best-practices/SKILL.md +125 -0
- package/dist/template/.opencode/skill/react-best-practices/metadata.json +15 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/_sections.md +46 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/_template.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-defer-await.md +80 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-dependencies.md +36 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-parallel.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/template/.opencode/skill/react-best-practices/rules/server-serialization.md +38 -0
- package/dist/template/.opencode/skill/supabase/SKILL.md +120 -0
- package/dist/template/.opencode/skill/supabase/mcp.json +27 -0
- package/dist/template/.opencode/skill/vercel-deploy-claimable/SKILL.md +112 -0
- package/dist/template/.opencode/skill/vercel-deploy-claimable/scripts/deploy.sh +249 -0
- package/dist/template/.opencode/skill/web-design-guidelines/SKILL.md +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# RealtimeKit Gotchas & Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Common Issues
|
|
4
|
+
|
|
5
|
+
### Issue: Cannot connect to meeting
|
|
6
|
+
**Causes**:
|
|
7
|
+
- Auth token invalid or expired
|
|
8
|
+
- API credentials lack correct permissions
|
|
9
|
+
- Network blocks WebRTC traffic (firewall/proxy)
|
|
10
|
+
|
|
11
|
+
**Solutions**:
|
|
12
|
+
- Verify token validity
|
|
13
|
+
- Check API token has **Realtime / Realtime Admin** permissions
|
|
14
|
+
- Enable TURN service for restrictive networks
|
|
15
|
+
|
|
16
|
+
### Issue: No video/audio tracks
|
|
17
|
+
**Causes**:
|
|
18
|
+
- Browser permissions not granted
|
|
19
|
+
- `video: true, audio: true` not set in initialization
|
|
20
|
+
- Device in use by another app
|
|
21
|
+
- Device not available
|
|
22
|
+
|
|
23
|
+
**Solutions**:
|
|
24
|
+
- Request browser permissions explicitly
|
|
25
|
+
- Verify initialization config
|
|
26
|
+
- Use `meeting.self.getAllDevices()` to debug device availability
|
|
27
|
+
- Close other apps using the device
|
|
28
|
+
|
|
29
|
+
### Issue: Participant count mismatched
|
|
30
|
+
**Cause**: `meeting.participants` doesn't include `meeting.self`
|
|
31
|
+
|
|
32
|
+
**Solution**: Total count = `meeting.participants.joined.size() + 1`
|
|
33
|
+
|
|
34
|
+
### Issue: Events not firing
|
|
35
|
+
**Causes**:
|
|
36
|
+
- Event listeners registered after actions occur
|
|
37
|
+
- Incorrect event name spelling
|
|
38
|
+
- Wrong namespace (e.g., `meeting.self` vs `meeting.participants`)
|
|
39
|
+
|
|
40
|
+
**Solutions**:
|
|
41
|
+
- Register listeners before calling `meeting.join()`
|
|
42
|
+
- Check event names against API documentation
|
|
43
|
+
- Verify correct namespace for events
|
|
44
|
+
|
|
45
|
+
### Issue: CORS errors in API calls
|
|
46
|
+
**Cause**: Making REST API calls from client-side
|
|
47
|
+
|
|
48
|
+
**Solution**: All REST API calls **must** be server-side (Workers, backend). Never expose API tokens to clients.
|
|
49
|
+
|
|
50
|
+
### Issue: Preset not applying
|
|
51
|
+
**Causes**:
|
|
52
|
+
- Preset doesn't exist in App
|
|
53
|
+
- `preset_name` doesn't match exactly (case-sensitive)
|
|
54
|
+
- Participant created before preset
|
|
55
|
+
|
|
56
|
+
**Solutions**:
|
|
57
|
+
- Verify preset exists via Dashboard or API
|
|
58
|
+
- Check exact spelling and case
|
|
59
|
+
- Create preset before adding participants
|
|
60
|
+
|
|
61
|
+
### Issue: Token reuse errors
|
|
62
|
+
**Cause**: Reusing participant tokens across sessions
|
|
63
|
+
|
|
64
|
+
**Solution**: Generate fresh token per session. Use refresh endpoint if token expires during session.
|
|
65
|
+
|
|
66
|
+
### Issue: Video quality poor
|
|
67
|
+
**Causes**:
|
|
68
|
+
- Network bandwidth insufficient
|
|
69
|
+
- Resolution/bitrate too high for connection
|
|
70
|
+
- CPU overload
|
|
71
|
+
|
|
72
|
+
**Solutions**:
|
|
73
|
+
- Lower `mediaConfiguration.video` resolution/frameRate
|
|
74
|
+
- Monitor network conditions
|
|
75
|
+
- Reduce participant count or grid size
|
|
76
|
+
|
|
77
|
+
### Issue: Echo or audio feedback
|
|
78
|
+
**Cause**: Multiple devices picking up same audio source
|
|
79
|
+
|
|
80
|
+
**Solutions**:
|
|
81
|
+
- Enable `echoCancellation: true` in `mediaConfiguration.audio`
|
|
82
|
+
- Use headphones
|
|
83
|
+
- Mute when not speaking
|
|
84
|
+
|
|
85
|
+
### Issue: Screen share not working
|
|
86
|
+
**Causes**:
|
|
87
|
+
- Browser doesn't support screen sharing API
|
|
88
|
+
- Permission denied by user
|
|
89
|
+
- Wrong `displaySurface` configuration
|
|
90
|
+
|
|
91
|
+
**Solutions**:
|
|
92
|
+
- Use Chrome/Edge/Firefox (Safari limited support)
|
|
93
|
+
- Check browser permissions
|
|
94
|
+
- Try different `displaySurface` values ('window', 'monitor', 'browser')
|
|
95
|
+
|
|
96
|
+
## Limits
|
|
97
|
+
|
|
98
|
+
| Resource | Limit |
|
|
99
|
+
|----------|-------|
|
|
100
|
+
| Max participants per session | 100 |
|
|
101
|
+
| Max concurrent sessions per App | 1000 |
|
|
102
|
+
| Max recording duration | 6 hours |
|
|
103
|
+
| Max meeting duration | 24 hours |
|
|
104
|
+
| Max chat message length | 4000 characters |
|
|
105
|
+
| Max preset name length | 64 characters |
|
|
106
|
+
| Max meeting title length | 256 characters |
|
|
107
|
+
| Max participant name length | 256 characters |
|
|
108
|
+
| Token expiration | 24 hours (default) |
|
|
109
|
+
| WebRTC ports required | UDP 1024-65535 |
|
|
110
|
+
|
|
111
|
+
## Network Requirements
|
|
112
|
+
|
|
113
|
+
### Firewall Rules
|
|
114
|
+
Allow outbound UDP/TCP to:
|
|
115
|
+
- `*.cloudflare.com` ports 443, 80
|
|
116
|
+
- UDP ports 1024-65535 (WebRTC media)
|
|
117
|
+
|
|
118
|
+
### TURN Service
|
|
119
|
+
Enable for users behind restrictive firewalls/proxies:
|
|
120
|
+
```jsonc
|
|
121
|
+
// wrangler.jsonc
|
|
122
|
+
{
|
|
123
|
+
"vars": {
|
|
124
|
+
"TURN_SERVICE_ID": "your_turn_service_id"
|
|
125
|
+
}
|
|
126
|
+
// Set secret: wrangler secret put TURN_SERVICE_TOKEN
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
TURN automatically configured in SDK when enabled in account.
|
|
131
|
+
|
|
132
|
+
## Debugging Tips
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Check devices
|
|
136
|
+
const devices = await meeting.self.getAllDevices();
|
|
137
|
+
meeting.self.on('deviceListUpdate', ({ added, removed, devices }) => console.log('Devices:', { added, removed, devices }));
|
|
138
|
+
|
|
139
|
+
// Monitor participants
|
|
140
|
+
meeting.participants.joined.on('participantJoined', (p) => console.log(`${p.name} joined:`, { id: p.id, userId: p.userId, audioEnabled: p.audioEnabled, videoEnabled: p.videoEnabled }));
|
|
141
|
+
|
|
142
|
+
// Check room state
|
|
143
|
+
meeting.self.on('roomJoined', () => console.log('Room:', { meetingId: meeting.meta.meetingId, meetingTitle: meeting.meta.meetingTitle, participantCount: meeting.participants.joined.size() + 1, audioEnabled: meeting.self.audioEnabled, videoEnabled: meeting.self.videoEnabled }));
|
|
144
|
+
|
|
145
|
+
// Log all events
|
|
146
|
+
['roomJoined', 'audioUpdate', 'videoUpdate', 'screenShareUpdate', 'deviceUpdate', 'deviceListUpdate'].forEach(event => meeting.self.on(event, (data) => console.log(`[self] ${event}:`, data)));
|
|
147
|
+
['participantJoined', 'participantLeft'].forEach(event => meeting.participants.joined.on(event, (data) => console.log(`[participants] ${event}:`, data)));
|
|
148
|
+
meeting.chat.on('chatUpdate', (data) => console.log('[chat] chatUpdate:', data));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Security & Performance
|
|
152
|
+
|
|
153
|
+
### Security: Do NOT
|
|
154
|
+
- Expose `CLOUDFLARE_API_TOKEN` in client code, hardcode credentials in frontend
|
|
155
|
+
- Reuse participant tokens, store tokens in localStorage without encryption
|
|
156
|
+
- Allow client-side meeting creation
|
|
157
|
+
|
|
158
|
+
### Security: DO
|
|
159
|
+
- Generate tokens server-side only, use HTTPS, implement rate limiting
|
|
160
|
+
- Validate user auth before generating tokens, use `custom_participant_id` to map to your user system
|
|
161
|
+
- Set appropriate preset permissions per user role, rotate API tokens regularly
|
|
162
|
+
|
|
163
|
+
### Performance
|
|
164
|
+
- **CPU**: Lower video resolution/frameRate, disable video for audio-only, use `meeting.participants.active` for large meetings, implement virtual scrolling
|
|
165
|
+
- **Bandwidth**: Set max resolution in `mediaConfiguration`, disable screenshare audio if unneeded, use audio-only mode, implement adaptive bitrate
|
|
166
|
+
- **Memory**: Clean up event listeners on unmount, call `meeting.leave()` when done, don't store large participant arrays
|
|
167
|
+
|
|
168
|
+
## In This Reference
|
|
169
|
+
- [README.md](./README.md) - Overview, core concepts, quick start
|
|
170
|
+
- [configuration.md](./configuration.md) - SDK config, presets, wrangler setup
|
|
171
|
+
- [api.md](./api.md) - Client SDK APIs, REST endpoints
|
|
172
|
+
- [patterns.md](./patterns.md) - Common patterns, React hooks, backend integration
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# RealtimeKit Patterns
|
|
2
|
+
|
|
3
|
+
## UI Kit (Minimal Code)
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
// React
|
|
7
|
+
import { RtkMeeting } from '@cloudflare/realtimekit-react-ui';
|
|
8
|
+
<RtkMeeting authToken="<token>" onLeave={() => console.log('Left')} />
|
|
9
|
+
|
|
10
|
+
// Angular
|
|
11
|
+
@Component({ template: `<rtk-meeting [authToken]="authToken" (rtkLeave)="onLeave($event)"></rtk-meeting>` })
|
|
12
|
+
export class AppComponent { authToken = '<token>'; onLeave(event: unknown) {} }
|
|
13
|
+
|
|
14
|
+
// HTML/Web Components
|
|
15
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui/dist/realtimekit-ui/realtimekit-ui.esm.js"></script>
|
|
16
|
+
<rtk-meeting id="meeting"></rtk-meeting>
|
|
17
|
+
<script>document.getElementById('meeting').authToken = '<token>';</script>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core SDK Patterns
|
|
21
|
+
|
|
22
|
+
### Basic Setup
|
|
23
|
+
```typescript
|
|
24
|
+
import RealtimeKitClient from '@cloudflare/realtimekit';
|
|
25
|
+
|
|
26
|
+
const meeting = new RealtimeKitClient({ authToken, video: true, audio: true });
|
|
27
|
+
meeting.self.on('roomJoined', () => console.log('Joined:', meeting.meta.meetingTitle));
|
|
28
|
+
meeting.participants.joined.on('participantJoined', (p) => console.log(`${p.name} joined`));
|
|
29
|
+
await meeting.join();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Video Grid (React)
|
|
33
|
+
```typescript
|
|
34
|
+
function VideoGrid({ meeting }) {
|
|
35
|
+
const [participants, setParticipants] = useState([]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const update = () => setParticipants(meeting.participants.joined.toArray());
|
|
38
|
+
meeting.participants.joined.on('participantJoined', update);
|
|
39
|
+
meeting.participants.joined.on('participantLeft', update);
|
|
40
|
+
update();
|
|
41
|
+
return () => { meeting.participants.joined.off('participantJoined', update); meeting.participants.joined.off('participantLeft', update); };
|
|
42
|
+
}, [meeting]);
|
|
43
|
+
return <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))' }}>
|
|
44
|
+
{participants.map(p => <VideoTile key={p.id} participant={p} />)}
|
|
45
|
+
</div>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function VideoTile({ participant }) {
|
|
49
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (videoRef.current && participant.videoTrack) videoRef.current.srcObject = new MediaStream([participant.videoTrack]);
|
|
52
|
+
}, [participant.videoTrack]);
|
|
53
|
+
return <div><video ref={videoRef} autoPlay playsInline muted /><div>{participant.name}</div></div>;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Device Selection & Chat
|
|
58
|
+
```typescript
|
|
59
|
+
// Device selection
|
|
60
|
+
const devices = await meeting.self.getAllDevices();
|
|
61
|
+
const audioInputs = devices.filter(d => d.kind === 'audioinput');
|
|
62
|
+
const videoInputs = devices.filter(d => d.kind === 'videoinput');
|
|
63
|
+
meeting.self.on('deviceListUpdate', ({ added, removed }) => console.log('Devices:', { added, removed }));
|
|
64
|
+
const switchCamera = (deviceId: string) => { const d = devices.find(x => x.deviceId === deviceId); if (d) await meeting.self.setDevice(d); };
|
|
65
|
+
|
|
66
|
+
// Chat component
|
|
67
|
+
function ChatComponent({ meeting }) {
|
|
68
|
+
const [messages, setMessages] = useState(meeting.chat.messages);
|
|
69
|
+
const [input, setInput] = useState('');
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const handleUpdate = ({ messages }) => setMessages(messages);
|
|
72
|
+
meeting.chat.on('chatUpdate', handleUpdate);
|
|
73
|
+
return () => meeting.chat.off('chatUpdate', handleUpdate);
|
|
74
|
+
}, [meeting]);
|
|
75
|
+
const send = async () => { if (input.trim()) { await meeting.chat.sendTextMessage(input); setInput(''); } };
|
|
76
|
+
return <div><div>{messages.map((msg, i) => <div key={i}><strong>{msg.senderName}:</strong> {msg.text}</div>)}</div><input value={input} onChange={e => setInput(e.target.value)} onKeyPress={e => e.key === 'Enter' && send()} /><button onClick={send}>Send</button></div>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Custom hook
|
|
80
|
+
export function useMeeting(authToken: string) {
|
|
81
|
+
const [meeting, setMeeting] = useState<RealtimeKitClient | null>(null);
|
|
82
|
+
const [joined, setJoined] = useState(false);
|
|
83
|
+
const [participants, setParticipants] = useState([]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const client = new RealtimeKitClient({ authToken });
|
|
86
|
+
client.self.on('roomJoined', () => setJoined(true));
|
|
87
|
+
const update = () => setParticipants(client.participants.joined.toArray());
|
|
88
|
+
client.participants.joined.on('participantJoined', update);
|
|
89
|
+
client.participants.joined.on('participantLeft', update);
|
|
90
|
+
setMeeting(client);
|
|
91
|
+
return () => { client.leave(); };
|
|
92
|
+
}, [authToken]);
|
|
93
|
+
return { meeting, joined, participants, join: async () => meeting?.join(), leave: async () => meeting?.leave() };
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Backend Integration
|
|
98
|
+
|
|
99
|
+
### Token Generation (Express)
|
|
100
|
+
```typescript
|
|
101
|
+
app.post('/api/join-meeting', async (req, res) => {
|
|
102
|
+
const { meetingId, userName, presetName } = req.body;
|
|
103
|
+
const response = await fetch(
|
|
104
|
+
`https://api.cloudflare.com/client/v4/accounts/${process.env.ACCOUNT_ID}/realtime/kit/${process.env.APP_ID}/meetings/${meetingId}/participants`,
|
|
105
|
+
{
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.CLOUDFLARE_API_TOKEN}` },
|
|
108
|
+
body: JSON.stringify({ name: userName, preset_name: presetName, custom_participant_id: req.user.id })
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
const data = await response.json();
|
|
112
|
+
res.json({ authToken: data.result.authToken });
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Workers Integration
|
|
117
|
+
```typescript
|
|
118
|
+
export interface Env { CLOUDFLARE_API_TOKEN: string; CLOUDFLARE_ACCOUNT_ID: string; REALTIMEKIT_APP_ID: string; }
|
|
119
|
+
|
|
120
|
+
export default {
|
|
121
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
122
|
+
if (new URL(request.url).pathname === '/api/create-meeting') {
|
|
123
|
+
return fetch(`https://api.cloudflare.com/client/v4/accounts/${env.CLOUDFLARE_ACCOUNT_ID}/realtime/kit/${env.REALTIMEKIT_APP_ID}/meetings`, {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${env.CLOUDFLARE_API_TOKEN}` },
|
|
126
|
+
body: JSON.stringify({ title: 'Team Meeting' })
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return new Response('Not found', { status: 404 });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Best Practices
|
|
135
|
+
|
|
136
|
+
### Security
|
|
137
|
+
1. **Never expose API tokens client-side** - Generate participant tokens server-side only
|
|
138
|
+
2. **Don't reuse participant tokens** - Generate fresh token per session, use refresh endpoint if expired
|
|
139
|
+
3. **Use custom participant IDs** - Map to your user system for cross-session tracking
|
|
140
|
+
|
|
141
|
+
### Performance
|
|
142
|
+
1. **Event-driven updates** - Listen to events, don't poll. Use `toArray()` only when needed
|
|
143
|
+
2. **Media quality constraints** - Set appropriate resolution/bitrate limits based on network conditions
|
|
144
|
+
3. **Device management** - Enable `autoSwitchAudioDevice` for better UX, handle device list updates
|
|
145
|
+
|
|
146
|
+
### Architecture
|
|
147
|
+
1. **Separate Apps for environments** - staging vs production to prevent data mixing
|
|
148
|
+
2. **Preset strategy** - Create presets at App level, reuse across meetings
|
|
149
|
+
3. **Token management** - Backend generates tokens, frontend receives via authenticated endpoint
|
|
150
|
+
|
|
151
|
+
## In This Reference
|
|
152
|
+
- [README.md](./README.md) - Overview, core concepts, quick start
|
|
153
|
+
- [configuration.md](./configuration.md) - SDK config, presets, wrangler setup
|
|
154
|
+
- [api.md](./api.md) - Client SDK APIs, REST endpoints
|
|
155
|
+
- [gotchas.md](./gotchas.md) - Common issues, troubleshooting, limits
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Cloudflare Sandbox SDK
|
|
2
|
+
|
|
3
|
+
Secure isolated code execution in containers on Cloudflare's edge. Run untrusted code, manage files, expose services, integrate with AI agents.
|
|
4
|
+
|
|
5
|
+
**Use cases**: AI code execution, interactive dev environments, data analysis, CI/CD, code interpreters, multi-tenant execution.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
- Each sandbox = Durable Object + Container
|
|
10
|
+
- Persistent across requests (same ID = same sandbox)
|
|
11
|
+
- Isolated filesystem/processes/network
|
|
12
|
+
- Configurable sleep/wake for cost optimization
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { getSandbox, proxyToSandbox, type Sandbox } from '@cloudflare/sandbox';
|
|
18
|
+
export { Sandbox } from '@cloudflare/sandbox';
|
|
19
|
+
|
|
20
|
+
type Env = { Sandbox: DurableObjectNamespace<Sandbox>; };
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
24
|
+
// CRITICAL: proxyToSandbox MUST be called first for preview URLs
|
|
25
|
+
const proxyResponse = await proxyToSandbox(request, env);
|
|
26
|
+
if (proxyResponse) return proxyResponse;
|
|
27
|
+
|
|
28
|
+
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
|
|
29
|
+
const result = await sandbox.exec('python3 -c "print(2 + 2)"');
|
|
30
|
+
return Response.json({ output: result.stdout });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**wrangler.jsonc**:
|
|
36
|
+
```jsonc
|
|
37
|
+
{
|
|
38
|
+
"name": "my-sandbox-worker",
|
|
39
|
+
"main": "src/index.ts",
|
|
40
|
+
"compatibility_date": "2024-01-01",
|
|
41
|
+
|
|
42
|
+
"containers": [{
|
|
43
|
+
"class_name": "Sandbox",
|
|
44
|
+
"image": "./Dockerfile",
|
|
45
|
+
"instance_type": "lite", // lite | standard | heavy
|
|
46
|
+
"max_instances": 5
|
|
47
|
+
}],
|
|
48
|
+
|
|
49
|
+
"durable_objects": {
|
|
50
|
+
"bindings": [{ "class_name": "Sandbox", "name": "Sandbox" }]
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
"migrations": [{
|
|
54
|
+
"tag": "v1",
|
|
55
|
+
"new_sqlite_classes": ["Sandbox"]
|
|
56
|
+
}]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Dockerfile**:
|
|
61
|
+
```dockerfile
|
|
62
|
+
FROM docker.io/cloudflare/sandbox:latest
|
|
63
|
+
RUN pip3 install --no-cache-dir pandas numpy matplotlib
|
|
64
|
+
EXPOSE 8080 3000 # Required for wrangler dev
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Core APIs
|
|
68
|
+
|
|
69
|
+
- `getSandbox(namespace, id, options?)` → Get/create sandbox
|
|
70
|
+
- `sandbox.exec(command, options?)` → Execute command
|
|
71
|
+
- `sandbox.readFile(path)` / `writeFile(path, content)` → File ops
|
|
72
|
+
- `sandbox.startProcess(command, options)` → Background process
|
|
73
|
+
- `sandbox.exposePort(port, options)` → Get preview URL
|
|
74
|
+
- `sandbox.createSession(options)` → Isolated session
|
|
75
|
+
|
|
76
|
+
## Critical Rules
|
|
77
|
+
|
|
78
|
+
- ALWAYS call `proxyToSandbox()` first
|
|
79
|
+
- Same ID = reuse sandbox
|
|
80
|
+
- Use `/workspace` for persistent files
|
|
81
|
+
- `normalizeId: true` for preview URLs
|
|
82
|
+
- Retry on `CONTAINER_NOT_READY`
|
|
83
|
+
|
|
84
|
+
## Resources
|
|
85
|
+
|
|
86
|
+
- [Configuration](./configuration.md) - Config, CLI, environment
|
|
87
|
+
- [API Reference](./api.md) - Programmatic API, testing
|
|
88
|
+
- [Patterns](./patterns.md) - Common workflows, CI/CD
|
|
89
|
+
- [Gotchas](./gotchas.md) - Issues, limits, best practices
|
|
90
|
+
- [Official Docs](https://developers.cloudflare.com/sandbox/)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Command Execution
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// Basic
|
|
7
|
+
const result = await sandbox.exec('python3 script.py');
|
|
8
|
+
// Returns: { stdout, stderr, exitCode, success, duration }
|
|
9
|
+
|
|
10
|
+
// Streaming
|
|
11
|
+
await sandbox.exec('npm install', {
|
|
12
|
+
stream: true,
|
|
13
|
+
onOutput: (stream, data) => console.log(`[${stream}]`, data),
|
|
14
|
+
onComplete: (result) => console.log('Exit:', result.exitCode),
|
|
15
|
+
onError: (error) => console.error(error)
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// With env & cwd
|
|
19
|
+
await sandbox.exec('python3 test.py', {
|
|
20
|
+
cwd: '/workspace/project',
|
|
21
|
+
env: { API_KEY: 'secret', DEBUG: 'true' }
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## File Operations
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// Read
|
|
29
|
+
const file = await sandbox.readFile('/workspace/data.txt');
|
|
30
|
+
// Returns: { content, path }
|
|
31
|
+
|
|
32
|
+
// Write (creates dirs automatically)
|
|
33
|
+
await sandbox.writeFile('/workspace/deep/nested/file.txt', 'content');
|
|
34
|
+
|
|
35
|
+
// List
|
|
36
|
+
const files = await sandbox.listFiles('/workspace');
|
|
37
|
+
// Returns: [{ name, path, type: 'file'|'directory', size, modified }]
|
|
38
|
+
|
|
39
|
+
// Delete
|
|
40
|
+
await sandbox.deleteFile('/workspace/temp.txt');
|
|
41
|
+
await sandbox.deleteFile('/workspace/temp-dir', { recursive: true });
|
|
42
|
+
|
|
43
|
+
// Directory ops
|
|
44
|
+
await sandbox.mkdir('/workspace/new-dir', { recursive: true });
|
|
45
|
+
const exists = await sandbox.pathExists('/workspace/file.txt');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Background Processes
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Start
|
|
52
|
+
const process = await sandbox.startProcess('python3 -m http.server 8080', {
|
|
53
|
+
processId: 'web-server',
|
|
54
|
+
cwd: '/workspace/public',
|
|
55
|
+
env: { PORT: '8080' }
|
|
56
|
+
});
|
|
57
|
+
// Returns: { id, pid, command }
|
|
58
|
+
|
|
59
|
+
// Management
|
|
60
|
+
const processes = await sandbox.listProcesses();
|
|
61
|
+
const info = await sandbox.getProcess('web-server');
|
|
62
|
+
await sandbox.stopProcess('web-server');
|
|
63
|
+
const logs = await sandbox.getProcessLogs('web-server');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Port Exposure
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Expose
|
|
70
|
+
const exposed = await sandbox.exposePort(8080, {
|
|
71
|
+
name: 'web-app',
|
|
72
|
+
hostname: request.hostname
|
|
73
|
+
});
|
|
74
|
+
// Returns: { url, port, name, status }
|
|
75
|
+
|
|
76
|
+
// Check
|
|
77
|
+
const isExposed = await sandbox.isPortExposed(8080);
|
|
78
|
+
const portInfo = await sandbox.getExposedPort(8080);
|
|
79
|
+
const allPorts = await sandbox.getExposedPorts(request.hostname);
|
|
80
|
+
|
|
81
|
+
// Unexpose
|
|
82
|
+
await sandbox.unexposePort(8080);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Sessions (Isolated Contexts)
|
|
86
|
+
|
|
87
|
+
Each session maintains own shell state, env vars, cwd, process namespace.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Create
|
|
91
|
+
const session = await sandbox.createSession({
|
|
92
|
+
id: 'user-123',
|
|
93
|
+
name: 'User Workspace',
|
|
94
|
+
cwd: '/workspace/user123',
|
|
95
|
+
env: { USER_ID: '123', API_KEY: 'secret' }
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Use (full sandbox API bound to session context)
|
|
99
|
+
await session.exec('echo $USER_ID');
|
|
100
|
+
await session.writeFile('config.txt', 'data');
|
|
101
|
+
await session.startProcess('python3 worker.py', { processId: 'worker-1' });
|
|
102
|
+
|
|
103
|
+
// Retrieve
|
|
104
|
+
const session = await sandbox.getSession('user-123');
|
|
105
|
+
const sessions = await sandbox.listSessions();
|
|
106
|
+
|
|
107
|
+
// Delete
|
|
108
|
+
await sandbox.deleteSession('user-123');
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Code Interpreter
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const result = await sandbox.interpret('python', {
|
|
115
|
+
code: `
|
|
116
|
+
import matplotlib.pyplot as plt
|
|
117
|
+
plt.plot([1, 2, 3], [4, 5, 6])
|
|
118
|
+
plt.savefig('plot.png')
|
|
119
|
+
print("Chart created")
|
|
120
|
+
`,
|
|
121
|
+
files: {
|
|
122
|
+
'data.csv': 'name,value\nalice,10\nbob,20'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Returns: { outputs: [{ type, content }], files, error }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Error Handling
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// Command errors
|
|
132
|
+
const result = await sandbox.exec('python3 invalid.py');
|
|
133
|
+
if (!result.success) {
|
|
134
|
+
console.error('Exit code:', result.exitCode);
|
|
135
|
+
console.error('Stderr:', result.stderr);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// SDK errors
|
|
139
|
+
try {
|
|
140
|
+
await sandbox.readFile('/nonexistent');
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error.code === 'FILE_NOT_FOUND') { /* ... */ }
|
|
143
|
+
else if (error.code === 'CONTAINER_NOT_READY') { /* retry */ }
|
|
144
|
+
else if (error.code === 'TIMEOUT') { /* ... */ }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Retry pattern
|
|
148
|
+
async function execWithRetry(sandbox, cmd, maxRetries = 3) {
|
|
149
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
150
|
+
try {
|
|
151
|
+
return await sandbox.exec(cmd);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error.code === 'CONTAINER_NOT_READY' && i < maxRetries - 1) {
|
|
154
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Client Architecture
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
SandboxClient (aggregator)
|
|
167
|
+
├── CommandClient → exec(), streaming
|
|
168
|
+
├── FileClient → read/write/list/delete
|
|
169
|
+
├── ProcessClient → background processes
|
|
170
|
+
├── PortClient → expose services, preview URLs
|
|
171
|
+
├── GitClient → clone repos
|
|
172
|
+
├── UtilityClient → health, sessions
|
|
173
|
+
└── InterpreterClient → code execution (Python/JS)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Execution Modes**:
|
|
177
|
+
1. **Foreground** (exec): Blocking, captures output
|
|
178
|
+
2. **Background** (execStream/startProcess): Non-blocking, uses FIFOs, concurrent
|