Skip to content

Repository files navigation

mistwarp-api

OSL backend for MistWarp community, the MistWarp community platform. Rotur validator auth, flat JSON storage, Cloudflare R2 for project blobs, git.rotur.dev (Gitea) for repos, forks, and pull requests.

Run

Copy .env.example to .env, fill in the values, then run:

osl run main.osl

The server loads .env automatically. Real environment variables override .env.

Environment

VariableDefaultPurpose
PORT5627Listen port
APP_URLhttps://mwapi.mistium.comPublic URL of this API
ROTUR_APP_KEYmistwarpRotur validator app key
R2_ENDPOINThttps://accountid.r2.cloudflarestorage.com
R2_BUCKETmistwarpR2 bucket name
R2_ACCESS_KEY_IDR2 access key
R2_SECRET_ACCESS_KEYR2 secret key
R2_PUBLIC_BASEPublic custom domain for the bucket
GITEA_URLhttps://git.rotur.devGitea instance
GITEA_ADMIN_TOKENGitea admin token (sudo for forks, PRs, merges)
EDITOR_ORIGINhttps://warp.mistium.comEditor origin for CORS
ADMIN_USERSmistComma separated admin usernames

Deployment layout

The site and editor are one scratch-gui build (community pages live in scratch-gui/src/community), served on the frontend domain:

PathServes
/community app (webpack community entry -> index.html)
/editorscratch-gui editor
/embed.htmlscratch-gui embed player (project pages iframe this)
/project/, /explore, /users/, /settingscommunity app (client routing)

This API runs on a SEPARATE domain, mwapi.mistium.com. The frontend calls it at https://mwapi.mistium.com/api directly. In dev, leave the API base unset and webpack-dev-server proxies /api to http://localhost:5627. Auth is Bearer-token based (the session token returned by /api/auth), so a cross-domain API works without shared cookies. CORS echoes the request Origin with credentials, so any frontend origin is accepted.

R2 bucket only needs public GET (through R2_PUBLIC_BASE). All writes go through this server. With no R2 configured, the server falls back to local disk (data/blobs/, served at /blobs) so it runs locally with zero setup.

Upload pipeline

The editor POSTs a sparse sb3 to POST /api/projects/:id/upload (multipart, fields project and optional thumbnail). The server extracts at most 1 GiB of project.json, validates it incrementally, requires asset filenames to match their content, and limits every asset to 10 MiB and all assets to 50 MiB. The JSON is accepted only when its gzip representation is at most 20 MiB.

  • assets/<md5ext>: content addressed, shared across all projects and remixes, uploaded once ever
  • projects/<id>/project.json: the gzip-encoded playable snapshot
  • projects/<id>/thumb.png

Uploads per project are debounced to one per 24 hours (429 with retryAfterMs otherwise); git carries every save, R2 holds a daily snapshot. data/assets-index.json tracks which assets R2 already has so duplicates are never re-uploaded.

Auth flow

  1. Client holds a rotur token (rotur-sdk login).
  2. Client fetches https://api.rotur.dev/generate_validator?key=<ROTUR_APP_KEY>&auth=<token> (must be the same rotur instance the server validates against).
  3. Client calls POST /api/auth?v=<validator>; the API validates it against https://api.rotur.dev/validate and returns a 7 day session token (also set as the auth_token cookie). Bearer header and cookie are both accepted.

About

The mistwarp backend for projects and community, authed with @RoturTW

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages