Skip to main content
Glama
Southclaws

Storyden

by Southclaws
useImageUpload.ts3.79 kB
import { assetUpload } from "src/api/openapi-client/assets"; import { getAssetUploadMutationKey } from "@/api/openapi-client/assets"; import { APIError, Asset, AssetUploadParams } from "@/api/openapi-schema"; import { API_ADDRESS } from "@/config"; import { deriveError } from "@/utils/error"; export function useImageUpload() { async function upload(f: File, params?: AssetUploadParams) { if (!isSupportedImage(f.type)) { throw new Error(`Unsupported image format ${f.type}`); } const asset = await assetUpload(f, params); return asset; } async function uploadWithProgress( f: File, onProgress: (progress: number) => void, params?: AssetUploadParams, abortController?: AbortController, ): Promise<Asset> { if (!isSupportedImage(f.type)) { throw new Error(`Unsupported image format ${f.type}`); } const url = buildAssetUploadURL(params); return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.withCredentials = true; if (abortController) { abortController.signal.addEventListener("abort", () => { xhr.abort(); }); } xhr.upload.addEventListener("progress", (event) => { if (event.lengthComputable) { const progress = (event.loaded / event.total) * 100; onProgress(progress); } }); xhr.addEventListener("load", () => { if (xhr.status >= 200 && xhr.status < 300) { try { // TODO: Validate this properly, remove "as". const asset = JSON.parse(xhr.responseText) as Asset; resolve(asset); } catch (error) { reject(new Error("Failed to parse upload response")); } } else { try { // TODO: Validate this properly, remove "as". const apiError = JSON.parse(xhr.responseText) as APIError; // NOTE: Derive error should also handle these cases. reject( new Error( deriveError( apiError.message || apiError.error || "Upload failed", ), ), ); } catch { reject(new Error(`Upload failed with status ${xhr.status}`)); } } }); xhr.addEventListener("error", () => { reject(new Error("Network error during upload")); }); xhr.addEventListener("abort", () => { reject(new Error("Upload cancelled")); }); xhr.open("POST", url.toString()); xhr.setRequestHeader("Content-Type", "application/octet-stream"); // Send the file directly as the body xhr.send(f); }); } return { upload, uploadWithProgress, }; } // TODO: Support uploading arbitrary files. export function isSupportedImage(mime: string): boolean { const category = mime.split("/")[0]; switch (category) { case "image": return true; default: return false; } } export function hasImageFile( items: DataTransferItemList | DataTransferItem[], ): boolean { const itemArray = Array.from(items); return itemArray.some((item) => { if ("kind" in item && item.kind !== "file") { return false; } return item.type.startsWith("image/"); }); } export function getImageFiles(files: FileList | File[]): File[] { return Array.from(files).filter((file) => isSupportedImage(file.type)); } function buildAssetUploadURL(params?: AssetUploadParams): URL { const [uploadPath, uploadParams] = getAssetUploadMutationKey(params); const query = uploadParams ? "?" + new URLSearchParams(uploadParams).toString() : ""; const path = "/api" + uploadPath + query; const url = new URL(path, API_ADDRESS); return url; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server