Просмотр исходного кода

Merge branch 'feat/135772-pdf-page-bulk-export' into feat/135772-153348-enable-pdf-bulk-export-tsed

Futa Arai 1 год назад
Родитель
Сommit
5fe093add3

+ 3 - 0
.devcontainer/app/devcontainer.json

@@ -37,6 +37,9 @@
         "vitest.explorer",
         "ms-playwright.playwright"
       ],
+      "settings": {
+        "terminal.integrated.defaultProfile.linux": "bash"
+      }
     }
   },
 

+ 2 - 1
.devcontainer/compose.yml

@@ -42,7 +42,8 @@ services:
       - ../../growi-docker-compose/elasticsearch/v8/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
 
   pdf-converter:
-    image: mcr.microsoft.com/devcontainers/base:ubuntu
+    # enabling devcontainer 'features' was not working for secondary devcontainer (https://github.com/devcontainers/features/issues/1175)
+    image: mcr.microsoft.com/vscode/devcontainers/javascript-node:0-20
     volumes:
       - ..:/workspace/growi:delegated
       - pnpm-store:/workspace/growi/.pnpm-store

+ 4 - 7
.devcontainer/pdf-converter/devcontainer.json

@@ -4,12 +4,6 @@
   "service": "pdf-converter",
   "workspaceFolder": "/workspace/growi",
 
-  "features": {
-    "ghcr.io/devcontainers/features/node:1": {
-      "version": "20.18.0"
-    }
-  },
-
   // Use 'forwardPorts' to make a list of ports inside the container available locally.
   // "forwardPorts": [],
 
@@ -23,7 +17,10 @@
         "dbaeumer.vscode-eslint",
         "mhutchie.git-graph",
         "eamodio.gitlens"
-      ]
+      ],
+      "settings": {
+        "terminal.integrated.defaultProfile.linux": "bash"
+      }
     }
   }
 

+ 4 - 4
.devcontainer/pdf-converter/postCreateCommand.sh

@@ -1,14 +1,14 @@
-sudo chown -R vscode:vscode /workspace;
-
 # Instal additional packages
 sudo apt update
 sudo apt-get install -y --no-install-recommends \
-  chromium-browser locales fonts-ipafont fonts-ipaexfont fonts-ipafont-gothic fonts-ipafont-mincho
+  chromium locales fonts-ipafont fonts-ipaexfont fonts-ipafont-gothic fonts-ipafont-mincho
 sudo apt-get clean -y
 
 # Setup pnpm
 SHELL=bash pnpm setup
-eval "$(cat /home/vscode/.bashrc)"
+eval "$(cat /home/node/.bashrc)"
+# Update pnpm
+pnpm i -g pnpm
 
 # Install turbo
 pnpm install turbo --global

+ 53 - 55
apps/pdf-converter/docker/Dockerfile

@@ -1,83 +1,81 @@
-########################################################################
-# deps-resolver
-########################################################################
-FROM node:20-slim AS deps-resolver
+# syntax = docker/dockerfile:1
 
-WORKDIR /app
+##
+## base
+##
+FROM node:20-slim AS base
 
-COPY package.json yarn.lock ./
+ENV optDir="/opt"
 
-RUN yarn --frozen-lockfile
+WORKDIR ${optDir}
 
-RUN tar -cf node_modules.tar \
-  node_modules \
-  && rm -rf node_modules
+# install pnpm
+RUN apt-get update && apt-get install -y ca-certificates wget --no-install-recommends \
+  && wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
+ENV PNPM_HOME="/root/.local/share/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
 
+# install turbo
+RUN pnpm add turbo --global
 
-########################################################################
-# deps-resolver-prod
-########################################################################
-FROM deps-resolver AS deps-resolver-prod
 
-WORKDIR /app
 
-RUN yarn --production
+##
+## builder
+##
+FROM base AS builder
 
