Add UploadAttachment, a unary RPC that accepts a file in bounded chunks
and streams it to a temp file instead of holding the whole blob in one
request body and in memory. A call carrying a spec starts an upload and
returns an opaque upload_id; later calls carry that id with
write_offset,
data, and finish_write, following the Cloud Storage WriteObject shape.
Retrying the last chunk after a lost response is idempotent, uploads are
bound to their owner, and they expire after 30 minutes of inactivity.
CreateAttachment and the chunked finalize now share one processing
pipeline for motion-photo detection, EXIF stripping, and storage. The
motion-photo detector works over an io.ReaderAt so large JPEGs are never
loaded whole, and the request body cap is a single per-procedure lookup.
The web editor uploads through the new RPC in 2 MiB chunks with bounded
concurrency under the server's per-user limit.
Use the original UID format consistently across API, username, and store validation so UUID-based callers continue to work. Regenerate API documentation and add regression coverage for UUID memo IDs.
Validate new user-provided IDs using the AIP-122 format while retaining legacy UID compatibility. Correct resource annotations and canonical names returned by user stats.
Rework ListUsers to match the ListMemos pagination contract: opaque
PageToken, normalizePageSize, DB-level limit+1 look-ahead, and a
next_page_token. Adds Offset to store.FindUser with an OFFSET clause in
all three dialects, and an `id DESC` ORDER BY tiebreaker so offset pages
stay stable when created_ts ties.
Also align pagination across list endpoints:
- Bump DefaultPageSize 10 -> 50 to match the documented default; use
normalizePageSize in ListAttachments.
- Remove the never-implemented total_size field from all six list
responses (ListUsers, ListAttachments, ListMemoComments,
ListMemoReactions, ListUserSettings, ListPersonalAccessTokens) and
regenerate.
- useListUsers now pages through next_page_token so the admin members
view still loads every user past the default page size.
Migrates attachment and avatar binary serving from gRPC endpoints to a new dedicated HTTP fileserver package, fixing Safari video playback issues and improving architectural separation.
Key changes:
- Created server/router/fileserver package for all binary file serving
- Removed GetAttachmentBinary and GetUserAvatar gRPC endpoints from proto
- Implemented native HTTP handlers with full range request support
- Added authentication support (session cookies + JWT) to fileserver
- New avatar endpoint supports lookup by user ID or username
- Eliminated duplicate auth constants (imports from api/v1)
HTTP endpoints:
- Attachments: /file/attachments/:uid/:filename (unchanged URL)
- Avatars: /file/users/:identifier/avatar (new URL format)
This fixes Safari video/audio playback by using http.ServeContent() which properly handles HTTP 206 Partial Content responses and range request headers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>