UNPKG

@churchapps/helpers

Version:

Library of helper functions not specific to any one ChurchApps project or framework.

184 lines 6.75 kB
import { ErrorHelper } from "./ErrorHelper.js"; class ApiHelperClass { apiConfigs = []; isAuthenticated = false; onRequest; onError; getConfig(keyName) { let result = null; this.apiConfigs.forEach(config => { if (config.keyName === keyName) result = config; }); //if (result === null) throw new Error("Unconfigured API: " + keyName); return result; } setDefaultPermissions(jwt) { this.apiConfigs.forEach(config => { config.jwt = jwt; config.permissions = []; }); this.isAuthenticated = true; } setPermissions(keyName, jwt, permissions) { this.apiConfigs.forEach(config => { if (config.keyName === keyName) { config.jwt = jwt; config.permissions = permissions; } }); this.isAuthenticated = true; } clearPermissions() { this.apiConfigs.forEach(config => { config.jwt = ""; config.permissions = []; }); this.isAuthenticated = false; } async get(path, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "GET", headers: { Authorization: "Bearer " + config.jwt } }; return await this.fetchWithErrorHandling(config.url + path, requestOptions); } async getAnonymous(path, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "GET" }; return await this.fetchWithErrorHandling(config.url + path, requestOptions); } async post(path, data, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "POST", headers: { Authorization: "Bearer " + config.jwt, "Content-Type": "application/json" }, body: JSON.stringify(data) }; return await this.fetchWithErrorHandling(config.url + path, requestOptions); } async patch(path, data, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "PATCH", headers: { Authorization: "Bearer " + config.jwt, "Content-Type": "application/json" }, body: JSON.stringify(data) }; return await this.fetchWithErrorHandling(config.url + path, requestOptions); } async delete(path, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "DELETE", headers: { Authorization: "Bearer " + config.jwt } }; if (this.onRequest) this.onRequest(config.url + path, requestOptions); try { const response = await fetch(config.url + path, requestOptions); if (!response.ok) await this.throwApiError(response); } catch (e) { if (this.onError) this.onError(config.url + path, requestOptions, e); throw (e); } } async deleteAnonymous(path, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "DELETE" }; if (this.onRequest) this.onRequest(config.url + path, requestOptions); try { const response = await fetch(config.url + path, requestOptions); if (!response.ok) await this.throwApiError(response); } catch (e) { if (this.onError) this.onError(config.url + path, requestOptions, e); throw (e); } } async postAnonymous(path, data, apiName) { const config = this.getConfig(apiName); if (!config) throw new Error(`API configuration not found: ${apiName}`); const requestOptions = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }; return await this.fetchWithErrorHandling(config.url + path, requestOptions); } async fetchWithErrorHandling(url, requestOptions) { if (this.onRequest) this.onRequest(url, requestOptions); try { const response = await fetch(url, requestOptions); if (!response.ok) await this.throwApiError(response); else { if (response.status !== 204) { return response.json(); } } } catch (e) { throw (e); } } async throwApiError(response) { let msg = response.statusText; let body = ""; try { body = await response.text(); } catch { } if (body) { try { const json = JSON.parse(body); if (json && Array.isArray(json.errors) && json.errors.length > 0) msg = json.errors[0]; // Empty `{}` / `[]` bodies are just noise — keep the statusText instead so // Sentry doesn't fill up with "Error: {}" / "Error: []" entries. else if (body !== "{}" && body !== "[]") msg = body; } catch { msg = body; } } ErrorHelper.logError(response.status.toString(), response.url, msg); throw new Error(msg || "Error"); } } // Force singleton with immediate global assignment const getGlobalObject = () => { if (typeof window !== "undefined") return window; if (typeof global !== "undefined") return global; if (typeof globalThis !== "undefined") return globalThis; return {}; }; // Get or create singleton immediately - FORCE SINGLE INSTANCE const ensureSingleton = () => { const globalObj = getGlobalObject(); // Use a more unique key to avoid conflicts const SINGLETON_KEY = "__CHURCHAPPS_API_HELPER_SINGLETON__"; if (!globalObj[SINGLETON_KEY]) { globalObj[SINGLETON_KEY] = new ApiHelperClass(); } return globalObj[SINGLETON_KEY]; }; // Export the singleton instance export const ApiHelper = ensureSingleton(); //# sourceMappingURL=ApiHelper.js.map