/** * For more details on how to configure Wrangler, refer to: * https://developers.cloudflare.com/workers/wrangler/configuration/ */ { "$schema": "node_modules/wrangler/config-schema.json", "name": "cf-isupordown", "main": "src/index.ts", "compatibility_date": "2026-05-30", "assets": { // The path to the directory containing the `index.html` file to be served at `/` "directory": "./public", // Expose assets to the Worker so it can rewrite /analytics.js at the edge. "binding": "ASSETS", // Run the Worker first for this one path so it can inject the GA4 ID from // the GA_ID var; every other asset is still served directly (asset-first). "run_worker_first": [ "/analytics.js" ] }, // Google Analytics 4 measurement ID, injected into /analytics.js at the edge. // Empty here on purpose: forks/clones send NO analytics. Put your real // "G-XXXXXXXXXX" in wrangler.prod.jsonc (gitignored) — never in this public file. "vars": { "GA_ID": "", // Salt for the IP hash — override with `wrangler secret put VOTE_SALT` in // production (and set VOTE_SALT in .dev.vars for local dev). The empty // default here just satisfies the binding type; production must use a real secret. "VOTE_SALT": "", // Protomaps API key for the world map on /status/ pages. // Get a free key at https://protomaps.com — leave empty to disable the map. "PROTOMAPS_KEY": "" }, "observability": { "enabled": true }, "upload_source_maps": true, "compatibility_flags": [ "nodejs_compat" ], // Poll every 5 minutes and persist a snapshot to D1. "triggers": { "crons": [ "*/5 * * * *" ] }, // History/persistence store. When deploying via the Deploy Button, Cloudflare // provisions a new D1 database and fills in the database_id automatically. // For manual deploys: run `npx wrangler d1 create isupmap` and paste the id here. "d1_databases": [ { "binding": "DB", "database_name": "isupmap", "database_id": "" }, // Separate D1 for community vote data — isolated so vote storms during an // outage don't serialise behind the authoritative status writes in DB. // Create: `npx wrangler d1 create isupmap-reports` and paste the id below. { "binding": "REPORTS_DB", "database_name": "isupmap-reports", "database_id": "" } ], // Hot read-cache for the public snapshot: the cron writes the finished // snapshot JSON here each run and the /api/* routes read it, so reads never // touch D1. Replace the placeholder id below with your own — run // `npx wrangler kv namespace create SNAPSHOT_KV` and paste the id. Local dev // and tests simulate KV regardless of the id value. "kv_namespaces": [ { "binding": "SNAPSHOT_KV", "id": "00000000000000000000000000000000" } ], // Queue for buffering community vote writes. The consumer coalesces a burst // of votes into a handful of D1 inserts so the vote storm during an outage // doesn't hammer REPORTS_DB directly from the edge. // Create: `npx wrangler queues create isupmap-votes` (+ isupmap-votes-dlq). "queues": { "producers": [ { "binding": "VOTE_QUEUE", "queue": "isupmap-votes" } ], "consumers": [ { "queue": "isupmap-votes", "max_batch_size": 100, "max_batch_timeout": 60, "max_retries": 3, "dead_letter_queue": "isupmap-votes-dlq" } ] }, // Per-IP rate limiting for the public /api/* endpoints: 60 requests / 60s. // VOTE_RATE_LIMITER is tighter (10 req / 60 s) to cap vote-queue flooding. "ratelimits": [ { "name": "API_RATE_LIMITER", "namespace_id": "1001", "simple": { "limit": 60, "period": 60 } }, { "name": "VOTE_RATE_LIMITER", "namespace_id": "1002", "simple": { "limit": 10, "period": 60 } } ], // Analytics Engine dataset for logging upstream fetch events (per-attempt // latency, HTTP status, service id, source type). Query via the AE SQL API. // No setup needed — the dataset is created automatically on the first write. "analytics_engine_datasets": [ { "binding": "FETCH_ANALYTICS", "dataset": "isupmap_fetches" } ], "workers_dev": false, "preview_urls": false }