commits
- Add quota_warning to UploadSaveResponse
- Add warning to QuotaResponse
- Surface 80% quota warnings to clients after uploads
- Fix landing/build path for rust-embed
* phase6/cost-cache:
Phase 6: Cost calculation service with TTL cache
- Add api/src/cost/mod.rs with DashMap-based cost calculation cache
- Add GET /costs endpoint returning delta/base costs per game
- Add storage cost display to admin stats command
- Cache expires after 5 minutes to balance freshness vs performance
- Helps clients estimate upload costs before committing
- Add atomic reserve_quota() function with SELECT ... FOR UPDATE
- Replaces separate check_quota + increment_quota with single atomic operation
- Eliminates race condition between quota check and increment
- Add admin CLI commands: quota list, quota set, quota reset, quota show
- Track quota via gamer_quotas table
- Return HTTP 413 when quota exceeded on upload
- All save endpoints now require Authorization: Bearer <itchio_token>
- AuthService::verify_token() validates tokens against itch.io API
- upload_save validates gamer_id in body matches authenticated user
- download_save/get_save_metadata/get_quota_status derive gamer_id from token
- Returns 401 Unauthorized for missing/invalid tokens
- Returns 403 Forbidden for gamer_id mismatch
- Delta compression: upload stores delta if smaller than full data
- Delta reconstruction: download applies patches sequentially from base
- Quota tracking: gamer_quotas table with check/increment functions
- HTTP 413 Payload Too Large when quota exceeded
- Fixed tuple destructuring to use .clone() instead of ref
- Removed unused imports (NewType, sqlx::Row, std::io::Cursor)
- Add itch.io OAuth device code flow with AuthService
- Implement tuple composition pattern for poem-openapi v5
- Add game registration endpoint with API key generation
- Add save upload/download with delta compression infrastructure
- Use Object derive for payload types in poem-openapi v5
- Wire up GamesEndpoint, SavesEndpoint, AuthEndpoint via tuple
- Bump qbsdiff to 1.4, tower-http with compression-br feature
- Upgrade to poem-openapi v5 with correct #[OpenApi] macro
- Switch from rusqlite to sqlx async for database
- Wrap SpacesClient in Arc for Clone trait
- Fix expires() -> expires_in() for S3 presigning
- Update endpoint impls to return Result<Response>
- Add atomic reserve_quota() function with SELECT ... FOR UPDATE
- Replaces separate check_quota + increment_quota with single atomic operation
- Eliminates race condition between quota check and increment
- Add admin CLI commands: quota list, quota set, quota reset, quota show
- Track quota via gamer_quotas table
- Return HTTP 413 when quota exceeded on upload
- All save endpoints now require Authorization: Bearer <itchio_token>
- AuthService::verify_token() validates tokens against itch.io API
- upload_save validates gamer_id in body matches authenticated user
- download_save/get_save_metadata/get_quota_status derive gamer_id from token
- Returns 401 Unauthorized for missing/invalid tokens
- Returns 403 Forbidden for gamer_id mismatch
- Delta compression: upload stores delta if smaller than full data
- Delta reconstruction: download applies patches sequentially from base
- Quota tracking: gamer_quotas table with check/increment functions
- HTTP 413 Payload Too Large when quota exceeded
- Fixed tuple destructuring to use .clone() instead of ref
- Removed unused imports (NewType, sqlx::Row, std::io::Cursor)
- Add itch.io OAuth device code flow with AuthService
- Implement tuple composition pattern for poem-openapi v5
- Add game registration endpoint with API key generation
- Add save upload/download with delta compression infrastructure
- Use Object derive for payload types in poem-openapi v5
- Wire up GamesEndpoint, SavesEndpoint, AuthEndpoint via tuple
- Bump qbsdiff to 1.4, tower-http with compression-br feature
- Upgrade to poem-openapi v5 with correct #[OpenApi] macro
- Switch from rusqlite to sqlx async for database
- Wrap SpacesClient in Arc for Clone trait
- Fix expires() -> expires_in() for S3 presigning
- Update endpoint impls to return Result<Response>