-RUN tar -cf node_modules.tar \
-  node_modules \
-  && rm -rf node_modules
+ENV optDir="/opt"
 
+WORKDIR ${optDir}
 
-########################################################################
-# builder
-########################################################################
-FROM node:20-slim AS builder
+COPY . .
 
-WORKDIR /app
+RUN pnpm install ---frozen-lockfile
 
-COPY package.json yarn.lock tsconfig.json tsconfig.build.json .eslintrc.js ./
-COPY src ./src
-COPY --from=deps-resolver /app/node_modules.tar ./
+# build
+RUN turbo run build --filter @growi/pdf-converter
 
-RUN tar -xf node_modules.tar \
-  && rm node_modules.tar \
-  && yarn build \
-  && tar -cf packages.tar \
-    package.json \
-    yarn.lock \
-    dist \
-  && rm -rf node_modules
+# make artifacts
+RUN pnpm deploy out --prod --filter @growi/pdf-converter
+RUN rm -rf apps/pdf-converter/node_modules && mv out/node_modules apps/pdf-converter/node_modules
+RUN tar -zcf packages.tar.gz \
+  package.json \
+  apps/pdf-converter/package.json \
+  apps/pdf-converter/dist \
+  apps/pdf-converter/.env \
+  apps/pdf-converter/node_modules
 
 
-########################################################################
-# production
-########################################################################
+
+##
+## release
+##
 FROM node:20-slim
+LABEL maintainer="Yuki Takei <yuki@weseek.co.jp>"
 
-ENV NODE_ENV=production
-ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
-ENV LANG=ja_JP.UTF-8
+ENV NODE_ENV="production"
+ENV PUPPETEER_EXECUTABLE_PATH="/usr/bin/chromium"
+ENV LANG="ja_JP.UTF-8"
 
-RUN apt-get update && apt-get install -y tini chromium locales fonts-ipafont fonts-ipaexfont fonts-ipafont-gothic fonts-ipafont-mincho && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && echo "ja_JP UTF-8" > /etc/locale.gen && locale-gen
+ENV optDir="/opt"
+ENV appDir="${optDir}/pdf-converter"
 
