2026-05-28 22:06:15 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
// import required so Node type-strips this .cts (it has no other import).
|
|
|
|
|
import type { Db } from '../types/db';
|
|
|
|
|
|
refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
converted with @ts-nocheck (typing deferred). All requires updated to .cts.
Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
|
|
|
const { getSetting, setSetting } = require('../db/database.cts');
|
2026-05-28 22:06:15 -05:00
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
const SYNC_DAYS_MAX = 45; // SimpleFIN Bridge hard limit — requests beyond this return an error
|
|
|
|
|
const SYNC_DAYS_EFFECTIVE = 44; // 1-day buffer so request latency never tips over the hard limit
|
|
|
|
|
const SYNC_DAYS_DEFAULT = 30; // routine sync window (initial seed always uses SYNC_DAYS_EFFECTIVE)
|
|
|
|
|
const SYNC_INTERVAL_DEFAULT = 4; // hours
|
2026-05-28 22:06:15 -05:00
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
interface BankSyncConfig {
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
sync_days: number;
|
|
|
|
|
seed_days: number;
|
|
|
|
|
sync_days_max: number;
|
|
|
|
|
sync_interval_hours: number;
|
|
|
|
|
debug_logging: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getBankSyncConfig(): BankSyncConfig {
|
2026-07-06 14:23:53 -05:00
|
|
|
const dbValue = getSetting('bank_sync_enabled');
|
2026-05-28 22:06:15 -05:00
|
|
|
const envValue = process.env.BANK_SYNC_ENABLED;
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
let enabled: boolean;
|
2026-05-28 22:06:15 -05:00
|
|
|
if (dbValue !== null && dbValue !== undefined && dbValue !== '') {
|
|
|
|
|
enabled = dbValue === 'true';
|
|
|
|
|
} else if (envValue !== undefined && envValue !== '') {
|
|
|
|
|
enabled = envValue === 'true';
|
|
|
|
|
} else {
|
|
|
|
|
enabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
const syncDaysDb = parseInt(getSetting('simplefin_sync_days') || '', 10);
|
2026-05-28 22:06:15 -05:00
|
|
|
const syncDaysEnv = parseInt(process.env.SIMPLEFIN_SYNC_DAYS || '', 10);
|
2026-07-06 14:23:53 -05:00
|
|
|
const rawSyncDays =
|
|
|
|
|
Number.isFinite(syncDaysDb) && syncDaysDb > 0
|
|
|
|
|
? syncDaysDb
|
|
|
|
|
: Number.isFinite(syncDaysEnv) && syncDaysEnv > 0
|
|
|
|
|
? syncDaysEnv
|
|
|
|
|
: SYNC_DAYS_DEFAULT;
|
2026-05-29 02:51:30 -05:00
|
|
|
const syncDays = Math.min(rawSyncDays, SYNC_DAYS_EFFECTIVE);
|
2026-05-28 22:06:15 -05:00
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
const intervalDb = parseFloat(getSetting('simplefin_sync_interval_hours') || '');
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
const intervalEnv = parseFloat(process.env.SIMPLEFIN_SYNC_INTERVAL_HOURS || '');
|
2026-07-06 14:23:53 -05:00
|
|
|
const syncIntervalHours =
|
|
|
|
|
Number.isFinite(intervalDb) && intervalDb >= 0.5
|
|
|
|
|
? intervalDb
|
|
|
|
|
: Number.isFinite(intervalEnv) && intervalEnv >= 0.5
|
|
|
|
|
? intervalEnv
|
|
|
|
|
: SYNC_INTERVAL_DEFAULT;
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
const debugDb = getSetting('simplefin_debug_logging');
|
2026-06-07 19:41:17 -05:00
|
|
|
const debugEnv = process.env.SIMPLEFIN_DEBUG_LOGGING;
|
|
|
|
|
const debugLogging = debugDb === 'true' || (!debugDb && debugEnv === 'true');
|
|
|
|
|
|
2026-05-28 22:06:15 -05:00
|
|
|
return {
|
|
|
|
|
enabled,
|
|
|
|
|
sync_days: syncDays,
|
2026-06-07 19:41:17 -05:00
|
|
|
seed_days: SYNC_DAYS_EFFECTIVE,
|
|
|
|
|
sync_days_max: SYNC_DAYS_MAX,
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
sync_interval_hours: syncIntervalHours,
|
2026-06-07 19:41:17 -05:00
|
|
|
debug_logging: debugLogging,
|
2026-05-28 22:06:15 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
function setBankSyncEnabled(enabled: boolean): BankSyncConfig {
|
2026-05-28 22:06:15 -05:00
|
|
|
setSetting('bank_sync_enabled', enabled ? 'true' : 'false');
|
|
|
|
|
return getBankSyncConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
function setSyncIntervalHours(hours: number | string): BankSyncConfig {
|
|
|
|
|
const n = parseFloat(hours as string);
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
if (!Number.isFinite(n) || n < 0.5 || n > 168) {
|
2026-07-06 14:23:53 -05:00
|
|
|
throw Object.assign(new Error('sync_interval_hours must be between 0.5 and 168'), {
|
|
|
|
|
status: 400,
|
|
|
|
|
});
|
feat: configurable sync interval, auto-match, encryption note, admin link, SimpleFIN hyperlink
#1 Sync interval in admin UI:
- bankSyncConfigService: reads simplefin_sync_interval_hours from settings
(DB-first, env fallback, default 4h), setSyncIntervalHours() with validation
- bankSyncWorker: live-updates interval from getBankSyncConfig() each tick
- routes/admin: PUT accepts enabled and sync_interval_hours independently
- BankSyncAdminCard: number input (0.5 step, 0.5-168 range), dirty-checks both
#3 Auto-match after background sync:
- matchSuggestionService: autoMatchForUser() auto-applies suggestions ≥80
score (exact amount + date ±1d + name signal), lazy-requires matchTransactionToBill
- bankSyncWorker: calls autoMatchForUser after each successful sync, own try/catch
#4 Encryption note in BankSyncAdminCard below worker status panel
Also: error handling, admin link in tracker sidebar, SimpleFIN bridge hyperlink
2026-05-29 00:28:50 -05:00
|
|
|
}
|
|
|
|
|
setSetting('simplefin_sync_interval_hours', String(Math.round(n * 10) / 10));
|
|
|
|
|
return getBankSyncConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
function setSyncDays(days: number | string): BankSyncConfig {
|
|
|
|
|
const n = parseInt(days as string, 10);
|
2026-05-29 02:23:19 -05:00
|
|
|
if (!Number.isFinite(n) || n < 1 || n > SYNC_DAYS_MAX) {
|
2026-07-06 14:23:53 -05:00
|
|
|
throw Object.assign(
|
|
|
|
|
new Error(`sync_days must be between 1 and ${SYNC_DAYS_MAX} (SimpleFIN Bridge hard limit)`),
|
|
|
|
|
{ status: 400 },
|
|
|
|
|
);
|
2026-05-29 01:33:54 -05:00
|
|
|
}
|
|
|
|
|
setSetting('simplefin_sync_days', String(n));
|
|
|
|
|
return getBankSyncConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 10:47:16 -05:00
|
|
|
function setDebugLogging(enabled: boolean): BankSyncConfig {
|
2026-06-07 19:41:17 -05:00
|
|
|
setSetting('simplefin_debug_logging', enabled ? 'true' : 'false');
|
|
|
|
|
return getBankSyncConfig();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-06 15:51:56 -05:00
|
|
|
module.exports = {
|
2026-07-06 14:23:53 -05:00
|
|
|
getBankSyncConfig,
|
|
|
|
|
setBankSyncEnabled,
|
|
|
|
|
setSyncIntervalHours,
|
|
|
|
|
setSyncDays,
|
|
|
|
|
setDebugLogging,
|
|
|
|
|
SYNC_DAYS_MAX,
|
|
|
|
|
SYNC_DAYS_EFFECTIVE,
|
|
|
|
|
SYNC_DAYS_DEFAULT,
|
2026-06-06 15:51:56 -05:00
|
|
|
};
|