From 5f18ff16dee3060b12481e8631902d72717ea048 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Wed, 15 Nov 2023 07:44:34 +0100 Subject: [PATCH] feat: create base worker package --- packages/worker/.eslintrc.js | 39 ++++++++ packages/worker/.gitignore | 1 + packages/worker/.prettierrc.js | 6 ++ packages/worker/Dockerfile | 47 ++++++++++ packages/worker/Dockerfile.dev | 26 ++++++ packages/worker/build.js | 21 +++++ packages/worker/nodemon.json | 5 + packages/worker/package.json | 36 ++++++++ packages/worker/tsconfig.json | 52 +++++++++++ pnpm-lock.yaml | 162 +++++++++++++++++++++++++-------- 10 files changed, 356 insertions(+), 39 deletions(-) create mode 100644 packages/worker/.eslintrc.js create mode 100644 packages/worker/.gitignore create mode 100644 packages/worker/.prettierrc.js create mode 100644 packages/worker/Dockerfile create mode 100644 packages/worker/Dockerfile.dev create mode 100644 packages/worker/build.js create mode 100644 packages/worker/nodemon.json create mode 100644 packages/worker/package.json create mode 100644 packages/worker/tsconfig.json diff --git a/packages/worker/.eslintrc.js b/packages/worker/.eslintrc.js new file mode 100644 index 00000000..13f66352 --- /dev/null +++ b/packages/worker/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + root: true, + plugins: ['@typescript-eslint', 'import'], + extends: ['plugin:@typescript-eslint/recommended', 'airbnb', 'airbnb-typescript', 'eslint:recommended', 'plugin:import/typescript', 'prettier'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: './tsconfig.json', + tsconfigRootDir: __dirname, + }, + rules: { + 'import/prefer-default-export': 0, + 'class-methods-use-this': 0, + 'import/extensions': [ + 'error', + 'ignorePackages', + { + '': 'never', + js: 'never', + jsx: 'never', + ts: 'never', + tsx: 'never', + }, + ], + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: ['build.js', '**/*.test.{ts,tsx}', '**/mocks/**', '**/__mocks__/**', '**/*.setup.{ts,js}', '**/*.config.{ts,js}', '**/tests/**'], + }, + ], + 'arrow-body-style': 0, + 'no-underscore-dangle': 0, + 'no-console': 0, + }, + globals: { + NodeJS: true, + }, +}; diff --git a/packages/worker/.gitignore b/packages/worker/.gitignore new file mode 100644 index 00000000..849ddff3 --- /dev/null +++ b/packages/worker/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/worker/.prettierrc.js b/packages/worker/.prettierrc.js new file mode 100644 index 00000000..18502e8f --- /dev/null +++ b/packages/worker/.prettierrc.js @@ -0,0 +1,6 @@ +module.exports = { + singleQuote: true, + semi: true, + trailingComma: 'all', + printWidth: 200, +}; diff --git a/packages/worker/Dockerfile b/packages/worker/Dockerfile new file mode 100644 index 00000000..b73ef876 --- /dev/null +++ b/packages/worker/Dockerfile @@ -0,0 +1,47 @@ +ARG NODE_VERSION="18.16" +ARG ALPINE_VERSION="3.18" + +FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS node_base + +FROM node_base AS builder_base + +RUN npm install pnpm -g + +FROM node_base AS runner_base + +# Install docker +RUN apk upgrade --update-cache --available && \ + apk add openssl git docker docker-cli-compose curl && \ + rm -rf /var/cache/apk/* + +FROM builder_base AS builder + +WORKDIR /app + +COPY ./pnpm-lock.yaml ./ +COPY ./pnpm-workspace.yaml ./ +COPY ./patches ./patches +RUN pnpm fetch --no-scripts + +COPY ./packages ./packages + +RUN pnpm install -r --prefer-offline + +COPY ./packages/worker/build.js ./packages/worker/build.js +COPY ./packages/worker/src ./packages/worker/src +COPY ./packages/worker/package.json ./packages/worker/package.json +COPY ./packages/worker/assets ./packages/worker/assets + +RUN pnpm -r build --filter @runtipi/worker + +FROM runner_base AS app + +WORKDIR /app + +ENV NODE_ENV=production + +COPY --from=builder /app/packages/worker/dist . +COPY --from=builder /app/packages/worker/assets ./assets + +CMD ["node", "index.js", "start"] + diff --git a/packages/worker/Dockerfile.dev b/packages/worker/Dockerfile.dev new file mode 100644 index 00000000..d522377d --- /dev/null +++ b/packages/worker/Dockerfile.dev @@ -0,0 +1,26 @@ +ARG NODE_VERSION="18.16" +ARG ALPINE_VERSION="3.18" + +FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS node_base + +# Install docker +RUN apk upgrade --update-cache --available && \ + apk add openssl git docker docker-cli-compose curl unzip && \ + rm -rf /var/cache/apk/* + +RUN npm install pnpm -g + +WORKDIR /app + +COPY ./pnpm-lock.yaml ./ +COPY ./pnpm-workspace.yaml ./ +COPY ./patches ./patches +RUN pnpm fetch --no-scripts + +COPY ./packages/worker/assets ./assets +COPY ./packages ./packages + +RUN pnpm install -r --prefer-offline + +CMD ["pnpm", "--filter", "@runtipi/worker", "-r", "dev"] + diff --git a/packages/worker/build.js b/packages/worker/build.js new file mode 100644 index 00000000..98e885cc --- /dev/null +++ b/packages/worker/build.js @@ -0,0 +1,21 @@ +const { build } = require('esbuild'); + +const commandArgs = process.argv.slice(2); + +async function bundle() { + const start = Date.now(); + const options = { + entryPoints: ['./src/index.ts'], + outfile: './dist/index.js', + platform: 'node', + target: 'node18', + bundle: true, + color: true, + sourcemap: commandArgs.includes('--sourcemap'), + }; + + await build({ ...options, minify: true }); + console.log(`Build time: ${Date.now() - start}ms`); +} + +bundle(); diff --git a/packages/worker/nodemon.json b/packages/worker/nodemon.json new file mode 100644 index 00000000..8e05f778 --- /dev/null +++ b/packages/worker/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["src"], + "exec": "NODE_ENV=development tsx ./src/index.ts", + "ext": "js ts" +} diff --git a/packages/worker/package.json b/packages/worker/package.json new file mode 100644 index 00000000..eeba1c25 --- /dev/null +++ b/packages/worker/package.json @@ -0,0 +1,36 @@ +{ + "name": "@runtipi/worker", + "version": "1.0.0", + "description": "", + "main": "src/index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "node build.js", + "tsc": "tsc", + "dev": "dotenv -e ../../.env nodemon", + "knip": "knip" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/web-push": "^3.6.2", + "dotenv-cli": "^7.3.0", + "esbuild": "^0.19.4", + "knip": "^2.39.0", + "nodemon": "^3.0.1", + "tsx": "^3.14.0", + "typescript": "^5.2.2" + }, + "dependencies": { + "@runtipi/postgres-migrations": "^5.3.0", + "@runtipi/shared": "workspace:^", + "bullmq": "^4.13.0", + "dotenv": "^16.3.1", + "ioredis": "^5.3.2", + "pg": "^8.11.3", + "systeminformation": "^5.21.15", + "web-push": "^3.6.6", + "zod": "^3.22.4" + } +} diff --git a/packages/worker/tsconfig.json b/packages/worker/tsconfig.json new file mode 100644 index 00000000..5804523f --- /dev/null +++ b/packages/worker/tsconfig.json @@ -0,0 +1,52 @@ +{ + "compilerOptions": { + "target": "es2017", + "baseUrl": ".", + "outDir": "./dist", + "paths": { + "@/lib/*": [ + "./src/lib/*" + ], + "@/services": [ + "./src/services" + ], + "@/config/*": [ + "./src/config/*" + ], + }, + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "CommonJS", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "noUncheckedIndexedAccess": true, + "types": [ + "node" + ], + "experimentalDecorators": true + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "**/*.mjs", + "**/*.js", + "**/*.jsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e0a7beb..a2e5fd92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -312,9 +312,6 @@ importers: packages/cli: dependencies: - '@runtipi/postgres-migrations': - specifier: ^5.3.0 - version: 5.3.0 '@runtipi/shared': specifier: workspace:^ version: link:../shared @@ -342,24 +339,12 @@ importers: dotenv: specifier: ^16.3.1 version: 16.3.1 - ioredis: - specifier: ^5.3.2 - version: 5.3.2 log-update: specifier: ^5.0.1 version: 5.0.1 - pg: - specifier: ^8.11.3 - version: 8.11.3 semver: specifier: ^7.5.4 version: 7.5.4 - systeminformation: - specifier: ^5.21.15 - version: 5.21.15 - web-push: - specifier: ^3.6.6 - version: 3.6.6 zod: specifier: ^3.22.4 version: 3.22.4 @@ -373,9 +358,6 @@ importers: '@types/node': specifier: 20.8.10 version: 20.8.10 - '@types/web-push': - specifier: ^3.6.2 - version: 3.6.2 dotenv-cli: specifier: ^7.3.0 version: 7.3.0 @@ -385,6 +367,9 @@ importers: eslint-config-prettier: specifier: ^9.0.0 version: 9.0.0(eslint@8.52.0) + knip: + specifier: ^2.39.0 + version: 2.39.0 memfs: specifier: ^4.6.0 version: 4.6.0(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.2) @@ -413,6 +398,58 @@ importers: specifier: ^3.22.4 version: 3.22.4 + packages/worker: + dependencies: + '@runtipi/postgres-migrations': + specifier: ^5.3.0 + version: 5.3.0 + '@runtipi/shared': + specifier: workspace:^ + version: link:../shared + bullmq: + specifier: ^4.13.0 + version: 4.13.0 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 + ioredis: + specifier: ^5.3.2 + version: 5.3.2 + pg: + specifier: ^8.11.3 + version: 8.11.3 + systeminformation: + specifier: ^5.21.15 + version: 5.21.15 + web-push: + specifier: ^3.6.6 + version: 3.6.6 + zod: + specifier: ^3.22.4 + version: 3.22.4 + devDependencies: + '@types/web-push': + specifier: ^3.6.2 + version: 3.6.2 + dotenv-cli: + specifier: ^7.3.0 + version: 7.3.0 + esbuild: + specifier: ^0.19.4 + version: 0.19.4 + knip: + specifier: ^2.39.0 + version: 2.39.0 + nodemon: + specifier: ^3.0.1 + version: 3.0.1 + tsx: + specifier: ^3.14.0 + version: 3.14.0 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -1529,7 +1566,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -1550,14 +1587,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.8.10)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@18.18.8)(ts-node@10.9.1) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -1585,7 +1622,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 jest-mock: 29.7.0 dev: true @@ -1612,7 +1649,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 20.8.10 + '@types/node': 18.18.8 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -1645,7 +1682,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.19 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -1733,7 +1770,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.8.10 + '@types/node': 18.18.8 '@types/yargs': 17.0.22 chalk: 4.1.2 dev: true @@ -3162,7 +3199,7 @@ packages: /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 dev: true /@types/hast@3.0.0: @@ -3201,7 +3238,7 @@ packages: /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -3217,7 +3254,7 @@ packages: /@types/jsonfile@6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 dev: true /@types/lodash.merge@4.6.8: @@ -3239,6 +3276,12 @@ packages: /@types/ms@0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + /@types/node@18.18.8: + resolution: {integrity: sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==} + dependencies: + undici-types: 5.26.5 + dev: true + /@types/node@20.8.10: resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==} dependencies: @@ -3286,7 +3329,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 dev: true /@types/stack-utils@2.0.1: @@ -3320,7 +3363,7 @@ packages: /@types/web-push@3.6.2: resolution: {integrity: sha512-v6Wdk1eIVbAJQjEAa1ZxuG3cfOYTd6nSv55BVJMtLQUvQ07v80MPt2Voq/z71WKhy4CORu4L3aH+8SXKX4BD5g==} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 dev: true /@types/yargs-parser@21.0.0: @@ -6894,7 +6937,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -6943,6 +6986,47 @@ packages: - ts-node dev: true + /jest-config@29.7.0(@types/node@18.18.8)(ts-node@10.9.1): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.23.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.18.8 + babel-jest: 29.7.0(@babel/core@7.23.2) + chalk: 4.1.2 + ci-info: 3.8.0 + deepmerge: 4.3.0 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.1(@types/node@20.8.10)(typescript@5.2.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + /jest-config@29.7.0(@types/node@20.8.10)(ts-node@10.9.1): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7042,7 +7126,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -7058,7 +7142,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.6 - '@types/node': 20.8.10 + '@types/node': 18.18.8 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7109,7 +7193,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 jest-util: 29.7.0 dev: true @@ -7164,7 +7248,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -7195,7 +7279,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -7247,7 +7331,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -7272,7 +7356,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.8.10 + '@types/node': 18.18.8 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -7284,7 +7368,7 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.8.10 + '@types/node': 18.18.8 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1