refactor(server): finish services layer — subscription/spreadsheet/oidc/userDbImport → .cts

Completes the services/ TypeScript migration (0 .js remain). These four are the
largest, most dynamic modules (subscription-catalog matcher, xlsx/spreadsheet
parser, OIDC protocol client, SQLite user-DB importer); converted to .cts with a
top-of-file @ts-nocheck so they run via Node type-stripping now, with rich typing
deferred as an incremental follow-up. The other ~46 services are fully typed.

Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
null 2026-07-06 11:22:44 -05:00
parent 99e4927640
commit 409b8a5618
17 changed files with 18 additions and 14 deletions

View File

@ -1213,7 +1213,7 @@ module.exports = function buildVersionedMigrations(deps) {
description: 're-normalize merchant rules after & fix; ensure rejection expiry column', description: 're-normalize merchant rules after & fix; ensure rejection expiry column',
dependsOn: ['v0.89'], dependsOn: ['v0.89'],
run: function() { run: function() {
const { normalizeMerchant } = require('../../services/subscriptionService'); const { normalizeMerchant } = require('../../services/subscriptionService.cts');
// Re-normalize bill_merchant_rules stored under old normalization ("at t" → "att") // Re-normalize bill_merchant_rules stored under old normalization ("at t" → "att")
let billFixed = 0; let billFixed = 0;

View File

@ -409,7 +409,7 @@ const {
buildAuthModeStatus, buildAuthModeStatus,
buildSubmittedOidcConfig, buildSubmittedOidcConfig,
testOidcConfiguration, testOidcConfiguration,
} = require('../services/oidcService'); } = require('../services/oidcService.cts');
// GET /api/admin/auth-mode // GET /api/admin/auth-mode
router.get('/auth-mode', (req, res) => { router.get('/auth-mode', (req, res) => {

View File

@ -14,7 +14,7 @@ const { login, logout, hashPassword, cookieOpts, COOKIE_NAME, SINGLE_COOKIE_NAME
const { decryptSecret } = require('../services/encryptionService.cts'); const { decryptSecret } = require('../services/encryptionService.cts');
const { getCsrfToken } = require('../middleware/csrf'); const { getCsrfToken } = require('../middleware/csrf');
const { requireAuth, requireAdmin } = require('../middleware/requireAuth'); const { requireAuth, requireAdmin } = require('../middleware/requireAuth');
const { getPublicOidcInfo } = require('../services/oidcService'); const { getPublicOidcInfo } = require('../services/oidcService.cts');
const { ValidationError, formatError } = require('../utils/apiError.cts'); const { ValidationError, formatError } = require('../utils/apiError.cts');
const { standardizeError } = require('../middleware/errorFormatter'); const { standardizeError } = require('../middleware/errorFormatter');
const { passwordLimiter } = require('../middleware/rateLimiter'); const { passwordLimiter } = require('../middleware/rateLimiter');

View File

@ -22,7 +22,7 @@ const {
buildAuthorizationUrl, buildAuthorizationUrl,
exchangeAndVerifyTokens, exchangeAndVerifyTokens,
findOrProvisionUser, findOrProvisionUser,
} = require('../services/oidcService'); } = require('../services/oidcService.cts');
const NOT_ACTIVE = { error: 'OIDC authentication is not configured or not enabled on this server' }; const NOT_ACTIVE = { error: 'OIDC authentication is not configured or not enabled on this server' };

View File

@ -16,7 +16,7 @@ const { amortizationSchedule, debtAprSnapshot } = require('../services/aprServic
const { standardizeError } = require('../middleware/errorFormatter'); const { standardizeError } = require('../middleware/errorFormatter');
const { validatePaymentInput, serializePayment } = require('../services/paymentValidation.cts'); const { validatePaymentInput, serializePayment } = require('../services/paymentValidation.cts');
const { addMerchantRule, syncBillPaymentsFromSimplefin, merchantMatches } = require('../services/billMerchantRuleService.cts'); const { addMerchantRule, syncBillPaymentsFromSimplefin, merchantMatches } = require('../services/billMerchantRuleService.cts');
const { normalizeMerchant } = require('../services/subscriptionService'); const { normalizeMerchant } = require('../services/subscriptionService.cts');
const { decorateTransaction } = require('../services/transactionService.cts'); const { decorateTransaction } = require('../services/transactionService.cts');
const { const {
accountingActiveSql, accountingActiveSql,

View File

@ -7,11 +7,11 @@ const {
previewSpreadsheet, previewSpreadsheet,
applyImportDecisions, applyImportDecisions,
getImportHistory, getImportHistory,
} = require('../services/spreadsheetImportService'); } = require('../services/spreadsheetImportService.cts');
const { const {
previewUserDbImport, previewUserDbImport,
applyUserDbImport, applyUserDbImport,
} = require('../services/userDbImportService'); } = require('../services/userDbImportService.cts');
const { const {
previewCsvTransactions, previewCsvTransactions,
commitCsvTransactions, commitCsvTransactions,

View File

@ -7,7 +7,7 @@ const { passwordLimiter } = require('../middleware/rateLimiter');
const { getDb, getSetting } = require('../db/database'); const { getDb, getSetting } = require('../db/database');
const { hashPassword, invalidateOtherSessions, rotateSessionId, COOKIE_NAME, cookieOpts } = require('../services/authService.cts'); const { hashPassword, invalidateOtherSessions, rotateSessionId, COOKIE_NAME, cookieOpts } = require('../services/authService.cts');
const { getImportHistory } = require('../services/spreadsheetImportService'); const { getImportHistory } = require('../services/spreadsheetImportService.cts');
const { logAudit } = require('../services/auditService.cts'); const { logAudit } = require('../services/auditService.cts');
const { standardizeError } = require('../middleware/errorFormatter'); const { standardizeError } = require('../middleware/errorFormatter');
const { encryptSecret, decryptSecret } = require('../services/encryptionService.cts'); const { encryptSecret, decryptSecret } = require('../services/encryptionService.cts');

View File

@ -13,7 +13,7 @@ const {
monthlyEquivalent, monthlyEquivalent,
recordSubscriptionFeedback, recordSubscriptionFeedback,
searchSubscriptionTransactions, searchSubscriptionTransactions,
} = require('../services/subscriptionService'); } = require('../services/subscriptionService.cts');
const { addMerchantRule, applyMerchantRules } = require('../services/billMerchantRuleService.cts'); const { addMerchantRule, applyMerchantRules } = require('../services/billMerchantRuleService.cts');
router.get('/', (req, res) => { router.get('/', (req, res) => {

View File

@ -2,7 +2,7 @@
import type { Db } from '../types/db'; import type { Db } from '../types/db';
const { normalizeMerchant } = require('./subscriptionService'); const { normalizeMerchant } = require('./subscriptionService.cts');
const { getUserSettings } = require('./userSettings.cts'); const { getUserSettings } = require('./userSettings.cts');
const { applyBankPaymentAsSourceOfTruth } = require('./paymentAccountingService.cts'); const { applyBankPaymentAsSourceOfTruth } = require('./paymentAccountingService.cts');
const { localDateString } = require('../utils/dates.mts') as typeof import('../utils/dates.mts'); const { localDateString } = require('../utils/dates.mts') as typeof import('../utils/dates.mts');

View File

@ -1,3 +1,4 @@
// @ts-nocheck — converted to .cts (runs via Node type-stripping); rich typing deferred (large dynamic OIDC protocol client). TODO: type incrementally.
'use strict'; 'use strict';
/** /**

View File

@ -2,7 +2,7 @@
import type { Db } from '../types/db'; import type { Db } from '../types/db';
const { normalizeMerchant } = require('./subscriptionService'); const { normalizeMerchant } = require('./subscriptionService.cts');
const { localDateString } = require('../utils/dates.mts') as typeof import('../utils/dates.mts'); const { localDateString } = require('../utils/dates.mts') as typeof import('../utils/dates.mts');
const { toCents, fromCents } = require('../utils/money.mts') as typeof import('../utils/money.mts'); const { toCents, fromCents } = require('../utils/money.mts') as typeof import('../utils/money.mts');

View File

@ -1,3 +1,4 @@
// @ts-nocheck — converted to .cts (runs via Node type-stripping); rich typing deferred (1800-line dynamic spreadsheet/xlsx parser). TODO: type incrementally.
'use strict'; 'use strict';
// Security note: xlsx (SheetJS Community Edition) has known prototype-pollution // Security note: xlsx (SheetJS Community Edition) has known prototype-pollution

View File

@ -1,3 +1,4 @@
// @ts-nocheck — converted to .cts (runs via Node type-stripping); rich typing deferred (large, dynamic subscription-catalog matcher). TODO: type incrementally.
'use strict'; 'use strict';
const { billingCycleForCycleType, insertBill, validateBillData } = require('./billsService.cts'); const { billingCycleForCycleType, insertBill, validateBillData } = require('./billsService.cts');

View File

@ -8,7 +8,7 @@ const { getUserSettings } = require('./userSettings.cts');
const { computeBalanceDelta, applyBalanceDelta } = require('./billsService.cts'); const { computeBalanceDelta, applyBalanceDelta } = require('./billsService.cts');
const { computeAmountSuggestionsBatch } = require('./amountSuggestionService.cts'); const { computeAmountSuggestionsBatch } = require('./amountSuggestionService.cts');
const { accountingActiveSql } = require('./paymentAccountingService.cts'); const { accountingActiveSql } = require('./paymentAccountingService.cts');
const { normalizeMerchant } = require('./subscriptionService'); const { normalizeMerchant } = require('./subscriptionService.cts');
const { localDateString } = require('../utils/dates.mts'); const { localDateString } = require('../utils/dates.mts');
// Aggregation-heavy: money results flow through many .filter/.sort/arith, so a // Aggregation-heavy: money results flow through many .filter/.sort/arith, so a
// plain require (→ any) avoids Dollars|null friction (cf. analyticsService). // plain require (→ any) avoids Dollars|null friction (cf. analyticsService).

View File

@ -1,3 +1,4 @@
// @ts-nocheck — converted to .cts (runs via Node type-stripping); rich typing deferred (large dynamic SQLite user-DB importer). TODO: type incrementally.
'use strict'; 'use strict';
const crypto = require('crypto'); const crypto = require('crypto');

View File

@ -15,7 +15,7 @@ process.env.DB_PATH = dbPath;
const { getDb, closeDb } = require('../db/database'); const { getDb, closeDb } = require('../db/database');
const { buildUserDbExportFile } = require('../routes/export'); const { buildUserDbExportFile } = require('../routes/export');
const { previewUserDbImport, applyUserDbImport } = require('../services/userDbImportService'); const { previewUserDbImport, applyUserDbImport } = require('../services/userDbImportService.cts');
const mkUser = (db, name) => const mkUser = (db, name) =>
db.prepare("INSERT INTO users (username, password_hash, role, active) VALUES (?, 'x', 'user', 1)").run(name).lastInsertRowid; db.prepare("INSERT INTO users (username, password_hash, role, active) VALUES (?, 'x', 'user', 1)").run(name).lastInsertRowid;

View File

@ -12,7 +12,7 @@ const {
getSubscriptionRecommendations, getSubscriptionRecommendations,
recordSubscriptionFeedback, recordSubscriptionFeedback,
searchSubscriptionTransactions, searchSubscriptionTransactions,
} = require('../services/subscriptionService'); } = require('../services/subscriptionService.cts');
function createUser(db, suffix) { function createUser(db, suffix) {
return db.prepare(` return db.prepare(`