-USER node
-WORKDIR /app
+RUN apt-get update && apt-get install -y chromium locales fonts-ipafont fonts-ipaexfont fonts-ipafont-gothic fonts-ipafont-mincho \
+    && apt-get clean \
+    && rm -rf /var/lib/apt/lists/*; \
+    echo "ja_JP UTF-8" > /etc/locale.gen && locale-gen;
 
-COPY --from=deps-resolver-prod --chown=node:node \
-  /app/node_modules.tar ./
+# copy artifacts
 COPY --from=builder --chown=node:node \
-  /app/packages.tar ./
+  ${optDir}/packages.tar.gz ${appDir}/
 
-RUN tar -xf node_modules.tar \
-  && tar -xf packages.tar \
-  && rm node_modules.tar packages.tar
+USER node
+WORKDIR ${appDir}
+RUN tar -xf packages.tar.gz && rm packages.tar.gz
 
-# change permission for shared volume
-RUN mkdir -p /tmp/page-bulk-export && chmod -R 777 /tmp/page-bulk-export
+WORKDIR ${appDir}/apps/pdf-converter
 
 EXPOSE 3010
 
-ENTRYPOINT ["/usr/bin/tini", "-e", "143", "--"]
 CMD ["node", "dist/index.js"]

+ 7 - 2
apps/pdf-converter/package.json

@@ -6,13 +6,15 @@
   "license": "MIT",
   "private": true,
   "scripts": {
-    "dev:pdf-converter": "nodemon --watch \"src/**/*.ts\" --ignore \"node_modules/**/*\" --exec ts-node -r \"dotenv-flow/config\" src/index.ts",
+    "dev": "nodemon --watch \"src/**/*.ts\" --ignore \"node_modules/**/*\" --exec ts-node -r \"dotenv-flow/config\" src/index.ts",
     "lint": "pnpm eslint **/*.{js,ts}",
     "gen:client-code": "tsed run generate-swagger --output ./specs && orval",
     "build": "pnpm gen:client-code && tsc -p tsconfig.build.json"
   },
   "dependencies": {
+    "@godaddy/terminus": "^4.12.1",
     "@tsed/cli": "^5.4.3",
+    "@tsed/cli-core": "^5.4.3",
     "@tsed/cli-generate-swagger": "^5.4.3",
     "@tsed/common": "7.83.4",
     "@tsed/components-scan": "7.83.4",
@@ -23,9 +25,12 @@
     "@tsed/platform-express": "7.83.4",
     "@tsed/schema": "7.83.4",
     "@tsed/swagger": "7.83.4",
+    "@tsed/terminus": "7.83.4",
+    "axios": "^0.24.0",
     "express": "^4.19.2",
     "puppeteer": "^23.1.1",
-    "puppeteer-cluster": "^0.24.0"
+    "puppeteer-cluster": "^0.24.0",
+    "tslib": "^2.8.0"
   },
   "devDependencies": {
     "@types/connect": "^3.4.38",

+ 2 - 1
apps/pdf-converter/src/controllers/index.ts

@@ -1 +1,2 @@
-export { default } from './pdf';
+export { default as PdfCtrl } from './pdf';
+export { default as TerminusCtrl } from './terminus';

+ 25 - 0
apps/pdf-converter/src/controllers/terminus.ts

@@ -0,0 +1,25 @@
+import { Logger } from '@tsed/common';
+import { Inject, Injectable } from '@tsed/di';
+
+import PdfConvertService from '../service/pdf-convert';
+
+@Injectable()
+class TerminusCtrl {
+
+  @Inject()
+    logger: Logger;
+
+  constructor(private readonly pdfConvertService: PdfConvertService) {}
+
+  async $onSignal(): Promise<void> {
+    this.logger.info('Server is starting cleanup');
+    await this.pdfConvertService.closePuppeteerCluster();
+  }
+
+  $onShutdown(): void {
+    this.logger.info('Cleanup finished, server is shutting down');
+  }
+
+}
+
+export default TerminusCtrl;

+ 4 - 0
apps/pdf-converter/src/server.ts

@@ -2,6 +2,7 @@ import { PlatformApplication } from '@tsed/common';
 import { Configuration, Inject } from '@tsed/di';
 import express from 'express';
 import '@tsed/swagger';
+import '@tsed/terminus';
 
 import * as Controllers from './controllers';
 
@@ -26,6 +27,9 @@ const PORT = Number(process.env.PORT || 3010);
       specVersion: '3.0.1',
     },
   ],
+  terminus: {
+    signals: ['SIGINT', 'SIGTERM'],
+  },
 })
 class Server {
 

+ 16 - 11
apps/pdf-converter/src/service/pdf-convert.ts

@@ -3,7 +3,7 @@ import path from 'path';
 import { Readable, Writable } from 'stream';
 import { pipeline as pipelinePromise } from 'stream/promises';
 
-import type { Logger } from '@tsed/common';
+import { Logger } from '@tsed/common';
 import { Inject, Service } from '@tsed/di';
 import { Cluster } from 'puppeteer-cluster';
 
@@ -109,7 +109,22 @@ class PdfConvertService {
     }
   }
 
+  /**
+   * Close puppeteer cluster
+   */
+  async closePuppeteerCluster(): Promise<void> {
+    if (this.puppeteerCluster == null) {
+      this.logger.info('No puppeteer cluster running for closure');
+      return;
+    }
+
+    this.logger.info('Closing puppeteer cluster...');
+    await this.puppeteerCluster.idle();
+    await this.puppeteerCluster.close();
+  }
+
   private isJobCompleted(jobId: string): boolean {
+    if (this.jobList[jobId] == null) return true;
     return this.jobList[jobId].status === JobStatus.PDF_EXPORT_DONE || this.jobList[jobId].status === JobStatus.FAILED;
   }
 
