Move all server calls from the deprecated legacy routes to /api/v1, with token authentication. The legacy routes still work but send a Deprecation: true header and will be removed later (see Sansan/MusicServer#31).
Do #38 (start sync with POST) first, or together with this.
Token flow
POST /api/v1/token with JSON {"password": "<API password>", "client_type": "godot"} returns {"token", "expires_at", "client_type"}. The token is valid for 24 hours.
Send it on every /api/v1 request: Authorization: Bearer <token>.
A missing, unknown or expired token returns 401 with {"error": "..."}.
Token creation is rate-limited to 10 requests per minute per client (429 when exceeded). Request a token once and reuse it, never per call.
If the server has no API_PASSWORD set, any password works. If it has DISABLE_SESSION_AUTH=true, no token is needed at all.
DELETE /api/v1/token invalidates the token, for example on quit.
Suggested structure
HttpTransport owns the token: it adds the Authorization header, and on a 401 it requests a new token once and retries the original request once. Callers don't need to know about tokens.
The password comes from settings (Settings), next to Settings.default_path. Don't hardcode it.
MusicServerClient prefixes paths with /api/v1. Everything else stays the same.
The fake transport in tests can simulate an expired token (first call 401, then 200) to test the retry.
No v1 version; use GET /api/v1/version as a reachability check
Responses now also contain UUIDs: /music/info and /music/list have SoundtrackUuid and SongUuid. New UUID endpoints: GET /api/v1/soundtracks, /api/v1/soundtracks/{uuid}, /api/v1/songs/{uuid}, /api/v1/songs/{uuid}/file (streams the song).
The OpenAPI spec is served by the server at /openapi (Swagger UI at /swagger/index.html).
Acceptance criteria
No calls to legacy routes remain
Token requested once, reused, and refreshed automatically on 401
Password configurable in settings
Unit tests for token handling (header added, refresh + retry on 401, only one retry)
Move all server calls from the deprecated legacy routes to `/api/v1`, with token authentication. The legacy routes still work but send a `Deprecation: true` header and will be removed later (see Sansan/MusicServer#31).
Do #38 (start sync with POST) first, or together with this.
## Token flow
- `POST /api/v1/token` with JSON `{"password": "<API password>", "client_type": "godot"}` returns `{"token", "expires_at", "client_type"}`. The token is valid for **24 hours**.
- Send it on every `/api/v1` request: `Authorization: Bearer <token>`.
- A missing, unknown or expired token returns **401** with `{"error": "..."}`.
- Token creation is rate-limited to **10 requests per minute per client** (429 when exceeded). Request a token once and reuse it, never per call.
- If the server has no `API_PASSWORD` set, any password works. If it has `DISABLE_SESSION_AUTH=true`, no token is needed at all.
- `DELETE /api/v1/token` invalidates the token, for example on quit.
## Suggested structure
- **`HttpTransport`** owns the token: it adds the `Authorization` header, and on a 401 it requests a new token once and retries the original request once. Callers don't need to know about tokens.
- The password comes from settings (`Settings`), next to `Settings.default_path`. Don't hardcode it.
- **`MusicServerClient`** prefixes paths with `/api/v1`. Everything else stays the same.
- The fake transport in tests can simulate an expired token (first call 401, then 200) to test the retry.
## Endpoint mapping
| Legacy | `/api/v1` |
|---|---|
| `/music`, `/music/rand`, `/music/rand/low`, `/music/info`, `/music/list`, `/music/addQue`, `/music/reset`, `/music/played`, `/music/all`, `/music/all/order`, `/music/soundTest` | Same path under `/api/v1/...`, same responses |
| `/characters` | `/api/v1/character/list` |
| `/character?name=` | `/api/v1/character?name=` |
| `POST /sync`, `GET /sync/progress` | `POST /api/v1/sync`, `GET /api/v1/sync/progress` |
| `/version` | `/api/v1/version` |
| `/download`, `/download/windows`, `/download/linux` (for #12, #13) | `/api/v1/download/...` |
| `/health` | No v1 version; use `GET /api/v1/version` as a reachability check |
Responses now also contain UUIDs: `/music/info` and `/music/list` have `SoundtrackUuid` and `SongUuid`. New UUID endpoints: `GET /api/v1/soundtracks`, `/api/v1/soundtracks/{uuid}`, `/api/v1/songs/{uuid}`, `/api/v1/songs/{uuid}/file` (streams the song).
The OpenAPI spec is served by the server at `/openapi` (Swagger UI at `/swagger/index.html`).
## Acceptance criteria
- No calls to legacy routes remain
- Token requested once, reused, and refreshed automatically on 401
- Password configurable in settings
- Unit tests for token handling (header added, refresh + retry on 401, only one retry)
Update from MusicServer (develop, commit 973ebf2): the API docs are now generated with Huma instead of swag.
Spec: OpenAPI 3.1 at /openapi.json (also /openapi.yaml, and OpenAPI 3.0 at /openapi-3.0.json). Interactive docs at /docs. /openapi redirects to /openapi.json. Only /api/v1 is documented; legacy routes are hidden but still work.
Health:GET /api/v1/health now exists and needs no token (returns {"status": "up"}).
Sync aliases removed:/sync/new, /sync/quick and /sync/new/full are gone. Use POST /sync and POST /sync/full.
Errors: every error body is {"error": "..."}. Invalid or missing parameters (for example ?song=abc, a malformed UUID, limit=0) now return 422 instead of 400.
Lists: empty lists are [], never null. Arrays in the spec are not nullable.
**Update from MusicServer (`develop`, commit 973ebf2):** the API docs are now generated with Huma instead of swag.
- **Spec:** OpenAPI 3.1 at `/openapi.json` (also `/openapi.yaml`, and OpenAPI 3.0 at `/openapi-3.0.json`). Interactive docs at `/docs`. `/openapi` redirects to `/openapi.json`. Only `/api/v1` is documented; legacy routes are hidden but still work.
- **Health:** `GET /api/v1/health` now exists and needs no token (returns `{"status": "up"}`).
- **Sync aliases removed:** `/sync/new`, `/sync/quick` and `/sync/new/full` are gone. Use `POST /sync` and `POST /sync/full`.
- **Errors:** every error body is `{"error": "..."}`. Invalid or missing parameters (for example `?song=abc`, a malformed UUID, `limit=0`) now return **422** instead of 400.
- **Lists:** empty lists are `[]`, never `null`. Arrays in the spec are not nullable.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Move all server calls from the deprecated legacy routes to
/api/v1, with token authentication. The legacy routes still work but send aDeprecation: trueheader and will be removed later (see Sansan/MusicServer#31).Do #38 (start sync with POST) first, or together with this.
Token flow
POST /api/v1/tokenwith JSON{"password": "<API password>", "client_type": "godot"}returns{"token", "expires_at", "client_type"}. The token is valid for 24 hours./api/v1request:Authorization: Bearer <token>.{"error": "..."}.API_PASSWORDset, any password works. If it hasDISABLE_SESSION_AUTH=true, no token is needed at all.DELETE /api/v1/tokeninvalidates the token, for example on quit.Suggested structure
HttpTransportowns the token: it adds theAuthorizationheader, and on a 401 it requests a new token once and retries the original request once. Callers don't need to know about tokens.Settings), next toSettings.default_path. Don't hardcode it.MusicServerClientprefixes paths with/api/v1. Everything else stays the same.Endpoint mapping
/api/v1/music,/music/rand,/music/rand/low,/music/info,/music/list,/music/addQue,/music/reset,/music/played,/music/all,/music/all/order,/music/soundTest/api/v1/..., same responses/characters/api/v1/character/list/character?name=/api/v1/character?name=POST /sync,GET /sync/progressPOST /api/v1/sync,GET /api/v1/sync/progress/version/api/v1/version/download,/download/windows,/download/linux(for #12, #13)/api/v1/download/.../healthGET /api/v1/versionas a reachability checkResponses now also contain UUIDs:
/music/infoand/music/listhaveSoundtrackUuidandSongUuid. New UUID endpoints:GET /api/v1/soundtracks,/api/v1/soundtracks/{uuid},/api/v1/songs/{uuid},/api/v1/songs/{uuid}/file(streams the song).The OpenAPI spec is served by the server at
/openapi(Swagger UI at/swagger/index.html).Acceptance criteria
Update from MusicServer (
develop, commit 973ebf2): the API docs are now generated with Huma instead of swag./openapi.json(also/openapi.yaml, and OpenAPI 3.0 at/openapi-3.0.json). Interactive docs at/docs./openapiredirects to/openapi.json. Only/api/v1is documented; legacy routes are hidden but still work.GET /api/v1/healthnow exists and needs no token (returns{"status": "up"})./sync/new,/sync/quickand/sync/new/fullare gone. UsePOST /syncandPOST /sync/full.{"error": "..."}. Invalid or missing parameters (for example?song=abc, a malformed UUID,limit=0) now return 422 instead of 400.[], nevernull. Arrays in the spec are not nullable.