3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

refactor: new dev/prod containers

- Use a single Dockerfile for all Zeppelin services
- Add a Dockerfile in project root that can be used by
  app hosting services
- Provide a standalone and lightweight prod setup
  - Standalone is the same as the old setup, with mysql+nginx
  - Lightweight only runs bot+backend+dash, no mysql/nginx
- Remove mounted mysql data folders for dev and prod
  - This resolves permission issues caused by the mount
  - The mysql service uses a regular named volume now
- Simplify .env options and clearly separate different prod setups
- Remove update.sh
  - Different setups require different update procedures, so a common
    update.sh no longer works
This commit is contained in:
Dragory 2024-03-17 18:49:31 +02:00
parent 730b8c1d6b
commit 509d96ce83
No known key found for this signature in database
30 changed files with 948 additions and 274 deletions

View file

@ -5,5 +5,5 @@
"service": "devenv",
"remoteUser": "ubuntu",
"workspaceFolder": "/home/ubuntu/zeppelin"
"workspaceFolder": "/workspace/zeppelin"
}

View file

@ -8,4 +8,97 @@
node_modules
/backend/dist
/shared/dist
/dashboard/dist
# FROM GITIGNORE:
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.clinic
.clinic-bot
.clinic-api
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
*.env
.env
# windows folder options
desktop.ini
# PHPStorm
.idea/
# Misc
/convert.js
/startscript.js
.cache
npm-ls.txt
npm-audit.txt
.vscode/launch.json
# Debug files
*.debug.ts
*.debug.js
.vscode/
config-errors.txt
/config-schema.json
*.tsbuildinfo

View file

@ -1,3 +1,7 @@
# ==========================
# GENERAL OPTIONS
# ==========================
# 32 character encryption key
KEY=
@ -17,58 +21,63 @@ STAFF=
# A comma-separated list of server IDs that should be allowed by default
DEFAULT_ALLOWED_SERVERS=
# When using the Docker-based development environment, this is only used internally. The API will be available at localhost:DOCKER_DEV_WEB_PORT/api.
API_PORT=3000
# Only required if relevant feature is used
#PHISHERMAN_API_KEY=
# The user ID and group ID that should be used within the Docker containers
# This should match your own user ID and group ID. Run `id -u` and `id -g` to find them.
DOCKER_USER_UID=
DOCKER_USER_GID=
#
# DOCKER (DEVELOPMENT)
# NOTE: You only need to fill in these values for running the development environment. See production config further below.
#
# ==========================
# DEVELOPMENT
# NOTE: You only need to fill in these values for running the development environment
# ==========================
DOCKER_DEV_WEB_PORT=3300
DEVELOPMENT_WEB_PORT=3300
# The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver
DOCKER_DEV_MYSQL_PORT=3001
DEVELOPMENT_MYSQL_PORT=3356
# Password for the Zeppelin database user
DOCKER_DEV_MYSQL_PASSWORD=
DEVELOPMENT_MYSQL_PASSWORD=password
# Password for the MySQL root user
DOCKER_DEV_MYSQL_ROOT_PASSWORD=
DEVELOPMENT_MYSQL_ROOT_PASSWORD=password
# The development environment container has an SSH server that you can connect to.
# This is the port that server is exposed to the host on.
DOCKER_DEV_SSH_PORT=3002
DOCKER_DEV_SSH_PASSWORD=password
DEVELOPMENT_SSH_PORT=3022
DEVELOPMENT_SSH_PASSWORD=password
# If your user has a different UID than 1000, you might have to fill that in here to avoid permission issues
#DOCKER_DEV_UID=1000
#DEVELOPMENT_UID=1000
#
# DOCKER (PRODUCTION)
# NOTE: You only need to fill in these values for running the production environment. See development config above.
#
DOCKER_PROD_DOMAIN=
DOCKER_PROD_WEB_PORT=443
# ==========================
# PRODUCTION - STANDALONE
# NOTE: You only need to fill in these values for running the standalone production environment
# ==========================
STANDALONE_DOMAIN=
STANDALONE_WEB_PORT=443
# The MySQL database running in the container is exposed to the host on this port,
# allowing access with database tools such as DBeaver
DOCKER_PROD_MYSQL_PORT=3001
STANDALONE_MYSQL_PORT=3356
# Password for the Zeppelin database user
DOCKER_PROD_MYSQL_PASSWORD=
STANDALONE_MYSQL_PASSWORD=
# Password for the MySQL root user
DOCKER_PROD_MYSQL_ROOT_PASSWORD=
STANDALONE_MYSQL_ROOT_PASSWORD=
# You only need to set these if you're running an external database.
# In a standard setup, the database is run in a docker container.
#DB_HOST=
#DB_USER=
#DB_PASSWORD=
#DB_DATABASE=
# ==========================
# PRODUCTION - LIGHTWEIGHT
# NOTE: You only need to fill in these values for running the lightweight production environment
# ==========================
# Ports where the API/dashboard are exposed on the host
LIGHTWEIGHT_API_PORT=3001
LIGHTWEIGHT_DASHBOARD_PORT=3002
LIGHTWEIGHT_DB_HOST=
LIGHTWEIGHT_DB_PORT=
LIGHTWEIGHT_DB_USER=
LIGHTWEIGHT_DB_PASSWORD=
LIGHTWEIGHT_DB_DATABASE=

4
.gitignore vendored
View file

@ -87,3 +87,7 @@ config-errors.txt
/config-schema.json
*.tsbuildinfo
# Legacy data folders
/docker/development/data
/docker/production/data

20
Dockerfile Normal file
View file