@@ -252,16 +267,6 @@ class PdfConvertService {
       });
       return pdfResult;
     });
-
-    // close cluster on app termination
-    const handleClose = async() => {
-      this.logger.info('Closing puppeteer cluster...');
-      await this.puppeteerCluster?.idle();
-      await this.puppeteerCluster?.close();
-      process.exit();
-    };
-    process.on('SIGINT', handleClose);
-    process.on('SIGTERM', handleClose);
   }
 
   /**

+ 95 - 62
pnpm-lock.yaml

@@ -59,7 +59,7 @@ importers:
         version: 4.3.1(vite@5.4.6(@types/node@20.14.0)(sass@1.77.6)(terser@5.36.0))
       '@vitest/coverage-v8':
         specifier: ^2.1.1
-        version: 2.1.1(vitest@2.1.1)
+        version: 2.1.1(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.36.0))
       '@vitest/ui':
         specifier: ^2.1.1
         version: 2.1.1(vitest@2.1.1)
@@ -77,7 +77,7 @@ importers:
         version: 12.1.6(eslint@8.41.0)(next@14.2.13(@babel/core@7.24.6)(@playwright/test@1.46.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.6))(typescript@5.0.4)
       eslint-config-weseek:
         specifier: ^2.1.1
-        version: 2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0)
+        version: 2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0)
       eslint-import-resolver-typescript:
         specifier: ^3.2.5
         version: 3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)
@@ -179,7 +179,7 @@ importers:
         version: 2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.36.0)
       vitest-mock-extended:
         specifier: ^2.0.2
-        version: 2.0.2(typescript@5.0.4)(vitest@2.1.1)
+        version: 2.0.2(typescript@5.0.4)(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.36.0))
 
   apps/app:
     dependencies:
@@ -828,7 +828,7 @@ importers:
         version: 3.1.0
       eslint-plugin-jest:
         specifier: ^26.5.3
-        version: 26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2)
+        version: 26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)))(typescript@5.4.2)
       fslightbox-react:
         specifier: ^1.7.6
         version: 1.7.6(prop-types@15.8.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -852,7 +852,7 @@ importers:
         version: 4.2.0
       jest:
         specifier: ^29.5.0
-        version: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+        version: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       jest-date-mock:
         specifier: ^1.0.8
         version: 1.0.10
@@ -888,7 +888,7 @@ importers:
         version: 5.1.0(react@18.2.0)
       react-dnd:
         specifier: ^14.0.5
-        version: 14.0.5(@types/hoist-non-react-statics@3.3.5)(@types/node@20.14.0)(@types/react@18.3.3)(react@18.2.0)
+        version: 14.0.5(@types/hoist-non-react-statics@3.3.5)(@types/node@22.8.7)(@types/react@18.3.3)(react@18.2.0)
       react-dnd-html5-backend:
         specifier: ^14.1.0
         version: 14.1.0
@@ -931,9 +931,15 @@ importers:
 
   apps/pdf-converter:
     dependencies:
+      '@godaddy/terminus':
+        specifier: ^4.12.1
+        version: 4.12.1
       '@tsed/cli':
         specifier: ^5.4.3
         version: 5.4.3(@tsed/cli-core@5.4.3(@babel/core@7.24.6)(@tsed/core@7.83.4)(@tsed/di@7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)))(ejs@3.1.10)(hogan.js@3.0.2)(lodash@4.17.21)(mustache@4.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@tsed/core@7.83.4)(@tsed/di@7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4))
+      '@tsed/cli-core':
+        specifier: ^5.4.3
+        version: 5.4.3(@babel/core@7.24.6)(@tsed/core@7.83.4)(@tsed/di@7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)))(ejs@3.1.10)(hogan.js@3.0.2)(lodash@4.17.21)(mustache@4.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
       '@tsed/cli-generate-swagger':
         specifier: ^5.4.3
         version: 5.4.3(@tsed/common@7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4))(@tsed/swagger@7.83.4(@tsed/common@7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4)))
@@ -964,6 +970,12 @@ importers:
       '@tsed/swagger':
         specifier: 7.83.4
         version: 7.83.4(@tsed/common@7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4))
+      '@tsed/terminus':
+        specifier: 7.83.4
+        version: 7.83.4(@godaddy/terminus@4.12.1)(@tsed/common@7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4))(@tsed/core@7.83.4)(@tsed/di@7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)))(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4))
+      axios:
+        specifier: ^0.24.0
+        version: 0.24.0
       express:
         specifier: ^4.19.2
         version: 4.21.0
@@ -973,6 +985,9 @@ importers:
       puppeteer-cluster:
         specifier: ^0.24.0
         version: 0.24.0(puppeteer@23.6.1(typescript@5.4.2))
+      tslib:
+        specifier: ^2.8.0
+        version: 2.8.0
     devDependencies:
       '@types/connect':
         specifier: ^3.4.38
@@ -4475,6 +4490,15 @@ packages:
     peerDependencies:
       '@tsed/common': 7.83.4
 
+  '@tsed/terminus@7.83.4':
+    resolution: {integrity: sha512-1K/aKp/ALGEoNhursVnjC2x8piybLHOxcyRUDaJ40RsuIV5ohYDVXghywBWTNFhRghfBjc3SggYLMjIojM4n2Q==}
+    peerDependencies:
+      '@godaddy/terminus': ^4.7.1
+      '@tsed/common': 7.83.4
+      '@tsed/core': 7.83.4
+      '@tsed/di': 7.83.4
+      '@tsed/schema': 7.83.4
+
   '@tsed/typeorm@6.43.0':
     resolution: {integrity: sha512-B2xU8fsKQYaAW+DNDoAOvawmqaqmKLia17p9AdTcc1aaxsJ51KTdpOxn9CkwcvWExMqyJNrJldELiaH5LuBqOw==}
     peerDependencies:
@@ -15831,27 +15855,27 @@ snapshots:
   '@jest/console@29.7.0':
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       jest-message-util: 29.7.0
       jest-util: 29.7.0
       slash: 3.0.0
 
-  '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))':
+  '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))':
     dependencies:
       '@jest/console': 29.7.0
       '@jest/reporters': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       ci-info: 3.9.0
       exit: 0.1.2
       graceful-fs: 4.2.11
       jest-changed-files: 29.7.0
-      jest-config: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      jest-config: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       jest-haste-map: 29.7.0
       jest-message-util: 29.7.0
       jest-regex-util: 29.6.3
@@ -15880,7 +15904,7 @@ snapshots:
     dependencies:
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       jest-mock: 29.7.0
 
   '@jest/expect-utils@29.7.0':
@@ -15898,7 +15922,7 @@ snapshots:
     dependencies:
       '@jest/types': 29.6.3
       '@sinonjs/fake-timers': 10.3.0
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       jest-message-util: 29.7.0
       jest-mock: 29.7.0
       jest-util: 29.7.0
@@ -15920,7 +15944,7 @@ snapshots:
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
       '@jridgewell/trace-mapping': 0.3.25
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       collect-v8-coverage: 1.0.2
       exit: 0.1.2
@@ -15990,7 +16014,7 @@ snapshots:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.6
       '@types/istanbul-reports': 3.0.4
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       '@types/yargs': 17.0.32
       chalk: 4.1.2
 
@@ -18156,6 +18180,15 @@ snapshots:
       swagger-ui-dist: 5.17.14
       tslib: 2.6.1
 
+  '@tsed/terminus@7.83.4(@godaddy/terminus@4.12.1)(@tsed/common@7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4))(@tsed/core@7.83.4)(@tsed/di@7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)))(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4))':
+    dependencies:
+      '@godaddy/terminus': 4.12.1
+      '@tsed/common': 7.83.4(@tsed/engines@7.83.4)(@tsed/logger-file@6.7.8(@tsed/logger@6.7.8))(@tsed/logger@6.7.8)(@tsed/openspec@7.83.4)
+      '@tsed/core': 7.83.4
+      '@tsed/di': 7.83.4(@tsed/core@7.83.4)(@tsed/logger@6.7.8)(@tsed/schema@7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4))
+      '@tsed/schema': 7.83.4(@tsed/core@7.83.4)(@tsed/openspec@7.83.4)
+      tslib: 2.6.1
+
   '@tsed/typeorm@6.43.0(typeorm@0.2.45(mysql2@2.3.3)(redis@3.1.2))':
     dependencies:
       tslib: 2.1.0
@@ -18226,7 +18259,7 @@ snapshots:
 
   '@types/cors@2.8.17':
     dependencies:
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
 
   '@types/css-modules@1.0.2': {}
 
@@ -18279,7 +18312,7 @@ snapshots:
 
   '@types/graceful-fs@4.1.9':
     dependencies:
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
 
   '@types/hast@2.3.4':
     dependencies:
@@ -18303,7 +18336,7 @@ snapshots:
 
   '@types/is-stream@1.1.0':
     dependencies:
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
 
   '@types/istanbul-lib-coverage@2.0.6': {}
 
@@ -18484,7 +18517,7 @@ snapshots:
 
   '@types/whatwg-url@8.2.1':
     dependencies:
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       '@types/webidl-conversions': 6.1.1
 
   '@types/yargs-parser@21.0.3': {}
@@ -18723,7 +18756,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@vitest/coverage-v8@2.1.1(vitest@2.1.1)':
+  '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.36.0))':
     dependencies:
       '@ampproject/remapping': 2.3.0
       '@bcoe/v8-coverage': 0.2.3
@@ -20314,13 +20347,13 @@ snapshots:
       isobject: 3.0.1
       lazy-cache: 2.0.2
 
-  create-jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)):
+  create-jest@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)):
     dependencies:
       '@jest/types': 29.6.3
       chalk: 4.1.2
       exit: 0.1.2
       graceful-fs: 4.2.11
-      jest-config: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      jest-config: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       jest-util: 29.7.0
       prompts: 2.4.2
     transitivePeerDependencies:
@@ -21021,7 +21054,7 @@ snapshots:
     dependencies:
       '@types/cookie': 0.4.1
       '@types/cors': 2.8.17
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       accepts: 1.3.8
       base64id: 2.0.0
       cookie: 0.4.1
@@ -21241,7 +21274,7 @@ snapshots:
     optionalDependencies:
       source-map: 0.6.1
 
-  eslint-config-airbnb-base@13.1.0(eslint-plugin-import@2.26.0)(eslint@8.41.0):
+  eslint-config-airbnb-base@13.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       eslint: 8.41.0
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
@@ -21249,10 +21282,10 @@ snapshots:
       object.assign: 4.1.5
       object.entries: 1.1.5
 
-  eslint-config-airbnb@17.1.0(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0):
+  eslint-config-airbnb@17.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       eslint: 8.41.0
-      eslint-config-airbnb-base: 13.1.0(eslint-plugin-import@2.26.0)(eslint@8.41.0)
+      eslint-config-airbnb-base: 13.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0)
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
       eslint-plugin-jsx-a11y: 6.5.1(eslint@8.41.0)
       eslint-plugin-react: 7.30.1(eslint@8.41.0)
@@ -21266,8 +21299,8 @@ snapshots:
       '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
       eslint: 8.41.0
       eslint-import-resolver-node: 0.3.6
-      eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0)
-      eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint@8.41.0)
+      eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0)
+      eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0))(eslint@8.41.0)
       eslint-plugin-jsx-a11y: 6.5.1(eslint@8.41.0)
       eslint-plugin-react: 7.30.1(eslint@8.41.0)
       eslint-plugin-react-hooks: 4.6.0(eslint@8.41.0)
@@ -21278,14 +21311,14 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-config-weseek@2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0):
+  eslint-config-weseek@2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       '@babel/core': 7.24.6
       '@babel/eslint-parser': 7.24.7(@babel/core@7.24.6)(eslint@8.41.0)
       '@typescript-eslint/eslint-plugin': 5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4)
       '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
       eslint: 8.41.0
-      eslint-config-airbnb: 17.1.0(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0)
+      eslint-config-airbnb: 17.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0)
       eslint-import-resolver-typescript: 3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
       eslint-plugin-react: 7.30.1(eslint@8.41.0)
@@ -21301,7 +21334,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0):
+  eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       debug: 4.3.7(supports-color@5.5.0)
       eslint: 8.41.0
@@ -21327,18 +21360,18 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0)):
+  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0)):
     dependencies:
       debug: 3.2.7
       find-up: 2.1.0
     optionalDependencies:
       '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
       eslint-import-resolver-node: 0.3.6
-      eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0)
+      eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0)
     transitivePeerDependencies:
       - supports-color
 
-  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5):
+  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)):
     dependencies:
       debug: 3.2.7
       find-up: 2.1.0
@@ -21349,7 +21382,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint@8.41.0):
+  eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       array-includes: 3.1.5
       array.prototype.flat: 1.3.2
@@ -21357,7 +21390,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.41.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0))
+      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0))
       has: 1.0.3
       is-core-module: 2.15.1
       is-glob: 4.0.3
@@ -21380,7 +21413,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.41.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5)
+      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))
       has: 1.0.3
       is-core-module: 2.15.1
       is-glob: 4.0.3
@@ -21406,13 +21439,13 @@ snapshots:
       - typescript
     optional: true
 
-  eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2):
+  eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)))(typescript@5.4.2):
     dependencies:
       '@typescript-eslint/utils': 5.59.7(eslint@8.41.0)(typescript@5.4.2)
       eslint: 8.41.0
     optionalDependencies:
       '@typescript-eslint/eslint-plugin': 5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2)
-      jest: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      jest: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
     transitivePeerDependencies:
       - supports-color
       - typescript
@@ -23108,7 +23141,7 @@ snapshots:
       '@jest/expect': 29.7.0
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       co: 4.6.0
       dedent: 1.5.3
@@ -23128,16 +23161,16 @@ snapshots:
       - babel-plugin-macros
       - supports-color
 
-  jest-cli@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)):
+  jest-cli@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)):
     dependencies:
-      '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
       chalk: 4.1.2
-      create-jest: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      create-jest: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       exit: 0.1.2
       import-local: 3.1.0
-      jest-config: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      jest-config: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       jest-util: 29.7.0
       jest-validate: 29.7.0
       yargs: 17.7.2
@@ -23147,7 +23180,7 @@ snapshots:
       - supports-color
       - ts-node
 
-  jest-config@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)):
+  jest-config@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)):
     dependencies:
       '@babel/core': 7.24.6
       '@jest/test-sequencer': 29.7.0
@@ -23172,8 +23205,8 @@ snapshots:
       slash: 3.0.0
       strip-json-comments: 3.1.1
     optionalDependencies:
-      '@types/node': 20.14.0
-      ts-node: 10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)
+      '@types/node': 22.8.7
+      ts-node: 10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)
     transitivePeerDependencies:
       - babel-plugin-macros
       - supports-color
@@ -23204,7 +23237,7 @@ snapshots:
       '@jest/environment': 29.7.0
       '@jest/fake-timers': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       jest-mock: 29.7.0
       jest-util: 29.7.0
 
@@ -23214,7 +23247,7 @@ snapshots:
     dependencies:
       '@jest/types': 29.6.3
       '@types/graceful-fs': 4.1.9
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       anymatch: 3.1.2
       fb-watchman: 2.0.2
       graceful-fs: 4.2.11
@@ -23255,7 +23288,7 @@ snapshots:
   jest-mock@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       jest-util: 29.7.0
 
   jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@@ -23290,7 +23323,7 @@ snapshots:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       emittery: 0.13.1
       graceful-fs: 4.2.11
@@ -23318,7 +23351,7 @@ snapshots:
       '@jest/test-result': 29.7.0
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       cjs-module-lexer: 1.3.1
       collect-v8-coverage: 1.0.2
@@ -23364,7 +23397,7 @@ snapshots:
   jest-util@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       chalk: 4.1.2
       ci-info: 3.9.0
       graceful-fs: 4.2.11
@@ -23383,7 +23416,7 @@ snapshots:
     dependencies:
       '@jest/test-result': 29.7.0
       '@jest/types': 29.6.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       ansi-escapes: 4.3.2
       chalk: 4.1.2
       emittery: 0.13.1
@@ -23398,17 +23431,17 @@ snapshots:
 
   jest-worker@29.7.0:
     dependencies:
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       jest-util: 29.7.0
       merge-stream: 2.0.0
       supports-color: 8.1.1
 
-  jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)):
+  jest@29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2)):
     dependencies:
-      '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
       '@jest/types': 29.6.3
       import-local: 3.1.0
-      jest-cli: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
+      jest-cli: 29.7.0(@types/node@22.8.7)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2))
     transitivePeerDependencies:
       - '@types/node'
       - babel-plugin-macros
@@ -25984,7 +26017,7 @@ snapshots:
     dependencies:
       dnd-core: 14.0.1
 
-  react-dnd@14.0.5(@types/hoist-non-react-statics@3.3.5)(@types/node@20.14.0)(@types/react@18.3.3)(react@18.2.0):
+  react-dnd@14.0.5(@types/hoist-non-react-statics@3.3.5)(@types/node@22.8.7)(@types/react@18.3.3)(react@18.2.0):
     dependencies:
       '@react-dnd/invariant': 2.0.0
       '@react-dnd/shallowequal': 2.0.0
@@ -25994,7 +26027,7 @@ snapshots:
       react: 18.2.0
     optionalDependencies:
       '@types/hoist-non-react-statics': 3.3.5
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       '@types/react': 18.3.3
 
   react-dom@18.2.0(react@18.2.0):
@@ -27903,14 +27936,14 @@ snapshots:
     optionalDependencies:
       '@swc/core': 1.5.25(@swc/helpers@0.5.11)
 
-  ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2):
+  ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@22.8.7)(typescript@5.4.2):
     dependencies:
       '@cspotcode/source-map-support': 0.8.1
       '@tsconfig/node10': 1.0.9
       '@tsconfig/node12': 1.0.11
       '@tsconfig/node14': 1.0.3
       '@tsconfig/node16': 1.0.3
-      '@types/node': 20.14.0
+      '@types/node': 22.8.7
       acorn: 8.12.1
       acorn-walk: 8.3.2
       arg: 4.1.3
@@ -28564,7 +28597,7 @@ snapshots:
       sass: 1.77.6
       terser: 5.36.0
 
-  vitest-mock-extended@2.0.2(typescript@5.0.4)(vitest@2.1.1):
+  vitest-mock-extended@2.0.2(typescript@5.0.4)(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.36.0)):
     dependencies:
       ts-essentials: 10.0.2(typescript@5.0.4)
       typescript: 5.0.4

+ 0 - 4
turbo.json

@@ -74,10 +74,6 @@
       ],
       "outputLogs": "new-only"
     },
-    "dev:pdf-converter": {
-      "cache": false,
-      "persistent": true
-    },
 
     "watch": {
       "outputs": ["dist/**"],