Skip to content

Commit

Permalink
Upgrade to ESM, update to latest dependencies (actualbudget#128)
Browse files Browse the repository at this point in the history
* Port to ESM

* + @types packages

* s/rmdir/rm/

* bump uuid

* Fix reading in eslintrc

* Add /build to eslintignore

* Update linting/types packages

* Stronger error checking

* - DOM globals

* update better-sqlite3

* Create .node-version

* Revert "update better-sqlite3"

This reverts commit 6b80038.
  • Loading branch information
j-f1 authored Feb 9, 2023
1 parent 76f398d commit be1c119
Show file tree
Hide file tree
Showing 19 changed files with 483 additions and 262 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
**/node_modules/*
**/log/*
**/shared/*
/build

supervise
File renamed without changes.
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18.14.0
2 changes: 1 addition & 1 deletion app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const run = require('./src/app');
import run from './src/app.js';

run().catch((err) => {
console.log('Error starting app:', err);
Expand Down
12 changes: 6 additions & 6 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const fs = require('fs');
const { join } = require('path');
const { getAccountDb } = require('./src/account-db');
const config = require('./src/load-config');
import fs from 'node:fs';
import path from 'node:path';
import getAccountDb from './src/account-db.js';
import config from './src/load-config.js';

// Delete previous test database (force creation of a new one)
const dbPath = join(config.serverFiles, 'account.sqlite');
const dbPath = path.join(config.serverFiles, 'account.sqlite');
if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath);

// Create path for test user files and delete previous files there
if (fs.existsSync(config.userFiles))
fs.rmdirSync(config.userFiles, { recursive: true });
fs.rmSync(config.userFiles, { recursive: true });
fs.mkdirSync(config.userFiles);

// Insert a fake "valid-token" fixture that can be reused
Expand Down
25 changes: 15 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"version": "23.2.6",
"license": "MIT",
"description": "actual syncing server",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node app",
"lint": "eslint .",
"build": "tsc",
"test": "jest",
"test": "NODE_OPTIONS='--experimental-vm-modules --trace-warnings' jest",
"types": "tsc --noEmit --incremental",
"verify": "yarn -s lint && yarn types"
},
Expand All @@ -22,21 +22,26 @@
"express": "4.18.2",
"express-actuator": "1.8.4",
"express-response-size": "^0.0.3",
"uuid": "^3.3.2"
"uuid": "^9.0.0"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/better-sqlite3": "^7.5.0",
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/express-actuator": "^1.8.0",
"@types/jest": "^29.2.3",
"@types/node": "^17.0.31",
"@types/node": "^17.0.45",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^5.23.0",
"eslint": "^8.15.0",
"eslint-plugin-prettier": "^4.0.0",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"eslint": "^8.33.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.3.1",
"prettier": "^2.6.2",
"prettier": "^2.8.3",
"supertest": "^6.3.1",
"typescript": "^4.6.4"
"typescript": "^4.9.5"
},
"packageManager": "[email protected]"
}
14 changes: 6 additions & 8 deletions src/account-db.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
let fs = require('fs');
let { join } = require('path');
let { openDatabase } = require('./db');
let config = require('./load-config');
import fs from 'node:fs';
import { join } from 'node:path';
import openDatabase from './db.js';
import config, { projectRoot } from './load-config.js';
let accountDb = null;

function getAccountDb() {
export default function getAccountDb() {
if (accountDb == null) {
if (!fs.existsSync(config.serverFiles)) {
console.log('MAKING SERVER DIR');
Expand All @@ -18,7 +18,7 @@ function getAccountDb() {

if (needsInit) {
let initSql = fs.readFileSync(
join(__dirname, '../sql/account.sql'),
join(projectRoot, 'sql/account.sql'),
'utf8'
);
accountDb.exec(initSql);
Expand All @@ -27,5 +27,3 @@ function getAccountDb() {

return accountDb;
}

module.exports = { getAccountDb };
19 changes: 9 additions & 10 deletions src/app-account.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
let express = require('express');
let bcrypt = require('bcrypt');
let uuid = require('uuid');
let errorMiddleware = require('./util/error-middleware');
let { validateUser } = require('./util/validate-user');
let { getAccountDb } = require('./account-db');
import express from 'express';
import * as bcrypt from 'bcrypt';
import * as uuid from 'uuid';
import errorMiddleware from './util/error-middleware.js';
import validateUser from './util/validate-user.js';
import getAccountDb from './account-db.js';

let app = express();
app.use(errorMiddleware);

function init() {
export { app as handlers };

export function init() {
// eslint-disable-previous-line @typescript-eslint/no-empty-function
}

Expand Down Expand Up @@ -111,6 +113,3 @@ app.get('/validate', (req, res) => {
});

app.use(errorMiddleware);

module.exports.handlers = app;
module.exports.init = init;
45 changes: 27 additions & 18 deletions src/app-sync.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
let fs = require('fs/promises');
let { Buffer } = require('buffer');
let express = require('express');
let uuid = require('uuid');
let { validateUser } = require('./util/validate-user');
let errorMiddleware = require('./util/error-middleware');
let { getAccountDb } = require('./account-db');
let { getPathForUserFile, getPathForGroupFile } = require('./util/paths');

let simpleSync = require('./sync-simple');

let actual = require('@actual-app/api');
import fs from 'node:fs/promises';
import { Buffer } from 'node:buffer';
import express from 'express';
import * as uuid from 'uuid';
import validateUser from './util/validate-user.js';
import errorMiddleware from './util/error-middleware.js';
import getAccountDb from './account-db.js';
import { getPathForUserFile, getPathForGroupFile } from './util/paths.js';

import * as simpleSync from './sync-simple.js';

import actual from '@actual-app/api';
let SyncPb = actual.internal.SyncProtoBuf;

const app = express();
app.use(errorMiddleware);
export { app as handlers };

// eslint-disable-next-line
async function init() {}
export async function init() {}

// This is a version representing the internal format of sync
// messages. When this changes, all sync files need to be reset. We
Expand Down Expand Up @@ -203,15 +204,22 @@ app.post('/upload-user-file', async (req, res) => {
}

let accountDb = getAccountDb();
if (typeof req.headers['x-actual-name'] !== 'string') {
res.status(400).send('single x-actual-name is required');
return;
}
let name = decodeURIComponent(req.headers['x-actual-name']);
let fileId = req.headers['x-actual-file-id'];
let groupId = req.headers['x-actual-group-id'] || null;
let encryptMeta = req.headers['x-actual-encrypt-meta'] || null;
let syncFormatVersion = req.headers['x-actual-format'] || null;

let keyId = encryptMeta ? JSON.parse(encryptMeta).keyId : null;
let keyId =
encryptMeta && typeof encryptMeta === 'string'
? JSON.parse(encryptMeta).keyId
: null;

if (!fileId) {
if (!fileId || typeof fileId !== 'string') {
throw new Error('fileId is required');
}

Expand Down Expand Up @@ -290,6 +298,10 @@ app.get('/download-user-file', async (req, res) => {
}
let accountDb = getAccountDb();
let fileId = req.headers['x-actual-file-id'];
if (typeof fileId !== 'string') {
res.status(400).send('Single file ID is required');
return;
}

// Do some authentication
let rows = accountDb.all(
Expand Down Expand Up @@ -403,6 +415,3 @@ app.post('/delete-user-file', (req, res) => {
accountDb.mutate('UPDATE files SET deleted = TRUE WHERE id = ?', [fileId]);
res.send(JSON.stringify({ status: 'ok' }));
});

module.exports.handlers = app;
module.exports.init = init;
10 changes: 5 additions & 5 deletions src/app-sync.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const fs = require('fs');
const request = require('supertest');
const { handlers: app } = require('./app-sync');
const { getAccountDb } = require('./account-db');
const { getPathForUserFile } = require('./util/paths');
import fs from 'node:fs';
import request from 'supertest';
import { handlers as app } from './app-sync.js';
import getAccountDb from './account-db.js';
import { getPathForUserFile } from './util/paths.js';

describe('/download-user-file', () => {
describe('default version', () => {
Expand Down
20 changes: 10 additions & 10 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const fs = require('fs');
const express = require('express');
const actuator = require('express-actuator');
const bodyParser = require('body-parser');
const cors = require('cors');
const config = require('./load-config');
import fs from 'node:fs';
import express from 'express';
import actuator from 'express-actuator';
import bodyParser from 'body-parser';
import cors from 'cors';
import config from './load-config.js';

const accountApp = require('./app-account');
const syncApp = require('./app-sync');
import * as accountApp from './app-account.js';
import * as syncApp from './app-sync.js';

const app = express();

Expand Down Expand Up @@ -45,7 +45,7 @@ function parseHTTPSConfig(value) {
return fs.readFileSync(value);
}

module.exports = async function run() {
export default async function run() {
if (!fs.existsSync(config.serverFiles)) {
fs.mkdirSync(config.serverFiles);
}
Expand All @@ -69,4 +69,4 @@ module.exports = async function run() {
app.listen(config.port, config.hostname);
}
console.log('Listening on ' + config.hostname + ':' + config.port + '...');
};
}
25 changes: 21 additions & 4 deletions src/db.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
let Database = require('better-sqlite3');
import Database from 'better-sqlite3';

class WrappedDatabase {
constructor(db) {
this.db = db;
}

/**
* @param {string} sql
* @param {string[]} params
*/
all(sql, params = []) {
let stmt = this.db.prepare(sql);
return stmt.all(...params);
}

/**
* @param {string} sql
* @param {string[]} params
*/
first(sql, params = []) {
let rows = this.all(sql, params);
return rows.length === 0 ? null : rows[0];
}

/**
* @param {string} sql
*/
exec(sql) {
this.db.exec(sql);
}

/**
* @param {string} sql
* @param {string[]} params
*/
mutate(sql, params = []) {
let stmt = this.db.prepare(sql);
let info = stmt.run(...params);
return { changes: info.changes, insertId: info.lastInsertRowid };
}

/**
* @param {() => void} fn
*/
transaction(fn) {
return this.db.transaction(fn)();
}
Expand All @@ -34,8 +52,7 @@ class WrappedDatabase {
}
}

function openDatabase(filename) {
/** @param {string} filename */
export default function openDatabase(filename) {
return new WrappedDatabase(new Database(filename));
}

module.exports = { openDatabase };
Loading

0 comments on commit be1c119

Please sign in to comment.