refactor(server): migrate app entry point to TypeScript (.cts) — server migration 100%
Completes the JS→TS server migration. server.js → server.cts (Node type-stripping, no build step), and every launch/config reference now points at it: package.json (main/dev:api/start/check:server) and the Docker CMD. scripts/seedDemoData.js is required at runtime by routes/user.cts, so it crosses into the server runtime — migrated to .cts and its require of db/database updated to the .cts path. The remaining scripts/*.js are standalone dev/ops tooling (outside the runtime and the check:server boundary); their stale extensionless requires of now-.cts modules were repaired so they still run, and the PM2 ecosystem config entry point was updated to server.cts. Verified: 0 runtime .js remain in the server tree; typecheck:server and check:server clean; 226/226 tests pass; `node server.cts` boots and /api/health returns 200. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
135bd98c6a
commit
20d2e8965b
|
|
@ -51,4 +51,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|||
CMD node -e "require('http').get('http://127.0.0.1:'+(process.env.PORT||3000)+'/api/health',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"
|
||||
|
||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||
CMD ["node", "server.js"]
|
||||
CMD ["node", "server.cts"]
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
"name": "bill-tracker",
|
||||
"version": "0.40.0",
|
||||
"description": "Monthly bill tracking system",
|
||||
"main": "server.js",
|
||||
"main": "server.cts",
|
||||
"engines": {
|
||||
"node": ">=22.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev:api": "node --watch server.js",
|
||||
"dev:api": "node --watch server.cts",
|
||||
"dev:ui": "vite",
|
||||
"dev": "concurrently \"npm run dev:api\" \"npm run dev:ui\"",
|
||||
"build": "vite build",
|
||||
"check:server": "find server.js db middleware routes services utils workers \\( -name '*.js' -o -name '*.mts' -o -name '*.cts' -o -name '*.ts' \\) -print0 | xargs -0 -n1 node --check",
|
||||
"check:server": "find server.cts db middleware routes services utils workers \\( -name '*.js' -o -name '*.mts' -o -name '*.cts' -o -name '*.ts' \\) -print0 | xargs -0 -n1 node --check",
|
||||
"typecheck:server": "tsc --noEmit -p tsconfig.server.json",
|
||||
"lint": "eslint client",
|
||||
"typecheck": "tsc --noEmit -p tsconfig.json",
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
"test:e2e:probe": "node e2e/setup/prepare-db.js && playwright test --project=probe",
|
||||
"smoke:prod": "bash scripts/prod-smoke.sh",
|
||||
"ci": "npm run lint && npm run typecheck && npm run typecheck:server && npm run check:server && npm run test:all && npm run build",
|
||||
"start": "node server.js"
|
||||
"start": "node server.cts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.1.2",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { Req, Res, Next } from '../types/http';
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getDb } = require('../db/database.cts');
|
||||
const { seedDemoData } = require('../scripts/seedDemoData');
|
||||
const { seedDemoData } = require('../scripts/seedDemoData.cts');
|
||||
const { demoDataLimiter } = require('../middleware/rateLimiter.cts');
|
||||
const { eraseUserData } = require('../services/userDataService.cts');
|
||||
const { standardizeError } = require('../middleware/errorFormatter.cts');
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
apps: [
|
||||
{
|
||||
name: 'bill-tracker',
|
||||
script: 'server.js',
|
||||
script: 'server.cts',
|
||||
cwd: '/opt/bill-tracker',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
const { closeDb, getDb, getDbPath } = require('../db/database');
|
||||
const { closeDb, getDb, getDbPath } = require('../db/database.cts');
|
||||
|
||||
try {
|
||||
getDb();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const path = require('path');
|
|||
const DB_PATH = process.env.DB_PATH || path.join(__dirname, '..', 'db', 'bills.db');
|
||||
|
||||
// Import database helper
|
||||
const { getDb, ensureUserDefaultCategories } = require('../db/database');
|
||||
const { getDb, ensureUserDefaultCategories } = require('../db/database.cts');
|
||||
// Money columns (expected_amount, current_balance, minimum_payment) are stored as
|
||||
// integer cents since migration v1.03 — convert the demo dollars before insert.
|
||||
const { toCents } = require('../utils/money.mts');
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { cookieOpts } = require('../services/authService');
|
||||
const { cookieOpts } = require('../services/authService.cts');
|
||||
|
||||
function withEnv(values, fn) {
|
||||
const saved = {};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const {
|
|||
resolveYearMonth,
|
||||
findBillMatches: serviceFindBillMatches,
|
||||
buildRecommendation: serviceBuildRecommendation,
|
||||
} = require('../services/spreadsheetImportService');
|
||||
} = require('../services/spreadsheetImportService.cts');
|
||||
|
||||
// ─── Re-implement helpers for row-level tests (avoids DB init) ────────────────
|
||||
|
||||
|
|
@ -517,8 +517,8 @@ function runApplyRegression(name, body) {
|
|||
const APPLY_SETUP = `
|
||||
const assert = require('assert');
|
||||
const xlsx = require('xlsx');
|
||||
const { getDb, ensureUserDefaultCategories } = require('./db/database');
|
||||
const { previewSpreadsheet, applyImportDecisions } = require('./services/spreadsheetImportService');
|
||||
const { getDb, ensureUserDefaultCategories } = require('./db/database.cts');
|
||||
const { previewSpreadsheet, applyImportDecisions } = require('./services/spreadsheetImportService.cts');
|
||||
async function setup() {
|
||||
const db = getDb();
|
||||
db.prepare('INSERT INTO users (username,password_hash) VALUES (?,?)').run('importer','x');
|
||||
|
|
@ -615,8 +615,8 @@ ${APPLY_SETUP}
|
|||
runApplyRegression('create_new_bill imports related paid months for same detected bill', `
|
||||
const assert = require('assert');
|
||||
const xlsx = require('xlsx');
|
||||
const { getDb } = require('./db/database');
|
||||
const { previewSpreadsheet, applyImportDecisions } = require('./services/spreadsheetImportService');
|
||||
const { getDb } = require('./db/database.cts');
|
||||
const { previewSpreadsheet, applyImportDecisions } = require('./services/spreadsheetImportService.cts');
|
||||
(async () => {
|
||||
const db = getDb();
|
||||
db.prepare('INSERT INTO users (username,password_hash) VALUES (?,?)').run('importer','x');
|
||||
|
|
@ -857,8 +857,8 @@ const assert = require('assert');
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const Database = require('better-sqlite3');
|
||||
const { getDb, ensureUserDefaultCategories } = require('./db/database');
|
||||
const { previewUserDbImport, applyUserDbImport } = require('./services/userDbImportService');
|
||||
const { getDb, ensureUserDefaultCategories } = require('./db/database.cts');
|
||||
const { previewUserDbImport, applyUserDbImport } = require('./services/userDbImportService.cts');
|
||||
|
||||
function createExportBuffer(nameSuffix = '') {
|
||||
const file = path.join('/tmp', 'bill-tracker-user-export-test-' + process.pid + '-' + Date.now() + nameSuffix + '.sqlite');
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ const path = require('path');
|
|||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bill-tracker-oidc-'));
|
||||
process.env.DB_PATH = path.join(tempDir, 'test.sqlite');
|
||||
|
||||
const { getDb, getSetting, setSetting, closeDb } = require('../db/database');
|
||||
const oidcService = require('../services/oidcService');
|
||||
const { getDb, getSetting, setSetting, closeDb } = require('../db/database.cts');
|
||||
const oidcService = require('../services/oidcService.cts');
|
||||
|
||||
function clearOidcEnv() {
|
||||
for (const key of [
|
||||
|
|
@ -467,7 +467,7 @@ test('admin role only granted by configured group', async () => {
|
|||
});
|
||||
|
||||
test('OIDC-created user cannot local-password login', async () => {
|
||||
const { login } = require('../services/authService');
|
||||
const { login } = require('../services/authService.cts');
|
||||
clearOidcEnv();
|
||||
resetOidcSettings();
|
||||
await oidcService.findOrProvisionUser({
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck — app entry/bootstrap converted to .cts (Node type-stripping); Express wiring, typing deferred.
|
||||
const express = require('express');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const path = require('path');
|
||||
Loading…
Reference in New Issue