-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrangler.jsonc
More file actions
196 lines (184 loc) · 6.77 KB
/
wrangler.jsonc
File metadata and controls
196 lines (184 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "emdashcms-org",
"main": "src/worker.ts",
"compatibility_date": "2026-04-01",
"assets": {
"directory": "./dist/client"
},
"d1_databases": [
{
"binding": "DB",
"database_name": "emdashcms-org",
"database_id": "bcf2073c-1006-4b8f-9700-daf3325f63eb"
}
],
"r2_buckets": [
{
"binding": "ARTIFACTS",
"bucket_name": "emdashcms-org-artifacts"
}
],
"kv_namespaces": [
{
"binding": "CACHE",
"id": "8986ecd0a90d42a0a4265dc0c2293a7a"
}
],
// Three queues power this worker:
// - emdashcms-audit: fail-closed plugin audit pipeline (Phase 5).
// - emdashcms-notifications: email + in-app notification dispatch (Phase 12).
// - emdashcms-og: deferred OG image generation for social share previews
// (Phase 16). OG rendering via `workers-og` (Satori + resvg-wasm) costs
// 200-500ms CPU per image — 20-50x the 10ms Workers Free-tier request-path
// budget. The /og/plugin/[id].png and /og/theme/[id].png routes are a
// thin R2 proxy; on cache miss they enqueue a job on this queue and serve
// a placeholder PNG. The consumer runs inside the 15-minute queue worker
// wall clock and 90s CPU budget declared below, outside the 10ms ceiling.
"queues": {
"producers": [
{
"binding": "AUDIT_QUEUE",
"queue": "emdashcms-audit"
},
{
"binding": "NOTIF_QUEUE",
"queue": "emdashcms-notifications"
},
{
"binding": "OG_QUEUE",
"queue": "emdashcms-og"
}
],
"consumers": [
{
"queue": "emdashcms-audit",
"max_batch_size": 1,
"max_batch_timeout": 30,
"max_retries": 3,
"dead_letter_queue": "emdashcms-audit-dlq"
},
{
"queue": "emdashcms-notifications",
"max_batch_size": 1,
"max_batch_timeout": 30,
"max_retries": 3,
"dead_letter_queue": "emdashcms-notifications-dlq"
},
{
"queue": "emdashcms-og",
"max_batch_size": 1,
"max_batch_timeout": 30,
"max_retries": 3,
"dead_letter_queue": "emdashcms-og-dlq"
}
]
},
"ai": {
"binding": "AI",
// AI bindings always reach Cloudflare's remote inference tier — no
// local emulation exists. Setting `remote: true` silences the
// "AI bindings always access remote resources" warning Wrangler
// emits in dev/test, where the binding is otherwise assumed local.
"remote": true
},
// Edge-cached rate limiters (free tier). Counters live in Cloudflare's
// local-machine cache, never touching D1. Two namespaces:
// - GENERAL: 60 req / 60s — applies to most public API requests
// - AUTH: 20 req / 60s — stricter limit for /api/v1/auth/*
"ratelimits": [
{
"name": "GENERAL_RATE_LIMITER",
"namespace_id": "1001",
"simple": { "limit": 60, "period": 60 }
},
{
"name": "AUTH_RATE_LIMITER",
"namespace_id": "1002",
"simple": { "limit": 20, "period": 60 }
}
],
// Cron triggers:
// - "0 * * * *": hourly cleanup of expired rate_limits rows
// - "5 9 * * *": daily notification digest (09:05 UTC — D-09 in 12-CONTEXT.md)
// - "5 0 * * 0": weekly digest snapshot (Sunday 00:05 UTC — D-22 in 14-CONTEXT.md)
//
// NOTE: the batch-poller cron ("*/2 * * * *") was removed alongside
// the batch-capable audit models — Workers Free tier enforces a 10ms
// CPU budget on cron triggers which the poller's JSON+D1 workload
// doesn't fit within. See src/lib/audit/prompt.ts for the full
// explanation and src/lib/audit/batch-poller.ts for the dormant
// polling code. When batch is re-enabled (via a queue-self-requeue
// pattern, not a cron), this list stays unchanged.
"triggers": {
"crons": ["0 * * * *", "5 9 * * *", "5 0 * * 0"]
},
"placement": {
"mode": "smart"
},
// Raise the CPU time limit from the 30s default to 90s. Queue
// consumers inherit the Worker CPU limit, and heavy audit models
// (Gemma 4 26B-A4B, GLM-4.7-Flash reasoning, GPT-OSS-120B) run
// through `ai.run()` — that wait time does NOT count as CPU, so
// real usage stays well under 100ms per audit in practice.
//
// Observed: test plugins audit in <20s end-to-end. The 90s ceiling
// is a safety margin for unusually large tarballs doing heavier
// in-process work (parsing, static scanning) while the model thinks,
// without giving runaway loops a 5-minute blast radius against the
// free-tier daily CPU budget. Queue consumer wall-clock stays at
// the 15-minute platform default.
//
// Docs: https://developers.cloudflare.com/queues/platform/limits/#increasing-queue-consumer-worker-cpu-limits
"limits": {
"cpu_ms": 90000
},
"observability": {
"enabled": true,
"logs": {
"enabled": true,
"invocation_logs": true
},
"traces": {
"enabled": true
}
},
// GitHub OAuth App client ID and App ID (not secrets — safe as vars)
// TURNSTILE_SITE_KEY: create widget at dash.cloudflare.com → Turnstile (Smart placement)
//
// AUDIT_MODE governs how new plugin versions are gated on upload:
// - 'auto' (current): run the static scanner + Workers AI audit as a
// combined gate. Static findings are merged into the final audit
// row regardless; the AI verdict decides pass/warn/fail. Neuron-budget
// bound — if the daily budget is exhausted we fall back to
// static-only + manual review. This gives us deterministic pattern
// coverage (static) AND nuanced logic-level review (AI) in one pass.
// - 'static-first': run the static scanner only, no AI on the hot path.
// Blocking → rejected, soft → flagged, clean → published. AI audit
// stays available via the admin "Run AI" button. Cheaper and more
// deterministic, but misses logic-level issues the static scanner
// can't pattern-match for (subtle data-flow exfiltration, novel
// malicious patterns). Consider flipping to this if AI spend gets
// uncomfortable or if we ship a paid-tier verification workflow.
// - 'manual': skip AI, leave status='pending' for human moderation.
// - 'off': same as manual — legacy.
"vars": {
"GITHUB_CLIENT_ID": "Ov23liIu0eF3FtxoIcYU",
"GITHUB_APP_ID": "3345980",
"SUPERADMIN_GITHUB_IDS": "959104",
"TURNSTILE_SITE_KEY": "0x4AAAAAAC1FBCZjp5kjJ99c",
"AUDIT_MODE": "auto"
},
// Secrets set via: wrangler secret put <NAME>
// In dev, provide these in .dev.vars (already gitignored)
// GITHUB_WEBHOOK_SECRET and GITHUB_APP_PRIVATE_KEY are optional until configured
"secrets": {
"required": [
"GITHUB_CLIENT_SECRET",
"JWT_SECRET",
"TURNSTILE_SECRET_KEY",
"UNOSEND_API_KEY",
"UNOSEND_WEBHOOK_SECRET"
]
}
}