Cloudflare Worker data API for MikWeb.
The Worker is published as https://data.mcmik.top/api. It forwards a small allowlisted API surface to the Minecraft data service and caches public JSON responses with the Worker Cache API. Buildings and building submissions are persisted in Worker KV. Public building reads use an in-memory cache, the Worker Cache API, and a KV summary snapshot.
Public API details are documented in openapi.yaml.
Public API:
GET /api/playersGET /api/buildingsGET /api/buildings/:idGET /api/bansGET /api/announcementsGET /health
Admin UI and write API:
GET /adminPOST /admin/api/buildingsPUT /admin/api/buildings/:idPATCH /admin/api/buildings/:idDELETE /admin/api/buildings/:idPOST /admin/api/buildings/importGET /admin/api/building-submissionsPOST /admin/api/building-submissions/repair-approvedPUT /admin/api/building-submissions/:idPUT /admin/api/building-submissions/:id/approvePUT /admin/api/building-submissions/:id/reject
Authenticated MikWeb account API:
POST /api/account/building-submissionsPOST /api/account/building-submissions/minePOST /api/account/players/resolve
- No arbitrary proxying. Every public route is allowlisted in
src/index.ts. - Public API routes only accept
GETandOPTIONS. - Buildings read routes are public
GETroutes. - Public API routes allow browser requests from any origin.
- Admin routes live under
/admin*and require Cloudflare Access. The Worker validates the Access JWT issuer and AUD before serving any/admin*response. - Buildings write routes reject cross-site browser requests and do not expose CORS preflight headers.
/admin/apiis not listed inopenapi.yaml. Treat it as an operational interface, not as a public API contract.workers_devis disabled so the Worker is intended to be reached through the configured custom domain only.- Upstream responses must be successful JSON before being persisted.
- Buildings and building submissions are stored in
BUILDINGS_KV; there is no active building Durable Object binding. - Public building reads use layered cache: bounded in-isolate memory, Worker Cache API JSON entries, and the
building-summary:v1KV snapshot. Filtered building-list cache keys include a summary version so mutations naturally stop hitting old query results. - Runtime hot paths use bounded TTL memory caches to reduce KV, Durable Object storage, and plugin request volume. These caches are deliberately small and expire quickly so they protect free-tier limits without becoming durable state.
- Building mutations write audit logs with action, building id, and Cloudflare Access identity. Payloads are not logged.
- Building image URLs must be relative paths or
https://URLs. - Player building submissions must come from authenticated MikWeb member accounts and use ImgBB WebP image URLs generated by MikWeb.
- Submission listing uses secondary KV indexes:
building-submission-player-pending:{uuid}:*for per-player pending limits andbuilding-submission-status:{status}:*for admin submission lists. Do not remove these indexes without rebuilding them from submission documents. POST /admin/api/building-submissions/repair-approvedis an admin maintenance action. It scans old approved submissions, restores missingbuilding:{id}records when needed, links duplicate existing buildings, deletes repaired approved submission records and stale approved indexes, then rebuildsbuilding-summary:v1and the public summary cache. Use it after a bad deploy or cache/index incident where approved submissions do not appear in the standard building list.- Rejected player building submissions are visible for 14 days.
mikdatawritesrejectedAtandexpiresAtwhen rejecting, then stores the submission document, player index key, and status index key with KVexpirationTtl. - Expired rejection cleanup normally relies on KV TTL. List reads still lazily delete stale rejected records and orphaned player index keys as a fallback. It does not delete already-uploaded ImgBB files because ImgBB delete URLs are not persisted in
mikdata.
Configure a Cloudflare Access self-hosted application for data.mcmik.top/admin*. The Worker checks Cf-Access-Jwt-Assertion, so X-Admin-Token is not used.
To find the Access settings:
CLOUDFLARE_ACCESS_ISSUER: Zero Trust team domain, for examplehttps://your-team.cloudflareaccess.com.CLOUDFLARE_ACCESS_AUD: Access application AUD tag from the application page.
Do not put upstream addresses or secrets in wrangler.jsonc. Store all runtime configuration as Cloudflare secrets:
| Variable | Required | Purpose |
|---|---|---|
MINECRAFT_SERVER_URL |
Yes | Main upstream data service base URL |
MINECRAFT_SERVER_ADDRESS |
Yes | Minecraft status fallback host |
MINECRAFT_SERVER_PORT |
Yes | Minecraft status fallback port |
CLOUDFLARE_ACCESS_ISSUER |
Yes | Access issuer, for example https://your-team.cloudflareaccess.com |
CLOUDFLARE_ACCESS_AUD |
Yes | Access application AUD tag for /admin* |
MIKWEB_AUTH_CLIENT_SECRET |
Yes | Shared server-side secret for MikWeb /api/auth/* and /api/account/* BFF requests |
WEBAUTHN_RP_ID |
No | Passkey RP ID, defaults to mcmik.top. It must match the MikWeb hostname or a registrable parent domain |
WEBAUTHN_ORIGIN |
No | Allowed Passkey origins, defaults to https://mcmik.top. Use comma-separated values for multiple origins |
Minecraft upstream requests use the VPC_SERVICE binding configured in wrangler.jsonc; MINECRAFT_SERVER_URL should be reachable through that VPC service.
Buildings and building submissions require the BUILDINGS_KV binding. The only active Durable Object binding is AUTH_STORE.
Passkey registration and login must happen on an origin compatible with WEBAUTHN_RP_ID. Production should use WEBAUTHN_RP_ID=mcmik.top and WEBAUTHN_ORIGIN=https://mcmik.top. For local MikWeb development, run MikData locally too and set WEBAUTHN_RP_ID=localhost with WEBAUTHN_ORIGIN=http://localhost:3000.
bunx wrangler secret put MINECRAFT_SERVER_URL
bunx wrangler secret put MINECRAFT_SERVER_ADDRESS
bunx wrangler secret put MINECRAFT_SERVER_PORT
bunx wrangler secret put CLOUDFLARE_ACCESS_ISSUER
bunx wrangler secret put CLOUDFLARE_ACCESS_AUD
bunx wrangler secret put MIKWEB_AUTH_CLIENT_SECRET
bunx wrangler secret put WEBAUTHN_RP_ID
bunx wrangler secret put WEBAUTHN_ORIGINFor local development, copy .dev.vars.example to .dev.vars and fill values. .dev.vars is ignored by git.
Install dependencies:
bun installCreate KV namespaces:
bunx wrangler kv namespace create BUILDINGS_KVPut the generated id values into wrangler.jsonc.
wrangler.jsonc still keeps the historical BuildingsWriter migration and a later deleted_classes migration so Cloudflare can delete the old class. Do not add a BUILDINGS_WRITER binding back unless the storage design changes again.
Run locally:
bun run devDeploy:
bun run deployCloudflare Cron refreshes stable routes every five minutes:
- players
- bans
- announcements