memory-journal-mcp 7.7.0 → 8.0.0
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/README.md +126 -56
- package/dist/chunk-6OHRCNYW.js +3231 -0
- package/dist/chunk-JFMITANR.js +5168 -0
- package/dist/{chunk-QCQPAF4I.js → chunk-MWNLAEHR.js} +301 -4321
- package/dist/{chunk-ARLYSFSI.js → chunk-UHSO65A4.js} +4242 -6092
- package/dist/cli.js +21 -3
- package/dist/index.d.ts +16 -13
- package/dist/index.js +4 -2
- package/dist/resources-IJVKDFGS.js +2 -0
- package/dist/tools-44DGXE3V.js +2 -0
- package/dist/worker-script.js +201 -20
- package/package.json +7 -4
- package/skills/README.md +62 -25
- package/skills/adversarial-performance/SKILL.md +139 -0
- package/skills/adversarial-performance/references/audit-categories.md +462 -0
- package/skills/adversarial-performance/references/copilot-performance-prompts.md +44 -0
- package/skills/adversarial-performance/references/copilot-usage.md +16 -0
- package/skills/adversarial-performance/references/feedback-loop.md +177 -0
- package/skills/adversarial-performance/references/multi-pass-performance-protocol.md +398 -0
- package/skills/adversarial-planner/SKILL.md +23 -54
- package/skills/adversarial-planner/references/copilot-integration.md +25 -40
- package/skills/adversarial-planner/references/copilot-usage.md +16 -0
- package/skills/adversarial-planner/references/multi-pass-protocol.md +4 -0
- package/skills/adversarial-security/SKILL.md +149 -0
- package/skills/adversarial-security/references/adversarial-base-protocol.md +44 -0
- package/skills/adversarial-security/references/audit-categories.md +723 -0
- package/skills/adversarial-security/references/copilot-security-prompts.md +142 -0
- package/skills/adversarial-security/references/copilot-usage.md +16 -0
- package/skills/adversarial-security/references/feedback-loop.md +206 -0
- package/skills/adversarial-security/references/journal-opt-out.md +7 -0
- package/skills/adversarial-security/references/multi-pass-security-protocol.md +403 -0
- package/skills/adversarial-skill-audit/SKILL.md +118 -0
- package/skills/adversarial-skill-audit/references/audit-categories.md +308 -0
- package/skills/adversarial-skill-audit/references/copilot-skill-prompts.md +68 -0
- package/skills/adversarial-skill-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-skill-audit/references/feedback-loop.md +155 -0
- package/skills/adversarial-skill-audit/references/multi-pass-skill-protocol.md +367 -0
- package/skills/adversarial-skill-audit/scripts/check-skills.ps1 +48 -0
- package/skills/adversarial-skill-audit/scripts/run-copilot.ps1 +52 -0
- package/skills/adversarial-workflow-audit/SKILL.md +82 -0
- package/skills/adversarial-workflow-audit/references/audit-categories.md +28 -0
- package/skills/adversarial-workflow-audit/references/copilot-usage.md +16 -0
- package/skills/adversarial-workflow-audit/scripts/check-workflows.ps1 +24 -0
- package/skills/agents-sdk/SKILL.md +220 -0
- package/skills/agents-sdk/references/callable.md +92 -0
- package/skills/agents-sdk/references/codemode.md +209 -0
- package/skills/agents-sdk/references/email.md +144 -0
- package/skills/agents-sdk/references/mcp/SKILL.md +65 -0
- package/skills/agents-sdk/references/mcp/code-mode-reference.md +245 -0
- package/skills/agents-sdk/references/mcp/oauth-reference.md +359 -0
- package/skills/agents-sdk/references/mcp/references/architecture-reference.md +208 -0
- package/skills/agents-sdk/references/mcp/references/cloudflare-quickstart.md +156 -0
- package/skills/agents-sdk/references/mcp/references/error-handling.md +343 -0
- package/skills/agents-sdk/references/mcp/references/http-security.md +164 -0
- package/skills/agents-sdk/references/mcp/references/implementation-guide.md +507 -0
- package/skills/agents-sdk/references/mcp/references/testing-reference.md +171 -0
- package/skills/agents-sdk/references/mcp.md +157 -0
- package/skills/agents-sdk/references/state-scheduling.md +164 -0
- package/skills/agents-sdk/references/streaming-chat.md +168 -0
- package/skills/agents-sdk/references/workflows.md +136 -0
- package/skills/auth-identity/SKILL.md +48 -0
- package/skills/autonomous-dev/SKILL.md +46 -23
- package/skills/autonomous-dev/references/workflow_orchestration.md +22 -0
- package/skills/aws/SKILL.md +39 -0
- package/skills/azure/SKILL.md +38 -0
- package/skills/bin/sync.js +7 -1
- package/skills/biome/SKILL.md +59 -0
- package/skills/bun/SKILL.md +8 -2
- package/skills/cloudflare/SKILL.md +37 -0
- package/skills/cloudflare/references/agents-sdk/README.md +95 -0
- package/skills/cloudflare/references/agents-sdk/api.md +195 -0
- package/skills/cloudflare/references/agents-sdk/configuration.md +178 -0
- package/skills/cloudflare/references/agents-sdk/gotchas.md +173 -0
- package/skills/cloudflare/references/agents-sdk/patterns.md +215 -0
- package/skills/cloudflare/references/ai-gateway/README.md +176 -0
- package/skills/cloudflare/references/ai-gateway/configuration.md +117 -0
- package/skills/cloudflare/references/ai-gateway/dynamic-routing.md +88 -0
- package/skills/cloudflare/references/ai-gateway/features.md +96 -0
- package/skills/cloudflare/references/ai-gateway/sdk-integration.md +110 -0
- package/skills/cloudflare/references/ai-gateway/troubleshooting.md +90 -0
- package/skills/cloudflare/references/ai-search/README.md +145 -0
- package/skills/cloudflare/references/ai-search/api.md +87 -0
- package/skills/cloudflare/references/ai-search/configuration.md +91 -0
- package/skills/cloudflare/references/ai-search/gotchas.md +92 -0
- package/skills/cloudflare/references/ai-search/patterns.md +87 -0
- package/skills/cloudflare/references/analytics-engine/README.md +96 -0
- package/skills/cloudflare/references/analytics-engine/api.md +112 -0
- package/skills/cloudflare/references/analytics-engine/configuration.md +107 -0
- package/skills/cloudflare/references/analytics-engine/gotchas.md +87 -0
- package/skills/cloudflare/references/analytics-engine/patterns.md +83 -0
- package/skills/cloudflare/references/api/README.md +66 -0
- package/skills/cloudflare/references/api/api.md +205 -0
- package/skills/cloudflare/references/api/configuration.md +158 -0
- package/skills/cloudflare/references/api/gotchas.md +231 -0
- package/skills/cloudflare/references/api/patterns.md +208 -0
- package/skills/cloudflare/references/api-shield/README.md +44 -0
- package/skills/cloudflare/references/api-shield/api.md +153 -0
- package/skills/cloudflare/references/api-shield/configuration.md +210 -0
- package/skills/cloudflare/references/api-shield/gotchas.md +132 -0
- package/skills/cloudflare/references/api-shield/patterns.md +185 -0
- package/skills/cloudflare/references/argo-smart-routing/README.md +96 -0
- package/skills/cloudflare/references/argo-smart-routing/api.md +253 -0
- package/skills/cloudflare/references/argo-smart-routing/configuration.md +205 -0
- package/skills/cloudflare/references/argo-smart-routing/gotchas.md +115 -0
- package/skills/cloudflare/references/argo-smart-routing/patterns.md +107 -0
- package/skills/cloudflare/references/bindings/README.md +127 -0
- package/skills/cloudflare/references/bindings/api.md +214 -0
- package/skills/cloudflare/references/bindings/configuration.md +200 -0
- package/skills/cloudflare/references/bindings/gotchas.md +210 -0
- package/skills/cloudflare/references/bindings/patterns.md +205 -0
- package/skills/cloudflare/references/bot-management/README.md +95 -0
- package/skills/cloudflare/references/bot-management/api.md +175 -0
- package/skills/cloudflare/references/bot-management/configuration.md +175 -0
- package/skills/cloudflare/references/bot-management/gotchas.md +116 -0
- package/skills/cloudflare/references/bot-management/patterns.md +181 -0
- package/skills/cloudflare/references/browser-rendering/README.md +84 -0
- package/skills/cloudflare/references/browser-rendering/api.md +108 -0
- package/skills/cloudflare/references/browser-rendering/configuration.md +78 -0
- package/skills/cloudflare/references/browser-rendering/gotchas.md +91 -0
- package/skills/cloudflare/references/browser-rendering/patterns.md +93 -0
- package/skills/cloudflare/references/c3/README.md +111 -0
- package/skills/cloudflare/references/c3/api.md +71 -0
- package/skills/cloudflare/references/c3/configuration.md +85 -0
- package/skills/cloudflare/references/c3/gotchas.md +97 -0
- package/skills/cloudflare/references/c3/patterns.md +84 -0
- package/skills/cloudflare/references/cache-reserve/README.md +150 -0
- package/skills/cloudflare/references/cache-reserve/api.md +184 -0
- package/skills/cloudflare/references/cache-reserve/configuration.md +170 -0
- package/skills/cloudflare/references/cache-reserve/gotchas.md +136 -0
- package/skills/cloudflare/references/cache-reserve/patterns.md +197 -0
- package/skills/cloudflare/references/containers/README.md +87 -0
- package/skills/cloudflare/references/containers/api.md +197 -0
- package/skills/cloudflare/references/containers/configuration.md +191 -0
- package/skills/cloudflare/references/containers/gotchas.md +182 -0
- package/skills/cloudflare/references/containers/patterns.md +204 -0
- package/skills/cloudflare/references/cron-triggers/README.md +101 -0
- package/skills/cloudflare/references/cron-triggers/api.md +224 -0
- package/skills/cloudflare/references/cron-triggers/configuration.md +190 -0
- package/skills/cloudflare/references/cron-triggers/gotchas.md +207 -0
- package/skills/cloudflare/references/cron-triggers/patterns.md +274 -0
- package/skills/cloudflare/references/d1/README.md +137 -0
- package/skills/cloudflare/references/d1/api.md +213 -0
- package/skills/cloudflare/references/d1/configuration.md +198 -0
- package/skills/cloudflare/references/d1/gotchas.md +98 -0
- package/skills/cloudflare/references/d1/patterns.md +240 -0
- package/skills/cloudflare/references/ddos/README.md +42 -0
- package/skills/cloudflare/references/ddos/api.md +158 -0
- package/skills/cloudflare/references/ddos/configuration.md +94 -0
- package/skills/cloudflare/references/ddos/gotchas.md +114 -0
- package/skills/cloudflare/references/ddos/patterns.md +220 -0
- package/skills/cloudflare/references/decision-trees.md +95 -0
- package/skills/cloudflare/references/do-storage/README.md +79 -0
- package/skills/cloudflare/references/do-storage/api.md +107 -0
- package/skills/cloudflare/references/do-storage/configuration.md +114 -0
- package/skills/cloudflare/references/do-storage/gotchas.md +153 -0
- package/skills/cloudflare/references/do-storage/patterns.md +210 -0
- package/skills/cloudflare/references/do-storage/testing.md +186 -0
- package/skills/cloudflare/references/durable-objects/README.md +194 -0
- package/skills/cloudflare/references/durable-objects/api.md +205 -0
- package/skills/cloudflare/references/durable-objects/configuration.md +160 -0
- package/skills/cloudflare/references/durable-objects/gotchas.md +200 -0
- package/skills/cloudflare/references/durable-objects/patterns.md +205 -0
- package/skills/cloudflare/references/email-routing/README.md +89 -0
- package/skills/cloudflare/references/email-routing/api.md +192 -0
- package/skills/cloudflare/references/email-routing/configuration.md +187 -0
- package/skills/cloudflare/references/email-routing/gotchas.md +203 -0
- package/skills/cloudflare/references/email-routing/patterns.md +241 -0
- package/skills/cloudflare/references/email-workers/README.md +153 -0
- package/skills/cloudflare/references/email-workers/api.md +227 -0
- package/skills/cloudflare/references/email-workers/configuration.md +115 -0
- package/skills/cloudflare/references/email-workers/gotchas.md +133 -0
- package/skills/cloudflare/references/email-workers/patterns.md +108 -0
- package/skills/cloudflare/references/graphql-api/README.md +147 -0
- package/skills/cloudflare/references/graphql-api/api.md +175 -0
- package/skills/cloudflare/references/graphql-api/configuration.md +151 -0
- package/skills/cloudflare/references/graphql-api/gotchas.md +111 -0
- package/skills/cloudflare/references/graphql-api/patterns.md +276 -0
- package/skills/cloudflare/references/hyperdrive/README.md +84 -0
- package/skills/cloudflare/references/hyperdrive/api.md +149 -0
- package/skills/cloudflare/references/hyperdrive/configuration.md +166 -0
- package/skills/cloudflare/references/hyperdrive/gotchas.md +77 -0
- package/skills/cloudflare/references/hyperdrive/patterns.md +203 -0
- package/skills/cloudflare/references/images/README.md +65 -0
- package/skills/cloudflare/references/images/api.md +101 -0
- package/skills/cloudflare/references/images/configuration.md +206 -0
- package/skills/cloudflare/references/images/gotchas.md +106 -0
- package/skills/cloudflare/references/images/patterns.md +126 -0
- package/skills/cloudflare/references/kv/README.md +90 -0
- package/skills/cloudflare/references/kv/api.md +163 -0
- package/skills/cloudflare/references/kv/configuration.md +148 -0
- package/skills/cloudflare/references/kv/gotchas.md +133 -0
- package/skills/cloudflare/references/kv/patterns.md +195 -0
- package/skills/cloudflare/references/miniflare/README.md +113 -0
- package/skills/cloudflare/references/miniflare/api.md +204 -0
- package/skills/cloudflare/references/miniflare/configuration.md +174 -0
- package/skills/cloudflare/references/miniflare/gotchas.md +179 -0
- package/skills/cloudflare/references/miniflare/patterns.md +187 -0
- package/skills/cloudflare/references/network-interconnect/README.md +104 -0
- package/skills/cloudflare/references/network-interconnect/api.md +220 -0
- package/skills/cloudflare/references/network-interconnect/configuration.md +123 -0
- package/skills/cloudflare/references/network-interconnect/gotchas.md +175 -0
- package/skills/cloudflare/references/network-interconnect/patterns.md +174 -0
- package/skills/cloudflare/references/observability/README.md +93 -0
- package/skills/cloudflare/references/observability/api.md +168 -0
- package/skills/cloudflare/references/observability/configuration.md +178 -0
- package/skills/cloudflare/references/observability/gotchas.md +125 -0
- package/skills/cloudflare/references/observability/patterns.md +105 -0
- package/skills/cloudflare/references/pages/README.md +92 -0
- package/skills/cloudflare/references/pages/api.md +205 -0
- package/skills/cloudflare/references/pages/configuration.md +216 -0
- package/skills/cloudflare/references/pages/gotchas.md +218 -0
- package/skills/cloudflare/references/pages/patterns.md +215 -0
- package/skills/cloudflare/references/pages-functions/README.md +104 -0
- package/skills/cloudflare/references/pages-functions/api.md +159 -0
- package/skills/cloudflare/references/pages-functions/configuration.md +130 -0
- package/skills/cloudflare/references/pages-functions/gotchas.md +102 -0
- package/skills/cloudflare/references/pages-functions/patterns.md +148 -0
- package/skills/cloudflare/references/pipelines/README.md +109 -0
- package/skills/cloudflare/references/pipelines/api.md +214 -0
- package/skills/cloudflare/references/pipelines/configuration.md +98 -0
- package/skills/cloudflare/references/pipelines/gotchas.md +84 -0
- package/skills/cloudflare/references/pipelines/patterns.md +87 -0
- package/skills/cloudflare/references/product-index.md +112 -0
- package/skills/cloudflare/references/pulumi/README.md +113 -0
- package/skills/cloudflare/references/pulumi/api.md +230 -0
- package/skills/cloudflare/references/pulumi/configuration.md +213 -0
- package/skills/cloudflare/references/pulumi/gotchas.md +205 -0
- package/skills/cloudflare/references/pulumi/patterns.md +260 -0
- package/skills/cloudflare/references/queues/README.md +99 -0
- package/skills/cloudflare/references/queues/api.md +211 -0
- package/skills/cloudflare/references/queues/configuration.md +151 -0
- package/skills/cloudflare/references/queues/gotchas.md +210 -0
- package/skills/cloudflare/references/queues/patterns.md +220 -0
- package/skills/cloudflare/references/r2/README.md +97 -0
- package/skills/cloudflare/references/r2/api.md +235 -0
- package/skills/cloudflare/references/r2/configuration.md +176 -0
- package/skills/cloudflare/references/r2/gotchas.md +190 -0
- package/skills/cloudflare/references/r2/patterns.md +203 -0
- package/skills/cloudflare/references/r2-data-catalog/README.md +157 -0
- package/skills/cloudflare/references/r2-data-catalog/api.md +199 -0
- package/skills/cloudflare/references/r2-data-catalog/configuration.md +205 -0
- package/skills/cloudflare/references/r2-data-catalog/gotchas.md +170 -0
- package/skills/cloudflare/references/r2-data-catalog/patterns.md +191 -0
- package/skills/cloudflare/references/r2-sql/README.md +138 -0
- package/skills/cloudflare/references/r2-sql/SKILL.md.backup +512 -0
- package/skills/cloudflare/references/r2-sql/api.md +159 -0
- package/skills/cloudflare/references/r2-sql/configuration.md +152 -0
- package/skills/cloudflare/references/r2-sql/gotchas.md +228 -0
- package/skills/cloudflare/references/r2-sql/patterns.md +230 -0
- package/skills/cloudflare/references/realtime-sfu/README.md +66 -0
- package/skills/cloudflare/references/realtime-sfu/api.md +164 -0
- package/skills/cloudflare/references/realtime-sfu/configuration.md +141 -0
- package/skills/cloudflare/references/realtime-sfu/gotchas.md +138 -0
- package/skills/cloudflare/references/realtime-sfu/patterns.md +187 -0
- package/skills/cloudflare/references/realtimekit/README.md +118 -0
- package/skills/cloudflare/references/realtimekit/api.md +234 -0
- package/skills/cloudflare/references/realtimekit/configuration.md +226 -0
- package/skills/cloudflare/references/realtimekit/gotchas.md +206 -0
- package/skills/cloudflare/references/realtimekit/patterns.md +240 -0
- package/skills/cloudflare/references/sandbox/README.md +104 -0
- package/skills/cloudflare/references/sandbox/api.md +200 -0
- package/skills/cloudflare/references/sandbox/configuration.md +154 -0
- package/skills/cloudflare/references/sandbox/gotchas.md +201 -0
- package/skills/cloudflare/references/sandbox/patterns.md +195 -0
- package/skills/cloudflare/references/secrets-store/README.md +77 -0
- package/skills/cloudflare/references/secrets-store/api.md +199 -0
- package/skills/cloudflare/references/secrets-store/configuration.md +187 -0
- package/skills/cloudflare/references/secrets-store/gotchas.md +97 -0
- package/skills/cloudflare/references/secrets-store/patterns.md +218 -0
- package/skills/cloudflare/references/smart-placement/README.md +143 -0
- package/skills/cloudflare/references/smart-placement/api.md +192 -0
- package/skills/cloudflare/references/smart-placement/configuration.md +202 -0
- package/skills/cloudflare/references/smart-placement/gotchas.md +180 -0
- package/skills/cloudflare/references/smart-placement/patterns.md +190 -0
- package/skills/cloudflare/references/snippets/README.md +74 -0
- package/skills/cloudflare/references/snippets/api.md +214 -0
- package/skills/cloudflare/references/snippets/configuration.md +239 -0
- package/skills/cloudflare/references/snippets/gotchas.md +104 -0
- package/skills/cloudflare/references/snippets/patterns.md +135 -0
- package/skills/cloudflare/references/spectrum/README.md +52 -0
- package/skills/cloudflare/references/spectrum/api.md +184 -0
- package/skills/cloudflare/references/spectrum/configuration.md +203 -0
- package/skills/cloudflare/references/spectrum/gotchas.md +155 -0
- package/skills/cloudflare/references/spectrum/patterns.md +206 -0
- package/skills/cloudflare/references/static-assets/README.md +65 -0
- package/skills/cloudflare/references/static-assets/api.md +201 -0
- package/skills/cloudflare/references/static-assets/configuration.md +186 -0
- package/skills/cloudflare/references/static-assets/gotchas.md +164 -0
- package/skills/cloudflare/references/static-assets/patterns.md +189 -0
- package/skills/cloudflare/references/stream/README.md +123 -0
- package/skills/cloudflare/references/stream/api-live.md +202 -0
- package/skills/cloudflare/references/stream/api.md +206 -0
- package/skills/cloudflare/references/stream/configuration.md +151 -0
- package/skills/cloudflare/references/stream/gotchas.md +139 -0
- package/skills/cloudflare/references/stream/patterns.md +217 -0
- package/skills/cloudflare/references/tail-workers/README.md +92 -0
- package/skills/cloudflare/references/tail-workers/api.md +203 -0
- package/skills/cloudflare/references/tail-workers/configuration.md +178 -0
- package/skills/cloudflare/references/tail-workers/gotchas.md +206 -0
- package/skills/cloudflare/references/tail-workers/patterns.md +190 -0
- package/skills/cloudflare/references/terraform/README.md +100 -0
- package/skills/cloudflare/references/terraform/api.md +178 -0
- package/skills/cloudflare/references/terraform/configuration.md +197 -0
- package/skills/cloudflare/references/terraform/gotchas.md +150 -0
- package/skills/cloudflare/references/terraform/patterns.md +174 -0
- package/skills/cloudflare/references/tunnel/README.md +137 -0
- package/skills/cloudflare/references/tunnel/api.md +205 -0
- package/skills/cloudflare/references/tunnel/configuration.md +163 -0
- package/skills/cloudflare/references/tunnel/gotchas.md +159 -0
- package/skills/cloudflare/references/tunnel/networking.md +174 -0
- package/skills/cloudflare/references/tunnel/patterns.md +199 -0
- package/skills/cloudflare/references/turn/README.md +86 -0
- package/skills/cloudflare/references/turn/api.md +236 -0
- package/skills/cloudflare/references/turn/configuration.md +181 -0
- package/skills/cloudflare/references/turn/gotchas.md +236 -0
- package/skills/cloudflare/references/turn/patterns.md +228 -0
- package/skills/cloudflare/references/turnstile/README.md +102 -0
- package/skills/cloudflare/references/turnstile/api.md +253 -0
- package/skills/cloudflare/references/turnstile/configuration.md +242 -0
- package/skills/cloudflare/references/turnstile/gotchas.md +253 -0
- package/skills/cloudflare/references/turnstile/patterns.md +195 -0
- package/skills/cloudflare/references/vectorize/README.md +133 -0
- package/skills/cloudflare/references/vectorize/api.md +89 -0
- package/skills/cloudflare/references/vectorize/configuration.md +91 -0
- package/skills/cloudflare/references/vectorize/gotchas.md +83 -0
- package/skills/cloudflare/references/vectorize/patterns.md +92 -0
- package/skills/cloudflare/references/waf/README.md +125 -0
- package/skills/cloudflare/references/waf/api.md +203 -0
- package/skills/cloudflare/references/waf/configuration.md +215 -0
- package/skills/cloudflare/references/waf/gotchas.md +208 -0
- package/skills/cloudflare/references/waf/patterns.md +236 -0
- package/skills/cloudflare/references/web-analytics/README.md +149 -0
- package/skills/cloudflare/references/web-analytics/configuration.md +81 -0
- package/skills/cloudflare/references/web-analytics/gotchas.md +86 -0
- package/skills/cloudflare/references/web-analytics/integration.md +63 -0
- package/skills/cloudflare/references/web-analytics/patterns.md +98 -0
- package/skills/cloudflare/references/workerd/README.md +85 -0
- package/skills/cloudflare/references/workerd/api.md +219 -0
- package/skills/cloudflare/references/workerd/configuration.md +200 -0
- package/skills/cloudflare/references/workerd/gotchas.md +151 -0
- package/skills/cloudflare/references/workerd/patterns.md +205 -0
- package/skills/cloudflare/references/workers/README.md +110 -0
- package/skills/cloudflare/references/workers/api.md +197 -0
- package/skills/cloudflare/references/workers/configuration.md +184 -0
- package/skills/cloudflare/references/workers/frameworks.md +200 -0
- package/skills/cloudflare/references/workers/gotchas.md +145 -0
- package/skills/cloudflare/references/workers/patterns.md +220 -0
- package/skills/cloudflare/references/workers-ai/README.md +206 -0
- package/skills/cloudflare/references/workers-ai/api.md +115 -0
- package/skills/cloudflare/references/workers-ai/configuration.md +98 -0
- package/skills/cloudflare/references/workers-ai/gotchas.md +130 -0
- package/skills/cloudflare/references/workers-ai/patterns.md +122 -0
- package/skills/cloudflare/references/workers-for-platforms/README.md +95 -0
- package/skills/cloudflare/references/workers-for-platforms/api.md +212 -0
- package/skills/cloudflare/references/workers-for-platforms/configuration.md +178 -0
- package/skills/cloudflare/references/workers-for-platforms/gotchas.md +134 -0
- package/skills/cloudflare/references/workers-for-platforms/patterns.md +210 -0
- package/skills/cloudflare/references/workers-playground/README.md +131 -0
- package/skills/cloudflare/references/workers-playground/api.md +101 -0
- package/skills/cloudflare/references/workers-playground/configuration.md +169 -0
- package/skills/cloudflare/references/workers-playground/gotchas.md +88 -0
- package/skills/cloudflare/references/workers-playground/patterns.md +134 -0
- package/skills/cloudflare/references/workers-vpc/README.md +130 -0
- package/skills/cloudflare/references/workers-vpc/api.md +196 -0
- package/skills/cloudflare/references/workers-vpc/configuration.md +151 -0
- package/skills/cloudflare/references/workers-vpc/gotchas.md +171 -0
- package/skills/cloudflare/references/workers-vpc/patterns.md +235 -0
- package/skills/cloudflare/references/workflows/README.md +72 -0
- package/skills/cloudflare/references/workflows/api.md +237 -0
- package/skills/cloudflare/references/workflows/configuration.md +158 -0
- package/skills/cloudflare/references/workflows/gotchas.md +97 -0
- package/skills/cloudflare/references/workflows/patterns.md +245 -0
- package/skills/cloudflare/references/wrangler/README.md +143 -0
- package/skills/cloudflare/references/wrangler/api.md +188 -0
- package/skills/cloudflare/references/wrangler/configuration.md +198 -0
- package/skills/cloudflare/references/wrangler/gotchas.md +212 -0
- package/skills/cloudflare/references/wrangler/patterns.md +211 -0
- package/skills/cloudflare/references/zaraz/IMPLEMENTATION_SUMMARY.md +131 -0
- package/skills/cloudflare/references/zaraz/README.md +114 -0
- package/skills/cloudflare/references/zaraz/api.md +118 -0
- package/skills/cloudflare/references/zaraz/configuration.md +94 -0
- package/skills/cloudflare/references/zaraz/gotchas.md +88 -0
- package/skills/cloudflare/references/zaraz/patterns.md +77 -0
- package/skills/docker/SKILL.md +7 -101
- package/skills/docker/references/advanced-examples.md +71 -0
- package/skills/docker/references/templates.md +34 -0
- package/skills/docs-marketer/SKILL.md +178 -0
- package/skills/docs-marketer/references/audit-categories.md +328 -0
- package/skills/docs-marketer/references/copilot-docs-prompts.md +88 -0
- package/skills/docs-marketer/references/copilot-usage.md +16 -0
- package/skills/docs-marketer/references/feedback-loop.md +155 -0
- package/skills/docs-marketer/references/multi-pass-docs-protocol.md +410 -0
- package/skills/drizzle-orm/SKILL.md +82 -0
- package/skills/durable-objects/SKILL.md +167 -0
- package/skills/durable-objects/references/advanced_features.md +29 -0
- package/skills/durable-objects/references/rules.md +300 -0
- package/skills/durable-objects/references/testing.md +261 -0
- package/skills/durable-objects/references/workers.md +336 -0
- package/skills/gcp/SKILL.md +37 -0
- package/skills/github-actions/SKILL.md +5 -58
- package/skills/github-actions/references/templates.md +65 -0
- package/skills/github-commander/SKILL.md +13 -21
- package/skills/github-commander/workflows/copilot-audit.md +12 -12
- package/skills/github-copilot-cli/SKILL.md +21 -26
- package/skills/github-repo-setup/SKILL.md +136 -0
- package/skills/github-repo-setup/references/community-standards.md +136 -0
- package/skills/github-repo-setup/references/github-automation.md +490 -0
- package/skills/github-repo-setup/references/inline-templates.md +205 -0
- package/skills/github-repo-setup/references/project-config.md +320 -0
- package/skills/gitlab/SKILL.md +7 -2
- package/skills/gitlab/package-lock.json +389 -389
- package/skills/golang/SKILL.md +8 -1
- package/skills/graphql/SKILL.md +30 -0
- package/skills/hono/SKILL.md +82 -0
- package/skills/journal-optimizer/SKILL.md +206 -0
- package/skills/journal-optimizer/references/optimizer-scripts.md +169 -0
- package/skills/llm-app-engineering/SKILL.md +18 -0
- package/skills/monorepo/SKILL.md +56 -0
- package/skills/multi-agent-orchestration/SKILL.md +14 -0
- package/skills/mysql/SKILL.md +6 -2
- package/skills/next-best-practices/SKILL.md +86 -0
- package/skills/next-best-practices/references/cache-components-examples.md +234 -0
- package/skills/next-best-practices/references/cache-components.md +210 -0
- package/skills/next-best-practices/references/upgrade-decision-tree.md +33 -0
- package/skills/next-best-practices/references/upgrade.md +43 -0
- package/skills/next-cache-components/SKILL.md +441 -0
- package/skills/next-upgrade/SKILL.md +43 -0
- package/skills/next-upgrade/references/decision-tree.md +33 -0
- package/skills/nodejs/SKILL.md +46 -0
- package/skills/opentelemetry/SKILL.md +62 -0
- package/skills/package.json +39 -4
- package/skills/playwright-standard/SKILL.md +6 -11
- package/skills/playwright-standard/references/locators.md +7 -0
- package/skills/postgres/SKILL.md +6 -1
- package/skills/python/SKILL.md +8 -70
- package/skills/python/references/advanced-patterns.md +37 -0
- package/skills/python/references/config-templates.md +48 -0
- package/skills/rag-pipelines/SKILL.md +14 -0
- package/skills/redis/SKILL.md +31 -0
- package/skills/render/SKILL.md +35 -0
- package/skills/rust/SKILL.md +15 -25
- package/skills/rust/references/borrow-checker.md +13 -0
- package/skills/rust/references/ecosystem.md +11 -0
- package/skills/sandbox-sdk/SKILL.md +186 -0
- package/skills/sandbox-sdk/references/api-quick-ref.md +113 -0
- package/skills/sandbox-sdk/references/examples.md +52 -0
- package/skills/shadcn-ui/SKILL.md +22 -57
- package/skills/skill-builder/SKILL.md +23 -424
- package/skills/skill-builder/references/tutorial.md +457 -0
- package/skills/sqlite/SKILL.md +16 -5
- package/skills/table.md +59 -0
- package/skills/tailwind-css/SKILL.md +11 -60
- package/skills/tailwind-css/references/component-patterns.md +52 -0
- package/skills/trpc/SKILL.md +56 -0
- package/skills/typescript/SKILL.md +30 -433
- package/skills/typescript/references/tutorial.md +453 -0
- package/skills/vercel-ai-sdk/SKILL.md +48 -0
- package/skills/vitest-standard/SKILL.md +5 -11
- package/skills/vitest-standard/references/assertions.md +11 -0
- package/skills/web-perf/SKILL.md +207 -0
- package/skills/workers-best-practices/SKILL.md +120 -0
- package/skills/workers-best-practices/references/anti-patterns.md +18 -0
- package/skills/workers-best-practices/references/review.md +174 -0
- package/skills/workers-best-practices/references/rules.md +485 -0
- package/skills/wrangler/SKILL.md +43 -0
- package/skills/wrangler/references/cli-commands.md +861 -0
- package/skills/zod/SKILL.md +48 -0
- package/dist/tools-P4VGG4FH.js +0 -1
- package/skills/react-best-practices/AGENTS.md +0 -2883
- package/skills/react-best-practices/SKILL.md +0 -138
- /package/skills/{react-best-practices → next-best-practices}/README.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/metadata.json +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_sections.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/_template.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-event-handler-refs.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-init-once.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/advanced-use-latest.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-api-routes.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-defer-await.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-parallel.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/async-suspense-boundaries.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-barrel-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-conditional.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-defer-third-party.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-dynamic-imports.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/bundle-preload.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-localstorage-schema.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-passive-event-listeners.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/client-swr-dedup.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-batch-dom-css.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-function-results.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-property-access.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-cache-storage.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-combine-iterations.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-early-exit.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-hoist-regexp.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-index-maps.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-length-check-first.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-min-max-loop.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-set-map-lookups.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/js-tosorted-immutable.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-activity.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-animate-svg-wrapper.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-conditional-render.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-content-visibility.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hoist-jsx.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-no-flicker.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-hydration-suppress-warning.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-svg-precision.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rendering-usetransition-loading.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-defer-reads.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-dependencies.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state-no-effect.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-derived-state.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-functional-setstate.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-lazy-state-init.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo-with-default-value.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-move-effect-to-event.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-simple-expression-in-memo.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-transitions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/rerender-use-ref-transient-values.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-after-nonblocking.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-auth-actions.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-lru.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-cache-react.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-dedup-props.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-parallel-fetching.md +0 -0
- /package/skills/{react-best-practices → next-best-practices}/rules/server-serialization.md +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Durable Objects Gotchas
|
|
2
|
+
|
|
3
|
+
## Common Errors
|
|
4
|
+
|
|
5
|
+
### "Hibernation Cleared My In-Memory State"
|
|
6
|
+
|
|
7
|
+
**Problem:** Variables lost after hibernation
|
|
8
|
+
**Cause:** DO auto-hibernates when idle; in-memory state not persisted
|
|
9
|
+
**Solution:** Use `ctx.storage` for critical data, `ws.serializeAttachment()` for per-connection metadata
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// ❌ Wrong - lost on hibernation
|
|
13
|
+
private userCount = 0;
|
|
14
|
+
async webSocketMessage(ws: WebSocket, msg: string) {
|
|
15
|
+
this.userCount++; // Lost!
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ✅ Right - persisted
|
|
19
|
+
async webSocketMessage(ws: WebSocket, msg: string) {
|
|
20
|
+
const count = this.ctx.storage.kv.get("userCount") || 0;
|
|
21
|
+
this.ctx.storage.kv.put("userCount", count + 1);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### "setTimeout Didn't Fire After Restart"
|
|
26
|
+
|
|
27
|
+
**Problem:** Scheduled work lost on eviction
|
|
28
|
+
**Cause:** `setTimeout` in-memory only; eviction clears timers
|
|
29
|
+
**Solution:** Use `ctx.storage.setAlarm()` for reliable scheduling
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// ❌ Wrong - lost on eviction
|
|
33
|
+
setTimeout(() => this.cleanup(), 3600000);
|
|
34
|
+
|
|
35
|
+
// ✅ Right - survives eviction
|
|
36
|
+
await this.ctx.storage.setAlarm(Date.now() + 3600000);
|
|
37
|
+
async alarm() { await this.cleanup(); }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### "Constructor Runs on Every Wake"
|
|
41
|
+
|
|
42
|
+
**Problem:** Expensive init logic slows all requests
|
|
43
|
+
**Cause:** Constructor runs on every wake (first request after eviction OR after hibernation)
|
|
44
|
+
**Solution:** Lazy initialization or cache in storage
|
|
45
|
+
|
|
46
|
+
**Critical understanding:** Constructor runs in two scenarios:
|
|
47
|
+
|
|
48
|
+
1. **Cold start** - DO evicted from memory, first request creates new instance
|
|
49
|
+
2. **Wake from hibernation** - DO with WebSockets hibernated, message/alarm wakes it
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// ❌ Wrong - expensive on every wake
|
|
53
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
54
|
+
super(ctx, env);
|
|
55
|
+
this.heavyData = this.loadExpensiveData(); // Slow!
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ✅ Right - lazy load
|
|
59
|
+
private heavyData?: HeavyData;
|
|
60
|
+
private getHeavyData() {
|
|
61
|
+
if (!this.heavyData) this.heavyData = this.loadExpensiveData();
|
|
62
|
+
return this.heavyData;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### "Durable Object Overloaded (503 errors)"
|
|
67
|
+
|
|
68
|
+
**Problem:** 503 errors under load
|
|
69
|
+
**Cause:** Single DO exceeding ~1K req/s throughput limit
|
|
70
|
+
**Solution:** Shard across multiple DOs (see [Patterns: Sharding](./patterns.md))
|
|
71
|
+
|
|
72
|
+
### "Storage Quota Exceeded (Write failures)"
|
|
73
|
+
|
|
74
|
+
**Problem:** Write operations failing
|
|
75
|
+
**Cause:** DO storage exceeding 10GB limit or account quota
|
|
76
|
+
**Solution:** Cleanup with alarms, use `deleteAll()` for old data, upgrade plan
|
|
77
|
+
|
|
78
|
+
### "CPU Time Exceeded (Terminated)"
|
|
79
|
+
|
|
80
|
+
**Problem:** Request terminated mid-execution
|
|
81
|
+
**Cause:** Processing exceeding 30s CPU time default limit
|
|
82
|
+
**Solution:** Increase `limits.cpu_ms` in wrangler.jsonc (max 300s) or chunk work
|
|
83
|
+
|
|
84
|
+
### "WebSockets Disconnect on Eviction"
|
|
85
|
+
|
|
86
|
+
**Problem:** Connections drop unexpectedly
|
|
87
|
+
**Cause:** DO evicted from memory without hibernation API
|
|
88
|
+
**Solution:** Use WebSocket hibernation handlers + client reconnection logic
|
|
89
|
+
|
|
90
|
+
### "Migration Failed (Deploy error)"
|
|
91
|
+
|
|
92
|
+
**Cause:** Non-unique tags, non-sequential tags, or invalid class names in migration
|
|
93
|
+
**Solution:** Check tag uniqueness/sequential ordering and verify class names are correct
|
|
94
|
+
|
|
95
|
+
### "RPC Method Not Found"
|
|
96
|
+
|
|
97
|
+
**Cause:** compatibility_date < 2024-04-03 preventing RPC usage
|
|
98
|
+
**Solution:** Update compatibility_date to >= 2024-04-03 or use fetch() instead of RPC
|
|
99
|
+
|
|
100
|
+
### "Only One Alarm Allowed"
|
|
101
|
+
|
|
102
|
+
**Cause:** Need multiple scheduled tasks but only one alarm supported per DO
|
|
103
|
+
**Solution:** Use event queue pattern to schedule multiple tasks with single alarm
|
|
104
|
+
|
|
105
|
+
### "Race Condition Despite Single-Threading"
|
|
106
|
+
|
|
107
|
+
**Problem:** Concurrent requests see inconsistent state
|
|
108
|
+
**Cause:** Async operations allow request interleaving (await = yield point)
|
|
109
|
+
**Solution:** Use `blockConcurrencyWhile()` for critical sections or atomic storage ops
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// ❌ Wrong - race condition
|
|
113
|
+
async incrementCounter() {
|
|
114
|
+
const count = await this.ctx.storage.get("count") || 0;
|
|
115
|
+
// ⚠️ Another request could execute here during await
|
|
116
|
+
await this.ctx.storage.put("count", count + 1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ✅ Right - atomic operation
|
|
120
|
+
async incrementCounter() {
|
|
121
|
+
return this.ctx.storage.sql.exec(
|
|
122
|
+
"INSERT INTO counters (id, value) VALUES (1, 1) ON CONFLICT(id) DO UPDATE SET value = value + 1 RETURNING value"
|
|
123
|
+
).one().value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ✅ Right - explicit locking
|
|
127
|
+
async criticalOperation() {
|
|
128
|
+
await this.ctx.blockConcurrencyWhile(async () => {
|
|
129
|
+
const count = await this.ctx.storage.get("count") || 0;
|
|
130
|
+
await this.ctx.storage.put("count", count + 1);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### "Migration Rollback Not Supported"
|
|
136
|
+
|
|
137
|
+
**Cause:** Attempting to rollback a migration after deployment
|
|
138
|
+
**Solution:** Test with `--dry-run` before deploying; migrations cannot be rolled back
|
|
139
|
+
|
|
140
|
+
### "deleted_classes Destroys Data"
|
|
141
|
+
|
|
142
|
+
**Problem:** Migration deleted all data
|
|
143
|
+
**Cause:** `deleted_classes` migration immediately destroys all DO instances and data
|
|
144
|
+
**Solution:** Test with `--dry-run`; use `transferred_classes` to preserve data during moves
|
|
145
|
+
|
|
146
|
+
### "Cold Starts Are Slow"
|
|
147
|
+
|
|
148
|
+
**Problem:** First request after eviction takes longer
|
|
149
|
+
**Cause:** DO constructor + initial storage access on cold start
|
|
150
|
+
**Solution:** Expected behavior; optimize constructor, use connection pooling in clients, consider warming strategy for critical DOs
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Warming strategy (periodically ping critical DOs)
|
|
154
|
+
export default {
|
|
155
|
+
async scheduled(event: ScheduledEvent, env: Env) {
|
|
156
|
+
const criticalIds = ['auth', 'sessions', 'locks']
|
|
157
|
+
await Promise.all(
|
|
158
|
+
criticalIds.map((name) => {
|
|
159
|
+
const id = env.MY_DO.idFromName(name)
|
|
160
|
+
const stub = env.MY_DO.get(id)
|
|
161
|
+
return stub.ping() // Keep warm
|
|
162
|
+
})
|
|
163
|
+
)
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Limits
|
|
169
|
+
|
|
170
|
+
| Limit | Free | Paid | Notes |
|
|
171
|
+
| ---------------------- | --------- | --------- | ------------------------------------- |
|
|
172
|
+
| SQLite storage per DO | 10 GB | 10 GB | Per Durable Object instance |
|
|
173
|
+
| SQLite total storage | 5 GB | Unlimited | Account-wide quota |
|
|
174
|
+
| Key+value size | 2 MB | 2 MB | Single KV pair (SQLite/async) |
|
|
175
|
+
| CPU time default | 30s | 30s | Per request; configurable |
|
|
176
|
+
| CPU time max | 300s | 300s | Set via `limits.cpu_ms` |
|
|
177
|
+
| DO classes | 100 | 500 | Distinct DO class definitions |
|
|
178
|
+
| SQL columns | 100 | 100 | Per table |
|
|
179
|
+
| SQL statement size | 100 KB | 100 KB | Max SQL query size |
|
|
180
|
+
| WebSocket message size | 32 MiB | 32 MiB | Per message |
|
|
181
|
+
| Request throughput | ~1K req/s | ~1K req/s | Per DO (soft limit - shard for more) |
|
|
182
|
+
| Alarms per DO | 1 | 1 | Use queue pattern for multiple events |
|
|
183
|
+
| Total DOs | Unlimited | Unlimited | Create as many instances as needed |
|
|
184
|
+
| WebSockets | Unlimited | Unlimited | Within 128MB memory limit per DO |
|
|
185
|
+
| Memory per DO | 128 MB | 128 MB | In-memory state + WebSocket buffers |
|
|
186
|
+
|
|
187
|
+
## Hibernation Caveats
|
|
188
|
+
|
|
189
|
+
1. **Memory cleared** - All in-memory variables lost; reconstruct from storage or `deserializeAttachment()`
|
|
190
|
+
2. **Constructor reruns** - Runs on wake; avoid expensive operations, use lazy initialization
|
|
191
|
+
3. **No guarantees** - DO may evict instead of hibernate; design for both
|
|
192
|
+
4. **Attachment limit** - `serializeAttachment()` data must be JSON-serializable, keep small
|
|
193
|
+
5. **Alarm wakes DO** - Alarm prevents hibernation until handler completes
|
|
194
|
+
6. **WebSocket state not automatic** - Must explicitly persist with `serializeAttachment()` or storage
|
|
195
|
+
|
|
196
|
+
## See Also
|
|
197
|
+
|
|
198
|
+
- **[Patterns](./patterns.md)** - Workarounds for common limitations
|
|
199
|
+
- **[API](./api.md)** - Storage limits and quotas
|
|
200
|
+
- **[Configuration](./configuration.md)** - Setting CPU limits
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Durable Objects Patterns
|
|
2
|
+
|
|
3
|
+
## When to Use Which Pattern
|
|
4
|
+
|
|
5
|
+
| Need | Pattern | ID Strategy |
|
|
6
|
+
| ---------------------- | ------------------ | ------------------------ |
|
|
7
|
+
| Rate limit per user/IP | Rate Limiting | `idFromName(identifier)` |
|
|
8
|
+
| Mutual exclusion | Distributed Lock | `idFromName(resource)` |
|
|
9
|
+
| >1K req/s throughput | Sharding | `newUniqueId()` or hash |
|
|
10
|
+
| Real-time updates | WebSocket Collab | `idFromName(room)` |
|
|
11
|
+
| User sessions | Session Management | `idFromName(sessionId)` |
|
|
12
|
+
| Background cleanup | Alarm-based | Any |
|
|
13
|
+
|
|
14
|
+
## RPC vs fetch()
|
|
15
|
+
|
|
16
|
+
**RPC** (compat ≥2024-04-03): Type-safe, simpler, default for new projects
|
|
17
|
+
**fetch()**: Legacy compat, HTTP semantics, proxying
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
const count = await stub.increment() // RPC
|
|
21
|
+
const count = await (await stub.fetch(req)).json() // fetch()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Sharding (High Throughput)
|
|
25
|
+
|
|
26
|
+
Single DO ~1K req/s max. Shard for higher throughput:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
export default {
|
|
30
|
+
async fetch(req: Request, env: Env): Promise<Response> {
|
|
31
|
+
const userId = new URL(req.url).searchParams.get('user')
|
|
32
|
+
const hash = hashCode(userId) % 100 // 100 shards
|
|
33
|
+
const id = env.COUNTER.idFromName(`shard:${hash}`)
|
|
34
|
+
return env.COUNTER.get(id).fetch(req)
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function hashCode(str: string): number {
|
|
39
|
+
let hash = 0
|
|
40
|
+
for (let i = 0; i < str.length; i++) hash = (hash << 5) - hash + str.charCodeAt(i)
|
|
41
|
+
return Math.abs(hash)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Decisions:**
|
|
46
|
+
|
|
47
|
+
- **Shard count**: 10-1000 typical (start with 100, measure, adjust)
|
|
48
|
+
- **Shard key**: User ID, IP, session - must distribute evenly (use hash)
|
|
49
|
+
- **Aggregation**: Coordinator DO or external system (D1, R2)
|
|
50
|
+
|
|
51
|
+
## Rate Limiting
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
async checkLimit(key: string, limit: number, windowMs: number): Promise<boolean> {
|
|
55
|
+
const req = this.ctx.storage.sql.exec("SELECT COUNT(*) as count FROM requests WHERE key = ? AND timestamp > ?", key, Date.now() - windowMs).one();
|
|
56
|
+
if (req.count >= limit) return false;
|
|
57
|
+
this.ctx.storage.sql.exec("INSERT INTO requests (key, timestamp) VALUES (?, ?)", key, Date.now());
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Distributed Lock
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
private held = false;
|
|
66
|
+
async acquire(timeoutMs = 5000): Promise<boolean> {
|
|
67
|
+
if (this.held) return false;
|
|
68
|
+
this.held = true;
|
|
69
|
+
await this.ctx.storage.setAlarm(Date.now() + timeoutMs);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
async release() { this.held = false; await this.ctx.storage.deleteAlarm(); }
|
|
73
|
+
async alarm() { this.held = false; } // Auto-release on timeout
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Hibernation-Aware Pattern
|
|
77
|
+
|
|
78
|
+
Preserve state across hibernation:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
async fetch(req: Request): Promise<Response> {
|
|
82
|
+
const [client, server] = Object.values(new WebSocketPair());
|
|
83
|
+
const userId = new URL(req.url).searchParams.get("user");
|
|
84
|
+
server.serializeAttachment({ userId }); // Survives hibernation
|
|
85
|
+
this.ctx.acceptWebSocket(server, ["room:lobby"]);
|
|
86
|
+
server.send(JSON.stringify({ type: "init", state: this.ctx.storage.kv.get("state") }));
|
|
87
|
+
return new Response(null, { status: 101, webSocket: client });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async webSocketMessage(ws: WebSocket, msg: string) {
|
|
91
|
+
const { userId } = ws.deserializeAttachment(); // Retrieve after wake
|
|
92
|
+
const state = this.ctx.storage.kv.get("state") || {};
|
|
93
|
+
state[userId] = JSON.parse(msg);
|
|
94
|
+
this.ctx.storage.kv.put("state", state);
|
|
95
|
+
for (const c of this.ctx.getWebSockets("room:lobby")) c.send(msg);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Real-time Collaboration
|
|
100
|
+
|
|
101
|
+
Broadcast updates to all connected clients:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
async webSocketMessage(ws: WebSocket, msg: string) {
|
|
105
|
+
const data = JSON.parse(msg);
|
|
106
|
+
this.ctx.storage.kv.put("doc", data.content); // Persist
|
|
107
|
+
for (const c of this.ctx.getWebSockets()) if (c !== ws) c.send(msg); // Broadcast
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### WebSocket Reconnection
|
|
112
|
+
|
|
113
|
+
**Client-side** (exponential backoff):
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
class ResilientWS {
|
|
117
|
+
private delay = 1000
|
|
118
|
+
connect(url: string) {
|
|
119
|
+
const ws = new WebSocket(url)
|
|
120
|
+
ws.onclose = () =>
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
this.connect(url)
|
|
123
|
+
this.delay = Math.min(this.delay * 2, 30000)
|
|
124
|
+
}, this.delay)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Server-side** (cleanup on close):
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
async webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean) {
|
|
133
|
+
const { userId } = ws.deserializeAttachment();
|
|
134
|
+
this.ctx.storage.sql.exec("UPDATE users SET online = false WHERE id = ?", userId);
|
|
135
|
+
for (const c of this.ctx.getWebSockets()) c.send(JSON.stringify({ type: "user_left", userId }));
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Session Management
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
async createSession(userId: string, data: object): Promise<string> {
|
|
143
|
+
const id = crypto.randomUUID(), exp = Date.now() + 86400000;
|
|
144
|
+
this.ctx.storage.sql.exec("INSERT INTO sessions VALUES (?, ?, ?, ?)", id, userId, JSON.stringify(data), exp);
|
|
145
|
+
await this.ctx.storage.setAlarm(exp);
|
|
146
|
+
return id;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async getSession(id: string): Promise<object | null> {
|
|
150
|
+
const row = this.ctx.storage.sql.exec("SELECT data FROM sessions WHERE id = ? AND expires_at > ?", id, Date.now()).one();
|
|
151
|
+
return row ? JSON.parse(row.data) : null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async alarm() { this.ctx.storage.sql.exec("DELETE FROM sessions WHERE expires_at <= ?", Date.now()); }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Multiple Events (Single Alarm)
|
|
158
|
+
|
|
159
|
+
Queue pattern to schedule multiple events:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
async scheduleEvent(id: string, runAt: number) {
|
|
163
|
+
await this.ctx.storage.put(`event:${id}`, { id, runAt });
|
|
164
|
+
const curr = await this.ctx.storage.getAlarm();
|
|
165
|
+
if (!curr || runAt < curr) await this.ctx.storage.setAlarm(runAt);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async alarm() {
|
|
169
|
+
const events = await this.ctx.storage.list({ prefix: "event:" }), now = Date.now();
|
|
170
|
+
let next = null;
|
|
171
|
+
for (const [key, ev] of events) {
|
|
172
|
+
if (ev.runAt <= now) {
|
|
173
|
+
await this.processEvent(ev);
|
|
174
|
+
await this.ctx.storage.delete(key);
|
|
175
|
+
} else if (!next || ev.runAt < next) next = ev.runAt;
|
|
176
|
+
}
|
|
177
|
+
if (next) await this.ctx.storage.setAlarm(next);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Graceful Cleanup
|
|
182
|
+
|
|
183
|
+
Use `ctx.waitUntil()` to complete work after response:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
async myMethod() {
|
|
187
|
+
const response = { success: true };
|
|
188
|
+
this.ctx.waitUntil(this.ctx.storage.sql.exec("DELETE FROM old_data WHERE timestamp < ?", cutoff));
|
|
189
|
+
return response;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Best Practices
|
|
194
|
+
|
|
195
|
+
- **Design**: Use `idFromName()` for coordination, `newUniqueId()` for sharding, minimize constructor work
|
|
196
|
+
- **Storage**: Prefer SQLite, batch with transactions, set alarms for cleanup, use PITR before risky ops
|
|
197
|
+
- **Performance**: ~1K req/s per DO max - shard for more, cache in memory, use alarms for deferred work
|
|
198
|
+
- **Reliability**: Handle 503 with retry+backoff, design for cold starts, test migrations with `--dry-run`
|
|
199
|
+
- **Security**: Validate inputs in Workers, rate limit DO creation, use jurisdiction for compliance
|
|
200
|
+
|
|
201
|
+
## See Also
|
|
202
|
+
|
|
203
|
+
- **[API](./api.md)** - ctx methods, WebSocket handlers
|
|
204
|
+
- **[Gotchas](./gotchas.md)** - Hibernation caveats, common errors
|
|
205
|
+
- **[DO Storage](../do-storage/README.md)** - Storage patterns and transactions
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Cloudflare Email Routing Skill Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Cloudflare Email Routing enables custom email addresses for your domain that route to verified destination addresses. It's free, privacy-focused (no storage/access), and includes Email Workers for programmatic email processing.
|
|
6
|
+
|
|
7
|
+
**Available to all Cloudflare customers using Cloudflare as authoritative nameserver.**
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Basic email handler
|
|
13
|
+
export default {
|
|
14
|
+
async email(message, env, ctx) {
|
|
15
|
+
// CRITICAL: Must consume stream before response
|
|
16
|
+
const parser = new PostalMime.default()
|
|
17
|
+
const email = await parser.parse(await message.raw.arrayBuffer())
|
|
18
|
+
|
|
19
|
+
// Process email
|
|
20
|
+
console.log(`From: ${message.from}, Subject: ${email.subject}`)
|
|
21
|
+
|
|
22
|
+
// Forward or reject
|
|
23
|
+
await message.forward('verified@destination.com')
|
|
24
|
+
},
|
|
25
|
+
} satisfies ExportedHandler<Env>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Reading Order
|
|
29
|
+
|
|
30
|
+
**Start here based on your goal:**
|
|
31
|
+
|
|
32
|
+
1. **New to Email Routing?** → [configuration.md](configuration.md) → [patterns.md](patterns.md)
|
|
33
|
+
2. **Adding Workers?** → [api.md](api.md) § Worker Runtime API → [patterns.md](patterns.md)
|
|
34
|
+
3. **Sending emails?** → [api.md](api.md) § SendEmail Binding
|
|
35
|
+
4. **Managing via API?** → [api.md](api.md) § REST API Operations
|
|
36
|
+
5. **Debugging issues?** → [gotchas.md](gotchas.md)
|
|
37
|
+
|
|
38
|
+
## Decision Tree
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Need to receive emails?
|
|
42
|
+
├─ Simple forwarding only? → Dashboard rules (configuration.md)
|
|
43
|
+
├─ Complex logic/filtering? → Email Workers (api.md + patterns.md)
|
|
44
|
+
└─ Parse attachments/body? → postal-mime library (patterns.md § Parse Email)
|
|
45
|
+
|
|
46
|
+
Need to send emails?
|
|
47
|
+
├─ From Worker? → SendEmail binding (api.md § SendEmail)
|
|
48
|
+
└─ From external app? → Use external SMTP/API service
|
|
49
|
+
|
|
50
|
+
Having issues?
|
|
51
|
+
├─ Email not arriving? → gotchas.md § Mail Authentication
|
|
52
|
+
├─ Worker crashing? → gotchas.md § Stream Consumption
|
|
53
|
+
└─ Forward failing? → gotchas.md § Destination Verification
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Key Concepts
|
|
57
|
+
|
|
58
|
+
**Routing Rules**: Pattern-based forwarding configured via Dashboard/API. Simple but limited.
|
|
59
|
+
|
|
60
|
+
**Email Workers**: Custom TypeScript handlers with full email access. Handles complex logic, parsing, storage, rejection.
|
|
61
|
+
|
|
62
|
+
**SendEmail Binding**: Outbound email API for Workers. Transactional email only (no marketing/bulk).
|
|
63
|
+
|
|
64
|
+
**ForwardableEmailMessage**: Runtime interface for incoming emails. Provides headers, raw stream, forward/reject methods.
|
|
65
|
+
|
|
66
|
+
## In This Reference
|
|
67
|
+
|
|
68
|
+
- **[configuration.md](configuration.md)** - Setup, deployment, wrangler config
|
|
69
|
+
- **[api.md](api.md)** - REST API + Worker runtime API + types
|
|
70
|
+
- **[patterns.md](patterns.md)** - Common patterns with working examples
|
|
71
|
+
- **[gotchas.md](gotchas.md)** - Critical pitfalls, troubleshooting, limits
|
|
72
|
+
|
|
73
|
+
## Architecture
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Internet → MX Records → Cloudflare Email Routing
|
|
77
|
+
├─ Routing Rules (dashboard)
|
|
78
|
+
└─ Email Worker (your code)
|
|
79
|
+
├─ Forward to destination
|
|
80
|
+
├─ Reject with reason
|
|
81
|
+
├─ Store in R2/KV/D1
|
|
82
|
+
└─ Send outbound (SendEmail)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## See Also
|
|
86
|
+
|
|
87
|
+
- [Cloudflare Docs: Email Routing](https://developers.cloudflare.com/email-routing/)
|
|
88
|
+
- [Cloudflare Docs: Email Workers](https://developers.cloudflare.com/email-routing/email-workers/)
|
|
89
|
+
- [postal-mime npm package](https://www.npmjs.com/package/postal-mime)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Email Routing API Reference
|
|
2
|
+
|
|
3
|
+
## Worker Runtime API
|
|
4
|
+
|
|
5
|
+
### Email Handler Interface
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface ExportedHandler<Env = unknown> {
|
|
9
|
+
email?(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): void | Promise<void>
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### ForwardableEmailMessage
|
|
14
|
+
|
|
15
|
+
Main interface for incoming emails:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
interface ForwardableEmailMessage {
|
|
19
|
+
readonly from: string // Envelope sender (e.g., "sender@example.com")
|
|
20
|
+
readonly to: string // Envelope recipient (e.g., "you@yourdomain.com")
|
|
21
|
+
readonly headers: Headers // Web API Headers object
|
|
22
|
+
readonly raw: ReadableStream // Raw MIME message stream
|
|
23
|
+
|
|
24
|
+
setReject(reason: string): void
|
|
25
|
+
forward(rcptTo: string, headers?: Headers): Promise<void>
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Key Properties:**
|
|
30
|
+
|
|
31
|
+
| Property | Type | Description |
|
|
32
|
+
| --------- | ---------------- | -------------------------------------------- |
|
|
33
|
+
| `from` | `string` | Envelope sender (MAIL FROM), not header From |
|
|
34
|
+
| `to` | `string` | Envelope recipient (RCPT TO), not header To |
|
|
35
|
+
| `headers` | `Headers` | Email headers (Subject, From, To, etc.) |
|
|
36
|
+
| `raw` | `ReadableStream` | Raw MIME message (consume once only) |
|
|
37
|
+
|
|
38
|
+
**Methods:**
|
|
39
|
+
|
|
40
|
+
- `setReject(reason)`: Reject email with bounce message
|
|
41
|
+
- `forward(rcptTo, headers?)`: Forward to verified destination, optionally add headers
|
|
42
|
+
|
|
43
|
+
### Headers Object
|
|
44
|
+
|
|
45
|
+
Standard Web API Headers interface:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Access headers
|
|
49
|
+
const subject = message.headers.get('subject')
|
|
50
|
+
const from = message.headers.get('from')
|
|
51
|
+
const messageId = message.headers.get('message-id')
|
|
52
|
+
|
|
53
|
+
// Check spam score
|
|
54
|
+
const spamScore = parseFloat(message.headers.get('x-cf-spamh-score') || '0')
|
|
55
|
+
if (spamScore > 5) {
|
|
56
|
+
message.setReject('Spam detected')
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Common Headers
|
|
61
|
+
|
|
62
|
+
`subject`, `from`, `to`, `x-cf-spamh-score` (spam score), `message-id` (deduplication), `dkim-signature` (auth)
|
|
63
|
+
|
|
64
|
+
### Envelope vs Header Addresses
|
|
65
|
+
|
|
66
|
+
**Critical distinction:**
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Envelope addresses (routing, auth checks)
|
|
70
|
+
message.from // "bounce@sender.com" (actual sender)
|
|
71
|
+
message.to // "you@yourdomain.com" (your address)
|
|
72
|
+
|
|
73
|
+
// Header addresses (display, user-facing)
|
|
74
|
+
message.headers.get('from') // "Alice <alice@sender.com>"
|
|
75
|
+
message.headers.get('to') // "Bob <you@yourdomain.com>"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Use envelope addresses for:**
|
|
79
|
+
|
|
80
|
+
- Authentication/SPF checks
|
|
81
|
+
- Routing decisions
|
|
82
|
+
- Bounce handling
|
|
83
|
+
|
|
84
|
+
**Use header addresses for:**
|
|
85
|
+
|
|
86
|
+
- Display to users
|
|
87
|
+
- Reply-To logic
|
|
88
|
+
- User-facing filtering
|
|
89
|
+
|
|
90
|
+
## SendEmail Binding
|
|
91
|
+
|
|
92
|
+
Outbound email API for transactional messages.
|
|
93
|
+
|
|
94
|
+
### Configuration
|
|
95
|
+
|
|
96
|
+
```jsonc
|
|
97
|
+
// wrangler.jsonc
|
|
98
|
+
{
|
|
99
|
+
"send_email": [{ "name": "EMAIL" }],
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### TypeScript Types
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
interface Env {
|
|
107
|
+
EMAIL: SendEmail
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface SendEmail {
|
|
111
|
+
send(message: EmailMessage): Promise<void>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface EmailMessage {
|
|
115
|
+
from: string | { name?: string; email: string }
|
|
116
|
+
to: string | { name?: string; email: string } | Array<string | { name?: string; email: string }>
|
|
117
|
+
subject: string
|
|
118
|
+
text?: string
|
|
119
|
+
html?: string
|
|
120
|
+
headers?: Headers
|
|
121
|
+
reply_to?: string | { name?: string; email: string }
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Send Email Example
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
interface Env {
|
|
129
|
+
EMAIL: SendEmail
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default {
|
|
133
|
+
async fetch(request, env, ctx): Promise<Response> {
|
|
134
|
+
await env.EMAIL.send({
|
|
135
|
+
from: { name: 'Acme Corp', email: 'noreply@yourdomain.com' },
|
|
136
|
+
to: [{ name: 'Alice', email: 'alice@example.com' }, 'bob@example.com'],
|
|
137
|
+
subject: 'Your order #12345 has shipped',
|
|
138
|
+
text: 'Track your package at: https://track.example.com/12345',
|
|
139
|
+
html: "<p>Track your package at: <a href='https://track.example.com/12345'>View tracking</a></p>",
|
|
140
|
+
reply_to: { name: 'Support', email: 'support@yourdomain.com' },
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
return new Response('Email sent')
|
|
144
|
+
},
|
|
145
|
+
} satisfies ExportedHandler<Env>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### SendEmail Constraints
|
|
149
|
+
|
|
150
|
+
- **From address**: Must be on verified domain (your domain with Email Routing enabled)
|
|
151
|
+
- **Volume limits**: Transactional only, no bulk/marketing email
|
|
152
|
+
- **Rate limits**: 100 emails/minute on Free plan, higher on Paid
|
|
153
|
+
- **No attachments**: Use links to hosted files instead
|
|
154
|
+
- **No DKIM control**: Cloudflare signs automatically
|
|
155
|
+
|
|
156
|
+
## REST API Operations
|
|
157
|
+
|
|
158
|
+
Base URL: `https://api.cloudflare.com/client/v4`
|
|
159
|
+
|
|
160
|
+
### Authentication
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
curl -H "Authorization: Bearer $API_TOKEN" https://api.cloudflare.com/client/v4/...
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Key Endpoints
|
|
167
|
+
|
|
168
|
+
| Operation | Method | Endpoint |
|
|
169
|
+
| ------------------ | ------ | ------------------------------------------ |
|
|
170
|
+
| Enable routing | POST | `/zones/{zone_id}/email/routing/enable` |
|
|
171
|
+
| Disable routing | POST | `/zones/{zone_id}/email/routing/disable` |
|
|
172
|
+
| List rules | GET | `/zones/{zone_id}/email/routing/rules` |
|
|
173
|
+
| Create rule | POST | `/zones/{zone_id}/email/routing/rules` |
|
|
174
|
+
| Verify destination | POST | `/zones/{zone_id}/email/routing/addresses` |
|
|
175
|
+
| List destinations | GET | `/zones/{zone_id}/email/routing/addresses` |
|
|
176
|
+
|
|
177
|
+
### Create Routing Rule Example
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/rules" \
|
|
181
|
+
-H "Authorization: Bearer $API_TOKEN" \
|
|
182
|
+
-H "Content-Type: application/json" \
|
|
183
|
+
-d '{
|
|
184
|
+
"enabled": true,
|
|
185
|
+
"name": "Forward sales",
|
|
186
|
+
"matchers": [{"type": "literal", "field": "to", "value": "sales@yourdomain.com"}],
|
|
187
|
+
"actions": [{"type": "forward", "value": ["alice@company.com"]}],
|
|
188
|
+
"priority": 0
|
|
189
|
+
}'
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Matcher types: `literal` (exact match), `all` (catch-all).
|