← Files WixARCHIVED FILE

skills/wix-headless-templates/shared/capabilities/media-upload/app/wix/media-upload/client.ts

1.5 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

// Safe browser half of the optional Media Upload capability.
// The browser supplies bytes only. It cannot choose a destination or elevate a Wix call:
// the named policy is enforced by /api/wix/media-upload on the server.

export type UploadedMedia = {
  id: string;
  url?: string;
  uploadUrl: string;
};

type UploadPolicyRequest = {
  policyId: string;
  fileName: string;
  mimeType: string;
  sizeInBytes: number;
};

export async function uploadMedia(policyId: string, file: File | Blob, fileName?: string): Promise<UploadedMedia> {
  const mimeType = file.type;
  const request: UploadPolicyRequest = {
    policyId,
    fileName: fileName ?? (file instanceof File ? file.name : "upload"),
    mimeType,
    sizeInBytes: file.size,
  };
  const ticket = await fetch("/api/wix/media-upload", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(request),
  });
  if (!ticket.ok) throw new Error(`Upload could not be authorized (${ticket.status})`);
  const { uploadUrl } = (await ticket.json()) as UploadedMedia;

  const uploaded = await fetch(uploadUrl, {
    method: "PUT",
    headers: { "Content-Type": mimeType },
    body: file,
  });
  const payload = (await uploaded.json().catch(() => null)) as
    | { file?: { id?: string; url?: string }; id?: string; url?: string }
    | null;
  const media = payload?.file ?? payload;
  if (!uploaded.ok || !media?.id) throw new Error(`Upload failed (${uploaded.status})`);

  return { id: media.id, url: media.url, uploadUrl };
}

SHA-256: ccbabff8cc4031c918cce07914c58e1669fd694b79be09cdd37095b19eb2152a