"use node"; import { FinTSClient, FinTSConfig, type BankingInformation, type ClientResponse, } from "lib-fints"; import { resolveFintsEnvFields } from "./fintsConfig"; export type FintsInteractionKind = | { type: "sync"; syncSystemId: boolean } | { type: "balance"; accountNumber: string } | { type: "statements"; accountNumber: string; from?: string; to?: string; preferCamt: boolean }; export type SerializedFintsSession = { bankingInformation: BankingInformation; tanMethodId?: number; tanMediaName?: string; tanReference: string; tanContinuation: "sync" | "balance" | "statements"; }; export type FintsEnvConfig = { productId: string; productVersion: string; url: string; blz: string; login: string; pin: string; tanMethodId?: number; tanMediaName?: string; bankingInformation?: BankingInformation; }; /** @deprecated Import from ./fintsConfig */ export { FINTS_PRODUCT_ID_PLACEHOLDER, getFintsConfigStatus } from "./fintsConfig"; export type { FintsConfigStatus } from "./fintsConfig"; export function resolveFintsEnv(overrides?: { blz?: string; url?: string; login?: string; productId?: string; productVersion?: string; tanMethodId?: number; tanMediaName?: string; bankingInformationJson?: string; pin?: string; }): FintsEnvConfig { const fields = resolveFintsEnvFields(overrides); if (fields.usesProductIdPlaceholder) { console.warn("[fints] FINTS_PRODUCT_ID fehlt – Platzhalter wird verwendet"); } let bankingInformation: BankingInformation | undefined; if (overrides?.bankingInformationJson) { bankingInformation = JSON.parse(overrides.bankingInformationJson) as BankingInformation; } return { productId: fields.productId, productVersion: fields.productVersion, url: fields.url, blz: fields.blz, login: fields.login, pin: fields.pin, tanMethodId: overrides?.tanMethodId, tanMediaName: overrides?.tanMediaName, bankingInformation, }; } export function createFinTsClient(config: FintsEnvConfig): FinTSClient { const fintsConfig = config.bankingInformation ? FinTSConfig.fromBankingInformation( config.productId, config.productVersion, config.bankingInformation, config.login, config.pin, config.tanMethodId, config.tanMediaName, ) : FinTSConfig.forFirstTimeUse( config.productId, config.productVersion, config.url, config.blz, config.login, config.pin, ); const client = new FinTSClient(fintsConfig); if (config.tanMethodId) { client.selectTanMethod(config.tanMethodId); } if (config.tanMediaName) { client.selectTanMedia(config.tanMediaName); } return client; } export function buildSessionSnapshot( client: FinTSClient, tanReference: string, tanContinuation: SerializedFintsSession["tanContinuation"], ): SerializedFintsSession { return { bankingInformation: client.config.bankingInformation, tanMethodId: client.config.selectedTanMethod?.id, tanMediaName: client.config.selectedTanMethod?.activeTanMedia?.[0], tanReference, tanContinuation, }; } export async function continueWithTan( client: FinTSClient, session: SerializedFintsSession, tan?: string, ): Promise { switch (session.tanContinuation) { case "sync": return await client.synchronizeWithTan(session.tanReference, tan); case "balance": return await client.getAccountBalanceWithTan(session.tanReference, tan); case "statements": return await client.getAccountStatementsWithTan(session.tanReference, tan); } } export function encodePhotoTan(response: ClientResponse): { mimeType?: string; base64?: string; } { if (!response.tanPhoto?.image) return {}; const bytes = response.tanPhoto.image instanceof Uint8Array ? response.tanPhoto.image : new Uint8Array(response.tanPhoto.image); let binary = ""; for (const byte of bytes) { binary += String.fromCharCode(byte); } return { mimeType: response.tanPhoto.mimeType, base64: btoa(binary), }; } export function pickDecoupledTanMethod(client: FinTSClient): number | undefined { const methods = client.config.availableTanMethods; const decoupled = methods.find((m) => m.isDecoupled); if (decoupled) return decoupled.id; return methods[0]?.id; } export function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); }