HTTP API
INFO
The web app is built on this API; you only need it to script CodeRail. It may change while CodeRail is at 0.x.
All JSON. Auth is the cr_session cookie (HttpOnly) set by setup, login and signup. Errors are {error: string} with a 4xx/5xx status. The machine WebSocket protocol is in protocol/src/index.ts.
Account
| Method | Path | Body | Answer |
|---|---|---|---|
| GET | /api/me | {user: {id, username, isAdmin} | null, setup: boolean}. setup is true while no user exists | |
| POST | /api/setup | {token, username, password} | {user}. Only while no user exists. token is the deploy's SETUP_TOKEN |
| POST | /api/login | {username, password} | {user} |
| POST | /api/logout | {ok} | |
| POST | /api/password | {current, next} | {ok} |
| GET | /api/invites/:code | {valid, isAdmin} (no sign-in needed) | |
| POST | /api/signup | {code, username, password} | {user} |
Usernames: 2-32 of a-z 0-9 _ . -. Passwords: at least 8 characters.
Admin
| Method | Path | Body | Answer |
|---|---|---|---|
| GET | /api/users | [{id, username, isAdmin, disabled, createdAt}] (any signed-in user may list, to grant access) | |
| PATCH | /api/users/:id | {isAdmin?, disabled?} | {ok} (admin) |
| DELETE | /api/users/:id | {ok} (admin) | |
| GET | /api/invites | [{code, isAdmin, createdAt, expiresAt, createdBy}] (admin, unused only) | |
| POST | /api/invites | {isAdmin} | {code, url, expiresAt} (admin; 7 days) |
| DELETE | /api/invites/:code | {ok} (admin) | |
| GET | /api/audit?machine=&limit= | [{at, username, machineId, machineName, action, detail}] (admins see all, owners their machines) |
Machines
| Method | Path | Body | Answer |
|---|---|---|---|
| GET | /api/machines | MachineSummary[]: the machines the user has a grant on (admins: all, as owner) | |
| PATCH | /api/machines/:id | {name} | {ok} (owner) |
| DELETE | /api/machines/:id | {ok} (owner): revokes its token and disconnects it | |
| GET | /api/machines/:id/grants | [{userId, username, role, folders, harnesses, terminal}] (owner) | |
| PUT | /api/machines/:id/grants/:userId | {role, folders: string[]|null, harnesses: string[]|null, terminal} | {ok} (owner) |
| DELETE | /api/machines/:id/grants/:userId | {ok} (owner) | |
| POST | /api/machines/:id/preview | {port} | {url} (operator): a link that opens the machine's localhost:<port> on the preview host |
| GET (WS) | /api/machines/:id/ws | the machine socket |
Linking a computer
The bridge runs coderail link https://<host>. It calls POST /api/pair/start {name, info} and gets {code, secret, url}, prints the code and opens url (/link?code=…). The signed-in user confirms:
| Method | Path | Body | Answer |
|---|---|---|---|
| GET | /api/pair/:code | {code, name, info, expiresAt} | |
| POST | /api/pair/:code/approve | {name} | {machineId}: the approver becomes the machine's owner |
The bridge polls POST /api/pair/poll {code, secret} until it gets {machineId, token}, then connects to GET (WS) /api/bridge with Authorization: Bearer <token>.
Push
| Method | Path | Body | Answer |
|---|---|---|---|
| GET | /api/push/key | {publicKey} (VAPID, base64url) or {publicKey: null} when push is not set up | |
| POST | /api/push/subscribe | {subscription} (PushSubscription JSON) | {ok} |
| POST | /api/push/unsubscribe | {endpoint} | {ok} |
A push's payload is {title, body, url}; the service worker shows it and opens url on click.
Pages (the SPA's routes)
/ machines · /m/:id a machine · /m/:id/s/:sessionId a session on it · /link?code= approve a computer · /invite/:code sign up · /setup first admin · /settings account, users, invites, audit.