Skip to content

Encinet/mikdata

Repository files navigation

Mik Data

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.

Routes

Public API:

  • GET /api/players
  • GET /api/buildings
  • GET /api/buildings/:id
  • GET /api/bans
  • GET /api/announcements
  • GET /health

Admin UI and write API:

  • GET /admin
  • POST /admin/api/buildings
  • PUT /admin/api/buildings/:id
  • PATCH /admin/api/buildings/:id
  • DELETE /admin/api/buildings/:id
  • POST /admin/api/buildings/import
  • GET /admin/api/building-submissions
  • POST /admin/api/building-submissions/repair-approved
  • PUT /admin/api/building-submissions/:id
  • PUT /admin/api/building-submissions/:id/approve
  • PUT /admin/api/building-submissions/:id/reject

Authenticated MikWeb account API:

  • POST /api/account/building-submissions
  • POST /api/account/building-submissions/mine
  • POST /api/account/players/resolve

Security Model

  • No arbitrary proxying. Every public route is allowlisted in src/index.ts.
  • Public API routes only accept GET and OPTIONS.
  • Buildings read routes are public GET routes.
  • 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/api is not listed in openapi.yaml. Treat it as an operational interface, not as a public API contract.
  • workers_dev is 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:v1 KV 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 and building-submission-status:{status}:* for admin submission lists. Do not remove these indexes without rebuilding them from submission documents.
  • POST /admin/api/building-submissions/repair-approved is an admin maintenance action. It scans old approved submissions, restores missing building:{id} records when needed, links duplicate existing buildings, deletes repaired approved submission records and stale approved indexes, then rebuilds building-summary:v1 and 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. mikdata writes rejectedAt and expiresAt when rejecting, then stores the submission document, player index key, and status index key with KV expirationTtl.
  • 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 example https://your-team.cloudflareaccess.com.
  • CLOUDFLARE_ACCESS_AUD: Access application AUD tag from the application page.

Runtime Configuration

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_ORIGIN

For local development, copy .dev.vars.example to .dev.vars and fill values. .dev.vars is ignored by git.

Setup

Install dependencies:

bun install

Create KV namespaces:

bunx wrangler kv namespace create BUILDINGS_KV

Put 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 dev

Deploy:

bun run deploy

Refresh Behavior

Cloudflare Cron refreshes stable routes every five minutes:

  • players
  • bans
  • announcements

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Contributors