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 { 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 => { const response = await fetch(url); if (!response.ok) { throw new Error(`${response.status} ${response.statusText}`); } return parsePayload(await response.json()); }; const loadBrowserLocalPayload = async (): Promise => { if (typeof location === 'undefined') { return undefined; } try { return await fetchPayload('/.onlygit/fee-schedules.json'); } catch { return undefined; } }; const loadNodeLocalPayload = async (): Promise => { if (!isNodeRuntime()) { return undefined; } try { const dynamicImport = new Function('specifier', 'return import(specifier)') as (specifier: string) => Promise; 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);