UNPKG

socaity

Version:

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

885 lines (884 loc) 32.8 kB
var F = Object.defineProperty; var v = (l, e, t) => e in l ? F(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t; var o = (l, e, t) => v(l, typeof e != "symbol" ? e + "" : e, t); import { MediaList as L, MediaDict as O, parseSocaityAPIJobResult as $ } from "@socaity/media-toolkit"; import { Asset3DFile as V, AudioFile as X, MediaFile as Y, MediaFileFactory as ee, MediaList as te, VideoFile as se, detectCategoryFromMimeType as re, detectMimeTypeFromUrl as ie, getAcceptedTypes as oe, getCategoryDisplayName as ae, getMimeTypeFromExtension as ne, isFileReaderObject as ce, isFileResult as le, isUrl as he } from "@socaity/media-toolkit"; class N 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, N); } } const P = class P { constructor(e = {}) { o(this, "apiKey"); o(this, "baseUrl"); o(this, "pollInterval"); o(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 P.instance || (P.instance = new P()), P.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 N("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 N("Invalid API key format. API keys should be 67 characters long. Get your API key from https://www.socaity.ai"); } const t = P.getInstance(); Object.assign(t, e); } }; o(P, "instance"); let w = P; const p = { INITIALIZING: "INITIALIZING", SENDING: "SENDING", TRACKING: "TRACKING", PROCESSING_RESULT: "PROCESSING_RESULT", COMPLETED: "COMPLETED", FAILED: "FAILED" }, c = { CREATED: "CREATED", QUEUED: "QUEUED", PROCESSING: "PROCESSING", COMPLETED: "COMPLETED", FAILED: "FAILED", CANCELLED: "CANCELLED", UNKNOWN: "UNKNOWN" }; class G { parse(e) { if (e == null) return this.errorJob("No response received"); if (typeof e == "string") try { return this.parseObject(JSON.parse(e)); } catch { return { id: "", status: c.COMPLETED, progress: 1, message: null, result: e, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() }; } return this.parseObject(e); } // ── Internal helpers ────────────────────────────────────────────────── parseObject(e) { if (typeof e != "object" || e === null) return this.errorJob("Invalid response format"); const t = e, s = this.str(t.job_id) || this.str(t.id) || "", r = this.status(t.status), i = this.progress(t.progress, r), n = this.str(t.message), a = this.str(t.error); let h; const g = t.links; if (g) h = { status: g.status, cancel: g.cancel }; else { const b = this.str(t.refresh_job_url), m = this.str(t.cancel_job_url); (b || m) && (h = { status: b || void 0, cancel: m || void 0 }); } return { id: s, status: r, progress: i, message: n, result: t.result, error: a, createdAt: this.date(t.createdAt ?? t.created_at), updatedAt: this.date(t.updatedAt ?? t.updated_at), links: h }; } errorJob(e) { const t = /* @__PURE__ */ new Date(); return { id: "", status: c.FAILED, progress: 0, message: e, result: null, error: e, createdAt: t, updatedAt: t }; } str(e) { return typeof e == "string" ? e : null; } date(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(); } status(e) { return typeof e != "string" || !e ? c.UNKNOWN : { COMPLETED: c.COMPLETED, SUCCEEDED: c.COMPLETED, FINISHED: c.COMPLETED, CREATED: c.CREATED, FAILED: c.FAILED, ERROR: c.FAILED, IN_PROGRESS: c.PROCESSING, PROCESSING: c.PROCESSING, RUNNING: c.PROCESSING, BOOTING: c.PROCESSING, QUEUED: c.QUEUED, PENDING: c.QUEUED, IN_QUEUE: c.QUEUED, STARTING: c.QUEUED, CANCELLED: c.CANCELLED, CANCELED: c.CANCELLED }[e.toUpperCase()] || c.UNKNOWN; } /** * Normalise the progress value to a 0-1 float. * Accepts a bare number, a numeric string, or a legacy nested object. */ progress(e, t) { let s = 0; if (typeof e == "number") s = e; else if (typeof e == "string") s = parseFloat(e) || 0; else if (e && typeof e == "object") { const r = e; s = typeof r.progress == "number" ? r.progress : parseFloat(String(r.progress)) || 0; } return isNaN(s) && (s = 0), s = Math.max(0, Math.min(1, s)), t === c.COMPLETED && (s = 1), s; } } const k = class k { constructor() { o(this, "config"); o(this, "abortController"); o(this, "responseParser"); this.config = w.getInstance(), this.abortController = new AbortController(), this.responseParser = new G(); } // ── URL helpers ────────────────────────────────────────────────────── /** * Resolve a gateway-relative path (e.g. /gateway/v1/status/xxx) * against the *origin* of the configured baseUrl. * Already-absolute URLs are returned as-is. */ resolveGatewayUrl(e) { if (e.startsWith("http://") || e.startsWith("https://")) return e; try { return `${new URL(this.config.baseUrl).origin}${e.startsWith("/") ? "" : "/"}${e}`; } catch { return `${this.config.baseUrl}/${e.replace(/^\//, "")}`; } } buildQueryString(e) { if (!e || Object.keys(e).length === 0) return ""; const t = new URLSearchParams(); for (const [s, r] of Object.entries(e)) if (r != null) if (r instanceof L) { const i = r.toBase64(!0); t.append(s, i.length === 1 ? i[0] : JSON.stringify(i)); } else typeof r == "object" ? t.append(s, JSON.stringify(r)) : t.append(s, String(r)); return t.toString(); } // ── Auth ───────────────────────────────────────────────────────────── requireApiKey(e) { const t = e || this.config.apiKey; if (!t) throw new Error("API key not provided"); return t; } authHeaders(e) { return { Authorization: `Bearer ${e}` }; } // ── Parameter preparation ──────────────────────────────────────────── isFileTypeParam(e) { const t = ["file", "image", "audio", "video"]; return e.definition && !Array.isArray(e.definition) ? !!(e.definition.format && t.includes(e.definition.format)) : Array.isArray(e.definition) ? e.definition.some((s) => !!(s.format && t.includes(s.format))) : !1; } /** * Organise endpoint parameters into query / body / file buckets. * Files are sent inline as blobs in the FormData. */ async prepareRequest(e, t) { var n; const s = { queryParams: {}, bodyParams: {}, fileParams: {} }; if (!((n = e.parameters) != null && n.length)) return s; const r = {}, i = {}; for (const a of e.parameters) { const h = t[a.name] ?? a.default; if (h === void 0 && a.required) throw new Error(`Required parameter '${a.name}' is missing`); h !== void 0 && (i[a.name] = a.location === "query" ? "query" : "body", this.isFileTypeParam(a) ? r[a.name] = h : a.location === "query" ? s.queryParams[a.name] = h : s.bodyParams[a.name] = h); } if (Object.keys(r).length > 0) { const { fileParams: a, nonFileParams: h } = await this.processFileParams(r); s.fileParams = a; for (const [g, b] of Object.entries(h)) i[g] === "query" ? s.queryParams[g] = b : s.bodyParams[g] = b; } return s.bodyParams.is_public = t.is_public ?? !1, s.bodyParams.keep = t.keep ?? !1, s; } /** * Load files via MediaDict and convert processable ones to inline blobs. */ async processFileParams(e) { const t = new O({ downloadFiles: !1, readSystemFiles: !0, fileName: "fileParams" }); await t.fromAny(e); const s = t.getNonFileParams(!1), r = t.getProcessableFiles({ ignoreErrors: !0, silent: !0 }), i = t.getUrlFiles(); if (r.length > 0) { const n = this.prepareFilesForSend(r); for (const a of r.keys()) a in n || (s[a] = e[a]); Object.assign(i, n); } return { fileParams: i, nonFileParams: s }; } prepareFilesForSend(e) { const t = {}; for (const s of e.keys()) { const r = e.get(s); if (r instanceof O) { const n = r.getProcessableFiles({ ignoreErrors: !0, silent: !0 }); n.length > 0 && (t[s] = this.prepareFilesForSend(n)); continue; } if (r instanceof L) { const n = r.getProcessableFiles({ ignoreErrors: !0, silent: !0 }); if (n.length > 0) { const a = n.toBlob(); t[s] = n.length === 1 ? a[0] : a; } continue; } const i = new L({ files: [r] }); t[s] = i.toBlob()[0]; } return t; } // ── Core HTTP ──────────────────────────────────────────────────────── /** * Send a request to a service endpoint (URL = baseUrl + path). */ async sendRequest(e, t = "POST", s = {}, r = {}, i = {}, n) { const a = this.requireApiKey(n); this.abortController = new AbortController(); const { signal: h } = this.abortController, g = this.authHeaders(a); let b = `${this.config.baseUrl}/${e}`, m = null; if (t === "GET") { const d = { ...s, ...r, ...i }, u = this.buildQueryString(d); u && (b += `?${u}`); } else { const d = this.buildQueryString(s); d && (b += `?${d}`); const u = new FormData(); for (const [E, y] of Object.entries({ ...r, ...i })) y != null && (y instanceof Blob || y instanceof File ? u.append(E, y) : Array.isArray(y) ? y.forEach((I) => { I instanceof Blob || I instanceof File ? u.append(E, I) : typeof I == "object" ? u.append(E, new Blob([JSON.stringify(I)], { type: "application/json" })) : u.append(E, String(I)); }) : typeof y == "object" ? u.append(E, new Blob([JSON.stringify(y)], { type: "application/json" })) : u.append(E, String(y))); m = u; } try { const d = setTimeout(() => this.abort(), k.DEFAULT_TIMEOUT_MS), u = await fetch(b, { method: t, headers: g, body: m, signal: h }); if (clearTimeout(d), !u.ok) throw await this.formatError(u); const E = u.headers.get("content-type"); return E != null && E.includes("application/json") ? await u.json() : await u.text(); } catch (d) { throw d instanceof DOMException && d.name === "AbortError" ? new Error("Request canceled") : d instanceof Error ? d : new Error(`Network error: ${String(d)}`); } } /** * Submit a request to a defined endpoint and parse the response into JobData. */ async requestEndpoint(e, t, s) { const r = await this.prepareRequest(e, t), i = await this.sendRequest( e.path, e.method, r.queryParams, r.bodyParams, r.fileParams, s ); return this.responseParser.parse(i); } // ── Gateway requests (status / cancel) ─────────────────────────────── /** * Poll the current status of a job. * @param jobId - Job identifier (fallback to construct the path). * @param statusUrl - Gateway-relative path from `links.status`. */ async refreshStatus(e, t) { var a; const s = t || `/gateway/v1/status/${e}`, r = this.resolveGatewayUrl(s), i = await this.gatewayRequest(r, "GET"), n = (a = i.headers.get("content-type")) != null && a.includes("application/json") ? await i.json() : await i.text(); return this.responseParser.parse(n); } /** * Cancel a running job. * @param jobId - Job identifier (fallback). * @param cancelUrl - Gateway-relative path from `links.cancel`. */ async cancelJob(e, t) { const s = t || `/gateway/v1/cancel/${e}`, r = this.resolveGatewayUrl(s), i = await this.gatewayRequest(r, "POST"); if (!i.ok) throw await this.formatError(i); } async gatewayRequest(e, t = "GET", s = 6e4) { const r = this.requireApiKey(); this.abortController = new AbortController(); const { signal: i } = this.abortController, n = setTimeout(() => this.abort(), s); try { const a = await fetch(e, { method: t, headers: this.authHeaders(r), signal: i }); if (clearTimeout(n), !a.ok) throw await this.formatError(a); return a; } catch (a) { throw clearTimeout(n), a instanceof DOMException && a.name === "AbortError" ? new Error("Request canceled") : a instanceof Error ? a : new Error(`Network error: ${String(a)}`); } } // ── Utilities ──────────────────────────────────────────────────────── async formatError(e) { let t; try { const s = e.headers.get("content-type"); t = s != null && s.includes("application/json") ? JSON.stringify(await e.json()) : await e.text(); } catch { t = "Could not parse error response"; } return new Error(`API error (${e.status}): ${t}`); } abort() { this.abortController.abort(), this.abortController = new AbortController(); } }; o(k, "DEFAULT_TIMEOUT_MS", 12e4); let A = k; const j = typeof process < "u" && process.stdout && process.stdout.clearLine; let S; if (j) try { S = require("cli-progress"); } catch { console.warn("cli-progress package not found. Using basic console output for progress."); } const C = class C { constructor() { o(this, "multiBar"); o(this, "bars", /* @__PURE__ */ new Map()); o(this, "isInitialized", !1); j && S && (this.multiBar = new S.MultiBar({ clearOnComplete: !1, hideCursor: !0, format: "{bar} {percentage}% | {jobId} | {phase} | {message}" }), this.isInitialized = !0); } static getInstance() { return C.instance || (C.instance = new C()), C.instance; } createBar(e, t) { if (!this.isInitialized) return null; const s = this.multiBar.create(100, 0, { jobId: e, phase: t, message: "Starting..." }); return this.bars.set(e, s), s; } updateBar(e, t, s) { const r = this.bars.get(e); r && r.update(t, s); } removeBar(e) { const t = this.bars.get(e); t && (t.stop(), this.multiBar.remove(t), this.bars.delete(e)); } stopAll() { this.isInitialized && (this.multiBar.stop(), this.bars.clear()); } }; o(C, "instance"); let U = C; class R { constructor(e, t, s, r, i = !0) { o(this, "jobData"); o(this, "endpoint"); o(this, "processingState"); o(this, "jobManager"); o(this, "_result", null); o(this, "_error", null); o(this, "completed", !1); o(this, "resolvePromise"); o(this, "rejectPromise"); o(this, "promise"); o(this, "eventListeners", /* @__PURE__ */ new Map()); o(this, "verbose"); o(this, "progressBar", null); o(this, "progressBarManager"); o(this, "parseResultCallbacks", []); o(this, "pollErrorCount", 0); o(this, "lastLoggedMessage", null); this.jobData = e, this.jobManager = t, this.endpoint = s, this.verbose = i, this.processingState = { phase: p.INITIALIZING, progress: 0 }, this.progressBarManager = U.getInstance(), this.promise = new Promise((n, a) => { this.resolvePromise = n, this.rejectPromise = a; }), r && this.onParseResult(r), this.verbose && this.initProgressDisplay(), setTimeout(() => this.startTracking(), 0); } // ── Progress display ───────────────────────────────────────────────── initProgressDisplay() { this.verbose && (j && S ? (this.progressBar = this.progressBarManager.createBar( this.jobData.id || "initializing", this.processingState.phase ), this.updateProgressDisplay()) : this.logProgress()); } updateProgressDisplay() { if (!this.verbose) return; const e = this.calculateProgressPercent(), t = this.formatProgressMessage(); j && S && this.progressBar ? this.progressBarManager.updateBar(this.jobData.id, e, { phase: this.processingState.phase, message: t.replace(/^.*\| /, "") }) : this.logProgress(); } calculateProgressPercent() { return this.processingState.phase === p.TRACKING && this.jobData.progress > 0 ? Math.round(this.jobData.progress * 100) : { [p.INITIALIZING]: 0, [p.SENDING]: 10, [p.TRACKING]: 15, [p.PROCESSING_RESULT]: 90, [p.COMPLETED]: 100, [p.FAILED]: 100 }[this.processingState.phase] ?? 0; } formatProgressMessage() { const { phase: e } = this.processingState, t = this.jobData.id || "initializing", s = this.endpoint.path; if (e === p.INITIALIZING || e === p.SENDING) return `${e} job | API: ${s}`; if (e === p.TRACKING) { const r = this.jobData.progress > 0 ? `${Math.round(this.jobData.progress * 100)}%` : "unknown"; let i = `Job ${t} | Progress: ${r} | API: ${s}`; return this.jobData.message && (i += ` | ${this.jobData.message}`), i; } return `Job ${t} | ${e} | API: ${s}`; } logProgress() { const e = this.formatProgressMessage(); this.lastLoggedMessage !== e && (console.log(e), this.lastLoggedMessage = e); } stopProgressDisplay() { this.verbose && (j && S && this.progressBar && (this.progressBarManager.removeBar(this.jobData.id), this.progressBar = null), this.processingState.phase === p.COMPLETED ? console.log(`Job ${this.jobData.id} completed successfully (${this.endpoint.path})`) : this.processingState.phase === p.FAILED && console.log(`Job ${this.jobData.id} failed: ${this.processingState.message} (${this.endpoint.path})`)); } // ── Event system ───────────────────────────────────────────────────── on(e, t) { return this.eventListeners.has(e) || this.eventListeners.set(e, []), this.eventListeners.get(e).push(t), this; } emit(e, ...t) { var s; (s = this.eventListeners.get(e)) == null || s.forEach((r) => r(...t)); } // ── Polling loop ───────────────────────────────────────────────────── startTracking() { this.setPhase(p.TRACKING, 0, "Tracking job status"), this.pollJobStatus(); } async pollJobStatus() { var e, t, s; if (!(this.completed || !this.jobData.id)) try { const r = await this.jobManager.refreshStatus( this.jobData.id, (e = this.jobData.links) == null ? void 0 : e.status ); if (!r) { this.scheduleNextPoll(); return; } if (r.links || (r.links = {}), r.links.status = r.links.status || ((t = this.jobData.links) == null ? void 0 : t.status), r.links.cancel = r.links.cancel || ((s = this.jobData.links) == null ? void 0 : s.cancel), this.jobData = r, this.pollErrorCount = 0, this.emitJobUpdate(), this.verbose && this.updateProgressDisplay(), r.status === c.COMPLETED) { this.setPhase(p.PROCESSING_RESULT, 0.9, "Processing result"); try { this._result = await $(r.result), this._result = await this.runParseResultCallbacks(this._result), this.complete(); } catch (i) { this.fail(i instanceof Error ? i : new Error(String(i))); } } else r.status === c.FAILED ? this.fail(new Error(r.error || "Job failed with no error message")) : r.status === c.CANCELLED ? this.fail(new Error("Job was cancelled")) : this.scheduleNextPoll(); } catch (r) { if (console.error("Network error while polling job status:", r), this.pollErrorCount++, this.pollErrorCount >= 5) { this.fail(new Error( `Network polling failed after ${this.pollErrorCount} attempts: ${r instanceof Error ? r.message : String(r)}` )); return; } this.scheduleNextPoll(); } } scheduleNextPoll() { setTimeout(() => this.pollJobStatus(), this.jobManager.config.pollInterval); } // ── State transitions ──────────────────────────────────────────────── complete() { this.setPhase(p.COMPLETED, 1, "Job completed"), this.cleanup(), this.completed = !0, this.emit("completed", this._result), this.resolvePromise(this._result); } fail(e) { this.setPhase(p.FAILED, 1, e.message), this.cleanup(), this.completed = !0, this._error = e, this.emit("failed", e), this.rejectPromise(e); } cleanup() { this.stopProgressDisplay(); } setPhase(e, t, s) { this.processingState = { phase: e, progress: t, message: s }, this.verbose && this.updateProgressDisplay(), this.emit("processingUpdated", this.processingState); } emitJobUpdate() { this.emit("progressUpdated", { progress: this.jobData.progress, message: this.jobData.message }), this.emit("statusUpdated", this.jobData.status); } // ── Public API ─────────────────────────────────────────────────────── setVerbose(e) { return this.verbose = e, e && !this.progressBar && !this.completed ? this.initProgressDisplay() : !e && this.progressBar && this.stopProgressDisplay(), this; } onCompleted(e) { return this.on("completed", e), this.completed && this._result !== null && setTimeout(() => e(this._result), 0), this; } onFailed(e) { return this.on("failed", e), this.completed && this._error !== null && setTimeout(() => e(this._error), 0), this; } onProgress(e) { return this.on("progressUpdated", e), setTimeout(() => e({ progress: this.jobData.progress, message: this.jobData.message }), 0), this; } onStatus(e) { return this.on("statusUpdated", e), setTimeout(() => e(this.jobData.status), 0), this; } onProcessingUpdated(e) { return this.on("processingUpdated", e), setTimeout(() => e(this.processingState), 0), this; } onParseResult(e) { return this.parseResultCallbacks.push(e), this; } async runParseResultCallbacks(e) { let t = e; for (const s of this.parseResultCallbacks) { const r = await s(t); r !== void 0 && (t = r); } return t; } async cancel() { var e; try { const t = await this.jobManager.cancelJob( this.jobData.id, (e = this.jobData.links) == null ? void 0 : e.cancel ); return t && this.fail(new Error("Job cancelled by user")), t; } catch { return !1; } } get id() { return this.jobData.id; } get status() { return this.jobData.status; } get progress() { return this.jobData.progress; } get message() { return this.jobData.message; } get phase() { return this.processingState.phase; } then(e, t) { return this.promise.then(e, t); } } const D = class D { constructor(e) { o(this, "requestHandler"); o(this, "config"); o(this, "jobs"); o(this, "trackedJobs"); this.requestHandler = e, this.config = w.getInstance(), this.jobs = /* @__PURE__ */ new Map(), this.trackedJobs = /* @__PURE__ */ new Map(); } static getInstance(e) { return D.instance || (D.instance = new D(e ?? new A())), D.instance; } // ── Job submission ─────────────────────────────────────────────────── async submitJob(e, t, s) { const r = await this.requestHandler.requestEndpoint(e, t, s); return this.jobs.set(r.id, r), r; } // ── Status & cancellation ──────────────────────────────────────────── async refreshStatus(e, t) { return this.requestHandler.refreshStatus(e, t); } async cancelJob(e, t) { var r, i; const s = t || ((i = (r = this.jobs.get(e)) == null ? void 0 : r.links) == null ? void 0 : i.cancel); try { return await this.requestHandler.cancelJob(e, s), this.jobs.delete(e), this.trackedJobs.delete(e), !0; } catch { return !1; } } // ── Tracked-job registry ───────────────────────────────────────────── getTrackedJob(e) { return this.trackedJobs.get(e); } createTrackedJob(e, t, s, r = !0) { const i = new R(e, this, t, s, r); return e.id && (this.trackedJobs.set(e.id, i), this.jobs.set(e.id, e)), i; } getOrCreateTrackedJob(e, t, s, r = !0) { const i = e.id ? this.getTrackedJob(e.id) : void 0; return i || this.createTrackedJob(e, t, s, r); } getAllJobs() { return Array.from(this.trackedJobs.values()); } getJob(e) { return this.trackedJobs.get(e); } clearCompletedJobs() { for (const [e, t] of this.jobs.entries()) (t.status === c.COMPLETED || t.status === c.FAILED) && (this.jobs.delete(e), this.trackedJobs.delete(e)); } }; o(D, "instance"); let T = D; function q(l, e, t, s) { let r = l.toLowerCase(); r = r.replace(/\\/g, "/"); const i = (m) => m.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), n = i(t), a = new RegExp(`[^a-z0-9${n}]+`, "g"); r = r.replace(a, e); const h = new Set(t + e); for (const m of h) { const d = i(m), u = new RegExp(`${d}+`, "g"); r = r.replace(u, m); } const g = i(s + e), b = new RegExp(`^[${g}]+|[${g}]+$`, "g"); return r = r.replace(b, ""), r; } function J(l, e = !1) { let t = q( l, "-", e ? "/" : "", "-" ); return t = t.replace(/^\/+|\/+$/g, ""), t.length === 0 ? "no_name" : t; } class x { constructor(e) { o(this, "requestHandler"); o(this, "config"); o(this, "endpoints"); o(this, "jobManager"); /** Raw service identifier used as the URL path prefix: /{serviceId}/{endpoint} */ o(this, "serviceId"); /** Normalized display name, also used as registry key in APIClientFactory */ o(this, "name"); this.serviceId = e, this.name = J(e, !0), this.config = w.getInstance(), this.requestHandler = new A(), this.endpoints = /* @__PURE__ */ new Map(), this.jobManager = T.getInstance(this.requestHandler), this.registerEndpoints(), M.registerClient(this); } registerEndpoint(e) { const t = { ...e }, s = J(t.path, !0); t.path = `${this.serviceId}/${s}`, this.endpoints.set(s, t); } getEndpoint(e) { const t = J(e, !0), s = this.endpoints.get(t); if (!s) throw new Error(`Unknown endpoint: ${e}`); return s; } updateConfig(e) { w.update(e); } /** * Submit a job and return a TrackedJob for monitoring. */ async submitTrackedJob(e, t, s, r, i = !0) { const n = await this.jobManager.submitJob(e, t, r); return new R(n, this.jobManager, e, s, i); } /** * Run an endpoint end-to-end: submit, track, and return the final result. */ async runEndpoint(e, t, s, r, i = !0, n) { const a = this.getEndpoint(e), h = await this.jobManager.submitJob(a, t, s), g = this.jobManager.getOrCreateTrackedJob(h, a, r, i); return this.wireCallbacks(g, n), await g; } /** * Resume tracking of an existing job by ID. */ async resumeJobTracking(e, t, s, r = !0, i) { const n = this.getEndpoint(e), h = this.jobManager.getTrackedJob(t) ?? this.jobManager.getOrCreateTrackedJob( { id: t, status: c.QUEUED, progress: 0, message: null }, n, s, r ); return this.wireCallbacks(h, i), await h; } wireCallbacks(e, t) { t && (t.onProgress && e.onProgress(t.onProgress), t.onStatus && e.onStatus(t.onStatus), t.onProcessingUpdated && e.onProcessingUpdated(t.onProcessingUpdated), t.onCompleted && e.onCompleted(t.onCompleted), t.onFailed && e.onFailed(t.onFailed), t.onJobSubmitted && t.onJobSubmitted(e)); } getJobs() { return this.jobManager.getAllJobs(); } getJob(e) { return this.jobManager.getJob(e); } async cancelJob(e) { return this.jobManager.cancelJob(e); } } class B extends x { constructor(t, s) { super(t); o(this, "eps"); this.eps = s, this.registerEndpoints(); } registerEndpoints() { if (this.eps) for (const t of this.eps) this.registerEndpoint(t); } } const f = class f { constructor() { o(this, "registeredClients", /* @__PURE__ */ new Map()); o(this, "clientConstructors", /* @__PURE__ */ new Map()); } static getInstance() { return f.instance || (f.instance = new f()), f.instance; } static registerClientType(e, t) { const s = f.getInstance(), r = f.normalizeClientName(e); s.clientConstructors.set(r, t); } static registerClient(e) { const t = f.getInstance(), s = f.normalizeClientName(e.name); t.registeredClients.set(s, e); } static getClient(e) { const t = f.getInstance(), s = f.normalizeClientName(e); let r = t.registeredClients.get(s); if (!r) { const i = t.clientConstructors.get(s); if (!i) throw new Error( `Client "${e}" not found. Available clients: ${Array.from(t.clientConstructors.keys()).join(", ")}` ); r = new i(), t.registeredClients.set(s, r); } return r; } static getAvailableClients() { const e = f.getInstance(); return Array.from(e.clientConstructors.keys()); } static normalizeClientName(e) { return e.toLowerCase().replace(/[^a-z0-9-]/g, ""); } static createDynamicClient(e, t) { const s = new B(e, t); return this.registerClient(s), s; } }; o(f, "instance"); let M = f; class K { constructor(e = {}) { w.update(e); } getAvailableModels() { return M.getAvailableClients(); } } class z extends K { constructor(t = {}) { super(t); o(this, "_jobManager"); } get jobManager() { return this._jobManager || (this._jobManager = T.getInstance()), this._jobManager; } /** * Set the API key globally */ setApiKey(t) { w.update({ apiKey: t }); } /** * Set the base URL globally */ setBaseUrl(t) { w.update({ baseUrl: t }); } /** * Get a list of all active jobs * @returns Array of all tracked jobs */ getJobs() { return this.jobManager.getAllJobs(); } /** * Get a specific job by ID * @param jobId - ID of the job to retrieve * @returns The job if found, undefined otherwise */ getJob(t) { return this.jobManager.getJob(t); } /** * Cancel a running job * @param jobId - ID of the job to cancel * @returns Promise resolving to true if successful */ async cancelJob(t) { return this.jobManager.cancelJob(t); } } const W = new z(); typeof window < "u" && (window.socaity = W); typeof process < "u" && process.on && typeof process.on == "function" && process.on("uncaughtException", (l) => { if (l.name === "ApiKeyError") console.error(`${l.name}: ${l.message}`), process.exit(1); else throw l; }); export { x as APIClient, M as APIClientFactory, V as Asset3DFile, X as AudioFile, Y as MediaFile, ee as MediaFileFactory, te as MediaList, z as SocaitySDK, se as VideoFile, re as detectCategoryFromMimeType, ie as detectMimeTypeFromUrl, oe as getAcceptedTypes, ae as getCategoryDisplayName, ne as getMimeTypeFromExtension, ce as isFileReaderObject, le as isFileResult, he as isUrl, W as socaity }; //# sourceMappingURL=socaity.es.js.map