UNPKG

expo-finance-kit

Version:

Native Expo module for Apple FinanceKit - Access financial data from Apple Card and other accounts

190 lines 7.51 kB
/** * Balance management module for Expo Finance Kit * Handles fetching and managing account balance data */ import ExpoFinanceKit from '../ExpoFinanceKitModule'; import { FinanceKitErrorCode } from '../ExpoFinanceKit.types'; import { ensureAuthorized } from '../helpers'; import { validateBalanceQueryOptions, transformBalance } from '../utils/validators'; import { createFinanceKitError } from '../utils/errors'; /** * Fetches account balances * @param options - Query options for filtering balances * @returns Promise resolving to array of account balances */ export async function getBalances(options) { const isAuthorized = await ensureAuthorized(); if (!isAuthorized) { throw createFinanceKitError(FinanceKitErrorCode.Unauthorized, 'User has not authorized access to financial data'); } if (options) { validateBalanceQueryOptions(options); } try { const balances = await ExpoFinanceKit.getBalances(); let filteredBalances = balances.map(transformBalance); // Apply filters if (options?.accountIds && options.accountIds.length > 0) { filteredBalances = filteredBalances.filter((balance) => options.accountIds.includes(balance.accountId)); } return filteredBalances; } catch (error) { throw createFinanceKitError(FinanceKitErrorCode.Unknown, 'Failed to fetch balances', { originalError: error }); } } /** * Fetches balance for a specific account * @param accountId - The account ID to fetch balance for * @returns Promise resolving to the account balance or null */ export async function getBalanceByAccount(accountId) { if (!accountId || typeof accountId !== 'string') { throw createFinanceKitError(FinanceKitErrorCode.InvalidAccountId, 'Invalid account ID provided'); } const isAuthorized = await ensureAuthorized(); if (!isAuthorized) { throw createFinanceKitError(FinanceKitErrorCode.Unauthorized, 'User has not authorized access to financial data'); } try { // Use the new native method that gets balance for specific account const balance = await ExpoFinanceKit.getBalanceForAccount(accountId); return balance ? transformBalance(balance) : null; } catch (error) { // If the new method is not available, fall back to filtering if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string' && error.message.includes('getBalanceForAccount')) { const balances = await getBalances(); const filtered = balances.filter(b => b.accountId === accountId); return filtered.length > 0 ? filtered[0] : null; } throw createFinanceKitError(FinanceKitErrorCode.Unknown, 'Failed to fetch balance for account', { originalError: error }); } } /** * Fetches all balances and calculates total * @returns Promise resolving to total balance across all accounts */ export async function getTotalBalance() { const isAuthorized = await ensureAuthorized(); if (!isAuthorized) { throw createFinanceKitError(FinanceKitErrorCode.Unauthorized, 'User has not authorized access to financial data'); } try { // First get all accounts const accounts = await ExpoFinanceKit.getAccounts(); // Get current balance for each account const balancePromises = accounts.map(async (account) => { try { const balance = await ExpoFinanceKit.getBalanceForAccount(account.id); return balance ? transformBalance(balance) : null; } catch (error) { console.warn(`Failed to get balance for account ${account.id}:`, error); return null; } }); const balanceResults = await Promise.all(balancePromises); const validBalances = balanceResults.filter((b) => b !== null); const byCurrency = new Map(); let totalInUSD = 0; // Would need exchange rates for accurate conversion validBalances.forEach(balance => { const current = byCurrency.get(balance.currencyCode) || 0; byCurrency.set(balance.currencyCode, current + balance.amount); // For now, just sum all amounts (would need currency conversion) totalInUSD += balance.amount; }); return { total: totalInUSD, byCurrency, accounts: validBalances, }; } catch (error) { throw createFinanceKitError(FinanceKitErrorCode.Unknown, 'Failed to fetch total balance', { originalError: error }); } } /** * Gets balance summary for all accounts * @returns Promise resolving to balance summary */ export async function getBalanceSummary() { const balances = await getBalances(); // In a real implementation, we'd correlate with account types // For now, we'll use positive/negative balance as a proxy const totalAssets = balances .filter(b => b.amount > 0) .reduce((sum, b) => sum + b.amount, 0); const totalLiabilities = Math.abs(balances .filter(b => b.amount < 0) .reduce((sum, b) => sum + b.amount, 0)); return { totalAssets, totalLiabilities, netWorth: totalAssets - totalLiabilities, accountCount: balances.length, lastUpdated: Date.now(), }; } /** * Monitors balance changes over time * @param accountId - Account to monitor * @param callback - Callback function for balance updates * @returns Function to stop monitoring */ export function monitorBalanceChanges(accountId, callback) { let intervalId; let lastBalance = null; const checkBalance = async () => { try { const balance = await getBalanceByAccount(accountId); if (balance && balance.amount !== lastBalance) { lastBalance = balance.amount; callback(balance); } } catch (error) { console.error('Error monitoring balance:', error); } }; // Check every 5 minutes intervalId = setInterval(checkBalance, 5 * 60 * 1000); // Initial check checkBalance(); // Return cleanup function return () => { if (intervalId) { clearInterval(intervalId); } }; } /** * Gets historical balance data (simulated) * @param accountId - Account ID to get history for * @param days - Number of days of history * @returns Promise resolving to historical balance data */ export async function getBalanceHistory(accountId, days = 30) { // This would typically fetch from a data source that tracks balance history // For now, we'll simulate it const currentBalance = await getBalanceByAccount(accountId); if (!currentBalance) { throw createFinanceKitError(FinanceKitErrorCode.AccountNotFound, 'Account not found'); } const history = []; const dailyChange = (Math.random() - 0.5) * 100; // Simulate daily changes for (let i = days; i >= 0; i--) { const date = new Date(); date.setDate(date.getDate() - i); const variance = currentBalance.amount * 0.01 * (Math.random() - 0.5); const balance = currentBalance.amount + (dailyChange * i) + variance; history.push({ date: date.getTime(), balance: Math.round(balance * 100) / 100, }); } return history; } //# sourceMappingURL=balances.js.map