UNPKG

socaity

Version:

SDK for Generative AI. Build AI-powered applications with ease

1,602 lines 108 kB
var ie = Object.defineProperty; var re = (o, e, t) => e in o ? ie(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t; var l = (o, e, t) => re(o, typeof e != "symbol" ? e + "" : e, t); class z extends Error { constructor(e = "Invalid API key format. API keys should start with 'sk_' and be 67 characters long.") { super(e), this.name = "ApiKeyError", Error.captureStackTrace && Error.captureStackTrace(this, z); } } const T = class T { constructor(e = {}) { l(this, "apiKey"); l(this, "baseUrl"); l(this, "pollInterval"); l(this, "maxRetries"); this.apiKey = e.apiKey, this.baseUrl = e.baseUrl || "https://api.socaity.ai/v1", this.pollInterval = e.pollInterval || 5e3, this.maxRetries = e.maxRetries || 3; } /** * Get the global configuration instance */ static getInstance() { return T.instance || (T.instance = new T()), T.instance; } /** * Updates global configuration with new values */ static update(e) { if (e.apiKey !== void 0) { if (!e.apiKey.startsWith("sk_") && !e.apiKey.startsWith("tk_") && !e.apiKey.startsWith("ey")) throw new z("Invalid authentication token. Use either a Socaity API key from https://www.socaity.ai or a valid JWT token."); if (e.apiKey.startsWith("sk_") && !e.apiKey.startsWith("tk_") && e.apiKey.length !== 67) throw new z("Invalid API key format. API keys should be 67 characters long. Get your API key from https://www.socaity.ai"); } const t = T.getInstance(); Object.assign(t, e); } }; l(T, "instance"); let L = T; var m = /* @__PURE__ */ ((o) => (o.CREATED = "CREATED", o.QUEUED = "QUEUED", o.PROCESSING = "PROCESSING", o.COMPLETED = "COMPLETED", o.FAILED = "FAILED", o.UNKNOWN = "UNKNOWN", o))(m || {}), w = /* @__PURE__ */ ((o) => (o.INITIALIZING = "INITIALIZING", o.PREPARING = "PREPARING", o.SENDING = "SENDING", o.TRACKING = "TRACKING", o.PROCESSING_RESULT = "PROCESSING_RESULT", o.COMPLETED = "COMPLETED", o.FAILED = "FAILED", o))(w || {}); class ne { /** * Parse response into standardized job format * @param response - API response object or string * @returns Standardized SocaityJob object */ async parse(e) { if (e == null) return this.createErrorJob("No response received"); if (typeof e == "string") try { const t = JSON.parse(e); return this.parseObject(t); } catch { return { id: "", status: m.COMPLETED, progress: { progress: 1, message: null }, result: e, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() }; } return this.parseObject(e); } /** * Parse object responses into SocaityJob * @param response - Object to parse */ async parseObject(e) { if (typeof e != "object" || e === null) return this.createErrorJob("Invalid response format"); console.log("raw_response", e); const t = e, s = typeof t.id == "string" ? t.id : "", i = this.parseStatus(t.status), r = this.parseProgress(t, i), n = typeof t.error == "string" ? t.error : null, a = typeof t.refresh_job_url == "string" ? t.refresh_job_url : void 0, c = this.parseDate(t.createdAt), f = this.parseDate(t.updatedAt); return { id: s, status: i, progress: r, result: t.result, error: n, createdAt: c, updatedAt: f, refresh_job_url: a }; } /** * Creates a standard error job response * @param errorMessage - Error message to include */ createErrorJob(e) { const t = /* @__PURE__ */ new Date(); return { id: "", status: m.FAILED, progress: { progress: 0, message: e }, result: null, error: e, createdAt: t, updatedAt: t }; } /** * Parse date from various formats * @param dateValue - Date value to parse */ parseDate(e) { if (e instanceof Date) return e; if (typeof e == "string" || typeof e == "number") { const t = new Date(e); if (!isNaN(t.getTime())) return t; } return /* @__PURE__ */ new Date(); } /** * Parse status from different API formats * @param status - Status string to parse */ parseStatus(e) { if (typeof e != "string" || !e) return m.UNKNOWN; const t = e.toUpperCase(); return { COMPLETED: m.COMPLETED, SUCCEEDED: m.COMPLETED, FINISHED: m.COMPLETED, CREATED: m.CREATED, FAILED: m.FAILED, ERROR: m.FAILED, IN_PROGRESS: m.PROCESSING, PROCESSING: m.PROCESSING, RUNNING: m.PROCESSING, BOOTING: m.PROCESSING, QUEUED: m.QUEUED, PENDING: m.QUEUED, IN_QUEUE: m.QUEUED, STARTING: m.QUEUED }[t] || m.UNKNOWN; } /** * Parse progress from different API formats * @param response - Response object containing progress information * @param status - Parsed job status */ parseProgress(e, t) { let s = 0, i = null; const r = e.progress; if (typeof r == "number") s = r; else if (typeof r == "string") try { s = parseFloat(r); } catch { s = 0; } else if (r && typeof r == "object") { const n = r; if (typeof n.progress == "number") s = n.progress; else if (typeof n.progress == "string") try { s = parseFloat(n.progress); } catch { s = 0; } i = typeof n.message == "string" ? n.message : null; } return isNaN(s) && (s = 0), s = Math.max(0, Math.min(1, s)), t === m.COMPLETED && (s = 1), !i && typeof e.message == "string" && (i = e.message), { progress: s, message: i }; } } var oe = Object.defineProperty, ae = (o, e, t) => e in o ? oe(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t, b = (o, e, t) => ae(o, typeof e != "symbol" ? e + "" : e, t); const C = { mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", aac: "audio/aac", flac: "audio/flac", m4a: "audio/mp4", webm: "audio/webm" }, I = { mp4: "video/mp4", mov: "video/quicktime", avi: "video/x-msvideo", mkv: "video/x-matroska", wmv: "video/x-ms-wmv", webm: "video/webm", "3gp": "video/3gpp", flv: "video/x-flv" }, S = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", bmp: "image/bmp", ico: "image/x-icon", tiff: "image/tiff", tif: "image/tiff", avif: "image/avif" }, le = { pdf: "application/pdf", txt: "text/plain", html: "text/html", htm: "text/html", json: "application/json", js: "application/javascript", css: "text/css", xml: "application/xml", zip: "application/zip", csv: "text/csv", npz: "application/octet-stream" }, Q = { ...C, ...I, ...S, ...le }; function we(o) { const e = []; switch (o) { case "audio": e.push(...Object.values(C)), e.push(...Object.keys(C).map((t) => `.${t}`)); break; case "video": e.push(...Object.values(I)), e.push(...Object.keys(I).map((t) => `.${t}`)); break; case "image": e.push(...Object.values(S)), e.push(...Object.keys(S).map((t) => `.${t}`)); break; case "file": default: return ["*/*"]; } return e; } function be(o) { return { audio: "Audio", video: "Video", image: "Images", file: "Files" }[o] || o; } function _e(o) { return Object.values(C).includes(o) ? "audio" : Object.values(I).includes(o) ? "video" : Object.values(S).includes(o) ? "image" : null; } function K(o) { const e = (o.startsWith(".") ? o.slice(1) : o).toLowerCase(); return e in Q ? Q[e] : null; } const F = typeof window > "u"; async function Y(o) { if (o == null) return null; if (Array.isArray(o)) { const e = o.map((t) => Y(t)); return Promise.all(e); } if (G(o)) try { return await new p().fromDict(o); } catch { return o; } return o; } async function ce(o) { var e; if (o instanceof p) return o.getContentType(); if (G(o)) return o.content_type; if (X(o)) return o.type; if (typeof o == "string" && x(o)) { const t = (e = new URL(o).pathname.split(".").pop()) == null ? void 0 : e.toLowerCase(); if (t) { const s = K(t); if (s) return s; } try { const s = await fetch(o, { method: "HEAD", headers: { "User-Agent": "MediaFile/1.0.0" } }); if (s.ok) { const i = s.headers.get("content-type"); if (i) return i; } } catch { } } if (typeof o == "string" && o.startsWith("data:")) { const t = o.match(/^data:([^;,]+)/); if (t && t[1]) return t[1]; } if (typeof o == "string" && typeof window > "u") try { const t = await import("fs/promises"), s = await import("path"); await t.access(o); const i = s.extname(o).slice(1).toLowerCase(); if (i) { const r = K(i); if (r) return r; } } catch { } return typeof Blob < "u" && o instanceof Blob ? o.type : null; } function x(o) { try { const e = new URL(o); return e.protocol === "http:" || e.protocol === "https:"; } catch { return !1; } } function Fe(o) { if (typeof o != "string" || !x(o)) return null; try { const e = ((new URL(o).pathname || "").split("/").pop() || "").split("?")[0].split("#")[0].split("."), t = e.length > 1 ? e.pop().toLowerCase() : ""; return t ? K(t) : null; } catch { return null; } } function he(o) { return o.startsWith("data:") || ue(o); } function ue(o) { return /^[A-Za-z0-9+/=]+$/.test(o) && o.length % 4 === 0; } async function V(o) { if (!F) return !1; try { return (await (await import("fs/promises")).stat(o)).isFile(); } catch { return !1; } } function X(o) { return o && typeof o == "object" && typeof o.data == "string" && typeof o.type == "string" && typeof o.name == "string"; } function G(o) { return o && typeof o == "object" && "file_name" in o && "content_type" in o && "content" in o; } class j { /** * Create a MediaFile or specialized subclass from any supported data type. * Automatically detects data type and instantiates the appropriate class. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a MediaFile instance or specialized subclass */ static async create(e) { if (e == null) throw new Error("Cannot create MediaFile from null or undefined data"); const t = await ce(e); let s = N.default; return t && t.startsWith("image/") ? s = N.image : t && t.startsWith("audio/") ? s = N.audio : t && t.startsWith("video/") && (s = N.video), new s().fromAny(e); } } class p { /** * Creates a new MediaFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use */ constructor(e = "file", t = "application/octet-stream") { b(this, "content_type"), b(this, "file_name"), b(this, "_content", null), this.content_type = t, this.file_name = e; } /** * Factory method to create a MediaFile from any supported data type. * This is kept for backward compatibility. New code should use MediaFileFactory.create(). * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a MediaFile instance or specialized subclass * @deprecated Use MediaFileFactory.create() instead */ static async create(e) { return j.create(e); } /** * Load a file from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @param websafe - Prevents loading from file paths and malformatted base64 strings. * @returns Promise resolving to a MediaFile instance or null */ async fromAny(e) { if (e == null) throw new Error("Cannot create MediaFile from null or undefined data"); if (e instanceof p) return e; if (X(e)) { if (this.file_name = e.name || "file", this.content_type = e.type, typeof e.data == "string") return this.fromBase64(e.data); throw new Error("Invalid data format in FileReader object"); } if (F && this._isBuffer(e)) return this.fromBytes(e); if (typeof File < "u" && e instanceof File) { this.file_name = e.name, this.content_type = e.type || "application/octet-stream"; const t = await e.arrayBuffer(); return this.fromBytes(t); } if (typeof Blob < "u" && e instanceof Blob) { const t = await e.arrayBuffer(); return this.fromBytes(t); } if (e instanceof ArrayBuffer || e instanceof Uint8Array) return this.fromBytes(e); if (typeof e == "string") { if (x(e)) return await this.fromUrl(e); if (he(e)) return this.fromBase64(e); if (await V(e)) return await this.fromFile(e); throw typeof e == "string" ? new Error("Invalid data type for MediaFile " + e) : new Error("Invalid data type for MediaFile"); } return G(e) ? await this.fromDict(e) : this; } /** * Load file from a file path (Node.js only). * * @param filePath - Path to the file * @returns Promise resolving to the MediaFile instance */ async fromFile(e) { if (!F) throw new Error("Loading from file path is only supported in Node.js environment"); try { const t = await (await import("fs/promises")).readFile(e), s = await import("path"); return this.file_name = s.basename(e), this._content = this._bufferToArrayBuffer(t), this._setContentTypeFromFileName(), this; } catch (t) { throw new Error(`Failed to load file from path: ${e}. ${t.message}`); } } /** * Load file from a URL. * * @param url - URL to fetch the file from * @param headers - Optional headers for the request * @returns Promise resolving to the MediaFile instance */ async fromUrl(e, t) { const s = async (i, r) => await fetch(i, { headers: r || { "User-Agent": "MediaFile/1.0.0" } }); try { let i = await s(e, t); if (!i.ok) { if (i.status === 401 || i.status === 403) { const n = new URL(e); n.search = "", i = await s(n.toString(), t); } if (!i.ok) throw new Error(`HTTP error! Status: ${i.status}`); } this.content_type = i.headers.get("content-type") || "application/octet-stream"; const r = i.headers.get("content-disposition"); if (r) { const n = r.match(/filename=(?:['"]?)([^'";\n]+)/i); n && n[1] && (this.file_name = n[1]); } if (!this.file_name || this.file_name === "file") { const n = new URL(e).pathname.split("/"), a = n[n.length - 1]; a && a.trim() !== "" ? this.file_name = decodeURIComponent(a) : this.file_name = "downloaded_file"; } return this._content = await i.arrayBuffer(), this; } catch (i) { throw new Error(`Failed to load file from URL: ${e}. ${i.message}`); } } /** * Load file from base64 encoded string. * * @param base64Data - Base64 encoded string, optionally with data URI prefix * @returns The MediaFile instance */ fromBase64(e) { const { data: t, mediaType: s } = this._parseBase64Uri(e); s && (this.content_type = s); try { return this._content = F ? this._decodeBase64NodeJs(t) : this._decodeBase64Browser(t), this; } catch (i) { throw new Error(`Failed to decode base64 data: ${i.message}`); } } /** * Load file from binary data. * * @param data - ArrayBuffer, Buffer, or Uint8Array containing the file data * @returns The MediaFile instance */ fromBytes(e) { if (typeof SharedArrayBuffer < "u" && e instanceof SharedArrayBuffer) { const i = new Uint8Array(e), r = new ArrayBuffer(i.byteLength); return new Uint8Array(r).set(i), this._content = r, this; } if (e instanceof Uint8Array) { if (typeof SharedArrayBuffer < "u" && e.buffer instanceof SharedArrayBuffer) { const i = new ArrayBuffer(e.byteLength); new Uint8Array(i).set(e), this._content = i; } else this._content = e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength); return this; } if (F && this._isBuffer(e)) { const i = e; if (typeof SharedArrayBuffer < "u" && i.buffer instanceof SharedArrayBuffer) { const r = new ArrayBuffer(i.byteLength); new Uint8Array(r).set(i), this._content = r; } else this._content = i.buffer.slice(i.byteOffset, i.byteOffset + i.byteLength); return this; } const t = new Uint8Array(e), s = new ArrayBuffer(t.byteLength); return new Uint8Array(s).set(t), this._content = s, this; } /** * Load file from a FileResult object. * * @param fileResult - FileResult object with file metadata and base64 content * @returns The MediaFile instance */ async fromDict(e) { if (!e.content) throw new Error("Invalid FileResult object: missing content"); return this.file_name = e.file_name, this.content_type = e.content_type, await this.fromAny(e.content); } /** * Convert the file to a Blob (browser only). * * @returns Blob object representing the file */ toBlob() { if (this._ensureContent(), typeof Blob > "u") throw new Error("Blob is not available in this environment"); return new Blob([new Uint8Array(this._content)], { type: this.content_type }); } /** * Convert the file to an ArrayBuffer. * * @returns ArrayBuffer containing the file data */ toArrayBuffer() { return this._ensureContent(), this._content; } /** * Convert the file to a Uint8Array. * * @returns Uint8Array containing the file data */ toUint8Array() { return this._ensureContent(), new Uint8Array(this._content); } /** * Convert the file to a Node.js Buffer (Node.js only). * * @returns Buffer containing the file data */ toBuffer() { if (this._ensureContent(), !F) throw new Error("Buffer is only available in Node.js environment"); return Buffer.from(this._content); } /** * Convert the file to a base64 encoded string. * * @param includeDataUri - Whether to include the data URI prefix * @returns Base64 encoded string of the file data */ toBase64(e = !0) { this._ensureContent(); let t; if (F) t = Buffer.from(this._content).toString("base64"); else { const s = new Uint8Array(this._content); let i = ""; const r = 10240; for (let n = 0; n < s.length; n += r) { const a = s.subarray(n, Math.min(n + r, s.length)); i += String.fromCharCode.apply(null, Array.from(a)); } t = btoa(i); } return e ? `data:${this.content_type};base64,${t}` : t; } /** * Convert the file to a FileResult object. * * @returns FileResult object with file metadata and base64 content */ toJson() { return { file_name: this.file_name, content_type: this.content_type, content: this.toBase64() }; } /** * Save the file to disk (Node.js) or trigger download (browser). * * @param filePath - Optional file path (Node.js) or filename (browser) * @returns Promise that resolves when the file is saved */ async save(e) { this._ensureContent(); const t = e || this.file_name; if (F) try { const s = await import("fs/promises").then((n) => n.default || n), i = await import("path").then((n) => n.default || n); if (!i || typeof i.dirname != "function") throw new Error("Failed to load 'path' module."); const r = i.dirname(t); r !== "." && await s.mkdir(r, { recursive: !0 }).catch(() => { }), await s.writeFile(t, Buffer.from(this._content)); } catch (s) { throw new Error(`Failed to save file: ${s.message}`); } else { const s = this.toBlob(), i = URL.createObjectURL(s), r = document.createElement("a"); r.href = i, r.download = t, document.body.appendChild(r), r.click(), setTimeout(() => { document.body.removeChild(r), URL.revokeObjectURL(i); }, 100); } } /** * Get the file size in bytes. * * @param unit - Unit to return the size in ('bytes', 'kb', 'mb', or 'gb') * @returns File size in the specified unit */ fileSize(e = "bytes") { if (!this._content) return 0; const t = this._content.byteLength; switch (e) { case "kb": return t / 1024; case "mb": return t / (1024 * 1024); case "gb": return t / (1024 * 1024 * 1024); default: return t; } } /** * Get the file extension based on the content type or filename. * * @returns File extension without the leading dot, or null if it cannot be determined */ get extension() { var e; if (this.content_type && this.content_type !== "application/octet-stream") { const t = { "image/jpeg": "jpg", "image/png": "png", "image/gif": "gif", "image/webp": "webp", "image/svg+xml": "svg", "audio/mpeg": "mp3", "audio/wav": "wav", "audio/ogg": "ogg", "video/mp4": "mp4", "video/quicktime": "mov", "application/pdf": "pdf", "text/plain": "txt", "text/html": "html", "application/json": "json" }; if (this.content_type in t) return t[this.content_type]; if (F) try { const s = require("mime-types").extension(this.content_type); if (s) return s; } catch { } } return this.file_name && this.file_name.includes(".") && ((e = this.file_name.split(".").pop()) == null ? void 0 : e.toLowerCase()) || null; } /** * Get the filename. */ getFileName() { return this.file_name; } /** * Set the filename. */ setFileName(e) { this.file_name = e; } /** * Get the content type. */ getContentType() { return this.content_type; } /** * Set the content type. */ setContentType(e) { this.content_type = e; } /** * Read raw file data. * * @returns ArrayBuffer containing the file data */ read() { return this._ensureContent(), this._content; } /** * Check if the file is empty. * * @returns Boolean indicating if the file has content */ isEmpty() { return !this._content || this._content.byteLength === 0; } /** * Get info about the file. * * @returns Object with file information */ getInfo() { return { fileName: this.file_name, contentType: this.content_type, size: this.fileSize(), extension: this.extension }; } /** * Detect MIME type for the file based on file extension. * Updates the content_type property. * * @private */ _setContentTypeFromFileName() { var e; if (!this.file_name) return; const t = (e = this.file_name.split(".").pop()) == null ? void 0 : e.toLowerCase(); if (!t) return; if (F) try { const i = require("mime-types").lookup(this.file_name); if (i) { this.content_type = i; return; } } catch { } const s = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", mp4: "video/mp4", mov: "video/quicktime", pdf: "application/pdf", txt: "text/plain", html: "text/html", htm: "text/html", json: "application/json", js: "application/javascript", css: "text/css", xml: "application/xml", zip: "application/zip" }; t in s && (this.content_type = s[t]); } /** * Parse a base64 data URI into content and media type. * * @param data - Base64 string, potentially with data URI prefix * @returns Object containing the parsed data and media type * @private */ _parseBase64Uri(e) { if (e.startsWith("data:")) { const [t, s] = e.split(",", 2), i = t.match(/^data:([^;,]+)/), r = i ? i[1] : null; return { data: s, mediaType: r }; } return { data: e, mediaType: null }; } /** * Ensure content exists before operating on it. * * @private */ _ensureContent() { if (!this._content) throw new Error("No content available. Load content first using fromFile, fromUrl, etc."); } /** * Check if an object is a Buffer. * * @param obj - Object to check * @returns Whether the object is a Buffer * @private */ _isBuffer(e) { return F && Buffer.isBuffer(e); } /** * Decode base64 string in Node.js environment. * * @param base64 - Base64 string to decode * @returns ArrayBuffer containing the decoded data * @private */ _decodeBase64NodeJs(e) { const t = Buffer.from(e, "base64"); return this._bufferToArrayBuffer(t); } /** * Decode base64 string in browser environment. * * @param base64 - Base64 string to decode * @returns ArrayBuffer containing the decoded data * @private */ _decodeBase64Browser(e) { const t = atob(e), s = new Uint8Array(t.length); for (let i = 0; i < t.length; i++) s[i] = t.charCodeAt(i); return s.buffer; } /** * Convert a Node.js Buffer to an ArrayBuffer. * * @param buffer - Buffer to convert * @returns ArrayBuffer containing the data * @private */ _bufferToArrayBuffer(e) { if (typeof SharedArrayBuffer < "u" && e.buffer instanceof SharedArrayBuffer) { const t = new ArrayBuffer(e.byteLength); return new Uint8Array(t).set(new Uint8Array(e)), t; } else return e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength); } } class R extends p { /** * Creates a new ImageFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to image/png) */ constructor(e = "image", t = "image/png") { super(e, t); } /** * Factory method to create an ImageFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to an ImageFile instance */ static async create(e) { if (e == null) throw new Error("Cannot create ImageFile from null or undefined data"); return new R().fromAny(e); } /** * Override fromAny to ensure the content type is an image type. * * @param data - Data to load * @returns Promise resolving to an ImageFile instance */ async fromAny(e) { if (e instanceof R) return e; if (e instanceof p && !(e instanceof R)) { if (e.isEmpty()) throw new Error("Cannot create ImageFile from empty MediaFile"); return this.file_name = e.getFileName() || "image", this.content_type = e.getContentType(), this._content = e.read(), this._validateImageContentType(), this; } const t = await super.fromAny(e); return t.file_name = t.file_name || "image", t._validateImageContentType(), t; } /** * Creates an HTML image element from the image data. * * @param options - Optional image element attributes (width, height, alt, className) * @returns HTML string containing an image element */ toImageElement(e = {}) { if (typeof window > "u") throw new Error("Image elements are only available in browser environments"); this._ensureContent(); const t = this.toBase64(), { width: s, height: i, alt: r = "", className: n = "" } = e, a = s ? ` width="${s}"` : "", c = i ? ` height="${i}"` : "", f = n ? ` class="${n}"` : ""; return `<img src="${t}" alt="${r}"${a}${c}${f}>`; } /** * Create an actual DOM Image element (browser only). * * @param options - Optional image element attributes * @returns HTMLImageElement that can be added to the DOM */ toDOMImageElement(e = {}) { if (typeof window > "u") throw new Error("DOM Image elements are only available in browser environments"); this._ensureContent(); const t = this.toBlob(), s = URL.createObjectURL(t), i = new Image(); return e.width && (i.width = e.width), e.height && (i.height = e.height), e.alt && (i.alt = e.alt), e.className && (i.className = e.className), i.src = s, i.addEventListener("load", () => { setTimeout(() => URL.revokeObjectURL(s), 1e3); }), i; } /** * Get image dimensions (browser only). * * @returns Promise resolving to an object with width and height */ async getDimensions() { if (typeof window > "u") throw new Error("Getting image dimensions is only available in browser environments"); return new Promise((e, t) => { const s = new Image(); s.onload = () => { e({ width: s.naturalWidth, height: s.naturalHeight }); }, s.onerror = () => { t(new Error("Failed to load image for dimension calculation")); }; const i = this.toBlob(), r = URL.createObjectURL(i); s.src = r, s.addEventListener("load", () => { URL.revokeObjectURL(r); }, { once: !0 }); }); } /** * Validate that the content type is an image type. * If not, attempt to correct it based on file extension. * * @private */ _validateImageContentType() { var e; if (this.content_type.startsWith("image/")) return; const t = (e = this.extension) == null ? void 0 : e.toLowerCase(); if (t && t in S) { this.content_type = S[t]; return; } this._content && this._detectImageFormat(); } /** * Attempt to detect image format from file header. * Updates content_type if a format is detected. * * @private */ _detectImageFormat() { const e = new Uint8Array(this._content).slice(0, 12); if (e[0] === 255 && e[1] === 216 && e[2] === 255) { this.content_type = S.jpeg; return; } if (e[0] === 137 && e[1] === 80 && e[2] === 78 && e[3] === 71 && e[4] === 13 && e[5] === 10 && e[6] === 26 && e[7] === 10) { this.content_type = S.png; return; } if (e[0] === 71 && e[1] === 73 && e[2] === 70 && e[3] === 56 && (e[4] === 55 || e[4] === 57) && e[5] === 97) { this.content_type = S.gif; return; } if (e[0] === 82 && e[1] === 73 && e[2] === 70 && e[3] === 70 && e[8] === 87 && e[9] === 69 && e[10] === 66 && e[11] === 80) { this.content_type = S.webp; return; } if (this._content.byteLength > 100 && new TextDecoder().decode(new Uint8Array(this._content.slice(0, 100))).indexOf("<svg") !== -1) { this.content_type = S.svg; return; } this.content_type = S.png; } } class M extends p { /** * Creates a new AudioFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to audio/mpeg) */ constructor(e = "audio", t = "audio/wav") { super(e, t); } /** * Factory method to create an AudioFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to an AudioFile instance */ static async create(e) { if (e == null) throw new Error("Cannot create AudioFile from null or undefined data"); return new M().fromAny(e); } /** * Override fromAny to ensure the content type is an audio type. * * @param data - Data to load * @returns Promise resolving to an AudioFile instance */ async fromAny(e) { if (e instanceof M) return e; if (e instanceof p && !(e instanceof M)) { if (e.isEmpty()) throw new Error("Cannot create AudioFile from empty MediaFile"); return this.file_name = e.getFileName() || "audio", this.content_type = e.getContentType(), this._content = e.read(), this._validateAudioContentType(), this; } const t = await super.fromAny(e); return t.file_name = t.file_name || "audio", t._validateAudioContentType(), t; } /** * Creates an HTML audio element from the audio data. * * @returns HTMLAudioElement that can be used for playback */ toAudioElement() { if (typeof window > "u") throw new Error("Audio elements are only available in browser environments"); this._ensureContent(); const e = this.toBlob(), t = URL.createObjectURL(e), s = new Audio(t); return s.addEventListener("canplaythrough", () => { setTimeout(() => URL.revokeObjectURL(t), 1e3); }), s; } /** * Play the audio (browser only). * * @returns Promise that resolves when audio playback starts */ async play() { if (typeof window > "u") throw new Error("Audio playback is only available in browser environments"); const e = this.toAudioElement(); return new Promise((t, s) => { e.addEventListener("play", () => t()), e.addEventListener("error", (i) => s(new Error(`Audio playback error: ${i}`))), e.play().catch(s); }); } /** * Get duration of the audio file in seconds (browser only). * * @returns Promise resolving to the duration in seconds */ async getDuration() { if (typeof window > "u") throw new Error("Getting audio duration is only available in browser environments"); const e = this.toAudioElement(); return new Promise((t) => { if (e.duration && !isNaN(e.duration)) { t(e.duration); return; } e.addEventListener("loadedmetadata", () => { t(e.duration); }); }); } /** * Create an embedded HTML audio player. * * @param options - Options for the audio player (controls, autoplay, loop) * @returns HTML string containing an audio element */ toHTMLPlayer(e = {}) { const t = this.toBase64(), { controls: s = !0, autoplay: i = !1, loop: r = !1 } = e; return `<audio src="${t}" ${s ? "controls" : ""} ${i ? "autoplay" : ""} ${r ? "loop" : ""}> Your browser does not support the audio element. </audio>`; } /** * Validate that the content type is an audio type. * If not, attempt to correct it based on file extension. * * @private */ _validateAudioContentType() { var e; if (this.content_type.startsWith("audio/")) return; const t = (e = this.extension) == null ? void 0 : e.toLowerCase(); if (t && t in C) { this.content_type = C[t]; return; } this._content && this._detectAudioFormat(); } /** * Attempt to detect audio format from file header. * Updates content_type if a format is detected. * * @private */ _detectAudioFormat() { const e = new Uint8Array(this._content).slice(0, 12); if (e[0] === 73 && e[1] === 68 && e[2] === 51) { this.content_type = C.mp3; return; } if (e[0] === 255 && (e[1] & 224) === 224) { this.content_type = C.mp3; return; } if (e[0] === 82 && e[1] === 73 && e[2] === 70 && e[3] === 70 && e[8] === 87 && e[9] === 65 && e[10] === 86 && e[11] === 69) { this.content_type = C.wav; return; } if (e[0] === 79 && e[1] === 103 && e[2] === 103 && e[3] === 83) { this.content_type = C.ogg; return; } if (e[0] === 102 && e[1] === 76 && e[2] === 97 && e[3] === 67) { this.content_type = C.flac; return; } this.content_type = C.mp3; } } class $ extends p { /** * Creates a new VideoFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to video/mp4) */ constructor(e = "video", t = "video/mp4") { super(e, t); } /** * Factory method to create a VideoFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a VideoFile instance */ static async create(e) { if (e == null) throw new Error("Cannot create VideoFile from null or undefined data"); return new $().fromAny(e); } /** * Override fromAny to ensure the content type is a video type. * * @param data - Data to load * @returns Promise resolving to a VideoFile instance */ async fromAny(e) { if (e instanceof $) return e; if (e instanceof p && !(e instanceof $)) { if (e.isEmpty()) throw new Error("Cannot create VideoFile from empty MediaFile"); return this.file_name = e.getFileName() || "video", this.content_type = e.getContentType(), this._content = e.read(), this._validateVideoContentType(), this; } const t = await super.fromAny(e); return t.file_name = t.file_name || "video", t._validateVideoContentType(), t; } /** * Creates an HTML video element from the video data. * * @returns HTMLVideoElement that can be used for playback */ toVideoElement() { if (typeof window > "u") throw new Error("Video elements are only available in browser environments"); this._ensureContent(); const e = this.toBlob(), t = URL.createObjectURL(e), s = document.createElement("video"); return s.src = t, s.addEventListener("loadedmetadata", () => { setTimeout(() => URL.revokeObjectURL(t), 1e3); }), s; } /** * Play the video (browser only). * * @returns Promise that resolves when video playback starts */ async play() { if (typeof window > "u") throw new Error("Video playback is only available in browser environments"); const e = this.toVideoElement(); return new Promise((t, s) => { e.addEventListener("play", () => t()), e.addEventListener("error", (i) => s(new Error(`Video playback error: ${i}`))), e.play().catch(s); }); } /** * Get duration of the video file in seconds (browser only). * * @returns Promise resolving to the duration in seconds */ async getDuration() { if (typeof window > "u") throw new Error("Getting video duration is only available in browser environments"); const e = this.toVideoElement(); return new Promise((t) => { if (e.duration && !isNaN(e.duration)) { t(e.duration); return; } e.addEventListener("loadedmetadata", () => { t(e.duration); }); }); } /** * Get dimensions of the video (width and height). * * @returns Promise resolving to an object with width and height properties */ async getDimensions() { if (typeof window > "u") throw new Error("Getting video dimensions is only available in browser environments"); const e = this.toVideoElement(); return new Promise((t) => { if (e.videoWidth && e.videoHeight) { t({ width: e.videoWidth, height: e.videoHeight }); return; } e.addEventListener("loadedmetadata", () => { t({ width: e.videoWidth, height: e.videoHeight }); }); }); } /** * Create a thumbnail from the video at a specific time point. * * @param timeSeconds - Time in seconds for the thumbnail (defaults to 0) * @returns Promise resolving to a Blob containing the thumbnail image */ async createThumbnail(e = 0) { if (typeof window > "u") throw new Error("Creating thumbnails is only available in browser environments"); const t = this.toVideoElement(); return new Promise((s, i) => { t.addEventListener("loadedmetadata", async () => { try { t.currentTime = e, await new Promise((a) => { const c = () => { t.removeEventListener("seeked", c), a(); }; t.addEventListener("seeked", c); }); const r = document.createElement("canvas"); r.width = t.videoWidth, r.height = t.videoHeight; const n = r.getContext("2d"); if (!n) throw new Error("Failed to get canvas context"); n.drawImage(t, 0, 0, r.width, r.height), r.toBlob((a) => { a ? s(a) : i(new Error("Failed to create thumbnail blob")); }, "image/jpeg", 0.95); } catch (r) { i(r); } }), t.addEventListener("error", (r) => { i(new Error(`Video loading error: ${r}`)); }); }); } /** * Create an embedded HTML video player. * * @param options - Options for the video player * @returns HTML string containing a video element */ toHtmlPlayer(e = {}) { const t = this.toBase64(), { controls: s = !0, autoplay: i = !1, loop: r = !1, muted: n = !1, width: a, height: c, poster: f } = e; return `<video src="${t}" ${s ? "controls" : ""} ${i ? "autoplay" : ""} ${r ? "loop" : ""} ${n ? "muted" : ""} ${a ? `width="${a}"` : ""} ${c ? `height="${c}"` : ""} ${f ? `poster="${f}"` : ""}> Your browser does not support the video element. </video>`; } /** * Validate that the content type is a video type. * If not, attempt to correct it based on file extension. * * @private */ _validateVideoContentType() { var e; if (this.content_type.startsWith("video/")) return; const t = (e = this.extension) == null ? void 0 : e.toLowerCase(); if (t && t in I) { this.content_type = I[t]; return; } this._content && this._detectVideoFormat(); } /** * Attempt to detect video format from file header. * Updates content_type if a format is detected. * * @private */ _detectVideoFormat() { const e = new Uint8Array(this._content).slice(0, 16); if (e[4] === 102 && e[5] === 116 && e[6] === 121 && e[7] === 112) { this.content_type = I.mp4; return; } if (e[4] === 119 && e[5] === 105 && e[6] === 100 && e[7] === 101 || e[4] === 109 && e[5] === 100 && e[6] === 97 && e[7] === 116 || e[4] === 102 && e[5] === 114 && e[6] === 101 && e[7] === 101 || e[4] === 112 && e[5] === 110 && e[6] === 111 && e[7] === 116 || e[4] === 115 && e[5] === 107 && e[6] === 105 && e[7] === 112 || e[4] === 109 && e[5] === 111 && e[6] === 111 && e[7] === 118) { this.content_type = I.mov; return; } if (e[0] === 26 && e[1] === 69 && e[2] === 223 && e[3] === 163) { this.content_type = I.webm; return; } if (e[0] === 82 && e[1] === 73 && e[2] === 70 && e[3] === 70 && e[8] === 65 && e[9] === 86 && e[10] === 73 && e[11] === 32) { this.content_type = I.avi; return; } if (e[0] === 70 && e[1] === 76 && e[2] === 86) { this.content_type = I.flv; return; } if (e[4] === 102 && e[5] === 116 && e[6] === 121 && e[7] === 112 && e[8] === 51 && e[9] === 103 && e[10] === 112) { this.content_type = I["3gp"]; return; } this.content_type = I.mp4; } } class E { /** * Initialize MediaList with optional files and configuration. * * @param options - Configuration options */ constructor(e = {}) { b(this, "_mediaFiles", []), b(this, "_urlFiles", []), b(this, "_nonProcessableFiles", []), b(this, "_mediaContainers", []), b(this, "downloadFiles"), b(this, "readSystemFiles"), b(this, "fileName"), this.fileName = e.fileName || "MediaList", this.downloadFiles = e.downloadFiles !== void 0 ? e.downloadFiles : !0, this.readSystemFiles = e.readSystemFiles !== void 0 ? e.readSystemFiles : !0, e.files && this._initializeFiles(e.files); } /** * Initialize files synchronously (only for already-loaded MediaFile instances). * For async loading from URLs/paths, use fromAny() or extend() instead. * * @private */ _initializeFiles(e) { for (const t of e) t instanceof p ? this._addMediaFile(t) : this._nonProcessableFiles.push(t); } /** * Load files from any supported data sources. * This method processes files asynchronously. * * @param data - Array of data to load (URLs, paths, MediaFiles, etc.) * @returns Promise resolving to this MediaList instance */ async fromAny(e) { if (!e || !Array.isArray(e)) return this; for (const t of e) await this._processFile(t); return this; } /** * Process a single file and automatically categorize it. * * @param file - File to process (URL, path, MediaFile, etc.) * @returns Promise resolving to the processed file or original value * @private */ async _processFile(e) { if (e instanceof p) return this._addMediaFile(e), e; if (e == null || typeof e == "string" && e.length === 0) return this._nonProcessableFiles.push(e), e; if (typeof e == "string") { if (x(e)) { if (!this.downloadFiles) return this._urlFiles.push(e), e; try { const t = await j.create(e); return this._addMediaFile(t), t; } catch { return this._nonProcessableFiles.push(e), e; } } if (await V(e)) { if (!this.readSystemFiles) return this._nonProcessableFiles.push(e), e; try { const t = await j.create(e); return this._addMediaFile(t), t; } catch { return this._nonProcessableFiles.push(e), e; } } } try { const t = await j.create(e); return this._addMediaFile(t), t; } catch { return this._nonProcessableFiles.push(e), e; } } /** * Add a MediaFile to the appropriate internal list. * * @param file - MediaFile to add * @private */ _addMediaFile(e) { this._mediaFiles.push(e), this._isMediaContainer(e) && this._mediaContainers.push(e); } /** * Check if a file is a media container. * * @param file - File to check * @returns Whether the file is a media container * @private */ _isMediaContainer(e) { return e && typeof e == "object" && "getProcessableFiles" in e && "getLeafFiles" in e; } /** * Get all items in their original order. * * @private */ get _allItems() { return [...this._mediaFiles, ...this._urlFiles, ...this._nonProcessableFiles]; } /** * Get all leaf files (non-container media files) and their indices. * * @returns Object with files array and indices array */ getLeafFiles() { const e = [], t = []; for (let s = 0; s < this._mediaFiles.length; s++) { const i = this._mediaFiles[s]; this._mediaContainers.includes(i) || (e.push(i), t.push(s)); } return { files: e, indices: t }; } /** * Get all media containers from this list and their indices. * * @returns Object with containers array and indices array */ getMediaContainers() { const e = [], t = []; for (const s of this._mediaContainers) { const i = this._mediaFiles.indexOf(s); i !== -1 && (e.push(s), t.push(i)); } return { containers: e, indices: t }; } /** * Get all processable files from the container. * Validates that all files can be processed for batch operations. * * @param options - Processing options * @returns New MediaList with processable files */ getProcessableFiles(e = {}) { const { ignoreErrors: t = !1, raiseException: s = !0, silent: i = !1 } = e; if (t) return new E({ files: this._mediaFiles, downloadFiles: this.downloadFiles, readSystemFiles: this.readSystemFiles, fileName: this.fileName }); const r = []; for (const n of this._mediaFiles) this._mediaContainers.includes(n) || r.push(n); for (const n of this._mediaContainers) { const a = n.getProcessableFiles({ raiseException: !1, silent: !0 }); if (a.length > 0) for (const c of a) r.push(c); } if (this._urlFiles.length + this._nonProcessableFiles.length > 0 && (s || !i)) { const n = [...this._urlFiles, ...this._nonProcessableFiles], a = `Files not processed: ${JSON.stringify(n)}. Check configuration (downloadFiles=${this.downloadFiles}, readSystemFiles=${this.readSystemFiles})`; if (s) throw new Error(a); i || console.warn(a); } return new E({ files: r, downloadFiles: this.downloadFiles, readSystemFiles: this.readSystemFiles, fileName: this.fileName }); } /** * Get all non-processed URL files. * * @returns Array of URL strings */ getUrlFiles() { return [...this._urlFiles]; } /** * Get all non-processed file path files. * * @returns Array of file path strings */ getFilePathFiles() { const e = []; for (const t of this._nonProcessableFiles) typeof t == "string" && !x(t) && e.push(t); return e; } /** * Get all non-file parameters from the container. * * @param includeUrls - Whether to include URL files in the result * @returns Array of non-processable items */ getNonFileParams(e = !0) { const t = [...this._nonProcessableFiles]; e && t.push(...this._urlFiles); for (const s of this._mediaContainers) { const i = s.getNonFileParams(e); i.length > 0 && t.push(...i); } return t; } /** * Convert all media files to base64 strings. * * @param includeDataUri - Whether to include the data URI prefix * @returns Array of base64 strings */ toBase64(e = !0) { return this._mediaFiles.map((t) => t.toBase64(e)); } /** * Convert all media files to Blob objects (browser only). * * @returns Array of Blob objects */ toBlob() { return this._mediaFiles.map((e) => e.toBlob()); } /** * Convert all media files to ArrayBuffer objects. * * @returns Array of ArrayBuffer objects */ toArrayBuffer() { return this._mediaFiles.map((e) => e.toArrayBuffer()); } /** * Convert all media files to Uint8Array objects. * * @returns Array of Uint8Array objects */ toUint8Array() { return this._mediaFiles.map((e) => e.toUint8Array()); } /** * Convert all media fi