- Create cache dir if missing - Moved Sqlite queries to queries.ts - Updated dependencies - Added pino-pretty to dev-dependencies - Changed Sqlite to store tokens as separate rows - Removed in-memory storage of tokens - isValidToken function - Throw Exception if refresh token is present but invalid - Fixed fetch query in smn http file
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
import { type Actual, ActualImpl } from "@/actual.ts"
|
|
import { cronJobDaily } from "@/cron.ts"
|
|
import {
|
|
type Bank,
|
|
Sparebank1Impl,
|
|
type Transaction,
|
|
} from "@/bank/sparebank1.ts"
|
|
import { bankTransactionIntoActualTransaction } from "@/mappings.ts"
|
|
import {
|
|
ACTUAL_ACCOUNT_IDS,
|
|
ACTUAL_DATA_DIR,
|
|
BANK_ACCOUNT_IDS,
|
|
} from "../config.ts"
|
|
import logger from "@/logger.ts"
|
|
import type { UUID } from "node:crypto"
|
|
import { createDb } from "@/bank/db/queries.ts"
|
|
import * as fs from "node:fs"
|
|
|
|
// TODO Transports api for pino https://github.com/pinojs/pino/blob/HEAD/docs/transports.md
|
|
// TODO create .cache if missing
|
|
|
|
export async function daily(actual: Actual, bank: Bank): Promise<void> {
|
|
// Fetch transactions from the bank
|
|
const transactions = await fetchTransactionsFromPastDay(bank)
|
|
logger.info(`Fetched ${transactions.length} transactions`)
|
|
|
|
// TODO multiple accounts
|
|
const accountId = ACTUAL_ACCOUNT_IDS[0] as UUID
|
|
const actualTransactions = transactions.map((transaction) =>
|
|
bankTransactionIntoActualTransaction(transaction, accountId),
|
|
)
|
|
|
|
logger.debug(
|
|
`Mapped ${JSON.stringify(transactions)} to ${JSON.stringify(actualTransactions)} transactions`,
|
|
)
|
|
|
|
// TODO Import transactions into Actual
|
|
// If multiple accounts, loop over them
|
|
// Get account ID from mapper
|
|
|
|
const response = await actual.importTransactions(
|
|
accountId,
|
|
actualTransactions,
|
|
)
|
|
logger.info(`ImportTransactionsResponse=${JSON.stringify(response)}`)
|
|
}
|
|
|
|
async function fetchTransactionsFromPastDay(
|
|
bank: Bank,
|
|
): Promise<ReadonlyArray<Transaction>> {
|
|
return bank.transactionsPastDay(BANK_ACCOUNT_IDS)
|
|
}
|
|
|
|
function createCacheDirIfMissing(): void {
|
|
if (!fs.existsSync(ACTUAL_DATA_DIR)) {
|
|
logger.info(`Missing '${ACTUAL_DATA_DIR}', creating...`)
|
|
fs.mkdirSync(ACTUAL_DATA_DIR)
|
|
}
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
logger.info("Starting application")
|
|
|
|
createCacheDirIfMissing()
|
|
|
|
const actual = await ActualImpl.init()
|
|
const databaseFileName = "default.sqlite"
|
|
const db = createDb(databaseFileName)
|
|
logger.info(`Started SQLlite database with filename="${databaseFileName}"`)
|
|
|
|
logger.info("Waiting for CRON job to start")
|
|
|
|
cronJobDaily(async () => {
|
|
logger.info("Running daily job")
|
|
await daily(actual, new Sparebank1Impl(db))
|
|
logger.info("Finished daily job")
|
|
})
|
|
|
|
// logger.info("Shutting down")
|
|
// await actual.shutdown()
|
|
// db.close()
|
|
}
|
|
|
|
void main()
|