Files

94 lines
3.0 KiB
TypeScript
Raw Permalink Normal View History

import type { IFeeSchedulePayload } from './feeschedules.types.js';
export const FEE_SCHEDULE_DATA_URL = 'https://code.foss.global/fin.cx/fee-schedules/raw/branch/main/.onlygit/fee-schedules.json';
export async function loadFeeSchedulePayload(url = FEE_SCHEDULE_DATA_URL): Promise<IFeeSchedulePayload> {
let remoteError: unknown;
try {
return await fetchPayload(url);
} catch (error) {
remoteError = error;
}
const browserLocalPayload = await loadBrowserLocalPayload();
if (browserLocalPayload) {
return browserLocalPayload;
}
const nodeLocalPayload = await loadNodeLocalPayload();
if (nodeLocalPayload) {
return nodeLocalPayload;
}
throw new Error(`Failed to load fee schedule data from ${url}: ${formatError(remoteError)}`);
}
const fetchPayload = async (url: string): Promise<IFeeSchedulePayload> => {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`${response.status} ${response.statusText}`);
}
return parsePayload(await response.json());
};
const loadBrowserLocalPayload = async (): Promise<IFeeSchedulePayload | undefined> => {
if (typeof location === 'undefined') {
return undefined;
}
try {
return await fetchPayload('/.onlygit/fee-schedules.json');
} catch {
return undefined;
}
};
const loadNodeLocalPayload = async (): Promise<IFeeSchedulePayload | undefined> => {
if (!isNodeRuntime()) {
return undefined;
}
try {
const dynamicImport = new Function('specifier', 'return import(specifier)') as (specifier: string) => Promise<any>;
const [{ readFile }, { fileURLToPath }, path] = await Promise.all([
dynamicImport('node:fs/promises'),
dynamicImport('node:url'),
dynamicImport('node:path'),
]);
const currentDir = path.dirname(fileURLToPath(import.meta.url));
const filePath = path.resolve(currentDir, '../.onlygit/fee-schedules.json');
const fileContent = await readFile(filePath, 'utf8');
return parsePayload(JSON.parse(fileContent));
} catch {
return undefined;
}
};
const parsePayload = (payload: unknown): IFeeSchedulePayload => {
if (!payload || typeof payload !== 'object') {
throw new Error('Fee schedule payload is not an object.');
}
const typedPayload = payload as IFeeSchedulePayload;
if (!Array.isArray(typedPayload.catalogs) || !Array.isArray(typedPayload.scheduleData)) {
throw new Error('Fee schedule payload is missing catalogs or scheduleData arrays.');
}
return typedPayload;
};
const isNodeRuntime = (): boolean => {
return typeof process !== 'undefined' && Boolean(process.versions?.node);
};
const formatError = (error: unknown): string => {
return error instanceof Error ? error.message : String(error);
};
export const feeSchedulePayload = await loadFeeSchedulePayload();
export const FEE_SCHEDULE_CATALOGS = feeSchedulePayload.catalogs;
export const FEE_SCHEDULE_DATA = feeSchedulePayload.scheduleData;
export const SUPPORTED_COUNTRY_CODES = FEE_SCHEDULE_CATALOGS.map((catalog) => catalog.countryCode);