@churchapps/helpers
Version:
Library of helper functions not specific to any one ChurchApps project or framework.
184 lines • 6.75 kB
JavaScript
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