Files
react-editor-shopify/services/media-adapter.ts
2026-05-05 13:42:40 -04:00

66 lines
2.0 KiB
TypeScript

import type {
MediaAdapter,
MediaItem,
MediaPage,
} from "@reacteditor/plugin-media";
const MEDIA_BASE = "https://www.frontend-ai.com";
const MEDIA_API_KEY = (import.meta.env.VITE_API_KEY as string | undefined) ?? "";
export const frontendAiMediaAdapter: MediaAdapter = {
fetchList: async ({ query, cursor, signal }) => {
const url = new URL("/api/media", MEDIA_BASE);
if (query) url.searchParams.set("query", query);
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
method: "GET",
headers: { "X-Api-Key": MEDIA_API_KEY },
signal,
});
if (!res.ok) throw new Error(`List failed: ${res.status}`);
return (await res.json()) as MediaPage;
},
upload: (file, opts) =>
new Promise<MediaItem>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("POST", `${MEDIA_BASE}/api/media`);
xhr.setRequestHeader("X-Api-Key", MEDIA_API_KEY);
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) opts?.onProgress?.(e.loaded / e.total);
};
xhr.onload = () => {
if (xhr.status >= 400) {
reject(new Error(xhr.responseText || `Upload failed: ${xhr.status}`));
return;
}
try {
resolve(JSON.parse(xhr.responseText) as MediaItem);
} catch (err) {
reject(err instanceof Error ? err : new Error(String(err)));
}
};
xhr.onerror = () => reject(new Error("Network error"));
xhr.onabort = () => {
const err = new Error("Aborted");
err.name = "AbortError";
reject(err);
};
opts?.signal?.addEventListener("abort", () => xhr.abort());
const fd = new FormData();
fd.append("file", file);
xhr.send(fd);
}),
delete: async (id) => {
const res = await fetch(
`${MEDIA_BASE}/api/media/${encodeURIComponent(id)}`,
{
method: "DELETE",
headers: { "X-Api-Key": MEDIA_API_KEY },
},
);
if (!res.ok) throw new Error(`Delete failed: ${res.status}`);
},
};