Media
client.media handles every file that touches the platform: token images, series asset bundles, and generative code. For the end-to-end pattern, see media upload flow.
MediaKind
Section titled “MediaKind”Every asset declares its kind up front — kind is not inferred from MIME type:
| Kind | Use for |
|---|---|
MediaKind.File | Single blob (image, video, audio, metadata JSON) |
MediaKind.Directory | Zip archive — extracted after upload |
import { MediaKind } from "@highlightxyz/sdk";Create an upload session
Section titled “Create an upload session”const res = await client.media.createUploadSession({ kind: MediaKind.File, fileName: "artwork.png", mimeType: "image/png", fileSize: 1024000, // scope: "CollectionLogo" | "CollectionAsset" | ... (optional)});// { data: { media: Media.Entity, upload: { url, method, headers } } }Returns a signed upload URL. fileSize is validated against the per-kind limit up front (see size limits).
PUT the bytes
Section titled “PUT the bytes”You can either use fetch directly against upload.url or call client.media.upload which does the same with the SDK’s auth headers:
// Preferred: direct PUTawait fetch(session.upload.url, { method: session.upload.method, headers: { ...session.upload.headers, authorization: `Bearer ${accessToken}`, }, body: buffer,});Drive processing
Section titled “Drive processing”After PUT, File assets transition straight to Ready. Directory assets trigger extraction and go Pending → Processing → Ready.
If you need to force progression (rare — mostly for retrying a failed Directory extraction):
await client.media.process({ mediaId });Idempotent. Ready and Processing assets are returned as-is.
Get status
Section titled “Get status”const res = await client.media.get({ mediaId });// res.data.status: "Pending" | "Processing" | "Ready" | "Failed"// res.data.url: string | null (resolved URL when Ready)// res.data.locations: Array<{ provider, role, ref, ... }>// res.data.archive?: { totalFiles, manifest: [...] } (Directory only)Poll at ~2s intervals until status === "Ready" or "Failed".
Enumerate a Directory’s children
Section titled “Enumerate a Directory’s children”const res = await client.media.listChildren({ mediaId, limit: 100, cursor: nextCursor,});// res.data.entries[].key, .size, .mimeType, .idFetch one child’s full Entity (including a resolved URL):
const res = await client.media.getChild({ mediaId, path: "index.html",});// res.data.url, .status, .locationsArchive to Arweave
Section titled “Archive to Arweave”await client.media.publish({ mediaId });File→ publishes the blob to Arweave.Directory→ publishes a manifest over all children.
Idempotent. Adds an Arweave entry to the asset’s locations.
For collection metadata specifically, prefer client.collection.finalizeBaseUri — it archives the token-metadata directory and flips the on-chain baseURI in one call.
Delete
Section titled “Delete”await client.media.delete({ mediaId });Returns MediaInUseError (409) if the media is referenced by a deployed contract or live generative code. Arweave locations are immutable and remain on-chain.
Size limits
Section titled “Size limits”| Kind | Max |
|---|---|
| File (image) | 50 MB |
| File (audio) | 250 MB |
| File (video) | 500 MB |
| File (metadata) | 1 MB |
| Directory | 1 GB |
Related
Section titled “Related”- Media & storage concept
- Media upload flow — end-to-end pattern
- Errors: media errors — typed failures
- REST API: media