socaity
Version:
SDK for Generative AI. Build AI-powered applications with ease
1,602 lines • 108 kB
JavaScript
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