mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-09 06:02:22 -05:00
Enable Typescript in sync-server (#4887)
* attempt at running with typescript * release notes * working jest tests for TS files * working docker image build * remaining docker images * cleanup * ensure vitest is working * get tests passing in ci * less strict * update release notes * use tsc compiled assets in the published package * scripts * update yarn.lock * Use build path for electron app * PR feedback: move sync-server build out of bin/build-browser * PR feedback: undo moduleResolution change * extend main tsconfig and fix types * PR feedback on scripts and when the sync-server build runs * fix lint (unrelated change) --------- Co-authored-by: alecbakholdin <alecbakholdin@gmail.com>
This commit is contained in:
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Build Web
|
||||
run: ./bin/package-browser
|
||||
run: yarn build:browser
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Build Server
|
||||
run: cd packages/sync-server && yarn build
|
||||
run: yarn workspace @actual-app/sync-server build
|
||||
- name: Upload Build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
2
.github/workflows/docker-edge.yml
vendored
2
.github/workflows/docker-edge.yml
vendored
@@ -78,7 +78,7 @@ jobs:
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Build Web
|
||||
run: ./bin/package-browser
|
||||
run: yarn build:server
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v5
|
||||
|
||||
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
- name: Set up environment
|
||||
uses: ./.github/actions/setup
|
||||
- name: Build Web
|
||||
run: ./bin/package-browser
|
||||
run: yarn build:server
|
||||
|
||||
- name: Build and push ubuntu image
|
||||
uses: docker/build-push-action@v5
|
||||
|
||||
2
.github/workflows/netlify-release.yml
vendored
2
.github/workflows/netlify-release.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
run: npm install netlify-cli@17.10.1 -g
|
||||
|
||||
- name: Build Actual
|
||||
run: ./bin/package-browser
|
||||
run: yarn build:browser
|
||||
|
||||
- name: Deploy to Netlify
|
||||
id: netlify_deploy
|
||||
|
||||
2
.github/workflows/publish-npm-packages.yml
vendored
2
.github/workflows/publish-npm-packages.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build Web
|
||||
run: yarn build:browser
|
||||
run: yarn build:server
|
||||
|
||||
- name: Pack the web and server packages
|
||||
run: |
|
||||
|
||||
@@ -45,6 +45,7 @@ yarn workspace @actual-app/web build --mode=desktop # electron specific build
|
||||
# required for running the sync-server server
|
||||
yarn workspace loot-core build:browser
|
||||
yarn workspace @actual-app/web build:browser
|
||||
yarn workspace @actual-app/sync-server build
|
||||
|
||||
yarn workspace desktop-electron update-client
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"start:browser": "npm-run-all --parallel 'start:browser-*'",
|
||||
"start:browser-backend": "yarn workspace loot-core watch:browser",
|
||||
"start:browser-frontend": "yarn workspace @actual-app/web start:browser",
|
||||
"build:server": "yarn build:browser",
|
||||
"build:server": "yarn build:browser && yarn workspace @actual-app/sync-server build",
|
||||
"build:browser": "./bin/package-browser",
|
||||
"build:desktop": "./bin/package-electron",
|
||||
"build:api": "yarn workspace @actual-app/api build",
|
||||
|
||||
@@ -228,6 +228,7 @@ async function startSyncServer() {
|
||||
const serverPath = path.join(
|
||||
// require.resolve will recursively search up the workspace for the module
|
||||
path.dirname(require.resolve('@actual-app/sync-server/package.json')),
|
||||
'build',
|
||||
'app.js',
|
||||
);
|
||||
|
||||
|
||||
@@ -53,9 +53,8 @@ ENV NODE_ENV=production
|
||||
|
||||
# Pull in only the necessary artifacts (built node_modules, server files, etc.)
|
||||
COPY --from=builder /app/node_modules /app/node_modules
|
||||
COPY --from=builder /app/packages/sync-server/package.json /app/packages/sync-server/app.js ./
|
||||
COPY --from=builder /app/packages/sync-server/src ./src
|
||||
COPY --from=builder /app/packages/sync-server/migrations ./migrations
|
||||
COPY --from=builder /app/packages/sync-server/package.json ./
|
||||
COPY --from=builder /app/packages/sync-server/build ./
|
||||
|
||||
ENTRYPOINT ["/sbin/tini","-g", "--"]
|
||||
EXPOSE 5006
|
||||
|
||||
@@ -54,9 +54,8 @@ ENV NODE_ENV=production
|
||||
|
||||
# Pull in only the necessary artifacts (built node_modules, server files, etc.)
|
||||
COPY --from=builder /app/node_modules /app/node_modules
|
||||
COPY --from=builder /app/packages/sync-server/package.json /app/packages/sync-server/app.js ./
|
||||
COPY --from=builder /app/packages/sync-server/src ./src
|
||||
COPY --from=builder /app/packages/sync-server/migrations ./migrations
|
||||
COPY --from=builder /app/packages/sync-server/package.json ./
|
||||
COPY --from=builder /app/packages/sync-server/build ./
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini","-g", "--"]
|
||||
EXPOSE 5006
|
||||
|
||||
@@ -4,30 +4,27 @@
|
||||
"license": "MIT",
|
||||
"description": "actual syncing server",
|
||||
"bin": {
|
||||
"actual-server": "./bin/actual-server.js"
|
||||
"actual-server": "./build/bin/actual-server.js"
|
||||
},
|
||||
"type": "module",
|
||||
"files": [
|
||||
"bin",
|
||||
"src",
|
||||
"app.js",
|
||||
"migrations",
|
||||
"build",
|
||||
"default-db.sqlite",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "node app",
|
||||
"start-monitor": "nodemon app",
|
||||
"start": "yarn build && node build/app",
|
||||
"start-monitor": "nodemon --exec 'tsc && node build/app' --ignore './build/**/*' --ext 'ts,js' build/app",
|
||||
"build": "tsc",
|
||||
"test": "NODE_ENV=test NODE_OPTIONS='--experimental-vm-modules --trace-warnings' vitest",
|
||||
"db:migrate": "NODE_ENV=development node src/run-migrations.js up",
|
||||
"db:downgrade": "NODE_ENV=development node src/run-migrations.js down",
|
||||
"db:test-migrate": "NODE_ENV=test node src/run-migrations.js up",
|
||||
"db:test-downgrade": "NODE_ENV=test node src/run-migrations.js down",
|
||||
"reset-password": "node src/scripts/reset-password.js",
|
||||
"disable-openid": "node src/scripts/disable-openid.js",
|
||||
"health-check": "node src/scripts/health-check.js"
|
||||
"db:migrate": "yarn build && cross-env NODE_ENV=development node build/src/scripts/run-migrations.js up",
|
||||
"db:downgrade": "yarn build && cross-env NODE_ENV=development node build/src/scripts/run-migrations.js down",
|
||||
"db:test-migrate": "yarn build && cross-env NODE_ENV=test node build/src/scripts/run-migrations.js up",
|
||||
"db:test-downgrade": "yarn build && cross-env NODE_ENV=test node build/src/scripts/run-migrations.js down",
|
||||
"reset-password": "yarn build && node build/src/scripts/reset-password.js",
|
||||
"disable-openid": "yarn build && node build/src/scripts/disable-openid.js",
|
||||
"health-check": "yarn build && node build/src/scripts/health-check.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actual-app/crdt": "2.1.0",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-strict-ignore
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-strict-ignore
|
||||
import { Buffer } from 'node:buffer';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
@@ -55,7 +56,7 @@ const verifyFileExists = (fileId, filesService, res, errorObject) => {
|
||||
}
|
||||
};
|
||||
|
||||
app.post('/sync', async (req, res) => {
|
||||
app.post('/sync', async (req, res): Promise<void> => {
|
||||
let requestPb;
|
||||
try {
|
||||
requestPb = SyncProtoBuf.SyncRequest.deserializeBinary(req.body);
|
||||
@@ -73,11 +74,12 @@ app.post('/sync', async (req, res) => {
|
||||
const messages = requestPb.getMessagesList();
|
||||
|
||||
if (!since) {
|
||||
return res.status(422).send({
|
||||
res.status(422).send({
|
||||
details: 'since-required',
|
||||
reason: 'unprocessable-entity',
|
||||
status: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const filesService = new FilesService(getAccountDb());
|
||||
@@ -373,11 +375,12 @@ app.post('/delete-user-file', (req, res) => {
|
||||
const { fileId } = req.body;
|
||||
|
||||
if (!fileId) {
|
||||
return res.status(422).send({
|
||||
res.status(422).send({
|
||||
details: 'fileId-required',
|
||||
reason: 'unprocessable-entity',
|
||||
status: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const filesService = new FilesService(getAccountDb());
|
||||
@@ -88,7 +88,6 @@ if (process.env.NODE_ENV === 'development') {
|
||||
target: 'http://localhost:3001',
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
logLevel: 'debug',
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
@@ -100,7 +99,7 @@ if (process.env.NODE_ENV === 'development') {
|
||||
);
|
||||
}
|
||||
|
||||
function parseHTTPSConfig(value) {
|
||||
function parseHTTPSConfig(value: string) {
|
||||
if (value.startsWith('-----BEGIN')) {
|
||||
return value;
|
||||
}
|
||||
@@ -108,9 +107,13 @@ function parseHTTPSConfig(value) {
|
||||
}
|
||||
|
||||
export async function run() {
|
||||
const portVal = config.get('port');
|
||||
const port = typeof portVal === 'string' ? parseInt(portVal) : portVal;
|
||||
const hostname = config.get('hostname');
|
||||
const openIdConfig = config?.getProperties()?.openId;
|
||||
if (
|
||||
openIdConfig?.discoveryURL ||
|
||||
// @ts-expect-error FIXME no types for config yet
|
||||
openIdConfig?.issuer?.authorization_endpoint
|
||||
) {
|
||||
console.log('OpenID configuration found. Preparing server to use it');
|
||||
@@ -129,18 +132,17 @@ export async function run() {
|
||||
if (config.get('https.key') && config.get('https.cert')) {
|
||||
const https = await import('node:https');
|
||||
const httpsOptions = {
|
||||
...config.https,
|
||||
...config.get('https'),
|
||||
key: parseHTTPSConfig(config.get('https.key')),
|
||||
cert: parseHTTPSConfig(config.get('https.cert')),
|
||||
};
|
||||
https
|
||||
.createServer(httpsOptions, app)
|
||||
.listen(config.get('port'), config.get('hostname'));
|
||||
https.createServer(httpsOptions, app).listen(port, hostname);
|
||||
} else {
|
||||
app.listen(config.get('port'), config.get('hostname'));
|
||||
app.listen(port, hostname);
|
||||
}
|
||||
|
||||
// Signify to any parent process that the server has started. Used in electron desktop app
|
||||
// @ts-ignore-error electron types
|
||||
process.parentPort?.postMessage({ type: 'server-started' });
|
||||
|
||||
console.log(
|
||||
@@ -10,7 +10,9 @@ const require = createRequire(import.meta.url);
|
||||
const debug = createDebug('actual:config');
|
||||
const debugSensitive = createDebug('actual-sensitive:config');
|
||||
|
||||
const projectRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
||||
const projectRoot = path
|
||||
.dirname(path.dirname(fileURLToPath(import.meta.url)))
|
||||
.replace(/[\\/]build$/, '');
|
||||
const defaultDataDir = process.env.ACTUAL_DATA_DIR
|
||||
? process.env.ACTUAL_DATA_DIR
|
||||
: fs.existsSync('/data')
|
||||
|
||||
@@ -15,7 +15,7 @@ export function run(direction = 'up') {
|
||||
stateStore: `${path.join(config.get('dataDir'), '.migrate')}${
|
||||
config.get('mode') === 'test' ? '-test' : ''
|
||||
}`,
|
||||
migrationsDirectory: `${path.join(config.get('projectRoot'), 'migrations')}`,
|
||||
migrationsDirectory: `${path.join(config.get('projectRoot'), config.get('mode') === 'test' ? '' : 'build', 'migrations')}`,
|
||||
},
|
||||
(err, set) => {
|
||||
if (err) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { run } from './migrations.js';
|
||||
import { run } from '../migrations.js';
|
||||
|
||||
const direction = process.argv[2] || 'up';
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
// DOM for URL global in Node 16+
|
||||
"lib": ["ES2021"],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"resolveJsonModule": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "preserve",
|
||||
// Check JS files too
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node16",
|
||||
"module": "node16",
|
||||
"outDir": "build",
|
||||
"types": ["vite/client", "vitest/globals"]
|
||||
"moduleResolution": "node16",
|
||||
"noEmit": false,
|
||||
"outDir": "build"
|
||||
},
|
||||
"include": ["src/**/*.js", "types/global.d.ts"],
|
||||
"exclude": ["node_modules", "build", "./app-plaid.js", "coverage"]
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"migrations/**/*",
|
||||
"types/**/*",
|
||||
"app.ts",
|
||||
"bin/**/*"
|
||||
],
|
||||
"exclude": ["node_modules", "build", "coverage"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18-bookworm as deps
|
||||
FROM node:18-bookworm AS deps
|
||||
|
||||
# Install required packages
|
||||
RUN apt-get update && apt-get install -y openssl
|
||||
@@ -21,12 +21,12 @@ COPY ./bin/package-browser ./bin/package-browser
|
||||
|
||||
RUN yarn install
|
||||
|
||||
FROM deps as builder
|
||||
FROM deps AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY packages/ ./packages/
|
||||
RUN yarn build:browser
|
||||
RUN yarn build:server
|
||||
|
||||
# Focus the workspaces in production mode (including @actual-app/web you just built)
|
||||
RUN yarn workspaces focus @actual-app/sync-server --production
|
||||
@@ -38,7 +38,7 @@ RUN rm -rf ./node_modules/@actual-app/web ./node_modules/@actual-app/sync-server
|
||||
COPY ./packages/desktop-client/package.json ./node_modules/@actual-app/web/package.json
|
||||
RUN cp -r ./packages/desktop-client/build ./node_modules/@actual-app/web/build
|
||||
|
||||
FROM node:18-bookworm-slim as prod
|
||||
FROM node:18-bookworm-slim AS prod
|
||||
|
||||
# Minimal runtime dependencies
|
||||
RUN apt-get update && apt-get install -y tini && apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
||||
@@ -56,10 +56,9 @@ ENV NODE_ENV=production
|
||||
|
||||
# Pull in only the necessary artifacts (built node_modules, server files, etc.)
|
||||
COPY --from=builder /app/node_modules /app/node_modules
|
||||
COPY --from=builder /app/packages/sync-server/package.json /app/packages/sync-server/app.js ./
|
||||
COPY --from=builder /app/packages/sync-server/src ./src
|
||||
COPY --from=builder /app/packages/sync-server/migrations ./migrations
|
||||
COPY --from=builder /app/packages/sync-server/package.json ./
|
||||
COPY --from=builder /app/packages/sync-server/build ./build
|
||||
|
||||
ENTRYPOINT ["/usr/bin/tini", "-g", "--"]
|
||||
EXPOSE 5006
|
||||
CMD ["node", "app.js"]
|
||||
CMD ["node", "build/app.js"]
|
||||
|
||||
6
upcoming-release-notes/4887.md
Normal file
6
upcoming-release-notes/4887.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Enhancements
|
||||
authors: [rgoldfinger]
|
||||
---
|
||||
|
||||
Converted sync-server to run with typescript
|
||||
Reference in New Issue
Block a user