@ -0,0 +1,20 @@
FROM node:20
USER node
COPY --chown=node:node . /zeppelin
# Install dependencies for all packages
WORKDIR /zeppelin
RUN npm ci
# Build backend
WORKDIR /zeppelin/backend
RUN npm run build
# Build dashboard
WORKDIR /zeppelin/dashboard
RUN npm run build
# Prune dev dependencies
WORKDIR /zeppelin
RUN npm prune --production

View file

@ -1,34 +1,67 @@
# Zeppelin production environment
Zeppelin's production environment - that is, the **bot, API, and dashboard** - uses Docker.
Zeppelin's production environment uses Docker. There are a few different ways to run Zeppelin in production:
## Starting the production environment
1. **Standalone**
* The easiest way to get Zeppelin up and running. This setup comes with a built-in database and web server.
2. **Lightweight**
* In case you don't want to use the built-in database and web server. This setup only runs the bot, API, and dashboard themselves. You'll have to provide your own database connection options and set up a proxy server for the API and dashboard.
3. **Manual**
* If you only want to run a specific service, you can use Zeppelin's Dockerfile directly.
## Standalone
### Setup
1. Install Docker on the machine running the bot
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env`
4. Run `docker compose -f docker-compose.production.yml build`
5. Run `docker compose -f docker-compose.production.yml up -d`
3. Fill in the missing values in `.env` (including the "PRODUCTION - STANDALONE" section)
**Note:** The dashboard and API are exposed with a self-signed certificate. It is recommended to set up a proxy with a proper certificate in front of them. Cloudflare is a popular choice here.
**Note:** The dashboard and API are exposed with a self-signed certificate. It is recommended to set up a proxy with a proper certificate in front of them. A popular option for this is [Cloudflare Tunnel](https://www.cloudflare.com/products/tunnel/).
## Updating the bot
### Running the bot
`docker compose -f docker-compose.standalone.yml up -d`
### One-click script
If you've downloaded the bot's files by cloning the git repository, you can use `update.sh` to update the bot.
### Shutting the bot down
`docker compose -f docker-compose.standalone.yml down`
### Manual instructions
1. Shut the bot down: `docker compose -f docker-compose.production.yml down`
### Updating the bot
1. Shut the bot down
2. Update the files (e.g. `git pull`)
3. Build new images: `docker compose -f docker-compose.production.yml build`
3. Start the bot again: `docker compose -f docker-compose.production.yml up -d`
3. Rebuild: `docker compose -f docker-compose.standalone.yml build`
4. Run the bot again
### Ephemeral hotfixes
If you need to make a hotfix to the bot's source files directly on the server:
1. Shut the bot down: `docker compose -f docker-compose.production.yml down`
2. Make your edits
3. Build new images: `docker compose -f docker-compose.production.yml build`
4. Start the bot again: `docker compose -f docker-compose.production.yml up -d`
### Viewing logs
`docker compose -f docker-compose.standalone.yml logs -t -f`
Make sure to revert any hotfixes before updating the bot normally.
## Lightweight
## View logs
To view real-time logs, run `docker compose -f docker-compose.production.yml logs -t -f`
### Setup
1. Install Docker on the machine running the bot
2. Make a copy of `.env.example` called `.env`
3. Fill in the missing values in `.env` (including the "PRODUCTION - LIGHTWEIGHT" section)
### Running the bot
`docker compose -f docker-compose.lightweight.yml up -d`
### Shutting the bot down
`docker compose -f docker-compose.lightweight.yml down`
### Updating the bot
1. Shut the bot down
2. Update the files (e.g. `git pull`)
3. Rebuild: `docker compose -f docker-compose.lightweight.yml build`
4. Run the bot again
### Viewing logs
`docker compose -f docker-compose.lightweight.yml logs -t -f`
## Manual
1. Build the Zeppelin image: `docker build --tag 'zeppelin' .`
2. Run the service:
* Bot: `docker run zeppelin npm run start-bot`
* API: `docker run zeppelin npm run start-api`
* Dashboard: `docker run zeppelin npm run start-dashboard`
If you're using an application platform such as Railway, you can simply point it to Zeppelin's repository and it should pick up the Dockerfile from there.
For the start command, you can use the same commands as above: `npm run start-bot`, `npm run start-api`, `npm run start-dashboard`.
**Note:** You'll need to provide the necessary env variables. For example, `docker run --env-file .env zeppelin`

View file

@ -4,28 +4,28 @@
"description": "",
"private": true,
"scripts": {
"watch": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node start-dev.js\"",
"watch-yaml-parse-test": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"",
"watch": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"node start-dev.js\"",
"watch-yaml-parse-test": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"",
"build": "tsc --build",
"start-bot-dev": "cross-env NODE_ENV=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
"start-bot-dev": "NODE_ENV=development HOST_MODE=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
"start-bot-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
"start-bot-prod": "cross-env NODE_ENV=production node --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
"start-bot-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
"watch-bot": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-bot-dev\"",
"start-api-dev": "cross-env NODE_ENV=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
"watch-bot": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"npm run start-bot-dev\"",
"start-api-dev": "NODE_ENV=development HOST_MODE=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
"start-api-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
"start-api-prod": "cross-env NODE_ENV=production node --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
"start-api-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
"watch-api": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-api-dev\"",
"watch-api": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"npm run start-api-dev\"",
"typeorm": "node ./node_modules/typeorm/cli.js",
"migrate": "npm run typeorm -- migration:run -d dist/backend/src/data/dataSource.js",
"migrate-prod": "cross-env NODE_ENV=production npm run migrate",
"migrate-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
"migrate-dev": "NODE_ENV=development HOST_MODE=development npm run build && npm run migrate",
"migrate-rollback": "npm run typeorm -- migration:revert -d dist/backend/src/data/dataSource.js",
"migrate-rollback-prod": "cross-env NODE_ENV=production npm run migrate",
"migrate-rollback-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
"validate-active-configs": "cross-env NODE_ENV=development node --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt",
"export-config-json-schema": "cross-env NODE_ENV=development node --enable-source-maps dist/backend/src/exportSchemas.js > ../config-schema.json",
"migrate-rollback-dev": "NODE_ENV=development HOST_MODE=development npm run build && npm run migrate",
"validate-active-configs": "NODE_ENV=development HOST_MODE=development node --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt",
"export-config-json-schema": "NODE_ENV=development HOST_MODE=development node --enable-source-maps dist/backend/src/exportSchemas.js > ../config-schema.json",
"test": "npm run build && npm run run-tests",
"run-tests": "ava",
"test-watch": "tsc-watch --onSuccess \"npx ava\""

View file

@ -51,7 +51,7 @@ app.use((req, res, next) => {
return notFound(res);
});
const port = env.API_PORT;
const port = 3001;
app.listen(port, "0.0.0.0", () => console.log(`API server listening on port ${port}`)); // tslint:disable-line
startBackgroundTasks();

View file

@ -1,6 +1,7 @@
import moment from "moment-timezone";
import path from "path";
import { DataSource } from "typeorm";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions.js";
import { env } from "../env";
import { backendDir } from "../paths";
@ -9,13 +10,39 @@ moment.tz.setDefault("UTC");
const entities = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/data/entities/*.js"));
const migrations = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/migrations/*.js"));
type DbOpts = Pick<MysqlConnectionOptions, "host" | "port" | "username" | "password" | "database">;
let dbOpts: DbOpts;
if (env.HOST_MODE === "development") {
dbOpts = {
host: "mysql",
port: 3306,
username: "zeppelin",
password: env.DEVELOPMENT_MYSQL_PASSWORD,
database: "zeppelin",
};
} else if (env.HOST_MODE === "standalone") {
dbOpts = {
host: "mysql",
port: 3306,
username: "zeppelin",
password: env.STANDALONE_MYSQL_PASSWORD,
database: "zeppelin",
};
} else if (env.HOST_MODE === "lightweight") {
dbOpts = {
host: env.LIGHTWEIGHT_DB_HOST,
port: env.LIGHTWEIGHT_DB_PORT,
username: env.LIGHTWEIGHT_DB_USER,
password: env.LIGHTWEIGHT_DB_PASSWORD,
database: env.LIGHTWEIGHT_DB_DATABASE,
};
} else {
throw new Error(`Unknown host mode: ${env.HOST_MODE}`);
}
export const dataSource = new DataSource({
type: "mysql",
host: env.DB_HOST,
port: env.DB_PORT,
username: env.DB_USER,
password: env.DB_PASSWORD,
database: env.DB_DATABASE,
...dbOpts,
charset: "utf8mb4",
supportBigNumbers: true,
bigNumberStrings: true,

View file

@ -13,7 +13,6 @@ const envType = z.object({
DASHBOARD_URL: z.string().url(),
API_URL: z.string().url(),
API_PORT: z.preprocess((v) => Number(v), z.number().min(1).max(65535)).default(3000),
STAFF: z
.preprocess(
@ -39,18 +38,16 @@ const envType = z.object({
PHISHERMAN_API_KEY: z.string().optional(),
DOCKER_DEV_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development
DOCKER_PROD_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production
DEVELOPMENT_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development
STANDALONE_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production
DB_HOST: z.string().optional().default("mysql"),
DB_PORT: z
.preprocess((v) => Number(v), z.number())
.optional()
.default(3306),
DB_USER: z.string().optional().default("zeppelin"),
DB_PASSWORD: z.string().optional(), // Default is set to DOCKER_MYSQL_PASSWORD further below
DB_DATABASE: z.string().optional().default("zeppelin"),
LIGHTWEIGHT_DB_HOST: z.string().optional(),
LIGHTWEIGHT_DB_PORT: z.preprocess((v) => Number(v), z.number()).optional(),
LIGHTWEIGHT_DB_USER: z.string().optional(),
LIGHTWEIGHT_DB_PASSWORD: z.string().optional(),
LIGHTWEIGHT_DB_DATABASE: z.string().optional(),
HOST_MODE: z.enum(["development", "standalone", "lightweight"]).optional().default("lightweight"),
DEBUG: z
.string()
.optional()
@ -65,11 +62,3 @@ if (fs.existsSync(envPath)) {
}
export const env = envType.parse(toValidate);
if (!env.DB_PASSWORD) {
if (process.env.NODE_ENV === "production" && env.DOCKER_PROD_MYSQL_PASSWORD) {
env.DB_PASSWORD = env.DOCKER_PROD_MYSQL_PASSWORD;
} else if (env.DOCKER_DEV_MYSQL_PASSWORD) {
env.DB_PASSWORD = env.DOCKER_DEV_MYSQL_PASSWORD;
}
}

View file

@ -164,7 +164,7 @@ if (process.env.NODE_ENV === "production") {
}
// Verify required Node.js version
const REQUIRED_NODE_VERSION = "14.0.0";
const REQUIRED_NODE_VERSION = "16.9.0";
const requiredParts = REQUIRED_NODE_VERSION.split(".").map((v) => parseInt(v, 10));
const actualVersionParts = process.versions.node.split(".").map((v) => parseInt(v, 10));
for (const [i, part] of actualVersionParts.entries()) {

View file

@ -6,8 +6,7 @@
"scripts": {
"build": "rimraf dist && cross-env NODE_ENV=production webpack --config webpack.config.js",
"build-debug": "rimraf dist && cross-env NODE_ENV=development webpack --config webpack.config.js",
"watch": "cross-env NODE_ENV=development webpack-dev-server",
"watch-build": "rimraf dist && NODE_ENV=development webpack --config webpack.config.js --watch"
"watch": "cross-env NODE_ENV=development webpack-dev-server"
},
"devDependencies": {
"@babel/core": "^7.22.5",
@ -37,7 +36,9 @@
"webpack-merge": "^5.9.0"
},
"dependencies": {
"@fastify/static": "^7.0.1",
"@highlightjs/vue-plugin": "^1.0.2",
"fastify": "^4.26.2",
"highlight.js": "^11.8.0",
"humanize-duration": "^3.27.0",
"js-yaml": "^4.1.0",

14
dashboard/serve.js Normal file
View file

@ -0,0 +1,14 @@
const fastify = require("fastify")({ logger: true });
const fastifyStatic = require("@fastify/static");
const path = require("path");
fastify.register(fastifyStatic, {
root: path.join(__dirname, "dist"),
});
fastify.listen({ port: 3002, host: '0.0.0.0' }, (err, address) => {
if (err) {
throw err;
}
console.log(`Server listening on ${address}`);
});

View file

@ -175,7 +175,7 @@ if (process.env.NODE_ENV === "production") {
devServer: {
...(process.env.DEV_HOST ? { host: process.env.DEV_HOST } : undefined),
historyApiFallback: true,
port: 1234,
port: 3002,
},
});
}

View file

@ -1,30 +1,25 @@
version: '3'
name: zeppelin-dev
volumes:
vscode-remote: {}
vscode-server: {}
jetbrains-data: {}
home: {}
services:
nginx:
build:
context: ./docker/development/nginx
args:
DOCKER_DEV_WEB_PORT: ${DOCKER_DEV_WEB_PORT:?Missing DOCKER_DEV_WEB_PORT}
API_PORT: ${API_PORT:?Missing API_PORT}
DEVELOPMENT_WEB_PORT: ${DEVELOPMENT_WEB_PORT:?Missing DEVELOPMENT_WEB_PORT}
ports:
- "${DOCKER_DEV_WEB_PORT:?Missing DOCKER_DEV_WEB_PORT}:443"
volumes:
- ./:/zeppelin
- "${DEVELOPMENT_WEB_PORT:?Missing DEVELOPMENT_WEB_PORT}:443"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DOCKER_DEV_MYSQL_ROOT_PASSWORD?:Missing DOCKER_DEV_MYSQL_ROOT_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DEVELOPMENT_MYSQL_ROOT_PASSWORD?:Missing DEVELOPMENT_MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: zeppelin
MYSQL_USER: zeppelin
MYSQL_PASSWORD: ${DOCKER_DEV_MYSQL_PASSWORD?:Missing DOCKER_DEV_MYSQL_PASSWORD}
MYSQL_PASSWORD: ${DEVELOPMENT_MYSQL_PASSWORD?:Missing DEVELOPMENT_MYSQL_PASSWORD}
ports:
- ${DOCKER_DEV_MYSQL_PORT:?Missing DOCKER_DEV_MYSQL_PORT}:3306
- ${DEVELOPMENT_MYSQL_PORT:?Missing DEVELOPMENT_MYSQL_PORT}:3306
volumes:
- ./docker/development/data/mysql:/var/lib/mysql
command: --authentication-policy=mysql_native_password
@ -33,13 +28,10 @@ services:
build:
context: ./docker/development/devenv
args:
DOCKER_DEV_SSH_PASSWORD: ${DOCKER_DEV_SSH_PASSWORD:?Missing DOCKER_DEV_SSH_PASSWORD}
DOCKER_DEV_UID: ${DOCKER_DEV_UID:-1000}
DEVELOPMENT_SSH_PASSWORD: ${DEVELOPMENT_SSH_PASSWORD:?Missing DEVELOPMENT_SSH_PASSWORD}
DEVELOPMENT_UID: ${DEVELOPMENT_UID:-1000}
ports:
- "${DOCKER_DEV_SSH_PORT:?Missing DOCKER_DEV_SSH_PORT}:22"
- "${DEVELOPMENT_SSH_PORT:?Missing DEVELOPMENT_SSH_PORT}:22"
volumes:
- ./:/home/ubuntu/zeppelin
- ~/.ssh:/home/ubuntu/.ssh
- vscode-remote:/home/ubuntu/.vscode-remote
- vscode-server:/home/ubuntu/.vscode-server
- jetbrains-data:/home/ubuntu/.cache/JetBrains
- home:/home/ubuntu
- ./:/workspace/zeppelin

View file

@ -0,0 +1,60 @@
version: '3'
name: zeppelin-prod
services:
migrate:
depends_on:
mysql:
condition: service_healthy
build:
context: .
dockerfile: docker/production/zeppelin/Dockerfile
environment:
HOST_MODE: lightweight
working_dir: /zeppelin
command: ["npm", "run", "migrate-prod"]
api:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
dockerfile: docker/production/zeppelin/Dockerfile
restart: on-failure
environment:
DEBUG: ${DEBUG-}
HOST_MODE: lightweight
ports:
- "${LIGHTWEIGHT_API_PORT}:3001"
working_dir: /zeppelin/backend
command: ["npm", "run", "start-api-prod"]
bot:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
dockerfile: docker/production/zeppelin/Dockerfile
restart: on-failure
environment:
DEBUG: ${DEBUG-}
HOST_MODE: lightweight
working_dir: /zeppelin/backend
command: ["npm", "run", "start-bot-prod"]
dashboard:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
dockerfile: docker/production/zeppelin/Dockerfile
restart: on-failure
environment:
DEBUG: ${DEBUG-}
HOST_MODE: lightweight
ports:
- "${LIGHTWEIGHT_DASHBOARD_PORT}:3002"
working_dir: /zeppelin/dashboard
command: ["node", "serve.js"]

View file

@ -1,65 +0,0 @@
version: '3'
name: zeppelin-prod
services:
nginx:
build:
context: .
dockerfile: docker/production/nginx/Dockerfile
args:
API_PORT: ${API_PORT:?Missing API_PORT}
DOCKER_PROD_DOMAIN: ${DOCKER_PROD_DOMAIN:?Missing DOCKER_PROD_DOMAIN}
ports:
- "${DOCKER_PROD_WEB_PORT:?Missing DOCKER_PROD_WEB_PORT}:443"
volumes:
- ./:/zeppelin
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DOCKER_PROD_MYSQL_ROOT_PASSWORD?:Missing DOCKER_PROD_MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: zeppelin
MYSQL_USER: zeppelin
MYSQL_PASSWORD: ${DOCKER_PROD_MYSQL_PASSWORD?:Missing DOCKER_PROD_MYSQL_PASSWORD}
ports:
- 127.0.0.1:${DOCKER_PROD_MYSQL_PORT:?Missing DOCKER_PROD_MYSQL_PORT}:3306
volumes:
- ./docker/production/data/mysql:/var/lib/mysql
command: --authentication-policy=mysql_native_password
healthcheck:
test: "/usr/bin/mysql --user=root --password=\"${DOCKER_PROD_MYSQL_ROOT_PASSWORD}\" --execute \"SHOW DATABASES;\""
interval: 5s
timeout: 300s
retries: 60
migrate:
depends_on:
mysql:
condition: service_healthy
build:
context: .
dockerfile: docker/production/backend/Dockerfile
command: ["npm", "run", "migrate-prod"]
api:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
dockerfile: docker/production/backend/Dockerfile
restart: on-failure
environment:
DEBUG: ${DEBUG-}
command: ["npm", "run", "start-api-prod"]
bot:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
dockerfile: docker/production/backend/Dockerfile
restart: on-failure
environment:
DEBUG: ${DEBUG-}
command: ["/bin/bash", "/zeppelin/docker/production/start-bot.sh"]

View file

@ -0,0 +1,84 @@
version: '3'
name: zeppelin-prod
volumes:
mysql-data:
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${STANDALONE_MYSQL_ROOT_PASSWORD?:Missing STANDALONE_MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: zeppelin
MYSQL_USER: zeppelin
MYSQL_PASSWORD: ${STANDALONE_MYSQL_PASSWORD?:Missing STANDALONE_MYSQL_PASSWORD}
ports:
- 127.0.0.1:${STANDALONE_MYSQL_PORT:?Missing STANDALONE_MYSQL_PORT}:3306
# If you're upgrading from an older version, you can load your old database by switching the volumes below.
# Then, take a database dump from the old database, switch the volumes back, and load the dump into the new database.
volumes:
- mysql-data:/var/lib/mysql
# - ./docker/production/data/mysql:/var/lib/mysql
command: --authentication-policy=mysql_native_password
healthcheck:
test: "/usr/bin/mysql --user=root --password=\"${STANDALONE_MYSQL_ROOT_PASSWORD}\" --execute \"SHOW DATABASES;\""
interval: 5s
timeout: 300s
retries: 60
nginx:
build:
context: .
dockerfile: docker/production/nginx/Dockerfile
args:
STANDALONE_DOMAIN: ${STANDALONE_DOMAIN:?Missing STANDALONE_DOMAIN}
ports:
- "${STANDALONE_WEB_PORT:?Missing STANDALONE_WEB_PORT}:443"
migrate:
depends_on:
mysql:
condition: service_healthy
build:
context: .
environment:
HOST_MODE: standalone
working_dir: /zeppelin
command: ["npm", "run", "migrate-prod"]
api:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
restart: on-failure
environment:
HOST_MODE: standalone
DEBUG: ${DEBUG-}
working_dir: /zeppelin/backend
command: ["npm", "run", "start-api-prod"]
bot:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
restart: on-failure
environment:
HOST_MODE: standalone
DEBUG: ${DEBUG-}
working_dir: /zeppelin/backend
command: ["npm", "run", "start-bot-prod"]
dashboard:
depends_on:
migrate:
condition: service_completed_successfully
build:
context: .
restart: on-failure
environment:
HOST_MODE: standalone
DEBUG: ${DEBUG-}
working_dir: /zeppelin/dashboard
command: ["node", "serve.js"]

View file

@ -1,7 +1,7 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
ARG DOCKER_DEV_UID
ARG DOCKER_DEV_SSH_PASSWORD
ARG DEVELOPMENT_UID
ARG DEVELOPMENT_SSH_PASSWORD
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC
@ -15,15 +15,11 @@ RUN add-apt-repository ppa:git-core/ppa && apt-get update && apt-get install -y
# Set up SSH access
RUN apt-get install -y openssh-server iptables
RUN mkdir /var/run/sshd
RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u $DOCKER_DEV_UID ubuntu
RUN echo "ubuntu:${DOCKER_DEV_SSH_PASSWORD}" | chpasswd
RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u $DEVELOPMENT_UID ubuntu
RUN echo "ubuntu:${DEVELOPMENT_SSH_PASSWORD}" | chpasswd
# Set up proper permissions for volumes
RUN mkdir -p /home/ubuntu/zeppelin /home/ubuntu/.vscode-remote /home/ubuntu/.vscode-server /home/ubuntu/.cache/JetBrains
RUN chown -R ubuntu /home/ubuntu
# Install Node.js 18 and packages needed to build native packages
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
# Install Node.js 20 and packages needed to build native packages
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get install -y nodejs gcc g++ make python3
CMD ["/usr/sbin/sshd", "-D", "-e"]

View file

@ -1,11 +1,6 @@
FROM nginx
ARG API_PORT
ARG DOCKER_DEV_API_PORT
ARG DOCKER_DEV_DASHBOARD_PORT
RUN apt-get update && apt-get install -y openssl
RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/localhost-cert.key -out /etc/ssl/certs/localhost-cert.pem -days 3650 -subj '/CN=localhost' -nodes
COPY ./default.conf /etc/nginx/conf.d/default.conf
RUN sed -ir "s/_API_PORT_/${API_PORT}/g" /etc/nginx/conf.d/default.conf

View file

@ -3,24 +3,22 @@ server {
listen [::]:443 ssl http2;
server_name localhost;
root /zeppelin/dashboard/dist;
# Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable
set $backend_upstream "http://devenv:3001";
set $dashboard_upstream "http://devenv:3002";
location / {
index index.html;
try_files $uri $uri/ /index.html;
# Using a variable in proxy_pass also requires resolver to be set.
# This is the address of the internal docker compose DNS server.
resolver 127.0.0.11;
proxy_pass $dashboard_upstream$uri$is_args$args;
}
# Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable
set $backend_upstream "http://devenv:_API_PORT_";
location /api {
# Remove /api/ from the beginning when passing the path to the API process
rewrite /api(/.*)$ $1 break;
# Using a variable in proxy_pass also requires resolver to be set.
# This is the address of the internal docker compose DNS server.
resolver 127.0.0.11;
proxy_pass $backend_upstream$uri$is_args$args;
proxy_redirect off;

View file

@ -1,7 +0,0 @@
FROM node:18
USER node
COPY --chown=node:node . /zeppelin
WORKDIR /zeppelin/backend
RUN npm ci && npm run build

View file

@ -1,2 +0,0 @@
*
!.gitignore

View file

@ -1,2 +0,0 @@
*
!.gitignore

View file

@ -1,23 +1,9 @@
FROM node:18 AS builder
USER node
COPY --chown=node:node . /zeppelin
WORKDIR /zeppelin/dashboard
RUN ls -lah
RUN pwd
RUN npm ci && npm run build
FROM nginx
ARG API_PORT
ARG DOCKER_PROD_DOMAIN
ARG STANDALONE_DOMAIN
RUN apt-get update && apt-get install -y openssl
RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/zeppelin-self-signed-cert.key -out /etc/ssl/certs/zeppelin-self-signed-cert.pem -days 3650 -subj "/CN=${DOCKER_PROD_DOMAIN}" -nodes
RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/zeppelin-self-signed-cert.key -out /etc/ssl/certs/zeppelin-self-signed-cert.pem -days 3650 -subj "/CN=${STANDALONE_DOMAIN}" -nodes
COPY ./docker/production/nginx/default.conf /etc/nginx/conf.d/default.conf
RUN sed -ir "s/_API_PORT_/${API_PORT}/g" /etc/nginx/conf.d/default.conf
RUN sed -ir "s/_DOCKER_PROD_DOMAIN_/${DOCKER_PROD_DOMAIN}/g" /etc/nginx/conf.d/default.conf
COPY --from=builder /zeppelin/dashboard/dist /var/www
RUN sed -ir "s/_STANDALONE_DOMAIN_/${STANDALONE_DOMAIN}/g" /etc/nginx/conf.d/default.conf

View file

@ -1,26 +1,24 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name _DOCKER_PROD_DOMAIN_;
root /var/www;
location / {
index index.html;
try_files $uri $uri/ /index.html;
}
server_name _STANDALONE_DOMAIN_;
# Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable
set $backend_upstream "http://api:_API_PORT_";
set $backend_upstream "http://api:3001";
set $dashboard_upstream "http://dashboard:3002";
location / {
# Using a variable in proxy_pass also requires resolver to be set.
# This is the address of the internal docker compose DNS server.
resolver 127.0.0.11;
proxy_pass $dashboard_upstream$uri$is_args$args;
}
location /api {
# Remove /api/ from the beginning when passing the path to the API process
rewrite /api(/.*)$ $1 break;
# Using a variable in proxy_pass also requires resolver to be set.
# This is the address of the internal docker compose DNS server.
resolver 127.0.0.11;
proxy_pass $backend_upstream$uri$is_args$args;
proxy_redirect off;

View file

@ -1,13 +0,0 @@
#!/bin/bash
# This wrapper script is used to run different things based on the DEBUG env variable
# Exec is used to forward signals: https://unix.stackexchange.com/a/196053
cd /zeppelin/backend
if [ "$DEBUG" == "true" ]; then
echo "DEBUG MODE: Starting bot container without starting the bot"
exec tail -f /dev/null
else
echo "Starting bot"
exec npm run start-bot-prod
fi

481
package-lock.json generated
View file

@ -153,7 +153,9 @@
"name": "@zeppelinbot/dashboard",
"version": "1.0.0",
"dependencies": {
"@fastify/static": "^7.0.1",
"@highlightjs/vue-plugin": "^1.0.2",
"fastify": "^4.26.2",
"highlight.js": "^11.8.0",
"humanize-duration": "^3.27.0",
"js-yaml": "^4.1.0",
@ -3247,6 +3249,44 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@fastify/accept-negotiator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz",
"integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==",
"engines": {
"node": ">=14"
}
},
"node_modules/@fastify/ajv-compiler": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz",
"integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==",
"dependencies": {
"ajv": "^8.11.0",
"ajv-formats": "^2.1.1",
"fast-uri": "^2.0.0"
}
},
"node_modules/@fastify/ajv-compiler/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/@fastify/busboy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
@ -3255,6 +3295,106 @@
"node": ">=14"
}
},
"node_modules/@fastify/error": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz",
"integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ=="
},
"node_modules/@fastify/fast-json-stringify-compiler": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz",
"integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==",
"dependencies": {
"fast-json-stringify": "^5.7.0"
}
},
"node_modules/@fastify/merge-json-schemas": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz",
"integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==",
"dependencies": {
"fast-deep-equal": "^3.1.3"
}
},
"node_modules/@fastify/send": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz",
"integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==",
"dependencies": {
"@lukeed/ms": "^2.0.1",
"escape-html": "~1.0.3",
"fast-decode-uri-component": "^1.0.1",
"http-errors": "2.0.0",
"mime": "^3.0.0"
}
},
"node_modules/@fastify/send/node_modules/mime": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@fastify/static": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.1.tgz",
"integrity": "sha512-i1p/nELMknAisNfnjo7yhfoUOdKzA+n92QaMirv2NkZrJ1Wl12v2nyTYlDwPN8XoStMBAnRK/Kx6zKmfrXUPXw==",
"dependencies": {
"@fastify/accept-negotiator": "^1.0.0",
"@fastify/send": "^2.0.0",
"content-disposition": "^0.5.3",
"fastify-plugin": "^4.0.0",
"fastq": "^1.17.0",
"glob": "^10.3.4"
}
},
"node_modules/@fastify/static/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@fastify/static/node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
"minimatch": "^9.0.1",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
"path-scurry": "^1.10.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@fastify/static/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@fullhuman/postcss-purgecss": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz",
@ -3591,6 +3731,14 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true
},
"node_modules/@lukeed/ms": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz",
"integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@nearform/heap-profiler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@nearform/heap-profiler/-/heap-profiler-2.0.0.tgz",
@ -4822,6 +4970,11 @@
"node": ">=6.5"
}
},
"node_modules/abstract-logging": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -5106,6 +5259,11 @@
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"node_modules/archy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
"integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
@ -5736,6 +5894,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/avvio": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.0.tgz",
"integrity": "sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==",
"dependencies": {
"@fastify/error": "^3.3.0",
"archy": "^1.0.0",
"debug": "^4.0.0",
"fastq": "^1.17.1"
}
},
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@ -10104,6 +10273,16 @@
"node >=0.6.0"
]
},
"node_modules/fast-content-type-parse": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz",
"integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ=="
},
"node_modules/fast-decode-uri-component": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
"integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -10148,16 +10327,71 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-json-stringify": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.13.0.tgz",
"integrity": "sha512-XjTDWKHP3GoMQUOfnjYUbqeHeEt+PvYgvBdG2fRSmYaORILbSr8xTJvZX+w1YSAP5pw2NwKrGRmQleYueZEoxw==",
"dependencies": {
"@fastify/merge-json-schemas": "^0.1.0",
"ajv": "^8.10.0",
"ajv-formats": "^2.1.1",
"fast-deep-equal": "^3.1.3",
"fast-uri": "^2.1.0",
"json-schema-ref-resolver": "^1.0.1",
"rfdc": "^1.2.0"
}
},
"node_modules/fast-json-stringify/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/fast-json-stringify/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
"node_modules/fast-querystring": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
"integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
"dependencies": {
"fast-decode-uri-component": "^1.0.1"
}
},
"node_modules/fast-redact": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.4.0.tgz",
"integrity": "sha512-2gwPvyna0zwBdxKnng1suu/dTL5s8XEy2ZqH8mwDUwJdDkV8w5kp+JV26mupdK68HmPMbm6yjW9m7/Ys/BHEHg==",
"engines": {
"node": ">=6"
}
},
"node_modules/fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"node_modules/fast-uri": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz",
"integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw=="
},
"node_modules/fastest-levenshtein": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
@ -10167,11 +10401,48 @@
"node": ">= 4.9.1"
}
},
"node_modules/fastify": {
"version": "4.26.2",
"resolved": "https://registry.npmjs.org/fastify/-/fastify-4.26.2.tgz",
"integrity": "sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"dependencies": {
"@fastify/ajv-compiler": "^3.5.0",
"@fastify/error": "^3.4.0",
"@fastify/fast-json-stringify-compiler": "^4.3.0",
"abstract-logging": "^2.0.1",
"avvio": "^8.3.0",
"fast-content-type-parse": "^1.1.0",
"fast-json-stringify": "^5.8.0",
"find-my-way": "^8.0.0",
"light-my-request": "^5.11.0",
"pino": "^8.17.0",
"process-warning": "^3.0.0",
"proxy-addr": "^2.0.7",
"rfdc": "^1.3.0",
"secure-json-parse": "^2.7.0",
"semver": "^7.5.4",
"toad-cache": "^3.3.0"
}
},
"node_modules/fastify-plugin": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz",
"integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ=="
},
"node_modules/fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
"dev": true,
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dependencies": {
"reusify": "^1.0.4"
}
@ -10415,6 +10686,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/find-my-way": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.1.0.tgz",
"integrity": "sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-querystring": "^1.0.0",
"safe-regex2": "^2.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -12834,6 +13118,14 @@
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"node_modules/json-schema-ref-resolver": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz",
"integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==",
"dependencies": {
"fast-deep-equal": "^3.1.3"
}
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@ -13055,6 +13347,24 @@
"node": ">= 0.8.0"
}
},
"node_modules/light-my-request": {
"version": "5.12.0",
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.12.0.tgz",
"integrity": "sha512-P526OX6E7aeCIfw/9UyJNsAISfcFETghysaWHQAlQYayynShT08MOj4c6fBCvTWBrHXSvqBAKDp3amUPSCQI4w==",
"dependencies": {
"cookie": "^0.6.0",
"process-warning": "^3.0.0",
"set-cookie-parser": "^2.4.1"
}
},
"node_modules/light-my-request/node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -14981,6 +15291,14 @@
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
"dev": true
},
"node_modules/on-exit-leak-free": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
"integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@ -15670,6 +15988,87 @@
"node": ">=0.10.0"
}
},
"node_modules/pino": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/pino/-/pino-8.19.0.tgz",
"integrity": "sha512-oswmokxkav9bADfJ2ifrvfHUwad6MLp73Uat0IkQWY3iAw5xTRoznXbXksZs8oaOUMpmhVWD+PZogNzllWpJaA==",
"dependencies": {
"atomic-sleep": "^1.0.0",
"fast-redact": "^3.1.1",
"on-exit-leak-free": "^2.1.0",
"pino-abstract-transport": "v1.1.0",
"pino-std-serializers": "^6.0.0",
"process-warning": "^3.0.0",
"quick-format-unescaped": "^4.0.3",
"real-require": "^0.2.0",
"safe-stable-stringify": "^2.3.1",
"sonic-boom": "^3.7.0",
"thread-stream": "^2.0.0"
},
"bin": {
"pino": "bin.js"
}
},
"node_modules/pino-abstract-transport": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz",
"integrity": "sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==",
"dependencies": {
"readable-stream": "^4.0.0",
"split2": "^4.0.0"
}
},
"node_modules/pino-abstract-transport/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/pino-abstract-transport/node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/pino-std-serializers": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz",
"integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA=="
},
"node_modules/pino/node_modules/sonic-boom": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz",
"integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==",
"dependencies": {
"atomic-sleep": "^1.0.0"
}
},
"node_modules/pkg-conf": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz",
@ -18479,6 +18878,11 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/process-warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz",
"integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@ -18813,6 +19217,11 @@
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag=="
},
"node_modules/quick-format-unescaped": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"node_modules/quote-stream": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz",
@ -18990,6 +19399,14 @@
"node": ">=8.10.0"
}
},
"node_modules/real-require": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
"engines": {
"node": ">= 12.13.0"
}
},
"node_modules/rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
@ -19341,6 +19758,14 @@
"node": ">=4"
}
},
"node_modules/ret": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
"integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==",
"engines": {
"node": ">=4"
}
},
"node_modules/retimer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz",
@ -19359,12 +19784,16 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
"node_modules/rfdc": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz",
"integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg=="
},
"node_modules/rgb-regex": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
@ -19522,6 +19951,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-regex2": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
"integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
"dependencies": {
"ret": "~0.2.0"
}
},
"node_modules/safe-stable-stringify": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
"integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
"engines": {
"node": ">=10"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@ -19600,6 +20045,11 @@
"get-assigned-identifiers": "^1.1.0"
}
},
"node_modules/secure-json-parse": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
},
"node_modules/seedrandom": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
@ -19837,6 +20287,11 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"node_modules/set-cookie-parser": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
"integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ=="
},
"node_modules/set-function-length": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
@ -21540,6 +21995,14 @@
"node": ">=0.8"
}
},
"node_modules/thread-stream": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.4.1.tgz",
"integrity": "sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==",
"dependencies": {
"real-require": "^0.2.0"
}
},
"node_modules/threads": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz",
@ -21679,6 +22142,14 @@
"node": ">=8.0"
}
},
"node_modules/toad-cache": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz",
"integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==",
"engines": {
"node": ">=12"
}
},
"node_modules/toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",

View file

@ -6,7 +6,11 @@
"scripts": {
"format": "prettier --write \"./backend/src/**/*.{css,html,js,json,ts,tsx}\" \"./dashboard/src/**/*.{css,html,js,json,ts,tsx}\"",
"lint": "eslint \"./backend/src/**/*.{js,ts,tsx}\" \"./dashboard/src/**/*.{js,ts,tsx}\"",
"codestyle-check": "prettier --check \"./backend/src/**/*.{css,html,js,json,ts,tsx}\" \"./dashboard/src/**/*.{css,html,js,json,ts,tsx}\""
"codestyle-check": "prettier --check \"./backend/src/**/*.{css,html,js,json,ts,tsx}\" \"./dashboard/src/**/*.{css,html,js,json,ts,tsx}\"",
"start-bot": "cd backend && npm run start-bot-prod",
"start-api": "cd backend && npm run start-api-prod",
"start-dashboard": "cd dashboard && node serve.js"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.59.5",

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -e
echo Updating Zeppelin...
docker compose -f docker-compose.production.yml stop
git pull
docker compose -f docker-compose.production.yml build
docker compose -f docker-compose.production.yml up -d
echo Update finished!