Skip to content

feat(media): public media CRUD API routes (/api/media/v1)#68

Closed
ABB65 wants to merge 1 commit into
feat/media-api-foundationfrom
feat/media-api-routes
Closed

feat(media): public media CRUD API routes (/api/media/v1)#68
ABB65 wants to merge 1 commit into
feat/media-api-foundationfrom
feat/media-api-routes

Conversation

@ABB65

@ABB65 ABB65 commented Jun 18, 2026

Copy link
Copy Markdown
Member

Phase 2 — Public media CRUD API (/api/media/v1/...)

The external media management surface, built on the Phase 1 scope foundation (#67).

Stacked on #67 — base is feat/media-api-foundation. Merge #67 first; this PR retargets to main automatically.

Routes — /api/media/v1/[projectId]/assets/

Op Method Scope Notes
list GET assets media:read search / tags / type filter + page/sort
get GET assets/:id media:read project-scoped
upload POST assets media:write multipart binary or JSON {url} (SSRF-guarded)
update PATCH assets/:id media:write alt / tags / focal point
delete DELETE assets/:id media:write
bulk POST assets/bulk media:write delete/tag, ≤50, never cross-project

Design

  • resolveMediaApiContext — one gate for every route: Bearer-key validation → project match → scope → per-key hourly rate limit → plan feature → ee media provider. Mirrors the MCP Cloud proxy gate order; 503 in Community Edition (no media provider).
  • withMediaUrls — decorates assets with the CDN delivery URL + per-variant URLs (raw storage paths preserved). Public no-auth browser delivery via a custom domain stays ee/roadmap; this returns the Bearer-keyed /api/cdn/v1/... delivery URL.
  • Upload reuses the SSRF-hardened fetchRemoteMedia (URL mode) and the same MIME/size/storage-quota pipeline as the session route.

Local-files note

Only upload needs the file bytes → runs where the files are (Local MCP / CI). list/get/update/delete/bulk operate on ids + metadata, so they work over MCP Cloud too.

Tests

Unit tests for the gate (resolveMediaApiContext: project match, scope, rate limit, provider-null) + URL building. 688 green (unit + integration + nuxt). Full per-route integration tests + the scope UI (CDNPanel) are follow-ups (Phase 3).

The external media management surface external agents/CI use to upload
to Studio CDN and manage assets, built on the Phase 1 scope foundation.

- `server/utils/media-api.ts` — `resolveMediaApiContext`: the single gate
  every route runs through (Bearer-key validation, project match, scope,
  per-key hourly rate limit, plan feature, ee media provider; mirrors the
  MCP Cloud proxy gate order; 503 in Community Edition).
- `server/utils/media-url.ts` — `withMediaUrls` decorates assets with the
  CDN delivery URL + per-variant URLs (raw storage paths kept).
- Routes under `/api/media/v1/[projectId]/assets/`:
  - GET `assets` (list, media:read), GET `assets/:id` (get, media:read)
  - POST `assets` (upload, media:write) — multipart binary OR JSON {url}
    (SSRF-guarded), shared validated pipeline + atomic storage reservation
  - PATCH `assets/:id` (update meta), DELETE `assets/:id`, POST `assets/bulk`
    (delete/tag, capped at 50, never cross-project) — all media:write

Only `upload` needs the file bytes (local → Local MCP/CI); list/get/
update/delete/bulk operate on ids + metadata, so they work over MCP Cloud
too. Helper unit tests cover the gate decisions + URL building (688 green).
Full per-route integration tests are a follow-up.
@ABB65 ABB65 deleted the branch feat/media-api-foundation June 18, 2026 18:05
@ABB65 ABB65 closed this Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant