UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

260 lines (259 loc) 9.02 kB
var u = Object.defineProperty, f = (n, e, t) => e in n ? u(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t, d = (n, e, t) => f(n, typeof e != "symbol" ? e + "" : e, t); class p { constructor(e) { d(this, "config"), d(this, "requestInterceptors", []), d(this, "responseInterceptors", []), d(this, "errorHandlers", []), this.config = e; } // Configuration methods setConfig(e) { this.config = { ...this.config, ...e }; } setOrganizationContext(e) { this.config.organizationId = e; } clearOrganizationContext() { delete this.config.organizationId; } // Interceptor methods addRequestInterceptor(e) { this.requestInterceptors.push(e); } addResponseInterceptor(e) { this.responseInterceptors.push(e); } addErrorHandler(e) { this.errorHandlers.push(e); } // Main request method async request(e, t = {}) { const s = this.buildUrl(e, t.params); let r = this.buildRequestConfig(t); for (const o of this.requestInterceptors) r = await o(r); try { let i = await this.executeRequest(s, r); for (const a of this.responseInterceptors) i = await a(i); return await this.parseResponse(i); } catch (o) { const i = this.createAPIError(o); for (const a of this.errorHandlers) a(i); throw i; } } // Convenience methods async get(e, t) { return this.request(e, { ...t, method: "GET" }); } async post(e, t, s) { return this.request(e, { ...s, method: "POST", body: t }); } async put(e, t, s) { return this.request(e, { ...s, method: "PUT", body: t }); } async patch(e, t, s) { return this.request(e, { ...s, method: "PATCH", body: t }); } async delete(e, t) { return this.request(e, { ...t, method: "DELETE" }); } // Private helper methods buildUrl(e, t) { const s = new URL(e, this.config.baseUrl); if (t) for (const [r, o] of Object.entries(t)) o != null && s.searchParams.set(r, String(o)); return s.toString(); } buildRequestConfig(e) { const t = { "Content-Type": "application/json", ...this.config.headers, ...e.headers }; return this.config.apiKey ? t.Authorization = `Bearer ${this.config.apiKey}` : this.config.publishableKey && (t["X-Publishable-Key"] = this.config.publishableKey), (e.organizationId || this.config.organizationId) && (t["X-Organization-Id"] = e.organizationId || this.config.organizationId), { method: "GET", timeout: this.config.timeout || 3e4, retries: this.config.retries || 3, ...e, headers: t }; } async executeRequest(e, t) { const s = new AbortController(), r = t.timeout ? setTimeout(() => s.abort(), t.timeout) : null; try { const o = { method: t.method, headers: t.headers, signal: s.signal }; t.body && t.method !== "GET" && (o.body = typeof t.body == "string" ? t.body : JSON.stringify(t.body)); const i = await fetch(e, o); return r && clearTimeout(r), i; } catch (o) { throw r && clearTimeout(r), o; } } async parseResponse(e) { const t = e.headers.get("Content-Type") || ""; let s; if (t.includes("application/json") ? s = await e.json() : s = await e.text(), !e.ok) throw new Error(`HTTP ${e.status}: ${e.statusText}`, { cause: { status: e.status, data: s } }); return s && typeof s == "object" && "success" in s ? s : { success: !0, data: s }; } createAPIError(e) { if (e.cause && typeof e.cause == "object") { const { status: t, data: s } = e.cause; if (s && typeof s == "object" && "errors" in s) return { code: s.code || `HTTP_${t}`, message: s.message || e.message, details: s.details }; } return { code: "UNKNOWN_ERROR", message: e.message || "An unknown error occurred", details: { originalError: e } }; } } const w = (n) => new p(n), g = (n) => n && typeof n == "object" && "code" in n && "message" in n, m = (n) => g(n) ? n : { code: "UNKNOWN_ERROR", message: n?.message || "An unknown error occurred", details: { originalError: n } }, b = async (n, e = 3, t = 1e3) => { let s; for (let r = 1; r <= e; r++) try { return await n(); } catch (o) { if (s = o, r === e) break; const i = t * Math.pow(2, r - 1); await new Promise((a) => setTimeout(a, i)); } throw s; }, y = (n, e, t = 3e5) => { const s = /* @__PURE__ */ new Map(); return (async () => { const r = s.get(e); if (r && r.expires > Date.now()) return r.data; const o = await n(); return s.set(e, { data: o, expires: Date.now() + t }), o; })(); }, R = async (n, e = 5, t = 100) => { const s = []; for (let r = 0; r < n.length; r += e) { const o = n.slice(r, r + e), i = await Promise.all(o.map((a) => a())); s.push(...i), r + e < n.length && t > 0 && await new Promise((a) => setTimeout(a, t)); } return s; }, E = async (n, e, t, s = {}) => { const r = new FormData(); if (r.append("file", t), s.additionalData) for (const [o, i] of Object.entries(s.additionalData)) r.append(o, String(i)); return new Promise((o, i) => { const a = new XMLHttpRequest(); s.onProgress && a.upload.addEventListener("progress", (c) => { if (c.lengthComputable) { const h = c.loaded / c.total * 100; s.onProgress(h); } }), s.abortSignal && s.abortSignal.addEventListener("abort", () => { a.abort(), i(new Error("Upload aborted")); }), a.addEventListener("load", async () => { try { const c = JSON.parse(a.responseText); a.status >= 200 && a.status < 300 ? o(c) : i(new Error(`Upload failed: ${c.message || a.statusText}`)); } catch { i(new Error("Failed to parse upload response")); } }), a.addEventListener("error", () => { i(new Error("Upload failed")); }), a.open("POST", `${n.config.baseUrl}${e}`); const l = n.buildRequestConfig({}).headers || {}; for (const [c, h] of Object.entries(l)) c.toLowerCase() !== "content-type" && a.setRequestHeader(c, h); a.send(r); }); }, P = async (n, e, t, s = {}) => { const r = await fetch(`${n.config.baseUrl}${e}`, { headers: n.buildRequestConfig({}).headers, signal: s.abortSignal }); if (!r.ok) throw new Error(`Download failed: ${r.statusText}`); const o = await r.blob(), i = window.URL.createObjectURL(o), a = document.createElement("a"); a.style.display = "none", a.href = i, a.download = t || "download", document.body.appendChild(a), a.click(), window.URL.revokeObjectURL(i), document.body.removeChild(a); }; class I { constructor(e, t = {}) { this.url = e, this.config = t, d(this, "ws", null), d(this, "reconnectAttempts", 0), d(this, "maxReconnectAttempts", 5), d(this, "reconnectDelay", 1e3), d(this, "messageQueue", []), d(this, "eventHandlers", /* @__PURE__ */ new Map()); } connect() { return new Promise((e, t) => { try { const s = new URL(this.url); this.config.token && s.searchParams.set("token", this.config.token), this.config.organizationId && s.searchParams.set("organizationId", this.config.organizationId), this.ws = new WebSocket(s.toString()), this.ws.onopen = () => { for (this.reconnectAttempts = 0; this.messageQueue.length > 0; ) { const r = this.messageQueue.shift(); this.ws.send(JSON.stringify(r)); } e(); }, this.ws.onmessage = (r) => { try { const o = JSON.parse(r.data); this.handleMessage(o); } catch (o) { console.error("Failed to parse WebSocket message:", o); } }, this.ws.onclose = () => { this.ws = null, this.config.autoReconnect !== !1 && this.reconnectAttempts < this.maxReconnectAttempts && setTimeout(() => { this.reconnectAttempts++, this.connect(); }, this.reconnectDelay * Math.pow(2, this.reconnectAttempts)); }, this.ws.onerror = (r) => { t(r); }; } catch (s) { t(s); } }); } disconnect() { this.ws && (this.ws.close(), this.ws = null); } send(e) { this.ws && this.ws.readyState === WebSocket.OPEN ? this.ws.send(JSON.stringify(e)) : this.messageQueue.push(e); } on(e, t) { return this.eventHandlers.has(e) || this.eventHandlers.set(e, /* @__PURE__ */ new Set()), this.eventHandlers.get(e).add(t), () => { this.eventHandlers.get(e)?.delete(t); }; } handleMessage(e) { const { type: t, payload: s } = e; if (this.eventHandlers.has(t)) for (const r of this.eventHandlers.get(t)) r(s); } } export { p as APIClient, I as APIWebSocket, R as batchRequests, w as createAPIClient, P as downloadFile, m as handleAPIError, g as isAPIError, b as retryRequest, E as uploadFile, y as withCache }; //# sourceMappingURL=api.js.map